A site saved before the contacts list existed maps with no contacts, only
the legacy contact/phone fields. The site-record sync read the contacts
list alone, so the dialog blanked the POC, blocked a notes-only Save until
the contact was retyped, and when the work order had no POC the legacy
autofill made the diff report a contact edit nobody made. The legacy
contact is now the site's main contact for display, baseline and request.
Save sends the values it had when clicked, so the dialog's fields are now
disabled while the site update is in flight instead of accepting edits
that neither save would include.
The site-update mutation already toasts its own failure, so it sets
meta.suppressErrorToast and the global mutation toast no longer repeats it.
Site contacts carry only a name and a phone (LocationContact, and the
Sites page contact rows), so PATCH contact-info has nowhere to put an
additional contact's note. The Notes box on each additional contact card
let a dispatcher type one under copy saying contacts are saved to the
site record, but the note only reached this work order's copy and no
other work order at the site ever saw it.
The additional-contact Notes box is now hidden while the dialog edits the
site record. It stays where contacts are saved to the work order only:
inline create, the wizard, and an existing work order whose site record
failed to load.
Picking another site on an existing work order kept the old site's POC
name, phone and notes in the fields. When the new site's record failed
to load, the dialog never synced it, Save stayed enabled, and the work
order pointing at the new site was saved with the previous site's
contact and notes as its override.
A site switch now empties the POC name and phone for every work order,
and the notes for existing ones, so the fields hold either the new
site's record or what the dispatcher types for it.
The Site dialog loads extra contacts from the site record with their site
contact ids so the site request can update rows in place. buildSiteDialogPatch
copied those rows verbatim into the work-order patch, so onSave received
siteContactId (and half-filled rows) even though the type documents that the
id is never sent on work-order patches. The wire serializer already stripped
both, but the patch handed to the board did not.
Run the patch's extra contacts through normalizeAdditionalContacts, the same
helper the work-order serializer uses, so the patch carries only complete
name/phone/notes rows. An emptied list still clears the work order's copy.
The site request keeps its ids because it is built from the form fields.
The page being read is re-derived after every render and every observed
resize, not only when the page count changes. The NOT REQUIRED stamp is
rendered inside the first sheet, above its greyed-out content, instead of
floating over the scroll panel.
The Uplift column hid its trigger on a Completed or Canceled work order
with no live uplift, so once cancelled/revoked uplifts stop counting as
"has uplift", their read-only history had no way in. The cell now always
opens the uplifts dialog; closed work orders show a dash instead of Manage.
Admins may revoke only admin-approved uplifts. The Work Order Uplifts
dialog showed Revoke to whoever requested an auto-approved uplift, so an
admin requester saw it and was sent into the optional-reason revoke flow.
Both the template preview and a work order's completion document render
through the shared frame, which now splits the letterhead and blocks into
A4-sized sheets with the brand bars on every sheet and shows Page X of Y
in the preview pill.
Switching to another site and back now loads the site record again, so its
extra contacts are not dropped on Save. The dialog also waits for the site
request to settle before syncing, so a record cached before an earlier save
is never shown or written back. Half-filled extra contacts stay off the site
record, as they already stay off the work order. The save path moves into
its own hook to keep the dialog state under the complexity limit.
When the site detail request fails, or the user types before it loads,
the dialog falls back to saving this work order only and never calls
updateContactInfo. The POC helper text still said contacts and notes were
saved to the site record, so a dispatcher could believe every work order
at the site now had the new contact. The helper text now follows the
site-record sync state and says the change applies to this work order
only whenever that fallback is active, including after a later refetch
succeeds.
The contact lock only covered a pending load. After a failed getById the
fields unlock, and a later successful refetch (focus, invalidation) still
ran the apply effect and overwrote whatever the dispatcher had typed.
The apply effect now skips once the user has typed since the last reset or
site switch, so the dialog stays on the work order's values and saves them
to the work order only; the site's unseen notes and contacts are never
written back. Picking another site still clears the marker and adopts it.
The server honours only the id set when one is sent, so a facet applied during an ids drill-down showed as an active chip while doing nothing. Applying any facet now drops the selection; applying the panel unchanged keeps it. The ids param is also capped at the server limit whatever built the set.
Overdue maps to work order type 8 on create, inline correction, board
reads and the type filter, instead of the Other enum and the past-due
flag. It lists the PM service catalog and never sends a severity. Past
Due moves to its own toggle in the advanced filter Status section and
narrows the other filters.
/workorders?ids=101,205,318 opens the board on exactly those work orders
through board/search's ids filter. The id set replaces every other
drill-down filter, a chip reads "Showing N selected work orders" and
clearing it returns to the weekly board. buildWorkOrderIdsHref builds
the link for alerts and linked-work-order lists.
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.
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.
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.
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.
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.
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.