diff --git a/tests/ui/perfherder/alerts-view/alert_status_countdown_test.jsx b/tests/ui/perfherder/alerts-view/alert_status_countdown_test.jsx index 2dd47412695..06990051d74 100644 --- a/tests/ui/perfherder/alerts-view/alert_status_countdown_test.jsx +++ b/tests/ui/perfherder/alerts-view/alert_status_countdown_test.jsx @@ -42,7 +42,7 @@ test('Alert is created on Monday, Triage countdown shows 3 working days', async const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Triage: 3 days left'); + expect(dueDateStatusText).toBe('Time left: 3 days left'); }); test('Alert is created on Monday, Triage countdown shows 2 working days', async () => { @@ -62,7 +62,7 @@ test('Alert is created on Monday, Triage countdown shows 2 working days', async const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Triage: 2 days left'); + expect(dueDateStatusText).toBe('Time left: 2 days left'); }); test('Alert is created on Monday, Triage countdown shows 1 working days', async () => { @@ -82,7 +82,7 @@ test('Alert is created on Monday, Triage countdown shows 1 working days', async const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Triage: 1 days left'); + expect(dueDateStatusText).toBe('Time left: 1 days left'); }); test('Alert is created on Monday, Triage countdown shows hours left', async () => { @@ -102,7 +102,7 @@ test('Alert is created on Monday, Triage countdown shows hours left', async () = const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Triage: 10 hours left'); + expect(dueDateStatusText).toBe('Time left: 10 hours left'); }); test('Alert is created on Monday, Triage countdown shows Overdue', async () => { @@ -122,7 +122,7 @@ test('Alert is created on Monday, Triage countdown shows Overdue', async () => { const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Triage: Overdue'); + expect(dueDateStatusText).toBe('Time left: Overdue'); }); test('Alert is created on Monday, Bug countdown shows 5 working days', async () => { @@ -143,7 +143,7 @@ test('Alert is created on Monday, Bug countdown shows 5 working days', async () const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Bug: 5 days left'); + expect(dueDateStatusText).toBe('Time left: 5 days left'); }); test('Alert is created on Monday, Bug countdown shows 4 working days', async () => { @@ -164,7 +164,7 @@ test('Alert is created on Monday, Bug countdown shows 4 working days', async () const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Bug: 4 days left'); + expect(dueDateStatusText).toBe('Time left: 4 days left'); }); test('Alert is created on Monday, Bug countdown shows 3 working days', async () => { @@ -185,7 +185,7 @@ test('Alert is created on Monday, Bug countdown shows 3 working days', async () const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Bug: 3 days left'); + expect(dueDateStatusText).toBe('Time left: 3 days left'); }); test('Alert is created on Monday, Bug countdown shows 2 working days', async () => { @@ -206,7 +206,7 @@ test('Alert is created on Monday, Bug countdown shows 2 working days', async () const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Bug: 2 days left'); + expect(dueDateStatusText).toBe('Time left: 2 days left'); }); test('Alert is created on Monday, Bug countdown shows 1 working days', async () => { @@ -227,7 +227,7 @@ test('Alert is created on Monday, Bug countdown shows 1 working days', async () const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Bug: 1 days left'); + expect(dueDateStatusText).toBe('Time left: 1 days left'); }); test('Alert is created on Monday, Bug countdown shows hours left', async () => { @@ -248,7 +248,7 @@ test('Alert is created on Monday, Bug countdown shows hours left', async () => { const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Bug: 23 hours left'); + expect(dueDateStatusText).toBe('Time left: 23 hours left'); }); test('Alert is created on Monday, Bug countdown shows Overdue', async () => { @@ -269,7 +269,7 @@ test('Alert is created on Monday, Bug countdown shows Overdue', async () => { const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Bug: Overdue'); + expect(dueDateStatusText).toBe('Time left: Overdue'); }); // testing what the tooltip shows for the cases when the alert is created either on Wednesday, Thursday, Friday or the weekend @@ -293,7 +293,7 @@ test('Alert is created on Wednesday, Triage countdown shows 3 working days', asy const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Triage: 3 days left'); + expect(dueDateStatusText).toBe('Time left: 3 days left'); }); test('Alert is created on Wednesday, Triage countdown shows 2 working days', async () => { @@ -314,7 +314,7 @@ test('Alert is created on Wednesday, Triage countdown shows 2 working days', asy const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Triage: 2 days left'); + expect(dueDateStatusText).toBe('Time left: 2 days left'); }); test('Alert is created on Wednesday, Triage countdown shows 1 working days', async () => { @@ -335,10 +335,10 @@ test('Alert is created on Wednesday, Triage countdown shows 1 working days', asy const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Triage: 1 days left'); + expect(dueDateStatusText).toBe('Time left: 1 days left'); }); -test('Alert is created on Wednesday, Triage countdown shows hours left', async () => { +test('Alert is created on Wednesday, Triage countdown shows Overdue when due date has been reached', async () => { const alert = testAlertSummaries[0]; // created date day is set to Wednesday @@ -356,7 +356,7 @@ test('Alert is created on Wednesday, Triage countdown shows hours left', async ( const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Triage: 0 hours left'); + expect(dueDateStatusText).toBe('Time left: Overdue'); }); test('Alert is created on Wednesday, Triage countdown shows Overdue', async () => { @@ -377,7 +377,7 @@ test('Alert is created on Wednesday, Triage countdown shows Overdue', async () = const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Triage: Overdue'); + expect(dueDateStatusText).toBe('Time left: Overdue'); }); test('Alert is created on Wednesday, Bug countdown shows 5 working days', async () => { @@ -398,7 +398,7 @@ test('Alert is created on Wednesday, Bug countdown shows 5 working days', async const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Bug: 5 days left'); + expect(dueDateStatusText).toBe('Time left: 5 days left'); }); test('Alert is created on Wednesday, Bug countdown shows 4 working days', async () => { @@ -419,7 +419,7 @@ test('Alert is created on Wednesday, Bug countdown shows 4 working days', async const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Bug: 4 days left'); + expect(dueDateStatusText).toBe('Time left: 4 days left'); }); test('Alert is created on Wednesday, Bug countdown shows 3 working days', async () => { @@ -440,7 +440,7 @@ test('Alert is created on Wednesday, Bug countdown shows 3 working days', async const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Bug: 3 days left'); + expect(dueDateStatusText).toBe('Time left: 3 days left'); }); test('Alert is created on Wednesday, Bug countdown shows 2 working days', async () => { @@ -461,7 +461,7 @@ test('Alert is created on Wednesday, Bug countdown shows 2 working days', async const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Bug: 2 days left'); + expect(dueDateStatusText).toBe('Time left: 2 days left'); }); test('Alert is created on Wednesday, Bug countdown shows 1 working days', async () => { @@ -482,7 +482,7 @@ test('Alert is created on Wednesday, Bug countdown shows 1 working days', async const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Bug: 1 days left'); + expect(dueDateStatusText).toBe('Time left: 1 days left'); }); test('Alert is created on Wednesday, Bug countdown shows hours left', async () => { @@ -491,10 +491,10 @@ test('Alert is created on Wednesday, Bug countdown shows hours left', async () = // created date day is set to Wednesday alert.created = '2022-02-09T11:41:31.419156'; alert.first_triaged = '2022-02-09T11:41:31.419156'; - alert.bug_due_date = '2022-02-16T10:41:31.419156'; + alert.bug_due_date = '2022-02-16T12:41:31.419156'; // current day is set to Wednesday - Date.now = jest.fn(() => Date.parse('2022-02-16T12:40:31.419156')); + Date.now = jest.fn(() => Date.parse('2022-02-16T10:41:31.419156')); const { getByTestId } = testStatusDropdown([], alert); const dueDateIcon = await waitFor(() => getByTestId('triage-clock-icon')); @@ -503,7 +503,7 @@ test('Alert is created on Wednesday, Bug countdown shows hours left', async () = const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Bug: 2 hours left'); + expect(dueDateStatusText).toBe('Time left: 2 hours left'); }); test('Alert is created on Wednesday, Bug countdown shows Overdue', async () => { @@ -524,7 +524,7 @@ test('Alert is created on Wednesday, Bug countdown shows Overdue', async () => { const dueDateStatus = await waitFor(() => getByTestId('due-date-status')); const dueDateStatusText = dueDateStatus.querySelector('p').innerHTML; - expect(dueDateStatusText).toBe('Bug: Overdue'); + expect(dueDateStatusText).toBe('Time left: Overdue'); }); test('Alert is ready, countdown shows Ready for acknowledge', async () => { diff --git a/ui/perfherder/alerts/AlertStatusCountdown.jsx b/ui/perfherder/alerts/AlertStatusCountdown.jsx index 6f677d70a4f..cad28bc2737 100644 --- a/ui/perfherder/alerts/AlertStatusCountdown.jsx +++ b/ui/perfherder/alerts/AlertStatusCountdown.jsx @@ -10,139 +10,110 @@ import { countdownClasses } from '../perf-helpers/constants'; import { alertIsLinkedToBug, alertIsTriaged, - getCountdownText, - getTimeDifference, + getCountdownLabel, isWeekend, } from '../perf-helpers/alertCountdownHelper'; -export default class AlertStatusCountdown extends React.Component { - constructor(props) { - super(props); - - this.showCountdownToTriageIcon = true; - } - - getDueDateCountdownsStatus() { - const { alertSummary } = this.props; - let { - triage_due_date: triageDueDate, - bug_due_date: bugDueDate, - } = alertSummary; - - const currentDate = new Date(Date.now()); - triageDueDate = new Date(triageDueDate); - bugDueDate = new Date(bugDueDate); - - const timeToTriageDifference = getTimeDifference( - currentDate, - triageDueDate, - ); - const timeToBugDifference = getTimeDifference(currentDate, bugDueDate); - - const countdowns = { - triage: '', - bug: '', - }; +// Before: defined inside render() on every call, allocating a new object each time. +// After: module-level constant, allocated once. +const DUE_DATE_FORMAT = { + day: 'numeric', + month: 'short', + hour: '2-digit', + minute: '2-digit', +}; - if (isWeekend()) { - this.showCountdownToTriageIcon = false; - return countdowns; - } - if (alertIsTriaged(alertSummary)) { - countdowns.bug = getCountdownText( - currentDate, - bugDueDate, - timeToBugDifference, - ); - } else { - countdowns.triage = getCountdownText( - currentDate, - triageDueDate, - timeToTriageDifference, - ); - countdowns.bug = getCountdownText( - currentDate, - bugDueDate, - timeToBugDifference, - ); - } +// Before: 'en-UK' is not a valid BCP-47 locale tag and silently falls back to the +// system locale, producing inconsistent date formats across machines. +// After: 'en-GB' is the correct tag for British English. +const formatDate = (dateStr) => + new Date(dateStr).toLocaleString('en-GB', DUE_DATE_FORMAT); - return countdowns; - } +const iconClassFor = (label) => { + if (label === 'Overdue') return countdownClasses.overdue; + if (label.includes('hours')) return countdownClasses.today; + return countdownClasses.ok; +}; - getCountdownClass(countdown) { - if (countdown === 'Overdue') { - return countdownClasses.overdue; - } - if (countdown.endsWith('hours left')) { - return countdownClasses.today; - } - return countdownClasses.ok; +// Before: class component with a getDueDateCountdownsStatus() method that mutated +// this.showCountdownToTriageIcon as a side effect, computed both triage and bug +// countdowns even when only one was shown, and used three boolean flags +// (showTriageCountdown, showBugCountdown, showReady) to control what to render. +// triageDueDate / bugDueDate were also shadowed in render(): first holding a raw +// ISO string from alertSummary, then overwritten with a formatted display string. +// +// After: function component with a linear three-branch state machine — each branch +// returns exactly what it renders, with no shared mutable state. +export default function AlertStatusCountdown({ alertSummary }) { + const alertStatus = getStatus(alertSummary.status); + + if (alertStatus !== 'untriaged' || isWeekend()) { + return
; } - render() { - const { alertSummary } = this.props; - - const alertStatus = getStatus(alertSummary.status); - const countdown = this.getDueDateCountdownsStatus(); - let countdownClass; - let showTriageCountdown; - let showBugCountdown; - let showReady; - - if (!alertIsTriaged(alertSummary)) { - countdownClass = this.getCountdownClass(countdown.triage); - showTriageCountdown = true; - } else if (!alertIsLinkedToBug(alertSummary)) { - countdownClass = this.getCountdownClass(countdown.bug); - showBugCountdown = true; - } else { - countdownClass = countdownClasses.ready; - showReady = true; - } - - const showCountdown = - alertStatus === 'untriaged' && this.showCountdownToTriageIcon; + const triaged = alertIsTriaged(alertSummary); + const hasBug = alertIsLinkedToBug(alertSummary); + if (triaged && hasBug) { return ( -Triage: {countdown.triage}
- > - )} - {showBugCountdown && ( - <> -Bug: {countdown.bug}
- > - )} - {showReady &&Time left: {label}
+