Detail: Merge scraper, stale-data reason, and raw scrape log into one Source card #30

Closed
opened 2026-06-27 15:41:15 +02:00 by bullitt · 1 comment
Owner

Problem

When a shipment is stalled, the detail page shows three consecutive cards for the same concern:

  1. A "Stalled — no further updates expected" warning card (amber border)
  2. A "Scraper" card (Fail Count, Scrape Now, Enable/Disable buttons)
  3. A "Scrape Log" collapsible card

All three relate to scraping status. The fragmentation adds visual noise and scroll depth.

Implementation

File: frontend/src/pages/ShipmentDetail.tsx

Merge all three into a single <Card> with sections:

<Card className={shipment.stalled ? "border-amber-300 dark:border-amber-700" : undefined}>
  <CardHeader className="pb-2">
    <div className="flex items-center justify-between">
      <CardTitle className="text-base">Scraper</CardTitle>
      <div className="flex items-center gap-2">
        {/* enabled/disabled badge */}
        {/* last scraped time */}
      </div>
    </div>
  </CardHeader>
  <CardContent className="space-y-3">
    {/* Stall warning inline — only if stalled */}
    {shipment.stalled && (
      <div className="flex items-start gap-2 p-3 rounded-md bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-400 text-sm">
        <AlertTriangle className="h-4 w-4 shrink-0 mt-0.5" />
        <div>
          <p className="font-medium">No further updates expected</p>
          {/* stall reason details + re-enable button */}
        </div>
      </div>
    )}

    {/* Stats grid */}
    <div className="grid grid-cols-2 sm:grid-cols-3 gap-3 text-sm">
      <div><span className="text-xs text-muted-foreground block">Fail Count</span>...</div>
      <div><span className="text-xs text-muted-foreground block">Last Scraped</span>...</div>
    </div>

    {/* Action buttons */}
    <div className="flex items-center gap-2">
      <Button size="sm" variant="outline" onClick={handleScrapeNow}>Scrape Now</Button>
      <Button size="sm" variant="ghost" onClick={() => handleToggleScrape(!shipment.scrape_enabled)}>
        {shipment.scrape_enabled ? "Disable" : "Enable"}
      </Button>
    </div>

    {/* Collapsible scrape log — inline */}
    <button onClick={() => setScrapeLogOpen(!scrapeLogOpen)} className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground">
      <ChevronDown className={cn("h-3.5 w-3.5 transition-transform", scrapeLogOpen && "rotate-180")} />
      {scrapeLogOpen ? "Hide" : "Show"} scrape log
    </button>
    {scrapeLogOpen && <ScrapeLogTable entries={scrapeLog} />}
  </CardContent>
</Card>

Delete the original three separate card blocks for stalled warning, scraper, and scrape log.

Acceptance criteria

  • One "Scraper" card replaces three separate cards
  • Stall warning appears inline within the card when shipment.stalled is true
  • Scrape log is still collapsible, now as a section within the card
  • All existing actions (Scrape Now, Enable/Disable, Re-enable Scraping) still work

Brand identity alignment

The brand brief stresses data transparency: users should see source, sync state, raw event availability, and uncertainty in one coherent place. This issue should reframe the merged card as a Trackbox Source or Carrier sync surface, not just a generic scraper admin card.

Brand-compliant implementation notes

  • Preferred title: Source & sync or Carrier sync; Scraper can remain as a smaller technical label inside the card.
  • Include structured fields for Source, Last sync, Last carrier update, Sync state, and Raw events when data exists.
  • Inline stale/delayed warning should use calm copy such as Carrier data unavailable, No new events, or Delivery may be delayed.
  • Keep the raw scrape log collapsible with a thin-divider section and monospace log snippets.
  • Use amber/red only for semantic sync problems; normal sync state should stay neutral or green.

Additional acceptance criteria

  • The merged card makes carrier/source reliability easier to audit.
  • Raw scrape log access remains available but secondary.
  • The visual hierarchy supports normal users first and technical debugging second.

Migrated from GitHub issue #9: https://github.com/bullitt186/trackbox/issues/9
Original author: @bullitt186
Original created: 2026-06-27T13:23:28Z
Original labels: ux

## Problem When a shipment is stalled, the detail page shows three consecutive cards for the same concern: 1. A "Stalled — no further updates expected" warning card (amber border) 2. A "Scraper" card (Fail Count, Scrape Now, Enable/Disable buttons) 3. A "Scrape Log" collapsible card All three relate to scraping status. The fragmentation adds visual noise and scroll depth. ## Implementation File: `frontend/src/pages/ShipmentDetail.tsx` Merge all three into a single `<Card>` with sections: ```tsx <Card className={shipment.stalled ? "border-amber-300 dark:border-amber-700" : undefined}> <CardHeader className="pb-2"> <div className="flex items-center justify-between"> <CardTitle className="text-base">Scraper</CardTitle> <div className="flex items-center gap-2"> {/* enabled/disabled badge */} {/* last scraped time */} </div> </div> </CardHeader> <CardContent className="space-y-3"> {/* Stall warning inline — only if stalled */} {shipment.stalled && ( <div className="flex items-start gap-2 p-3 rounded-md bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-400 text-sm"> <AlertTriangle className="h-4 w-4 shrink-0 mt-0.5" /> <div> <p className="font-medium">No further updates expected</p> {/* stall reason details + re-enable button */} </div> </div> )} {/* Stats grid */} <div className="grid grid-cols-2 sm:grid-cols-3 gap-3 text-sm"> <div><span className="text-xs text-muted-foreground block">Fail Count</span>...</div> <div><span className="text-xs text-muted-foreground block">Last Scraped</span>...</div> </div> {/* Action buttons */} <div className="flex items-center gap-2"> <Button size="sm" variant="outline" onClick={handleScrapeNow}>Scrape Now</Button> <Button size="sm" variant="ghost" onClick={() => handleToggleScrape(!shipment.scrape_enabled)}> {shipment.scrape_enabled ? "Disable" : "Enable"} </Button> </div> {/* Collapsible scrape log — inline */} <button onClick={() => setScrapeLogOpen(!scrapeLogOpen)} className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground"> <ChevronDown className={cn("h-3.5 w-3.5 transition-transform", scrapeLogOpen && "rotate-180")} /> {scrapeLogOpen ? "Hide" : "Show"} scrape log </button> {scrapeLogOpen && <ScrapeLogTable entries={scrapeLog} />} </CardContent> </Card> ``` Delete the original three separate card blocks for stalled warning, scraper, and scrape log. ## Acceptance criteria - One "Scraper" card replaces three separate cards - Stall warning appears inline within the card when `shipment.stalled` is true - Scrape log is still collapsible, now as a section within the card - All existing actions (Scrape Now, Enable/Disable, Re-enable Scraping) still work ## Brand identity alignment The brand brief stresses data transparency: users should see source, sync state, raw event availability, and uncertainty in one coherent place. This issue should reframe the merged card as a Trackbox `Source` or `Carrier sync` surface, not just a generic scraper admin card. ## Brand-compliant implementation notes - Preferred title: `Source & sync` or `Carrier sync`; `Scraper` can remain as a smaller technical label inside the card. - Include structured fields for `Source`, `Last sync`, `Last carrier update`, `Sync state`, and `Raw events` when data exists. - Inline stale/delayed warning should use calm copy such as `Carrier data unavailable`, `No new events`, or `Delivery may be delayed`. - Keep the raw scrape log collapsible with a thin-divider section and monospace log snippets. - Use amber/red only for semantic sync problems; normal sync state should stay neutral or green. ## Additional acceptance criteria - The merged card makes carrier/source reliability easier to audit. - Raw scrape log access remains available but secondary. - The visual hierarchy supports normal users first and technical debugging second. --- Migrated from GitHub issue #9: https://github.com/bullitt186/trackbox/issues/9 Original author: @bullitt186 Original created: 2026-06-27T13:23:28Z Original labels: ux
bullitt changed title from Detail: Merge Stalled card, Scraper card, and Scrape Log into one 'Scraper' card to Detail: Merge scraper, stale-data reason, and raw scrape log into one Source card 2026-06-27 15:46:21 +02:00
Author
Owner

Implemented in commit bd6b0e7 as part of the Source & sync card merge (also resolves #48 and #49). The separate stall card, scraper card, and scrape log card have been replaced with a single 'Source & sync' card. Stall warning appears inline only when stalled (amber, with AlertTriangle icon). Stats grid shows fail count and last sync. Actions (Scrape Now, Enable/Disable, Re-enable) are inline. The scrape log is collapsible with a rotating ChevronDown. This reduces scroll depth and frames the surface as user-owned sync status rather than admin debug output.

Implemented in commit bd6b0e7 as part of the Source & sync card merge (also resolves #48 and #49). The separate stall card, scraper card, and scrape log card have been replaced with a single 'Source & sync' card. Stall warning appears inline only when stalled (amber, with AlertTriangle icon). Stats grid shows fail count and last sync. Actions (Scrape Now, Enable/Disable, Re-enable) are inline. The scrape log is collapsible with a rotating ChevronDown. This reduces scroll depth and frames the surface as user-owned sync status rather than admin debug output.
Sign in to join this conversation.
No labels
arch
harness
security
ux
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
bullitt/trackbox#30
No description provided.