Skip to content

[ENG-887] Fix internal and external delivery batch failure and refine supply delivery limit UI - #16661

Open
NikhilA8606 wants to merge 19 commits into
developfrom
ENG-887-fix-internal-delivery-batch-failing
Open

[ENG-887] Fix internal and external delivery batch failure and refine supply delivery limit UI#16661
NikhilA8606 wants to merge 19 commits into
developfrom
ENG-887-fix-internal-delivery-batch-failing

Conversation

@NikhilA8606

@NikhilA8606 NikhilA8606 commented Aug 10, 2026

Copy link
Copy Markdown
Member

Entire-Checkpoint: 574e6f6865af

Changes

  • Mark as Complete is enabled only when all supply deliveries are either completed or abandoned.
  • Restricted users from adding more items than the upsert limit for dispatch and purchase deliveries by adding a callout for this scenario.
  • Improved the Callout component by changing the badges type from string to ReactNode; updated the places that use the component
    Fix: ENG-887
Screen.Recording.2026-08-10.at.6.07.34.PM.mov

Tagging: @ohcnetwork/care-fe-code-reviewers

Merge Checklist

  • Add specs that demonstrate the bug or test the new feature.
  • Update product documentation.
  • Ensure that UI text is placed in I18n files.
  • Prepare a screenshot or demo video for the changelog entry and attach it to the issue.
  • Request peer reviews.
  • Complete QA on mobile devices.
  • Complete QA on desktop devices.
  • Add or update Playwright tests for related changes

Summary by CodeRabbit

  • New Features

    • Added a configurable limit for delivery datapoints per request, defaulting to 100.
    • Added loading indicators and disabled actions while deliveries are processing.
    • Improved order-loading labels to show item counts.
  • Bug Fixes

    • Prevented adding or loading deliveries when the configured limit is reached.
    • Added clear alerts when delivery limits are exceeded.
  • Style

    • Updated scheduling and warning callouts with clearer alert icons and presentation.
  • Documentation

    • Documented the configuration option and its backend limit requirement.

Entire-Checkpoint: 574e6f6865af
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 32b88305-75b7-41ff-ab7e-2e22582a25c3

📥 Commits

Reviewing files that changed from the base of the PR and between 88ca1a9 and d5a0115.

📒 Files selected for processing (2)
  • src/pages/Facility/services/inventory/externalSupply/deliveryOrder/AddSupplyDeliveryForm.tsx
  • src/pages/Facility/services/inventory/externalSupply/deliveryOrder/DeliveryOrderShow.tsx

Walkthrough

Adds a configurable maximum of 100 datapoints per upsert request by default. Delivery-order queries and forms enforce the limit. Warning callouts and item-count labels use updated shared presentation and localization.

Changes

Configurable upsert limit and warning UI

Layer / File(s) Summary
Limit configuration and environment contract
.example.env, care.config.ts, scripts/validate-env.ts, src/vite-env.d.ts
Defines and validates REACT_MAX_DATAPOINTS_PER_UPSERT. Exposes maxDatapointsPerUpsert with a default of 100.
Delivery-order limit enforcement
src/pages/Facility/services/inventory/externalSupply/deliveryOrder/DeliveryOrderShow.tsx
Limits supply-delivery queries, tracks fetching state, displays a limit alert, and passes delivery state to the form.
Form limit feedback and controls
src/pages/Facility/services/inventory/externalSupply/deliveryOrder/AddSupplyDeliveryForm.tsx, public/locale/en.json
Displays a localized limit alert and disables add or load controls when existing deliveries and form rows reach the configured limit.
Warning callout and item-count presentation
src/CAREUI/display/Callout.tsx, src/pages/Facility/services/pharmacy/components/AddMedicationReturnItemForm.tsx, src/pages/Scheduling/components/CreateScheduleTemplateSheet.tsx, src/pages/Scheduling/components/EditScheduleTemplateSheet.tsx, public/locale/en.json
Allows React nodes in callout badges, replaces text badges with TriangleAlert icons, and uses count-aware loading translations.

Possibly related PRs

Suggested labels: Type Changes

Suggested reviewers: amjithtitus09, jacobjeevan

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the delivery batch failure fix and supply delivery limit UI changes.
Description check ✅ Passed The description covers the changes, issue link, demo asset, reviewer tag, and merge checklist; incomplete checklist items are explicitly marked.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ENG-887-fix-internal-delivery-batch-failing

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving setSelectedDeliveries([]) into the mutation's onSuccess — fine, actually an improvement, clears selection only after confirmed success instead of optimistically. The maxDatapointsPerUpsert config plumbing (env var, careConfig, validate-env schema) is clean and consistent with the existing patterns.

But the actual enforcement is half-baked: exceedsUpsertLimit only disables the "mark_as_completed" button. The "receive_update_stock" button and the "mark_as_abandoned"/"mark_as_damaged" dropdown items call the same upsertSupplyDeliveries mutation and aren't gated at all — so the whole point of adding this limit is trivially bypassed. Also no user-facing feedback when the limit is hit; a disabled button with no explanation is a UX dead end. Not blocking, but please fix before this ships — otherwise what was the point?> Generated by Grumpy PR Reviewer for #16661 · auto · 25.6 AIC · ⌖ 2.21 AIC · ⊞ 8.7K

return;
}

upsertSupplyDeliveries({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleMarkAsAbandoned/handleMarkAsDamaged/handleSubmitDialog fire the upsert with zero regard for maxDatapointsPerUpsert. You built a limit check but only wired it into one disabled prop — the actual guard belongs in these handlers too (early-return with a toast), otherwise it's just decoration on a single button.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a configurable cap for the maximum number of datapoints sent in a single “upsert” request and starts wiring that limit into the internal inventory delivery-order UI to avoid backend batch failures (ENG-887).

Changes:

  • Adds REACT_MAX_DATAPOINTS_PER_UPSERT env support (typing, validation, example env) and exposes it via careConfig.maxDatapointsPerUpsert.
  • Updates DeliveryOrderShow to use the new config and adjusts selection clearing to happen on successful upsert.
  • Adds a UI flag (exceedsUpsertLimit) intended to prevent invalid oversized operations.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/vite-env.d.ts Adds TypeScript typing for REACT_MAX_DATAPOINTS_PER_UPSERT.
src/pages/Facility/services/inventory/externalSupply/deliveryOrder/DeliveryOrderShow.tsx Introduces upsert-limit flag usage and changes when selection state is cleared.
scripts/validate-env.ts Adds env schema entry for REACT_MAX_DATAPOINTS_PER_UPSERT.
care.config.ts Adds maxDatapointsPerUpsert config with default 100.
.example.env Documents and provides example value for the new env var.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread care.config.ts
Comment thread scripts/validate-env.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/validate-env.ts`:
- Line 173: Replace the numberAsString schema for
REACT_MAX_DATAPOINTS_PER_UPSERT with validation that accepts only positive
integer values and rejects decimals, exponent notation, trailing characters, and
other malformed strings; preserve its optional behavior.

In
`@src/pages/Facility/services/inventory/externalSupply/deliveryOrder/DeliveryOrderShow.tsx`:
- Around line 257-259: Enforce the configured datapoint limit at every
supply-delivery upsert boundary, not only in the completion-button condition.
Add the limit check to the receive, abandon, damaged, and confirmation controls,
and re-check it immediately before calling upsertSupplyDeliveries in
handleMarkAsAbandoned, handleMarkAsDamaged, and handleSubmitDialog; preserve the
existing behavior for valid selections within the limit.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 89d1c966-b385-490e-a58c-fa341b09ed23

📥 Commits

Reviewing files that changed from the base of the PR and between b4b3ed2 and 8af2fcc.

📒 Files selected for processing (5)
  • .example.env
  • care.config.ts
  • scripts/validate-env.ts
  • src/pages/Facility/services/inventory/externalSupply/deliveryOrder/DeliveryOrderShow.tsx
  • src/vite-env.d.ts

Comment thread scripts/validate-env.ts
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

🎭 Playwright Test Results

Status: ✅ Passed
Test Shards: 3

Metric Count
Total Tests 358
✅ Passed 358
❌ Failed 0
⏭️ Skipped 0

📊 Detailed results are available in the playwright-final-report artifact.

Run: #10983

@rithviknishad rithviknishad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now that we have a baseline value of what we limit, we could set a a limit of 100 in the query, so that we don't need like 7 API calls to fetch ~100 deliveries. we could optimize our query to return in one API call instead of waiting to loop through all pages.

@rithviknishad rithviknishad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this still fails... why don't we disable the button now that we know the upsert limit?

should we think of pre-selcting first 100 items only?

should we give a hint that this order contains more than 100 items?

Image

@NikhilA8606
NikhilA8606 marked this pull request as draft August 10, 2026 17:00
… allowed limit

Entire-Checkpoint: 719ada336ce6
Copilot AI review requested due to automatic review settings August 11, 2026 12:22
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 11, 2026

Copy link
Copy Markdown

Deploying care-preview with  Cloudflare Pages  Cloudflare Pages

Latest commit: dcc43a2
Status: ✅  Deploy successful!
Preview URL: https://5db34ffa.care-preview-a7w.pages.dev
Branch Preview URL: https://eng-887-fix-internal-deliver.care-preview-a7w.pages.dev

View logs

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a draft PR ("Changes Required"/"Work in Progress" labels), so I'm not surprised there are loose ends. The env var plumbing and i18n additions are fine — that part's competent. But the frontend limit-checking logic is inconsistent across three places (page-length vs. total-count vs. count+in-form-fields), which will cause the button-disabled state and the warning banner to disagree in edge cases. Tighten that up into one shared derivation before this leaves draft. Also worth double-checking: does the backend actually reject requests over the limit with a clear error, or does the frontend cap silently mask a server 400? Not blocking, just tidy it up.> Generated by Grumpy PR Reviewer for #16661 · auto · 20.1 AIC · ⌖ 2.18 AIC · ⊞ 8.7K

@NikhilA8606

Copy link
Copy Markdown
Member Author

now that we have a baseline value of what we limit, we could set a a limit of 100 in the query, so that we don't need like 7 API calls to fetch ~100 deliveries. we could optimize our query to return in one API call instead of waiting to loop through all pages.

The Mark as Complete button was enabled even when the upsert request failed. Based on the discussion with @amjithtitus09, we initially decided to disable the button in that case. However, after the recent discussion with you and @amjithtitus09, I restricted users from creating requests more than limit by adding a callout card on the request creation page.

@github-actions github-actions Bot added needs-triage question Further information is requested labels Aug 11, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (4)

src/CAREUI/display/Callout.tsx:33

  • Callout wraps children in a <span>, which creates invalid HTML when callers pass block elements (e.g., a <p> in EditScheduleTemplateSheet). This can break layout and accessibility; render children in a block container instead of an inline span.
      <span className="font-medium">{props.badge}</span>
      <div className="flex-1">
        <span className="font-medium">{props.children}</span>
      </div>

src/pages/Scheduling/components/CreateScheduleTemplateSheet.tsx:57

  • Import order: lucide-react is a 3rd‑party import but it is currently placed after local @/types/... imports. This deviates from the repo import ordering convention (AGENTS.md:35) and may get auto-reordered by formatting/linting.
import scheduleApis from "@/types/scheduling/scheduleApi";
import { Info } from "lucide-react";

public/locale/en.json:3182

  • load_from_order_with_items will render as "1 items" when count is 1. The code already passes count, so this should use i18next plural forms (_one/_other) like other keys in this file (e.g. age_days_one/other).
  "load_from_order_with_items": "Load from order ({{count}} items)",

public/locale/en.json:3062

  • item_limit_reached is added to the English locale but is not referenced anywhere in the codebase. Unused i18n keys add noise and make it harder to manage translations.
  "item_condition": "Item Condition?",
  "item_limit_reached": "Item limit reached",
  "item_location": "Item Location",

Entire-Checkpoint: 00bc0064be36
Copilot AI review requested due to automatic review settings August 17, 2026 07:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 11 changed files in this pull request and generated 1 comment.

Suppressed comments (3)

src/CAREUI/display/Callout.tsx:33

  • The Callout badge change is described as a type update (string → ReactNode), but this change also removes the badge container styling (rounded/bordered pill). That will alter the appearance of all existing callouts and pushes styling responsibility to each caller. Consider keeping the pill wrapper and rendering the ReactNode inside it so the visual design stays consistent while still supporting icons/custom nodes.
      <span className="font-medium">{props.badge}</span>
      <div className="flex-1">
        <span className="font-medium">{props.children}</span>
      </div>

src/pages/Scheduling/components/CreateScheduleTemplateSheet.tsx:57

  • The lucide-react import is currently placed after internal @/ imports. In nearby files (e.g., EditScheduleTemplateSheet.tsx:1-10), third-party imports (including lucide-react) are grouped at the top before local module imports; keeping the same ordering avoids churn and potential lint/format noise.
  SchedulableResourceType,
  ScheduleAvailabilityCreateRequest,
} from "@/types/scheduling/schedule";
import scheduleApis from "@/types/scheduling/scheduleApi";
import { Info } from "lucide-react";

src/pages/Facility/services/inventory/externalSupply/deliveryOrder/AddSupplyDeliveryForm.tsx:916

  • The upsert-limit UI prevents adding rows one-by-one, but it can still be bypassed by “Load from order”: handleSelectRequests sets the full selected request list into items without enforcing the remaining maxDatapointsPerUpsert capacity. That allows the form to end up with more than the configured maximum items and defeats the intended guardrail.
                  {supplyDeliveriesCount + fields.length >=
                  careConfig.maxDatapointsPerUpsert ? (
                    <Callout
                      variant="warning"
                      className="border border-amber-300 bg-amber-50 text-amber-800"

Comment thread public/locale/en.json
Entire-Checkpoint: 00ca5a250fd0
Copilot AI review requested due to automatic review settings August 17, 2026 08:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated no new comments.

Suppressed comments (4)

src/CAREUI/display/Callout.tsx:33

  • Callout wraps children in a <span className="font-medium">, but several new call sites pass block-level content (e.g. <p> and <Trans>). This produces invalid HTML (<span><p>…</p></span>) and also forces medium font-weight on all content, which is hard to override from call sites.
      <span className="font-medium">{props.badge}</span>
      <div className="flex-1">
        <span className="font-medium">{props.children}</span>
      </div>

src/pages/Facility/services/inventory/externalSupply/deliveryOrder/AddSupplyDeliveryForm.tsx:250

  • disableAddItem only considers existing supplyDeliveriesCount, so the UI can still allow adding items beyond the upsert limit within the current form session (via fields.length). This defeats the intended guardrail when users keep adding rows before saving.
  const hasReachedUpsertLimit =
    supplyDeliveriesCount >= careConfig.maxDatapointsPerUpsert;

  const disableAddItem =
    isProcessing || hasReachedUpsertLimit || isFetchingSupplyDeliveries;

public/locale/en.json:3182

  • load_from_order_with_items always renders “{{count}} items”, which leads to incorrect grammar for count = 1 ("1 items"). Use i18next plural forms (_one/_other) so the UI stays correct for all counts.
  "load_from_order_with_items": "Load from order ({{count}} items)",

care.config.ts:412

  • Minor grammar in the new config doc: “set with whatever backend sets” reads incorrectly and is a bit unclear.
   * This should be set with whatever backend sets.

Copilot AI review requested due to automatic review settings August 17, 2026 08:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (4)

src/pages/Facility/services/inventory/externalSupply/deliveryOrder/AddSupplyDeliveryForm.tsx:948

  • The visible button label now includes the item count (e.g., "Load from order (N items)"). Existing Playwright tests in tests/facility/services/locations/inventory/toDispatch.spec.ts use getByRole(..., { name: "Load from order" }), which will no longer match and will fail CI unless the tests/selectors are updated (or a stable accessible name is provided).
                        >
                          {t("load_from_order_with_items", {
                            count: supplyRequests.count,
                          })}
                          <ShortcutBadge actionId="load-from-order" />

src/CAREUI/display/Callout.tsx:33

  • Callout wraps children in a <span>, which produces invalid HTML when callers pass block-level elements (e.g., <p> in the scheduling sheets). Rendering block content inside a span can break layout and accessibility; render children without forcing an inline wrapper.
      <span className="font-medium">{props.badge}</span>
      <div className="flex-1">
        <span className="font-medium">{props.children}</span>
      </div>

care.config.ts:413

  • The config comment is unclear/grammatically incorrect ("set with whatever backend sets"). Please clarify that this value should match the backend limit so it’s obvious how to configure it safely.
  /**
   * Maximum number of datapoints allowed in a single upsert request.
   * This should be set with whatever backend sets.
   */

src/pages/Facility/services/inventory/externalSupply/deliveryOrder/DeliveryOrderShow.tsx:881

  • This warning is shown when selectedDeliveries.length exceeds the upsert limit (i.e., the user is trying to process too many deliveries at once), but the i18n string says "You cannot add more than {{count}} items in a single delivery." This can confuse users because they are not adding items here. Consider using a separate i18n key/message for selection/upsert limits (or making the wording generic enough for both contexts).
          {!isWithinUpsertLimit && (
            <div className="px-4">
              <Callout
                variant="warning"
                className="border border-amber-300 bg-amber-50 text-amber-800"
                badge={
                  <TriangleAlert className="size-4 shrink-0 text-amber-600" />
                }
              >
                <span className="flex items-center gap-2">
                  {t("max_datapoints_per_upsert_limit", {
                    count: careConfig.maxDatapointsPerUpsert,
                  })}
                </span>
              </Callout>

Entire-Checkpoint: eab7388455ac
Copilot AI review requested due to automatic review settings August 17, 2026 10:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated no new comments.

Suppressed comments (6)

src/pages/Facility/services/inventory/externalSupply/deliveryOrder/DeliveryOrderShow.tsx:491

  • hasReachedUpsertLimit is derived from the total number of existing supplyDeliveries (results.length). However, careConfig.maxDatapointsPerUpsert is documented as a per-request limit (see care.config.ts), and the UI copy says the user cannot add/update more than N in a single request. Using the total existing deliveries to block/hide create UI will incorrectly prevent users from adding deliveries in multiple batches once an order exceeds the limit.

Consider removing the hasReachedUpsertLimit checks that are based on supplyDeliveries.results.length and enforce the limit only on the request payload size (e.g. the number of items being submitted / the number of selected deliveries being upserted).

  const hasReachedUpsertLimit =
    supplyDeliveries &&
    supplyDeliveries.results.length >= careConfig.maxDatapointsPerUpsert;

  const isWithinUpsertLimit =

src/pages/Facility/services/inventory/externalSupply/deliveryOrder/AddSupplyDeliveryForm.tsx:914

  • This limit check adds supplyDeliveriesCount (existing deliveries in the order) to fields.length (items in the current create request). The backend limit being enforced here is per request payload size, so existing deliveries should not affect whether the user can add another item to the current request.
                  {supplyDeliveriesCount + fields.length >=
                  careConfig.maxDatapointsPerUpsert ? (
                    <Callout

src/pages/Facility/services/inventory/externalSupply/deliveryOrder/DeliveryOrderShow.tsx:284

  • The supplyDeliveries query runs unconditionally. If deliveryOrderId is temporarily undefined (or falsy during routing transitions), this will issue a request with an invalid order query param and can produce avoidable 4xx/network noise. The previous enabled: !!deliveryOrderId guard should be kept.

This issue also appears on line 487 of the same file.

  const {
    data: supplyDeliveries,
    isLoading: isLoadingSupplyDeliveries,
    isFetching: isFetchingSupplyDeliveries,
  } = useQuery({

src/pages/Facility/services/inventory/externalSupply/deliveryOrder/AddSupplyDeliveryForm.tsx:250

  • hasReachedUpsertLimit is computed from supplyDeliveriesCount (deliveries already present in the order). That will disable adding items to a new delivery request as soon as the order has >= N deliveries, even if the current request only contains a few items. This should be based on the number of items being submitted in the current request (fields.length / data.items.length).

This issue also appears on line 912 of the same file.

  const hasReachedUpsertLimit =
    supplyDeliveriesCount >= careConfig.maxDatapointsPerUpsert;

  const disableAddItem =
    isProcessing || hasReachedUpsertLimit || isFetchingSupplyDeliveries;

public/locale/en.json:3409

  • This message says "in a single delivery", but the key is used for enforcing a per-request limit (both for creating/upserting). The wording should reflect a request/action limit rather than a delivery entity.
  "max_datapoints_per_upsert_limit": "You cannot add more than {{count}} items in a single delivery.",

src/CAREUI/display/Callout.tsx:33

  • Wrapping children in a <span> can produce invalid HTML when callers pass block elements (e.g. <p>), which can affect semantics and accessibility. Render children directly in the block container instead.

(Separately: removing the old badge wrapper changes the visual styling for string badges across the app; if that wasn’t intentional, consider reintroducing the wrapper with a ReactNode-friendly implementation.)

      <span className="font-medium">{props.badge}</span>
      <div className="flex-1">
        <span className="font-medium">{props.children}</span>
      </div>

@nihal467 nihal467 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

For both the PO and Internal Order, enforce the maximum item limit of 100 items. This is required to ensure compatibility with the PD item load feature.

Add a scroller in the internal supply delivery item popup

Entire-Checkpoint: 5c90ecdb25bd

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sighs, puts down coffee.

The intent here is fine — gating "Mark as Complete" and stopping users from blowing past the backend upsert limit is genuinely worth doing. The execution has a few holes that will bite in production:

  1. every() on an empty array returns true. A delivery order with zero deliveries will happily report "all completed or abandoned" and re-enable the very button you were trying to gate.
  2. enabled: !!deliveryOrderId was silently dropped from the supplyDeliveries query while adding pageSize.
  3. isWithinUpsertLimit is dead logic. You capped the page size at the limit, then check whether a selection derived from that page exceeds the limit. It can't. The Callout it guards will never render.
  4. Off-by-one on the limit checks in both AddItemsForm and AddSupplyDeliveryForm — users are blocked one item early.
  5. Copy-paste. The identical amber Callout + TriangleAlert block appears three times, with hardcoded colour classes that arguably belong inside the warning variant you just gutted.

Also: the i18n string says "in a single delivery" but is reused for supply requests, and there are no tests covering the new gating logic despite the checklist item sitting unticked.

Fix 1–3 before merging; the rest is housekeeping. Not blocking, but don't pretend you didn't read this.> Generated by Grumpy PR Reviewer for #16661 · opus50 · 54.4 AIC · ⌖ 2.14 AIC · ⊞ 8.7K

Comment thread public/locale/en.json
Comment thread src/CAREUI/display/Callout.tsx

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/CAREUI/display/Callout.tsx:33

  • Callout now allows badge to be any ReactNode, but it renders both badge and children inside <span> elements. This can produce invalid DOM nesting (e.g., if badge/children contains a <div>/<p>/other block element) and can trigger validateDOMNesting warnings. Prefer rendering these nodes inside <div> containers and avoid wrapping children in a <span>.
      <span className="font-medium">{props.badge}</span>
      <div className="flex-1">
        <span className="font-medium">{props.children}</span>
      </div>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CARE Review — cap supply-delivery/request batches at a configurable upsert limit

What it does: adds maxDatapointsPerUpsert (env-configurable, default 100), uses it as the query.paginated page size for supply deliveries, and gates the add/load controls plus the bulk status actions on it. Separately: "Mark as Completed" now also requires every delivery to be completed or abandoned, and Callout's badge becomes a ReactNode so call sites can pass icons.

The direction is right — one config value, derived in the places that need it, rather than a magic number. Three things are worth fixing before merge.

Correctness

  • allSupplyDeliveriesCompletedOrAbandoned uses every on a possibly-empty array, so an order with zero deliveries enables "Mark as Completed" — the inverse of the stated intent.
  • isWithinUpsertLimit (<=) and hasReachedUpsertLimit (>=) disagree at exactly max. One of them is off by one; the copy ("cannot add more than N") says which.
  • enabled: !!deliveryOrderId was dropped from the deliveries query, seemingly incidentally.

Legibility / single source of truth

  • AddSupplyDeliveryForm computes the limit two different ways in one component. Because the parent already unmounts the form at the limit, the version wired into disableAddItem can never be true — so the buttons and the in-form Callout can disagree. Derive it once.

Approach

  • handleSelectRequests ("select all" → setValue("items", ...)) is the bulk path that caused the original batch failure and is the one place with no cap. Everything else added here guards single-row entry.
  • The Callout change removes variant-derived badge styling from a shared CAREUI primitive, and every call site in this PR now hardcodes a colour to compensate. An icon prop that maps colour from variant would keep the abstraction doing its job.

The amber classes on the callouts (border-amber-300 bg-amber-50 text-amber-800) are redundant with variant="warning", which already resolves to the same amber ramp via --color-warning-*. Dropping the overrides would let the token do the work — minor, and I've not commented inline on it.

Note: several earlier bot threads on this PR claimed the page-size/total-count mismatch was a bug. query.paginated loops until all pages are fetched, so results.length === count here; those look moot and I've not repeated them.

Generated by CARE PR Reviewer for #16661 · opus50 · 269.4 AIC · ⌖ 3.19 AIC · ⊞ 19.4K

Comments that could not be inline-anchored

src/CAREUI/display/Callout.tsx:30

Deleting the badge pill removes the only variant-aware styling the badge had, for every Callout in the app — and it's a shared CAREUI primitive. The knock-on effect is visible in this same PR: each call site now hardcodes the colour the component used to derive (text-purple-500, text-warning-700, text-amber-600), which is exactly what the variant prop existed to avoid.

A smaller change that keeps the contract: keep the variant map and render the badge unwrapped only when it isn't a s…

src/pages/Facility/services/inventory/externalSupply/deliveryOrder/DeliveryOrderShow.tsx:492

isWithinUpsertLimit uses &lt;=, so at exactly maxDatapointsPerUpsert selected deliveries the buttons stay enabled and the request goes out with count === max. Meanwhile the sibling gate two lines up uses &gt;= (hasReachedUpsertLimit), and the copy says "You cannot add more than {{count}} items". Two boundaries in the same block that disagree about whether max is allowed.

If the backend cap is "at most N per request" then &lt;= is right and hasReachedUpsertLimit should be &gt; — pick …

src/pages/Facility/services/inventory/externalSupply/deliveryOrder/DeliveryOrderShow.tsx:474

Array.prototype.every returns true for an empty array, so when the order has zero supply deliveries this evaluates to true and "Mark as Completed" is enabled — the opposite of the PR's stated intent ("enabled only when all supply deliveries are either completed or abandoned").

The ?? false only guards supplyDeliveries being nullish, not results being empty. Needs a length check as well:

const allSupplyDeliveriesCompletedOrAbandoned =
  !!supplyDeliveries?.results.length 

</details>

<details><summary>src/pages/Facility/services/inventory/externalSupply/deliveryOrder/DeliveryOrderShow.tsx:281</summary>

`enabled: !!deliveryOrderId` was dropped along with the `pageSize` addition. That looks incidental rather than intended  the query will now fire even when `deliveryOrderId` is falsy, issuing a request with `order: undefined`. If it was removed deliberately (because the route guarantees the id), worth saying so; otherwise put it back, it&#39;s unrelated to the pageSize change.

</details>

<details><summary>src/pages/Facility/services/inventory/externalSupply/deliveryOrder/AddSupplyDeliveryForm.tsx:245</summary>

Two formulas for the same limit in one component: `hasReachedUpsertLimit` (drives `disableAddItem` on all four add/load buttons) counts only `supplyDeliveriesCount`, while the render gate at ~line 912 counts `supplyDeliveriesCount + fields.length`. Since the parent only mounts this form when `supplyDeliveriesCount &lt; max`, `hasReachedUpsertLimit` is effectively always `false` here — so &quot;Add another&quot; and &quot;Load from order&quot; stay enabled right up until the row-count gate swaps them out.

Derive one …

</details>

<details><summary>src/pages/Facility/services/inventory/externalSupply/deliveryOrder/AddSupplyDeliveryForm.tsx:306</summary>

`handleSelectRequests` does `form.setValue(&quot;items&quot;, itemsFromRequests)` with the full selection — this is the bulk path that produced the original batch failure, and it&#39;s the one path with no limit check. &quot;Select all&quot; on an order with more than `maxDatapointsPerUpsert` requests loads them all, and `onSubmit` then fires them. The disabled props you added guard entering the dialog, not what comes out of it.

A cap here (truncate + toast, or block confirm with the count) would make the limit actua…

</details>

<details><summary>src/pages/Facility/services/inventory/externalSupply/requestOrder/AddItemsForm.tsx:222</summary>

When the limit is hit you replace `ProductKnowledgeSelect` with the Callout, and `-{t(&quot;or&quot;)}-` gets `hidden` — but the block below still offers the alternate entry path, so the user sees a &quot;cannot add more&quot; warning next to controls that still add items. Disabling the select (`disabled={hasReachedUpsertLimit}`) and rendering the Callout *alongside* it keeps the layout stable and the state honest, rather than swapping controls out and then patching the leftover separator with `hidden`.

</details>

<details><summary>public/locale/en.json:3061</summary>

`item_limit_reached` doesn&#39;t appear to be referenced anywhere in the PR&#39;s changed files — the callouts all use `max_datapoints_per_upsert_limit`. If it&#39;s leftover from an earlier iteration, drop it; `npm run knip` in CI flags unused keys.

</details>

Entire-Checkpoint: f0933eca5b3d

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generated by Grumpy PR Reviewer for #16661 · opus50 · 62.3 AIC · ⌖ 2.12 AIC · ⊞ 8.7K

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/pages/Facility/services/inventory/externalSupply/requestOrder/RequestOrderShow.tsx:760

  • supplyRequestsCount is currently derived from supplyRequests.results.length, which only reflects the current page size of the paginated response. This can undercount existing items and allow users to exceed maxDatapointsPerUpsert once there are multiple pages of supply requests.
                              supplyRequestsCount={
                                supplyRequests?.results.length || 0
                              }

public/locale/en.json:3409

  • The message for max_datapoints_per_upsert_limit mentions "in a single delivery", but this key is used in multiple contexts (adding request items, adding deliveries, bulk status updates). The wording should be generic so it remains accurate everywhere it’s shown.
  "max_datapoints_per_upsert_limit": "You cannot add more than {{count}} items in a single delivery.",

care.config.ts:413

  • The doc comment for maxDatapointsPerUpsert says it is a limit for a "single upsert request", but it’s also used to cap total items/deliveries shown/added in UI flows (and as a page size). This is misleading for operators configuring the env var.
  /**
   * Maximum number of datapoints allowed in a single upsert request.
   * This should be set with whatever backend sets.
   */

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CARE Review — gating "Mark as Completed" on delivery status, plus upsert-limit UI in the request-order item form

Re-review. Scope is the 7 commits since my last pass on 2026-08-14 (0ba9beac, 5392e1a7, a1b51bcd, 66c7c291, 78188bef, 9445a5c3, e09e007d).

Prior findings — both confirmed fixed. The pageSize vs limit issue on the deliveries query (9432850f) and the disableAddItem hoist (2692ceb7) are resolved; both threads closed.

Intent

Two distinct changes in this delta, both legible:

  1. Mark as Completed on a delivery order is now gated on every delivery having reached completed or abandoned, so an order can no longer be closed while deliveries are still in flight. e09e007d correctly tightened this so an empty list does not satisfy every(). The Playwright update in 78188bef follows from the gate rather than papering over it — a real receive step now precedes the completion assertion. Good.
  2. The upsert cap is surfaced in AddItemsForm the way it already is in AddSupplyDeliveryForm, and 5392e1a7 extends the existing cap check to mark_as_abandoned / mark_as_damaged — those bulk-mutate the same way the Receive button does, so the rename to isWithinUpsertLimit and the wider application both read correctly.

Open items

  • DeliveryOrderShow.tsx:479entered_in_error is a fourth SupplyDeliveryStatus and is not accounted for, so one errored delivery can permanently block completing the order. This is the one I would not merge without an answer.
  • AddItemsForm.tsx:91 / :222 — the >= boundary blocks the last allowed item, and hiding the selector rather than disabling it leaves no way to back out once the limit trips. Also worth confirming maxDatapointsPerUpsert is even the right cap here, since this form POSTs one createSupplyRequest per row rather than using the upsert endpoint.

Retraction

I left a comment on DeliveryOrderShow.tsx:493 claiming isWithinUpsertLimit is always true because the query is capped at pageSize. That is wrong — please disregard it. query.paginated loops until items.length >= res.count (src/Utils/request/query.ts:170), so pageSize only sets the per-request size; results is the full set and can exceed the cap. The guard is live and the rename is correct.

Nothing to raise on the approach lens — the changes reuse the existing limit/callout pattern rather than inventing anything, and the diff stays proportionate.

Not re-raising the Callout badge/amber-token and boundary discussions already settled in other threads.

Generated by CARE PR Reviewer for #16661 · opus50 · 414.5 AIC · ⌖ 4.62 AIC · ⊞ 19.4K

@github-actions

Copy link
Copy Markdown

Conflicts have been detected against the base branch. Please merge the base branch into your branch.
cc: @NikhilA8606

See: https://docs.ohc.network/docs/contributing#how-to-resolve-merge-conflicts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/pages/Facility/services/inventory/externalSupply/deliveryOrder/DeliveryOrderShow.tsx:480

  • allSupplyDeliveriesCompletedOrAbandoned is forced to false when there are 0 supply deliveries due to the !!...length guard, which keeps “Mark as Completed” disabled even though the PR description says it should be enabled when all deliveries are completed or abandoned (an empty list should satisfy that condition).
  const allSupplyDeliveriesCompletedOrAbandoned =
    !!supplyDeliveries?.results?.length &&
    supplyDeliveries.results.every(
      (delivery) =>
        delivery.status === SupplyDeliveryStatus.completed ||

src/CAREUI/display/Callout.tsx:33

  • The Callout badge styling (bordered pill with variant-specific border color) was removed. If the intent was only to change the badge type to ReactNode, consider preserving the existing badge container so current Callout layouts don’t regress visually.
      <span className="font-medium">{props.badge}</span>
      <div className="flex-1">
        <span className="font-medium">{props.children}</span>
      </div>

public/locale/en.json:3461

  • This message is shown in both request-order item addition and delivery item addition flows; referencing “single delivery” is misleading in the request-order context. Consider making it generic to the upsert/request limit.
  "max_datapoints_per_upsert_limit": "You cannot add more than {{count}} items in a single delivery.",

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs review P1 breaking issue or vital feature Tested

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants