Skip to content

Commit 8bd87b2

Browse files
authored
Merge pull request #1574 from microting/feat/web-drop-seconds-from-timestamps
fix(display): timestamps show HH:mm only, no seconds
2 parents 6d4f6b8 + 0d3560d commit 8bd87b2

4 files changed

Lines changed: 45 additions & 46 deletions

File tree

eform-client/playwright/e2e/plugins/time-planning-pn/b/dashboard-edit-multishift.spec.ts

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -370,22 +370,21 @@ test.describe('Dashboard — multi-shift (3-5) round-trip regression guard', ()
370370
});
371371

372372
/**
373-
* Phase 4 — second-precision DISPLAY: when a row's site has
374-
* `useOneMinuteIntervals = true` AND the planning has a precise
375-
* `start1StartedAt` stamp (e.g. 07:03:53), the plannings-table cell must
376-
* render the stamp at HH:mm:ss instead of the legacy HH:mm.
373+
* Plannings-table display contract: the cell always renders the actual
374+
* shift stamp as `HH:mm`, even when `AssignedSite.UseOneMinuteIntervals`
375+
* is on. Seconds are never shown regardless of the flag.
377376
*
378-
* Server-side seeding `AssignedSite.UseOneMinuteIntervals = true` plus
379-
* a planning with `Start1StartedAt = 2026-05-15 07:03:53` requires DB
380-
* fixture work the CI playwright shard doesn't yet wire up (the tests
381-
* here log in as admin and rely on the default seed). Captured here as
382-
* a TODO so the assertion shape survives any future fixture work; the
383-
* Phase 4 jest unit test on `formatStamp(...)` covers the contract for
384-
* the merge-blocking path.
377+
* Server-side seeding of `AssignedSite.UseOneMinuteIntervals = true`
378+
* plus a planning row with `Start1StartedAt = 2026-05-15 07:03:53`
379+
* requires DB fixture work the CI playwright shard doesn't yet wire up
380+
* (the tests here log in as admin and rely on the default seed).
381+
* Captured here as a TODO so the assertion shape survives any future
382+
* fixture work; the jest unit test on `formatStamp(...)` covers the
383+
* format-helper contract for the merge-blocking path.
385384
*/
386-
test.skip('plannings-table renders HH:mm:ss for actual stamp when site flag is on', async ({ page }) => {
387-
// TODO(phase 4 fixture): seed AssignedSite.UseOneMinuteIntervals = true
388-
// for the worker referenced by #cell3_0 AND a PlanRegistration row with
385+
test.skip('plannings-table renders HH:mm for actual stamp when site flag is on', async ({ page }) => {
386+
// TODO(fixture): seed AssignedSite.UseOneMinuteIntervals = true for the
387+
// worker referenced by #cell3_0 AND a PlanRegistration row with
389388
// Start1StartedAt = '2026-05-15T07:03:53Z' on a date that lands inside
390389
// the dashboard's default visible range.
391390
//
@@ -400,12 +399,12 @@ test.describe('Dashboard — multi-shift (3-5) round-trip regression guard', ()
400399
//
401400
// // The first-shift actual line is rendered with id firstShiftActual{rowIdx}_{colField}.
402401
// const firstShiftActual = page.locator('[id^="firstShiftActual"]').first();
403-
// await expect(firstShiftActual).toContainText('07:03:53');
404-
// // Negative guard — the legacy 5-min path would render '07:00' / '07:05' instead.
405-
// await expect(firstShiftActual).not.toContainText(/07:0[05]\s/);
402+
// await expect(firstShiftActual).toContainText('07:03');
403+
// // Negative guard — seconds are never displayed even when the flag is on.
404+
// await expect(firstShiftActual).not.toContainText('07:03:53');
406405
//
407406
// Until the fixture lands the unit test
408-
// `formatStamp (Phase 4) — uses HH:mm:ss format when row.useOneMinuteIntervals is true`
407+
// `formatStamp — uses HH:mm format when row.useOneMinuteIntervals is true`
409408
// covers the format-helper contract (eform-client/src/app/plugins/modules/time-planning-pn/
410409
// components/plannings/time-plannings-table/time-plannings-table.component.spec.ts).
411410
});

eform-client/src/app/plugins/modules/time-planning-pn/components/plannings/time-plannings-table/time-plannings-table.component.spec.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -376,9 +376,10 @@ describe('TimePlanningsTableComponent', () => {
376376
});
377377

378378
// ------------------------------------------------------------------
379-
// Phase 4 — second-precision display when UseOneMinuteIntervals is on
379+
// formatStamp / getStopTimeDisplayWithSeconds — always HH:mm
380+
// (`useOneMinuteIntervals` retained on the row but no longer affects display)
380381
// ------------------------------------------------------------------
381-
describe('formatStamp (Phase 4)', () => {
382+
describe('formatStamp', () => {
382383
it('returns empty string when value is falsy', () => {
383384
expect(component.formatStamp({ useOneMinuteIntervals: true }, null)).toBe('');
384385
expect(component.formatStamp({ useOneMinuteIntervals: true }, undefined as any)).toBe('');
@@ -397,16 +398,16 @@ describe('TimePlanningsTableComponent', () => {
397398
expect(result).toBe('07:03');
398399
});
399400

400-
it("uses HH:mm:ss format when row.useOneMinuteIntervals is true", () => {
401+
it("uses HH:mm format when row.useOneMinuteIntervals is true", () => {
401402
const transformSpy = jest
402403
.spyOn(component['datePipe'], 'transform')
403-
.mockReturnValue('07:03:53');
404+
.mockReturnValue('07:03');
404405
const result = component.formatStamp(
405406
{ useOneMinuteIntervals: true },
406407
'2026-05-15T07:03:53Z',
407408
);
408-
expect(transformSpy).toHaveBeenCalledWith('2026-05-15T07:03:53Z', 'HH:mm:ss', 'UTC');
409-
expect(result).toBe('07:03:53');
409+
expect(transformSpy).toHaveBeenCalledWith('2026-05-15T07:03:53Z', 'HH:mm', 'UTC');
410+
expect(result).toBe('07:03');
410411
});
411412

412413
it("falls back to HH:mm when row is null/undefined (defensive)", () => {
@@ -419,7 +420,7 @@ describe('TimePlanningsTableComponent', () => {
419420
});
420421
});
421422

422-
describe('getStopTimeDisplayWithSeconds (Phase 4)', () => {
423+
describe('getStopTimeDisplayWithSeconds', () => {
423424
it('returns empty string when either timestamp is falsy', () => {
424425
expect(
425426
component.getStopTimeDisplayWithSeconds({ useOneMinuteIntervals: true }, null, '2026-05-15T10:00:00Z'),
@@ -452,21 +453,22 @@ describe('TimePlanningsTableComponent', () => {
452453
expect(result).toBe('15:30');
453454
});
454455

455-
it("uses HH:mm:ss format when flag on", () => {
456+
it("uses HH:mm format when flag on", () => {
456457
const transformSpy = jest
457458
.spyOn(component['datePipe'], 'transform')
458-
.mockReturnValue('15:30:11');
459+
.mockReturnValue('15:30');
459460
const result = component.getStopTimeDisplayWithSeconds(
460461
{ useOneMinuteIntervals: true },
461462
'2026-05-15T07:00:00Z',
462463
'2026-05-15T15:30:11Z',
463464
);
464-
expect(transformSpy).toHaveBeenCalledWith('2026-05-15T15:30:11Z', 'HH:mm:ss', 'UTC');
465-
expect(result).toBe('15:30:11');
465+
expect(transformSpy).toHaveBeenCalledWith('2026-05-15T15:30:11Z', 'HH:mm', 'UTC');
466+
expect(result).toBe('15:30');
466467
});
467468
});
468469

469-
describe('convertHoursToTimeWithSeconds (Phase 4)', () => {
470+
// Dormant helper — production display no longer uses seconds.
471+
describe('convertHoursToTimeWithSeconds', () => {
470472
it('formats whole-hour values with seconds suffix', () => {
471473
expect(component.convertHoursToTimeWithSeconds(8)).toBe('08:00:00');
472474
});

eform-client/src/app/plugins/modules/time-planning-pn/components/plannings/time-plannings-table/time-plannings-table.component.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -291,24 +291,22 @@ export class TimePlanningsTableComponent implements OnInit, OnChanges, AfterView
291291
}
292292

293293
/**
294-
* Phase 4 second-precision sibling of the inline `datePipe.transform(..., 'HH:mm', 'UTC')`
295-
* calls used in the plannings table. When the row's site has
296-
* <c>useOneMinuteIntervals</c> on, the actual stamp cells render at
297-
* <c>HH:mm:ss</c>; otherwise falls through to the legacy <c>HH:mm</c>
298-
* format so flag-off rows are byte-identical to before.
294+
* Formats an actual shift timestamp for display in the plannings table.
295+
* Always renders as `HH:mm`; seconds are never displayed regardless of
296+
* the row's `useOneMinuteIntervals` flag. The `row` parameter is kept
297+
* for call-site stability.
299298
*/
300299
formatStamp(row: any, value: string | null | undefined): string {
301300
if (!value) {
302301
return '';
303302
}
304-
const fmt = row?.useOneMinuteIntervals ? 'HH:mm:ss' : 'HH:mm';
305-
return this.datePipe.transform(value, fmt, 'UTC') ?? '';
303+
return this.datePipe.transform(value, 'HH:mm', 'UTC') ?? '';
306304
}
307305

308306
/**
309-
* Phase 4 second-precision sibling of {@link getStopTimeDisplay}. Same
310-
* cross-day "24:00" guard as the legacy method, but emits seconds in the
311-
* normal case when the row's site has the flag on.
307+
* Stop-time display sibling of {@link getStopTimeDisplay} with the same
308+
* cross-day "24:00" guard. Always renders as `HH:mm`; the `WithSeconds`
309+
* suffix is a historical name — seconds are not emitted.
312310
*/
313311
getStopTimeDisplayWithSeconds(row: any, startedAt: string | null, stoppedAt: string | null): string {
314312
if (!startedAt || !stoppedAt) {
@@ -323,8 +321,7 @@ export class TimePlanningsTableComponent implements OnInit, OnChanges, AfterView
323321
) {
324322
return '24:00';
325323
}
326-
const fmt = row?.useOneMinuteIntervals ? 'HH:mm:ss' : 'HH:mm';
327-
return this.datePipe.transform(stoppedAt, fmt, 'UTC') ?? '';
324+
return this.datePipe.transform(stoppedAt, 'HH:mm', 'UTC') ?? '';
328325
}
329326

330327
onFirstColumnClick(row: any): void {

eform-client/src/app/plugins/modules/time-planning-pn/models/plannings/time-planning.model.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ export class TimePlanningModel {
1616
deviceManufacturer: string;
1717
softwareVersionIsValid: boolean;
1818
/**
19-
* Phase 4: mirror of the row's assigned-site UseOneMinuteIntervals flag.
20-
* When true, the plannings table renders actual stamps at HH:mm:ss instead
21-
* of HH:mm. Default false preserves byte-identical legacy behavior for
22-
* rows whose site has the flag off.
19+
* Mirror of the row's assigned-site UseOneMinuteIntervals flag. The flag now
20+
* controls only (a) the wire-precision of stored start/stop timestamps and
21+
* (b) the minutesGap input granularity in the workday-entity dialog (1-min
22+
* vs 5-min). Displayed timestamps in the plannings table always show
23+
* HH:mm regardless of the flag.
2324
*/
2425
useOneMinuteIntervals: boolean;
2526
}

0 commit comments

Comments
 (0)