Skip to content

OU-1399: pass ISO string to Timestamp component for valid date rendering#968

Merged
PeterYurkovich merged 2 commits into
openshift:mainfrom
tremes:ou-1399
Jun 1, 2026
Merged

OU-1399: pass ISO string to Timestamp component for valid date rendering#968
PeterYurkovich merged 2 commits into
openshift:mainfrom
tremes:ou-1399

Conversation

@tremes
Copy link
Copy Markdown
Contributor

@tremes tremes commented Jun 1, 2026

String(epochMs) produces a numeric string that new Date() cannot parse, resulting in Invalid Date and "-" displayed in the Start/End columns. Convert to ISO 8601 format via toISOString() instead.

Assisted-by: Claude Code:claude-opus-4-6

Summary by CodeRabbit

  • Improvements
    • Start and End timestamps now use standardized ISO formatting for consistent display.
    • When start or end times are unavailable (or an incident isn't resolved), the table shows '---' instead of a timestamp for clearer, more accurate incident status.

String(epochMs) produces a numeric string that new Date() cannot parse,
resulting in Invalid Date and "-" displayed in the Start/End columns.
Convert to ISO 8601 format via toISOString() instead.

Signed-off-by: Tomáš Remeš <tremes@redhat.com>
Assisted-by: Claude Code:claude-opus-4-6
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jun 1, 2026
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Jun 1, 2026

@tremes: This pull request references OU-1399 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the bug to target the "5.0.0" version, but no target version was set.

Details

In response to this:

String(epochMs) produces a numeric string that new Date() cannot parse, resulting in Invalid Date and "-" displayed in the Start/End columns. Convert to ISO 8601 format via toISOString() instead.

Assisted-by: Claude Code:claude-opus-4-6

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 1, 2026

Walkthrough

Start and End timestamp cells in incident details and the Start cell in the incidents table now conditionally render '---' when missing and otherwise pass ISO-8601 strings (via new Date(...).toISOString()) to the Timestamp component.

Changes

Timestamp Format Standardization

Layer / File(s) Summary
Compute and render Start in incidents table
web/src/components/Incidents/IncidentsTable.tsx
getMinStartDate computes the minimum alertsStartFiring across expanded rows and returns 0 for non-finite results; the Start cell renders a Timestamp with new Date(...).toISOString() when >0, otherwise '---'.
Render Start and End in details row
web/src/components/Incidents/IncidentsDetailsRowTable.tsx
Details row Start shows '---' when alertsStartFiring is falsy; End shows '---' when not resolved or alertsEndFiring is falsy; when present they render Timestamp with ISO-8601 strings created via new Date(...).toISOString().

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 15
✅ Passed checks (15 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately describes the main change: converting epoch values to ISO strings for proper Timestamp component rendering.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed Repository does not use Ginkgo testing framework (uses Go testing package instead). PR contains no Ginkgo tests, making the check not applicable.
Test Structure And Quality ✅ Passed Repository does not use Ginkgo testing framework. Go tests use standard testing package; Ginkgo is not a go.mod dependency and no Ginkgo patterns exist in codebase.
Microshift Test Compatibility ✅ Passed PR adds no Ginkgo e2e tests. Changes are to TypeScript React components and a standard Go unit test file; no e2e test framework patterns found.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No Ginkgo e2e tests added. PR contains only standard Go unit tests for HTTP server functionality, not cluster-related e2e tests requiring multi-node assumptions.
Topology-Aware Scheduling Compatibility ✅ Passed PR modifies only React/TypeScript UI components for timestamp rendering; no deployment manifests, operator code, or scheduling constraints are introduced.
Ote Binary Stdout Contract ✅ Passed PR modifies only TypeScript/React UI components (web/src/components/Incidents/). OTE Binary Stdout Contract check applies only to Go test binaries. No Go code or OTE binaries affected.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed PR contains no Ginkgo e2e tests. Changes are limited to TypeScript React components and standard Go unit tests (testing package), not Ginkgo e2e tests.
No-Weak-Crypto ✅ Passed PR contains no weak cryptography, custom crypto, or insecure secret comparisons; changes are limited to timestamp rendering in React components.
Container-Privileges ✅ Passed PR modifies only React/TypeScript UI components for date rendering; no container/K8s manifests or Dockerfiles were changed, so container-privileges check is not applicable.
No-Sensitive-Data-In-Logs ✅ Passed No logging statements or sensitive data exposure found in modified components. Changes only affect timestamp rendering with epoch-to-ISO conversion.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/src/components/Incidents/IncidentsTable.tsx (1)

94-99: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Consider UX for zero-timestamp edge case.

When alert.alertsExpandedRowData is empty or missing, getMinStartDate returns 0, which renders as "1970-01-01T00:00:00.000Z" (epoch start). This might be confusing for users.

Consider displaying a fallback like '---' when there's no valid start date, as already done for the resolved End timestamp in IncidentsDetailsRowTable.

📅 Proposed UX improvement
 const getMinStartDate = (alert: GroupedAlert): number => {
   if (!alert.alertsExpandedRowData || alert.alertsExpandedRowData.length === 0) {
-    return 0;
+    return -1; // Use -1 to signal "no data" instead of 0
   }
   return Math.min(...alert.alertsExpandedRowData.map((alertData) => alertData.alertsStartFiring));
 };

Then update the rendering logic (lines 183-185) to check for -1:

                     <Td dataLabel={columnNames.startDate}>
-                      <Timestamp
-                        timestamp={new Date(getMinStartDate(alert) * 1000).toISOString()}
-                      />
+                      {(() => {
+                        const minStart = getMinStartDate(alert);
+                        return minStart >= 0 ? (
+                          <Timestamp
+                            timestamp={new Date(minStart * 1000).toISOString()}
+                          />
+                        ) : (
+                          '---'
+                        );
+                      })()}
                     </Td>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/components/Incidents/IncidentsTable.tsx` around lines 94 - 99,
getMinStartDate currently returns 0 for missing/empty
alert.alertsExpandedRowData which renders as the epoch; change getMinStartDate
to return a sentinel (e.g., -1) for "no start date" and update the component
rendering that consumes getMinStartDate (where you render the start timestamp
for a GroupedAlert) to check for that sentinel and display the same fallback
string '---' used for resolved End timestamps in IncidentsDetailsRowTable;
adjust any types/locals (GroupedAlert, alertsExpandedRowData mapping)
accordingly so callers treat -1 as "no date" instead of a real timestamp.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/src/components/Incidents/IncidentsDetailsRowTable.tsx`:
- Around line 56-58: The End timestamp rendering using <Timestamp timestamp={new
Date(alertDetails.alertsEndFiring * 1000).toISOString()} /> can throw if
alertsEndFiring is null/undefined/NaN; apply the same defensive check used for
the Start timestamp: only render <Timestamp> (or pass a computed ISO string)
when alertDetails.resolved is true AND alertDetails.alertsEndFiring is
non-null/undefined and a valid number (e.g., check alertDetails.alertsEndFiring
!= null && !isNaN(Number(alertDetails.alertsEndFiring))); otherwise omit the
<Timestamp> or pass undefined so toISOString() is never called. Ensure you
update the IncidentsDetailsRowTable component where Timestamp and
alertDetails.alertsEndFiring are referenced.

In `@web/src/components/Incidents/IncidentsTable.tsx`:
- Around line 183-185: getMinStartDate(alert) may return null/undefined/NaN
causing new Date(...).toISOString() to throw; before calling toISOString() in
the Timestamp component use defensive validation: call getMinStartDate(alert),
ensure it is a finite number (or create a Date and check
!isNaN(date.getTime())), and only call toISOString() when valid; otherwise pass
a safe fallback (null/undefined/empty string) into <Timestamp /> so it can
render gracefully. Reference: getMinStartDate, alert, and the Timestamp
component usage in IncidentsTable.tsx.

---

Outside diff comments:
In `@web/src/components/Incidents/IncidentsTable.tsx`:
- Around line 94-99: getMinStartDate currently returns 0 for missing/empty
alert.alertsExpandedRowData which renders as the epoch; change getMinStartDate
to return a sentinel (e.g., -1) for "no start date" and update the component
rendering that consumes getMinStartDate (where you render the start timestamp
for a GroupedAlert) to check for that sentinel and display the same fallback
string '---' used for resolved End timestamps in IncidentsDetailsRowTable;
adjust any types/locals (GroupedAlert, alertsExpandedRowData mapping)
accordingly so callers treat -1 as "no date" instead of a real timestamp.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 080984eb-e33f-47d8-b431-90169aa15923

📥 Commits

Reviewing files that changed from the base of the PR and between f9b2b03 and f1c8a7c.

📒 Files selected for processing (2)
  • web/src/components/Incidents/IncidentsDetailsRowTable.tsx
  • web/src/components/Incidents/IncidentsTable.tsx

Comment thread web/src/components/Incidents/IncidentsDetailsRowTable.tsx
Comment thread web/src/components/Incidents/IncidentsTable.tsx Outdated
@PeterYurkovich
Copy link
Copy Markdown
Contributor

/lgtm

@openshift-ci openshift-ci Bot added lgtm Indicates that a PR is ready to be merged. approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Jun 1, 2026
@PeterYurkovich
Copy link
Copy Markdown
Contributor

/label qe-approved

@openshift-ci openshift-ci Bot added the qe-approved Signifies that QE has signed off on this PR label Jun 1, 2026
@PeterYurkovich
Copy link
Copy Markdown
Contributor

/cherry-pick release-coo-ocp-4.22

@openshift-cherrypick-robot
Copy link
Copy Markdown

@PeterYurkovich: once the present PR merges, I will cherry-pick it on top of release-coo-ocp-4.22 in a new PR and assign it to you.

Details

In response to this:

/cherry-pick release-coo-ocp-4.22

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@PeterYurkovich
Copy link
Copy Markdown
Contributor

QE to be completed within COO

@PeterYurkovich
Copy link
Copy Markdown
Contributor

/hold

@openshift-ci openshift-ci Bot added do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. and removed lgtm Indicates that a PR is ready to be merged. labels Jun 1, 2026
@PeterYurkovich
Copy link
Copy Markdown
Contributor

/lgtm

@PeterYurkovich
Copy link
Copy Markdown
Contributor

/unhold

@openshift-ci openshift-ci Bot added lgtm Indicates that a PR is ready to be merged. and removed do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. labels Jun 1, 2026
Guard against null/undefined/NaN/zero timestamp values that would
cause toISOString() to throw or render epoch (1970) dates. Show
'---' fallback instead, consistent with unresolved End timestamps.

Signed-off-by: Tomáš Remeš <tremes@redhat.com>
Assisted-by: Claude Code:claude-opus-4-6
@openshift-ci openshift-ci Bot removed the lgtm Indicates that a PR is ready to be merged. label Jun 1, 2026
@PeterYurkovich
Copy link
Copy Markdown
Contributor

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jun 1, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Jun 1, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: PeterYurkovich, tremes

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
web/src/components/Incidents/IncidentsDetailsRowTable.tsx (1)

48-54: ⚡ Quick win

Consider adding finite value check for consistency.

While the truthy check catches null, undefined, NaN, and 0, it doesn't guard against Infinity or -Infinity, which would cause toISOString() to throw a RangeError. The table file's getMinStartDate function uses Number.isFinite() to prevent this. For consistency and robustness, consider applying the same guard here.

🛡️ Proposed defensive enhancement
              <Td dataLabel="expanded-details-firingstart">
-                {alertDetails.alertsStartFiring ? (
+                {alertDetails.alertsStartFiring && Number.isFinite(alertDetails.alertsStartFiring) ? (
                  <Timestamp
                    timestamp={new Date(alertDetails.alertsStartFiring * 1000).toISOString()}
                  />
                ) : (
                  '---'
                )}
              </Td>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/components/Incidents/IncidentsDetailsRowTable.tsx` around lines 48 -
54, The current rendering uses a truthy check on alertDetails.alertsStartFiring
before calling new Date(...).toISOString(), but that can still allow
Infinity/-Infinity and cause a RangeError; update the condition to mirror
getMinStartDate by using Number.isFinite(alertDetails.alertsStartFiring) (or
similar finite check) before passing alertDetails.alertsStartFiring to Timestamp
so the Timestamp(...) call only happens for finite numeric values.
web/src/components/Incidents/IncidentsTable.tsx (1)

186-192: 💤 Low value

Consider caching the computed minimum start date.

The current implementation calls getMinStartDate(alert) twice: once for the condition check and once to compute the timestamp. While not a performance issue for small datasets, you could eliminate the duplicate call by computing it once.

♻️ Optional refactor to eliminate duplicate call
                   <Td dataLabel={columnNames.startDate}>
-                      {getMinStartDate(alert) > 0 ? (
+                      {(() => {
+                        const minStart = getMinStartDate(alert);
+                        return minStart > 0 ? (
                         <Timestamp
-                          timestamp={new Date(getMinStartDate(alert) * 1000).toISOString()}
+                          timestamp={new Date(minStart * 1000).toISOString()}
                         />
-                      ) : (
+                        ) : (
                         '---'
-                      )}
+                        );
+                      })()}
                   </Td>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/components/Incidents/IncidentsTable.tsx` around lines 186 - 192,
Compute getMinStartDate(alert) once and reuse it: before rendering the JSX for
this row, assign const minStart = getMinStartDate(alert) (or inside the map
callback/functional component scope) and then use minStart for the conditional
and for creating the Timestamp (new Date(minStart * 1000).toISOString()). Update
references in the IncidentsTable component so Timestamp and the '---' fallback
both use this cached minStart instead of calling getMinStartDate(alert) twice.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@web/src/components/Incidents/IncidentsDetailsRowTable.tsx`:
- Around line 48-54: The current rendering uses a truthy check on
alertDetails.alertsStartFiring before calling new Date(...).toISOString(), but
that can still allow Infinity/-Infinity and cause a RangeError; update the
condition to mirror getMinStartDate by using
Number.isFinite(alertDetails.alertsStartFiring) (or similar finite check) before
passing alertDetails.alertsStartFiring to Timestamp so the Timestamp(...) call
only happens for finite numeric values.

In `@web/src/components/Incidents/IncidentsTable.tsx`:
- Around line 186-192: Compute getMinStartDate(alert) once and reuse it: before
rendering the JSX for this row, assign const minStart = getMinStartDate(alert)
(or inside the map callback/functional component scope) and then use minStart
for the conditional and for creating the Timestamp (new Date(minStart *
1000).toISOString()). Update references in the IncidentsTable component so
Timestamp and the '---' fallback both use this cached minStart instead of
calling getMinStartDate(alert) twice.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 805acd08-11b9-410e-bf7f-daad632d8c8e

📥 Commits

Reviewing files that changed from the base of the PR and between f1c8a7c and 74b20d7.

📒 Files selected for processing (2)
  • web/src/components/Incidents/IncidentsDetailsRowTable.tsx
  • web/src/components/Incidents/IncidentsTable.tsx

@PeterYurkovich
Copy link
Copy Markdown
Contributor

/override ci/prow/e2e-aws-ovn

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Jun 1, 2026

@PeterYurkovich: Overrode contexts on behalf of PeterYurkovich: ci/prow/e2e-aws-ovn

Details

In response to this:

/override ci/prow/e2e-aws-ovn

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@PeterYurkovich PeterYurkovich merged commit 225aade into openshift:main Jun 1, 2026
10 checks passed
@openshift-cherrypick-robot
Copy link
Copy Markdown

@PeterYurkovich: new pull request created: #969

Details

In response to this:

/cherry-pick release-coo-ocp-4.22

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Jun 1, 2026

@tremes: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-aws-ovn 74b20d7 link unknown /test e2e-aws-ovn

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. qe-approved Signifies that QE has signed off on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants