Commit graph

1163 commits

Author SHA1 Message Date
Alexandre Brandizzi
eb01c59471 test(uplifts): drop the ticket key from the Approved on WO test name 2026-09-24 23:03:42 -03:00
Alexandre Brandizzi
d573ab59a9 refactor(vendor-portal): extract document row from VendorPortalDocuments
The changed-file maintainability gate caps functions at 150 lines;
VendorPortalDocuments reached 156. Move the per-document row into
VendorPortalDocumentRow with no behavior change.
2026-09-24 23:03:23 -03:00
Alexandre Brandizzi
b8d24d75a3 test(uplifts): cover an unknown row total with nothing granted on the WO (SH-394) 2026-09-24 23:00:27 -03:00
Alexandre Brandizzi
ec3f97dcf6 fix(uplifts): show a dash for Approved on WO when nothing is granted (SH-394)
A work order with a zero granted total rendered $0.00 in the Pending
table's Approved on WO column and in the detail modal's Total line.
Both now share isGrantedAmount, so zero or unknown totals render a dash
and the column always matches the modal Total.
2026-09-24 22:54:39 -03:00
Alexandre Brandizzi
6012ebabe7 fix(media): count HEIC and untyped phone files, guard overlapping picks
Persisted HEIC files and local files with an empty or octet-stream type
were classified as "other", so they did not count toward the 10 photo /
3 video limit. Both classifiers now recognise them by extension.

The Photos & Videos uploader and Extra Docs ignore a new selection while
the previous one is still being screened, and the vendor portal drops an
earlier pick whose video check finishes after a newer pick.

Also removes ticket keys from source comments.
2026-09-24 22:51:17 -03:00
Alexandre Brandizzi
ffff03fcc2 test(visual): refresh work-order baselines for lucide-react icon updates 2026-09-24 22:48:18 -03:00
Alexandre Brandizzi
8bb4c0c512 fix(dashboard): open the Unassigned tile as the Unassigned filter option
The tile link sent the board API token __unassigned__ as the dispatcher.
The drill-down parser stores that as an Advanced Filters dispatcher id,
while the filter UI only knows __unassigned, so the banner showed a raw
__unassigned__ chip, Assigned to did not tick Unassigned, and the option
could not clear it. Send ASSIGNEE_FILTER_UNASSIGNED, as the notification
queue link already does; toBoardSearchQueryParams still maps it to
__unassigned__ for /board/search, so the rows are unchanged.
2026-09-24 22:45:10 -03:00
Alexandre Brandizzi
62e38e4b81 chore(workorders): keep ticket keys out of test names
The review contract bars Jira keys in source comments and test names;
ticket identity lives in the PR, commit and branch. The previous commit
cleaned the source files; this strips the six (SH-391) suffixes the
branch added to test names and a test comment, keeping the behavioural
wording.
2026-09-24 22:41:05 -03:00
Alexandre Brandizzi
ec83829098 Merge remote-tracking branch 'origin/main' into lane/renovate
# Conflicts:
#	e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-filters.png
#	e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-list.png
#	e2e/__screenshots__/work-orders/work-orders.visual.spec.ts/wo-new.png
#	package-lock.json
#	package.json
2026-09-24 22:35:01 -03:00
Alexandre Brandizzi
b316168930 fix(vendor-portal): pre-check the per-work-order photo/video limit
The vendor completion upload and uplift evidence checked type, size and
duration but not the 10-photo / 3-video work-order limit. Use the counts the
dispatch detail now reports (shoc-backend#173), on the same basis as the
server: a new completion version does not count the document it replaces.
When the backend does not report counts yet, the server check still applies.
2026-09-24 22:29:20 -03:00
Alexandre Brandizzi
67cb490d52 test(dashboard): refresh visual baselines for the Unassigned tile and the Services entry
Rendered by the CI Playwright container at f64447f5.
2026-09-24 22:20:14 -03:00
Alexandre Brandizzi
cfe83fc489 fix(media): read video duration from the MP4/MOV header in the browser
The browser pre-check decoded the picked file through a video element and
an object URL, which CodeQL flags as DOM text reinterpreted as HTML. Parse
the moov/mvhd movie header from file slices instead, the same way the
server enforces the 90-second limit, so both sides read one duration.
Unreadable headers still never block an upload.
2026-09-24 22:14:42 -03:00
Alexandre Brandizzi
f64447f52c chore(dashboard): keep ticket keys out of source comments 2026-09-24 22:06:24 -03:00
Alexandre Brandizzi
7984640a5f Merge remote-tracking branch 'origin/fix/ab/sh-391-adv-filter-date-range' into feat/ab/sh-392-dashboard-unassigned 2026-09-24 22:05:33 -03:00
Alexandre Brandizzi
792dc6917b Merge remote-tracking branch 'origin/main' into feat/ab/sh-392-dashboard-unassigned
# Conflicts:
#	e2e/__screenshots__/dashboard/dashboard.visual.spec.ts/dashboard-admin.png
#	e2e/__screenshots__/dashboard/dashboard.visual.spec.ts/dashboard-dispatcher.png
2026-09-24 22:05:10 -03:00
Alexandre Brandizzi
c1fd8f6d88 chore(workorders): keep ticket keys out of source comments 2026-09-24 22:03:23 -03:00
Alexandre Brandizzi
c99e81d0d7 fix(media): pre-check duration and per-work-order counts on Extra Docs
Extra Docs advertised the 90-second limit but only checked type and size.
Both dispatcher surfaces now share one screening step (type, size, count,
duration), and the Completion Doc media tab and Extra Docs count the whole
work order's photos and videos rather than only their own tab's share.
Failed local uploads no longer count toward the limit.
2026-09-24 22:01:22 -03:00
Alexandre Brandizzi
8b58eb5f64
Merge pull request #250 from Sea-Haven-Industries/fix/sh-327-uplift-denial-message
Some checks are pending
Frontend checks / static (push) Waiting to run
Frontend checks / build (push) Waiting to run
Frontend checks / unit (push) Waiting to run
Frontend checks / Visual regression (push) Waiting to run
Frontend checks / browser-smoke (push) Waiting to run
Frontend checks / governance (push) Waiting to run
Frontend checks / ci-complete (push) Blocked by required conditions
Deploy Web / Resolve target (push) Waiting to run
Deploy Web / Deploy SPA to (push) Blocked by required conditions
fix: preserve uplift denial message
2026-09-25 00:52:28 +00:00
Alexandre Brandizzi
60b0638ea3 test(dashboard): update visual baselines for the Unassigned tile (SH-392)
Rendered by the CI Playwright container (mcr.microsoft.com/playwright:v1.61.1-noble)
at fca87b67.
2026-09-24 21:52:21 -03:00
Alexandre Brandizzi
20ef4a615d
Merge pull request #251 from Sea-Haven-Industries/albrand/tanstack-query-5.103.1
fix(deps): update TanStack Query to v5.103.1
2026-09-25 00:52:21 +00:00
Alexandre Brandizzi
563f81e163
Merge pull request #257 from Sea-Haven-Industries/feat/ab/sh-207-uplift-services-nav
feat(nav): add Uplift Approvals and Services to the sidebar (SH-207, SH-304)
2026-09-25 00:50:46 +00:00
Alexandre Brandizzi
cd888d933d
Merge pull request #258 from Sea-Haven-Industries/fix/ab/sh-390-clear-completed-date
fix(workorders): clear the completed date from the board cell (SH-390)
2026-09-25 00:50:40 +00:00
Alexandre Brandizzi
fca87b67cb test(dashboard): give the visual fixture an Unassigned count (SH-392) 2026-09-24 21:48:16 -03:00
Alexandre Brandizzi
11a753a2e9 docs(media): note the server now enforces the 90-second video limit 2026-09-24 21:39:07 -03:00
Alexandre Brandizzi
ab5e73ce82 test(workorders): type the terminal statuses in the SH-390 row test 2026-09-24 21:38:55 -03:00
Alexandre Brandizzi
ed931ea2eb SH-392: Unassigned KPI tile on the Dashboard
Shows open work orders with no dispatcher for the selected period and
drills into the same list on the board (dispatcher Unassigned, open
statuses, same dates; All time includes undated work orders).
2026-09-24 21:34:35 -03:00
Alexandre Brandizzi
51ca244524 fix(workorders): keep closed undated WOs out of the board page like the search (SH-391)
With no range selected, or with Unscheduled, the board search adds only
open undated work orders; completed and canceled ones without a date are
never unscheduled. The board page kept them. It now applies the same rule,
so both return the same rows.
2026-09-24 21:34:24 -03:00
Alexandre Brandizzi
b5da537c93 fix(media): classify client uploads by the server's type rule
A foreign declared type (e.g. video/3gpp on a .jpg) gave the file the video
size allowance in the browser while the server sizes it as a photo. Use the
same rule as the server: an allowlisted type decides, otherwise the extension.
2026-09-24 21:31:03 -03:00
Alexandre Brandizzi
f69c8a04eb fix(workorders): match a range on the board the same way the search does (SH-391)
A week-only row that still carries a scheduled date outside the range
passed the board search (its target week overlaps) but failed the
on-page filter, which judged it by the date alone. Both now accept a row
dated in the range or a week-only row whose target week overlaps it.
2026-09-24 21:10:40 -03:00
Alexandre Brandizzi
55f548d507 test(workorders): cover completed-date Clear through the board row (SH-390)
Clear on an open row reaches the board patch with completedDate empty;
Completed and Canceled rows offer no Clear and send no patch.
2026-09-24 21:04:37 -03:00
Alexandre Brandizzi
f65a48077d fix(vendor-portal): validate uploads against the server allowlist
Any image/* or video/* type passed the client check, so GIF, WebP and WebM
were only rejected after upload. Resolve the kind from the same allowlist
the server uses: an allowlisted browser type, otherwise the extension.
2026-09-24 21:01:36 -03:00
Alexandre Brandizzi
839246380a test(visual): update sidebar baselines for the Services entry 2026-09-24 20:59:54 -03:00
Alexandre Brandizzi
44e96cf2a3 fix(media): apply the SH-116 media contract to every upload surface
Photos up to 10 MB (JPG/PNG/HEIC), videos up to 100 MB and 90 s (MP4/MOV),
at most 10 photos and 3 videos per work order, pre-validated with stable
generic messages on the Photos & Videos modal, the Completion Doc media tab,
Extra Docs and the vendor portal. Video duration is read from metadata when
the browser can; unreadable metadata never blocks. Mobile MIME variants
(empty type, octet-stream with a video extension, QuickTime) stay accepted.
The signed completion PDF keeps its 50 MB cap.
2026-09-24 20:59:26 -03:00
Alexandre Brandizzi
0d6af0da59 fix(workorders): make the Advanced Filters date range narrow results (SH-391)
The Advanced Filters default was This week, and that value doubled as no
range, so an explicit This week searched every week. Other ranges passed
every undated WO through on the server. No range is now its own state
(nothing selected, like the prototype; clicking a selected range clears it).
It searches every week with undated rows, via includeDateless. Any selected
range narrows strictly. The pinned Unassigned queue and the WO# duplicate
lookup keep spanning every week.
2026-09-24 20:58:47 -03:00
Alexandre Brandizzi
15e2565aca fix(nav): hide Uplift Approvals when the can-approve refetch fails
React Query keeps the last successful data after a failed refetch, so an
earlier true kept the entry visible. Require a non-error query per tier,
and cover the real query path with a mocked API.
2026-09-24 20:53:05 -03:00
Alexandre Brandizzi
aee2ef5164 test(nav): cover single-tier approvers and can-approve errors in the sidebar 2026-09-24 20:50:20 -03:00
Alexandre Brandizzi
ec56bd0d7d feat(nav): add Uplift Approvals and Services to the sidebar (SH-207, SH-304)
Uplift Approvals appears in a new APPROVALS group only when GET
uplifts/can-approve is true for tier 1 or tier 2, the same rule the
approve/reject API enforces. Services is linked from a DATA MANAGEMENT
group for every user. Both entries highlight on their routes.
2026-09-24 20:48:09 -03:00
Alexandre Brandizzi
460397dacb fix(workorders): let dispatchers clear the completed date from the board cell (SH-390)
The completed-date cell editor had no Clear control. It now offers Clear
when a date is set and the row is editable, patching completedDate to an
empty value, which the board PATCH persists as null. Completed and
Canceled rows stay locked, matching set/change.
2026-09-24 20:44:08 -03:00
Alexandre Brandizzi
77db507e4e fix(deps): update npm minor and patch 2026-09-23 02:08:53 -03:00
renovate[bot]
1fd41e693a fix(deps): update tanstack query to v5.103.1 2026-09-23 01:35:17 -03:00
Alexandre Brandizzi
6367dc2a7a
Merge pull request #245 from Sea-Haven-Industries/renovate/terraform-minor-and-patch
Some checks failed
Frontend checks / static (push) Has been cancelled
Frontend checks / build (push) Has been cancelled
Frontend checks / unit (push) Has been cancelled
Frontend checks / Visual regression (push) Has been cancelled
Frontend checks / browser-smoke (push) Has been cancelled
Frontend checks / governance (push) Has been cancelled
Frontend checks / ci-complete (push) Has been cancelled
chore(deps): update terraform aws to ~> 6.65
2026-09-23 04:00:25 +00:00
Alexandre Brandizzi
1afdbc1dae
Merge pull request #243 from Sea-Haven-Industries/renovate/github-actions
chore(deps): update aws-actions/configure-aws-credentials action to v6.3.0
2026-09-23 03:55:00 +00:00
Alexandre Brandizzi
80640642cc fix: allowlist internal uplift denial copy 2026-09-22 23:41:17 -03:00
Alexandre Brandizzi
7b30895aca fix: map protected uplift create denial safely 2026-09-22 23:35:44 -03:00
Alexandre Brandizzi
c6e2704175 fix: allowlist uplift denial message 2026-09-22 23:23:52 -03:00
Alexandre Brandizzi
c472ce2a91 fix: preserve uplift denial message 2026-09-22 23:04:13 -03:00
npalseahaven
4965b8a076
Merge pull request #224 from Sea-Haven-Industries/refactor/dispatch-detail-modal-split-v2
Some checks failed
Frontend checks / static (push) Waiting to run
Frontend checks / build (push) Waiting to run
Frontend checks / unit (push) Waiting to run
Frontend checks / Visual regression (push) Waiting to run
Frontend checks / browser-smoke (push) Waiting to run
Frontend checks / governance (push) Waiting to run
Frontend checks / ci-complete (push) Blocked by required conditions
Deploy Web / Resolve target (push) Has been cancelled
Deploy Web / Deploy SPA to (push) Has been cancelled
refactor(vendor-portal,settings): move state and fetch logic into hook
2026-09-22 14:17:57 +00:00
renovate[bot]
6181415a04
chore(deps): update terraform aws to ~> 6.65 2026-09-22 05:28:10 +00:00
npal
86e43b66f4 fix: reset add-item draft on template selection change (SH-378)
TaskTemplateItemsField owns newItemText locally but stays mounted
across selectTemplate/startNewTemplate (which only call form.reset()),
so a typed draft survived switching templates - the base page cleared
this draft explicitly in both handleSelect and handleNew.

Remount TaskTemplateItemsField on selection change via key={selectedId}
instead of lifting the draft into the editor hook: it's transient
input-only state, not form data, so this keeps the fix local and lets
React's own remount semantics reset it. Confirmed the two new
regression tests fail without the key and pass with it.
2026-09-21 20:04:33 -05:00
Alexandre Brandizzi
e769b5fcc2
Merge pull request #227 from Sea-Haven-Industries/feat/ab/sh-288-event-notifications
Some checks are pending
Frontend checks / static (push) Waiting to run
Frontend checks / build (push) Waiting to run
Frontend checks / unit (push) Waiting to run
Frontend checks / Visual regression (push) Waiting to run
Frontend checks / browser-smoke (push) Waiting to run
Frontend checks / governance (push) Waiting to run
Frontend checks / ci-complete (push) Blocked by required conditions
Deploy Web / Resolve target (push) Waiting to run
Deploy Web / Deploy SPA to (push) Blocked by required conditions
feat(notifications): open assignment, comment, mention and uplift items where they happened (SH-288, SH-289, SH-290, SH-215)
2026-09-21 20:58:57 +00:00