Skip to content

feat(admin-pause): exact-minute pause display + edit under UseOneMinuteIntervals=true#1568

Merged
renemadsen merged 1 commit intostablefrom
feat/admin-exact-minute-pause
May 8, 2026
Merged

feat(admin-pause): exact-minute pause display + edit under UseOneMinuteIntervals=true#1568
renemadsen merged 1 commit intostablefrom
feat/admin-exact-minute-pause

Conversation

@renemadsen
Copy link
Copy Markdown
Member

Summary

Admin web UI now shows and persists exact-minute pause durations for sites with UseOneMinuteIntervals=true. Fully additive — flag-off code paths and existing pause1Id sentinel encoding stay bit-identical.

Closes the customer 855 case where a 12-second worker pause displayed as "00:15" in the admin edit dialog (legacy 5-min-tick formula off pause1Id=4).

Changes

DTO

  • TimePlanningPlanningPrDayModel: 5 new int? Pause1ExactMinutes-Pause5ExactMinutes properties (request-only, no schema migration).
  • planning-pr-day.model.ts: matching optional fields.

Angular workday-entity-dialog.component.ts

  • 5 new pauseNExact ternary vars next to existing pauseNId reads. Existing line 161 untouched.
  • FormControl value swap pauseNIdpauseNExact (the ternary defaults to pauseNId when flag-off, preserving bit-identity).
  • Additive write block after each existing pauseNId assignment (line 1321 untouched). When flag-on, sends pauseNExactMinutes = convertTimeToMinutes(value, false) (raw minutes, no sentinel).
  • New helpers computeExactPauseMinutes(shift) and getPauseTimestampPairs(shift).

C# TimePlanningPlanningService.Update

  • Additive top-level branch gated solely on UseOneMinuteIntervals && pauseNExactMinutes.HasValue. Loop dispatches to ApplyExactMinutePause(planning, shift, minutes).
  • UseDetailedPauseEditing completely ignored per business directive.

ApplyExactMinutePause helper

  • Anchors on existing Pause*StartedAt if present, else shift midpoint.
  • Computes Pause*StoppedAt = anchor + minutes.
  • Calls ClearPauseTimestamps(planning, shift) first to wipe sub-slot pairs (pause10-19, pause100-102 for shift 1; pause20-29, pause200-202 for shift 2) — AggregatePauseMinutes only sees the canonical slot.
  • exactMinutes == 0 short-circuits via ClearPauseTimestamps so admin can fully clear pauses (zero-clearing edge case fixed).

Constraints honored

  • Existing pause1Id sentinel-encoded read at line 161 untouched.
  • Existing pause1Id sentinel-encoded write at line 1321 untouched.
  • Existing C# write sites at lines 668/769/850/1302/1431/1538 untouched.
  • No eform-timeplanning-base edits.
  • No DB migration. New DTO fields are request-only.
  • UseDetailedPauseEditing not entangled — new branch is at top level outside it.

Test plan

  • Admin opens a workday with UseOneMinuteIntervals=true where a worker took a 3-minute pause: dialog shows "00:03" (not "00:00" or "00:05").
  • Admin edits that pause to "00:07" and saves: backend persists Pause1StoppedAt = Pause1StartedAt + 7 min; sub-slot pause10-pause102 timestamps are cleared. AggregatePauseMinutes returns 7.
  • Admin clears that pause to "00:00" and saves: all 14 timestamp pairs for shift 1 nulled; AggregatePauseMinutes returns 0; legacy pause1Id also cleared by existing line 1321 path.
  • Site with UseOneMinuteIntervals=false: dialog continues to display 5-min-tick decoded value; round-trip is bit-identical to stable HEAD.
  • CI green.

🤖 Generated with Claude Code

…teIntervals=true

Admin web UI now shows and persists exact-minute pause durations for sites
with UseOneMinuteIntervals=true. Fully additive — flag-off code paths and
existing pause1Id sentinel encoding are bit-identical.

Changes:
- DTO: 5 new int? Pause1ExactMinutes-Pause5ExactMinutes (request-only, no
  schema migration). Mirrored in planning-pr-day.model.ts.
- Angular workday-entity-dialog: 5 new pauseNExact ternary vars next to
  existing pauseNId reads (line 161 untouched), FormControl value swap
  pauseNId → pauseNExact (the ternary defaults to pauseNId when flag-off,
  preserving bit-identity), additive write block after each pauseNId
  assignment (line 1321 untouched). New helpers computeExactPauseMinutes,
  getPauseTimestampPairs.
- C# TimePlanningPlanningService.Update: additive top-level branch gated
  on UseOneMinuteIntervals && pauseNExactMinutes.HasValue. Loop dispatches
  to ApplyExactMinutePause(planning, shift, minutes). UseDetailedPauseEditing
  is completely ignored per user directive.
- ApplyExactMinutePause anchors on existing Pause*StartedAt if present,
  else shift midpoint; computes Pause*StoppedAt = anchor + minutes; clears
  sub-slot timestamps (pause10-19, pause100-102 for shift 1; analogous for
  shift 2) so AggregatePauseMinutes does not double-count. exactMinutes=0
  short-circuits via ClearPauseTimestamps so admin can clear pauses.
- ClearPauseTimestamps: shared helper for sub-slot null-out, called from
  both zero-clear and non-zero branches as single source of truth.

Customer 855: a 12-second worker pause that previously displayed as
"00:15" in admin (legacy 5-min-tick formula off pause1Id=4) will now
display the actual minute count when admin opens the day.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 8, 2026 12:04
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support in the admin workday edit dialog to display and persist pause durations in exact minutes when a site has UseOneMinuteIntervals=true, while keeping the legacy 5-minute Pause*Id behavior unchanged when the flag is off.

Changes:

  • Added request-only Pause1ExactMinutesPause5ExactMinutes fields to the planning day DTOs (C# + Angular model).
  • Updated the Angular workday dialog to derive pause duration from pause timestamp pairs (including sub-slot pauses) and to submit exact-minute values under the flag.
  • Updated TimePlanningPlanningService.Update to translate submitted exact-minute pauses into canonical Pause*StartedAt/Pause*StoppedAt timestamps and clear sub-slot pause intervals to avoid double counting.

Reviewed changes

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

File Description
eFormAPI/Plugins/TimePlanning.Pn/TimePlanning.Pn/Services/TimePlanningPlanningService/TimePlanningPlanningService.cs Applies exact-minute pause edits on UseOneMinuteIntervals, adds helpers to write canonical pause stamps and clear sub-slot intervals.
eFormAPI/Plugins/TimePlanning.Pn/TimePlanning.Pn/Infrastructure/Models/Planning/TimePlanningPlanningPrDayModel.cs Adds request-only Pause*ExactMinutes properties to the update model.
eform-client/src/app/plugins/modules/time-planning-pn/models/plannings/planning-pr-day.model.ts Adds optional pause*ExactMinutes fields to the Angular model.
eform-client/src/app/plugins/modules/time-planning-pn/components/plannings/time-planning-actions/workday-entity/workday-entity-dialog.component.ts Computes exact-minute pause display from timestamp pairs and submits exact-minute pause values when the flag is on.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 1400 to +1403
this.data.planningPrDayModels.pause1Id = this.convertTimeToMinutes(a1?.pause, true) === 0 ? null : this.convertTimeToMinutes(a1?.pause, true);
if (this.useOneMinuteIntervals) {
this.data.planningPrDayModels.pause1ExactMinutes = this.convertTimeToMinutes(a1?.pause, false);
}
// eslint-disable-next-line max-len
this.data.planningPrDayModels.pause2Id = this.convertTimeToMinutes(a2?.pause, true) === 0 ? null : this.convertTimeToMinutes(a2?.pause, true);
if (this.useOneMinuteIntervals) {
this.data.planningPrDayModels.pause2ExactMinutes = this.convertTimeToMinutes(a2?.pause, false);
Comment on lines 1420 to +1423
this.data.planningPrDayModels.pause3Id = this.convertTimeToMinutes(a3?.pause, true) === 0 ? null : this.convertTimeToMinutes(a3?.pause, true);
if (this.useOneMinuteIntervals) {
this.data.planningPrDayModels.pause3ExactMinutes = this.convertTimeToMinutes(a3?.pause, false);
}
// eslint-disable-next-line max-len
this.data.planningPrDayModels.pause4Id = this.convertTimeToMinutes(a4?.pause, true) === 0 ? null : this.convertTimeToMinutes(a4?.pause, true);
if (this.useOneMinuteIntervals) {
this.data.planningPrDayModels.pause4ExactMinutes = this.convertTimeToMinutes(a4?.pause, false);
// eslint-disable-next-line max-len
this.data.planningPrDayModels.pause5Id = this.convertTimeToMinutes(a5?.pause, true) === 0 ? null : this.convertTimeToMinutes(a5?.pause, true);
if (this.useOneMinuteIntervals) {
this.data.planningPrDayModels.pause5ExactMinutes = this.convertTimeToMinutes(a5?.pause, false);
Comment on lines +1054 to +1059
private computeExactPauseMinutes(shift: number): number {
let totalSeconds = 0;
for (const [start, stop] of this.getPauseTimestampPairs(shift)) {
if (start && stop) {
totalSeconds += (new Date(stop).getTime() - new Date(start).getTime()) / 1000;
}
Comment on lines +971 to +982
(1, model.Pause1ExactMinutes),
(2, model.Pause2ExactMinutes),
(3, model.Pause3ExactMinutes),
(4, model.Pause4ExactMinutes),
(5, model.Pause5ExactMinutes),
};
foreach (var (shift, minutes) in exactPauses)
{
if (minutes.HasValue)
{
ApplyExactMinutePause(planning, shift, minutes.Value);
}
Comment on lines +967 to +984
if (assignedSite.UseOneMinuteIntervals)
{
var exactPauses = new[]
{
(1, model.Pause1ExactMinutes),
(2, model.Pause2ExactMinutes),
(3, model.Pause3ExactMinutes),
(4, model.Pause4ExactMinutes),
(5, model.Pause5ExactMinutes),
};
foreach (var (shift, minutes) in exactPauses)
{
if (minutes.HasValue)
{
ApplyExactMinutePause(planning, shift, minutes.Value);
}
}
}
Comment on lines +1907 to +1914
private void ApplyExactMinutePause(PlanRegistration planning, int shift, int exactMinutes)
{
if (exactMinutes == 0)
{
ClearPauseTimestamps(planning, shift);
return;
}

@renemadsen renemadsen merged commit 65f8487 into stable May 8, 2026
40 of 41 checks passed
@renemadsen renemadsen deleted the feat/admin-exact-minute-pause branch May 8, 2026 12:19
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