Skip to content

LAD: change team status or task a team from the radio/ops log - #562

Merged
OSPFNeighbour merged 5 commits into
master-devfrom
rmacdonald-radiolog-wip
Oct 16, 2026
Merged

OSPFNeighbour merged 5 commits into
master-devfrom
rmacdonald-radiolog-wip

Conversation

@Rowantrek

Copy link
Copy Markdown
Collaborator

Summary

The Radio Log buttons on team rows and taskings now open the full Ops Log dialog, with the Radio tag already selected. That dialog can also change a team's status or task a team. Everything happens when you click Submit, and the log entry is only saved if the status change or tasking worked.

  • Change a team's status from a radio log. When the dialog's Incident and Team fields point at a team tasked to that incident, the footer shows the team's current status with an update to menu. The fields are filled in straight away when you open Radio Log from a tasking, or you can fill them in yourself.
  • Task a team from a radio or ops log. If that team isn't tasked to the incident, the footer offers Task Team and Task Team & SMS. Send SMS opens after the dialog closes.
  • Radio Log on teams and taskings, and the Spotlight radio command, open the full dialog, so you can add other tags. The incident, team and subject are filled in.
  • The Submit button no longer stays stuck on Submitting… when a save fails.
  • Ctrl+Enter from the Text box submits what you typed. Before, it failed with "You must enter text" because the box only updated when it lost focus. This also affected the existing New Ops Log dialog.
  • In dark mode, selected tags in the Ops/Radio Log dialogs are readable.

What happens on Submit

  1. The log is validated (text and at least one tag) before anything is sent.
  2. The status change or tasking goes first. If it fails, the dialog shows Beacon's reason and nothing is logged.
  3. The log entry is saved. If that fails after step 2 worked, the dialog says so, and a retry doesn't send the status or tasking again.
  4. Complete opens Beacon's completion screen only after the log saves. Task Team & SMS opens Send SMS once the dialog has closed.

Submit is also refused, with a reason, if things change while the dialog is open: the picked status is no longer valid, the tasking was called off elsewhere, or the team was tasked by someone else.

Implementation notes

  • Tasking.buildStatusChange(draft): the payload rules from updateTaskingStatus, now shared by the row dropdown and the dialog. The row dropdown builds exactly the same requests; its existing tests pass unchanged.
  • The status/tasking calls couldn't report failure. BeaconClient.tasking.updateTeamStatus, callOffTeam, untaskTeam and task use nullOnError, and main.js turned the null into cb([]), which reads as success. They now accept a throwOnError option. The defaults are unchanged, so existing callers (including the row dropdown) behave as before.
  • New Promise-based main.js helpers applyTaskingStatusChange and applyTaskTeam reject on failure. They don't show an alert; the dialog shows the error.
  • Finding the tasking (OpsLogModalVM):
    • Incident: only a picked incident suggestion counts, because that's what attaches the log to it.
    • Team: the typed callsign, or the teams a picked trackable asset is matched to.
    • Only an active tasking counts. A complete, called-off or untasked one offers Task Team instead, as instant tasking does.
    • If the incident's taskings haven't been fetched, they're fetched (existing cooldown applies).
  • The old text-only radio log dialog is removed. That's #RadioLogModal, RadioLogModalVM.js, its CSS, and attachJobRadioLogModal / attachTeamRadioLogModal / attachJobRadioLogModalByTeamAndIncident. The Spotlight radio command now opens the new dialog with the incident and team filled in, so the status change and Task Team work from there too.
  • lad-docs harness:
    • Fake ops-log tag groups (2, 3, 4, 27).
    • The mock's POST /Api/v1/Tasking and POST /Api/v1/OperationsLog now create real rows. Before, every write returned null, so a submitted log always counted as failed.
    • New shots: radio-log-dialog, radio-log-status-change, radio-log-task-team.

Docs

  • Logs & Messages: New Radio Log, Changing the Team's Status, Tasking the Team from a Log.
  • Tasking Teams: lists tasking from a log as a fourth way to task.
  • Team/Incident Register: updated the Radio Log button descriptions.
  • What's New: new "LAD radio logs with status changes" entry.

Testing

  • npm run lint: clean (zero warnings).
  • npm test: 1024 passed. New OpsLogModalVM.test.js covers submit order, every failure and retry path, Complete, Task Team & SMS waiting for the dialog to close, and finding the tasking from the fields.
  • Clicked through in the lad-docs harness (fake Beacon):
    • status change from a tasking row
    • blank Radio Log with the incident and team filled in by hand
    • Task Team & SMS (team tasked, log saved, Send SMS opened, one backdrop)
    • Spotlight radio for a tasked team (status menu) and an untasked team (Task Team)
    • dark mode
  • Not yet tested against real Beacon. In particular, it's worth confirming what Beacon returns when a status change, call off, untask or task fails (the error shown comes from the response body's Message/ModelState), and that a real tasking POST returns the created rows.

🤖 Generated with Claude Code

Rowantrek and others added 4 commits October 15, 2026 11:06
Removed old radio log modal, replaced with the newer ops log/radio log modal.
Radio Log opened from a tasking row now shows the team's current status
and an "update to" menu in the dialog footer. Picking a status is only a
draft; nothing is sent until Submit.

On Submit the status change goes first and the ops log entry is only
created if it worked, so the log never records a change that didn't
happen:
- status fails: the error is shown in the dialog, nothing is logged
- status no longer valid (team moved on while open): refused up front
- log fails after the status landed: says so, and a retry doesn't
  resend the status
- Complete opens Beacon's completion screen only after the log saves

Code:
- Tasking.buildStatusChange(): the payload rules from
  updateTaskingStatus, now shared by the row dropdown and the dialog
  (row behaviour unchanged)
- BeaconClient tasking status calls take a throwOnError option. They use
  nullOnError, so HTTP failures resolved null and looked like success
- main.js applyTaskingStatusChange(): Promise version that rejects on
  failure
- Status details (time, ETA/ETC, reason) render in the dialog body,
  which scrolls to them when a status is picked
- Fix the Submit button staying on "Submitting…" after a failed save

lad-docs harness:
- Fake ops log tag groups 2, 3, 4 and 27 so the Ops/Radio Log dialog
  shows tags. Names follow Beacon; ids are fake except those
  tagFactory.js keys an icon off (e.g. Radio 6, Phone Call 2)
- Shots: radio-log-dialog, radio-log-status-change

Docs:
- Logs & Messages: New Radio Log uses the full dialog; new Changing the
  Team's Status section
- Tasking, Team Register, Incident Register: link to it
- What's New entry and updated screenshots

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change a team's status from a radio log: when a radio or ops log's
Incident and Team fields point at a team tasked to that incident
(straight away when you open Radio Log from a tasking, or once you fill
them in), the bottom of the dialog shows the team's current status with
an "update to" menu. The new status is only set when you click Submit,
and the log entry is only saved if the status change worked.

Task a team from a radio or ops log: if the team in the log isn't tasked
to the incident, choose Task Team or Task Team & SMS at the bottom of
the dialog. The team is tasked when you click Submit, before the log
entry is saved, and Task Team & SMS opens Send SMS once the dialog
closes.

Finding the tasking from the fields:
- Incident: only a picked suggestion counts (that's what attaches the
  log); editing the text afterwards detaches it
- Team: the typed callsign, or the teams a picked trackable asset is
  matched to
- Only an active tasking counts; a complete/called-off/untasked one
  offers Task Team instead (as instant tasking does)
- Loads the incident's taskings if they haven't been fetched; Task Team
  waits for them and respects canTaskJob
- Changing either field drops a picked status or Task Team; a tasking
  that changes under an open dialog is refused at Submit with a reason
  instead of silently logging without it

Task Team:
- main.js applyTaskTeam(): Promise version of assignJobToTeam that only
  resolves if Beacon created the tasking; BeaconClient task() takes
  throwOnError
- Tasks first, then logs; a retry after a failed log doesn't task again
  and still opens the SMS
- Send SMS opens on the dialog's hidden event (opening a second modal
  mid-hide leaves body.modal-open in a bad state)

lad-docs harness:
- Mock POST /Api/v1/Tasking and /Api/v1/OperationsLog create real rows
  (other writes were null, so a submitted log always "failed")
- Shot: radio-log-task-team

Docs: Tasking the Team from a Log, filling in the fields yourself,
Tasking Teams lists the fourth way to task, What's New bullet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ing empty text

The Spotlight radio command now opens the Ops/Radio Log dialog with the
incident and team filled in, the same as Radio Log on a tasking. The
dialog finds the tasking from those fields, so the status change and
Task Team work from Spotlight too.

Nothing uses the old text-only radio log dialog any more, so it's
removed: #RadioLogModal, RadioLogModalVM.js, its CSS and
attachJobRadioLogModalByTeamAndIncident. Radio page comments that
pointed at RadioLogModalVM.js now point at OpsLogModalVM.js.

The dialog's Text and Subject boxes used the value binding, which only
updates the view model when the box loses focus, so Ctrl+Enter from the
Text box failed with "You must enter text". They now use textInput.

Docs: Logs & Messages and the Spotlight radio steps describe the new
dialog; What's New bullet mentions Spotlight.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@OSPFNeighbour OSPFNeighbour left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Pulled and tested in the lad-docs harness. Lint, tests (1024) and the dev build pass. The flows behave as described: the status change or tasking goes before the log, nothing is logged when it fails, a retry after a failed log save doesn't resend the status, Ctrl+Enter works, and Task Team & SMS leaves one backdrop. No page errors.

Two things inline: the submit error can be scrolled out of view, and the false-500 case on the tasking endpoints.

🤖 Generated with Claude Code


function showSubmitError(message) {
self.errorMessage(`Error: ${message}`);
self.showError(true);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The error banner can be out of view when Submit fails. The banner is at the top of .modal-body. When the status-change panel is open, the body is already scrolled down by the time you click Submit (scrollTop 114 at a 1400×1000 viewport). In the harness, a 400 or 500 on POST /Tasking/{id}/Onsite set the right text (Couldn't change DEM01 to "On site": Beacon said "…". The log entry was not saved.), but the banner wasn't visible, so the dialog just stays open with no reason shown. Smaller screens will be worse.

Suggest scrolling the body to the top here (e.g. document.querySelector('#CreateOpsLogModal .modal-body').scrollTop = 0, or scrollIntoView on the alert), or showing submit errors in/near the footer.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Resolved - when an error is displayed it will not scroll to the top of the modal.

signal,
json: payload,
nullOnError: true,
nullOnError: !ctx.throwOnError,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

A false 500 now blocks the log. The comment at the top of this file says these endpoints "intermittently return 500 despite applying the change", which is why they use nullOnError. With throwOnError, a false 500 means the log isn't saved. If the user retries, the status change or tasking is sent again even though Beacon already applied it. Beacon might reject the duplicate, or apply it twice (for example a second tasking).

Worth checking against real Beacon whether those 500s still happen. If they do, consider treating a 5xx as "unknown": re-fetch the tasking and continue with the log if the change landed, rather than reporting a failure.

The banner is at the top of the scrollable modal body, but Submit is in the
footer and the body is often scrolled down by then (e.g. with the status
change panel open), so a failed status change left the dialog open with no
visible reason.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@OSPFNeighbour
OSPFNeighbour merged commit 408ca5a into master-dev Oct 16, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants