This is an automated email from the ASF dual-hosted git repository.

voidmatcha pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/master by this push:
     new 52397c8cd5 [ZEPPELIN-6443] Avoid misleading elapsed-time footer when a 
running paragraph has no dateStarted
52397c8cd5 is described below

commit 52397c8cd585fd821837432ff94c2b49f4ba2fc5
Author: 김예나 <[email protected]>
AuthorDate: Wed Jul 22 00:02:43 2026 +0900

    [ZEPPELIN-6443] Avoid misleading elapsed-time footer when a running 
paragraph has no dateStarted
    
    ### What is this PR for?
    
    The Angular paragraph footer fell back to `new Date()` when `dateStarted` 
was undefined for a running paragraph, which rendered a misleading `Started 
less than a minute ago.` message — implying the run had just started when the 
real start time was simply unknown (a race where the paragraph is `RUNNING` 
before `dateStarted` is populated).
    
    This PR shows a neutral `Running…` label instead when the start time is 
unknown, and keeps the existing `Started X ago.` output when `dateStarted` is 
present. The same bug/fix applies to the React `ParagraphFooter` twin, and a 
unit test is added there for the missing-`dateStarted` case (the Angular 
project has no unit-test setup).
    
    The pre-existing `TODO(hsuanxyz) dateStarted undefined after start` is 
resolved.
    
    ### What type of PR is it?
    
    Bug Fix
    
    ### What is the Jira issue?
    
    https://issues.apache.org/jira/browse/ZEPPELIN-6443
    
    ### How should this be tested?
    
    - `cd zeppelin-web-angular && npm run lint`
    - React unit tests: `cd zeppelin-web-angular/projects/zeppelin-react && npm 
test` (covers the `Running…` / missing-`dateStarted` case)
    - Manually: run a paragraph and confirm the running (elapsed-time) and 
finished (execution-time) footers still render correctly.
    
    ### Screenshots (if appropriate)
    
    N/A
    
    ### Questions:
    
    - Does the licenses files need to update? No
    - Is there breaking changes for older versions? No
    - Does this needs documentation? No
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    Closes #5330 from kimyenac/ZEPPELIN-6443.
    
    Signed-off-by: YONGJAE LEE <[email protected]>
---
 .../components/paragraph/ParagraphFooter.spec.tsx  | 14 ++++++++++++
 .../src/components/paragraph/ParagraphFooter.tsx   | 25 +++++++++-------------
 .../notebook/paragraph/footer/footer.component.ts  |  9 ++++++--
 3 files changed, 31 insertions(+), 17 deletions(-)

diff --git 
a/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.spec.tsx
 
b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.spec.tsx
index 69d1476b4f..43e5bec30a 100644
--- 
a/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.spec.tsx
+++ 
b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.spec.tsx
@@ -96,6 +96,20 @@ describe('ParagraphFooter mount contract', () => {
     }
   });
 
+  it('renders a neutral "Running…" label while running without a dateStarted', 
() => {
+    mountFooter({
+      ...baseProps,
+      dateStarted: undefined,
+      showExecutionTime: false,
+      showElapsedTime: true
+    });
+
+    // A missing dateStarted must not produce a misleading "Started 0 seconds 
ago" message.
+    const elapsedTime = host!.querySelector('.elapsed-time')!;
+    expect(elapsedTime.textContent).toBe('Running…');
+    expect(elapsedTime.textContent).not.toMatch(/Started/);
+  });
+
   it('update() re-renders in place with new props', () => {
     mountFooter(baseProps);
     expect(host!.querySelector('.execution-time')).not.toBeNull();
diff --git 
a/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.tsx
 
b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.tsx
index d73f881653..1adec800f5 100644
--- 
a/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.tsx
+++ 
b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.tsx
@@ -26,11 +26,7 @@ export interface ParagraphFooterProps {
 }
 
 const isOutdated = (dateUpdated?: string, dateStarted?: string): boolean => {
-  return (
-    dateUpdated !== undefined &&
-    dateStarted !== undefined &&
-    Date.parse(dateUpdated) > Date.parse(dateStarted)
-  );
+  return dateUpdated !== undefined && dateStarted !== undefined && 
Date.parse(dateUpdated) > Date.parse(dateStarted);
 };
 
 const computeExecutionTime = (props: ParagraphFooterProps): string => {
@@ -43,10 +39,7 @@ const computeExecutionTime = (props: ParagraphFooterProps): 
string => {
     return isOutdated(dateUpdated, dateStarted) ? 'outdated' : '';
   }
 
-  const durationFormat = formatDistanceStrict(
-    new Date(dateStarted),
-    new Date(dateFinished)
-  );
+  const durationFormat = formatDistanceStrict(new Date(dateStarted), new 
Date(dateFinished));
   const endFormat = format(new Date(dateFinished), 'MMMM dd yyyy, h:mm:ss a');
   const userLabel = user === undefined || user === null ? 'anonymous' : user;
   let desc = `Took ${durationFormat}. Last updated by ${userLabel} at 
${endFormat}.`;
@@ -57,8 +50,13 @@ const computeExecutionTime = (props: ParagraphFooterProps): 
string => {
 };
 
 const computeElapsedTime = (dateStarted?: string): string => {
-  const base = dateStarted ? new Date(dateStarted) : new Date();
-  return `Started ${formatDistanceToNow(base)} ago.`;
+  // A running paragraph may not have a dateStarted yet (e.g. queued/pending 
on the
+  // interpreter). Fall back to a neutral label instead of measuring from 
"now", which
+  // would render a misleading "Started less than a minute ago." message.
+  if (!dateStarted) {
+    return 'Running…';
+  }
+  return `Started ${formatDistanceToNow(new Date(dateStarted))} ago.`;
 };
 
 export const ParagraphFooter = (props: ParagraphFooterProps) => {
@@ -79,10 +77,7 @@ export interface ParagraphFooterMountHandle {
   unmount: () => void;
 }
 
-export const mount = (
-  element: HTMLElement,
-  initialProps: ParagraphFooterProps
-): ParagraphFooterMountHandle => {
+export const mount = (element: HTMLElement, initialProps: 
ParagraphFooterProps): ParagraphFooterMountHandle => {
   if (!element) {
     throw new Error('Mount element is required');
   }
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts
 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts
index 6495742e26..7441edd2d5 100644
--- 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts
@@ -67,8 +67,13 @@ export class NotebookParagraphFooterComponent implements 
OnChanges {
   }
 
   getElapsedTime() {
-    // TODO(hsuanxyz) dateStarted undefined after start
-    return `Started ${formatDistanceToNow(this.dateStarted ? new 
Date(this.dateStarted) : new Date())} ago.`;
+    // A running paragraph may not have a dateStarted yet (e.g. queued/pending 
on the
+    // interpreter). Fall back to a neutral label instead of measuring from 
"now", which
+    // would render a misleading "Started less than a minute ago." message.
+    if (!this.dateStarted) {
+      return 'Running…';
+    }
+    return `Started ${formatDistanceToNow(new Date(this.dateStarted))} ago.`;
   }
 
   constructor() {}

Reply via email to