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

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


The following commit(s) were added to refs/heads/master by this push:
     new 6cca73b3bea Web console: Explore bugbash (#18343)
6cca73b3bea is described below

commit 6cca73b3bea2efd91cf8efab6cb4f191293abcc2
Author: Vadim Ogievetsky <[email protected]>
AuthorDate: Fri Aug 8 00:03:18 2025 +0100

    Web console: Explore bugbash (#18343)
    
    * fix ticks and timezone
    
    * error boundary 1
    
    * update licenses file
    
    * formatting
---
 licenses.yaml                                      |  2 +-
 web-console/package-lock.json                      | 14 +++---
 web-console/package.json                           |  2 +-
 web-console/src/utils/general.spec.ts              |  1 +
 web-console/src/utils/general.tsx                  |  2 +-
 web-console/src/utils/ticks.ts                     |  9 +++-
 .../components/error-boundary/error-boundary.scss  | 34 +++++++++++++
 .../components/error-boundary/error-boundary.tsx   | 57 ++++++++++++++++++++++
 .../components/module-pane/module-pane.tsx         |  3 +-
 .../src/views/explore-view/models/explore-state.ts |  3 +-
 10 files changed, 113 insertions(+), 14 deletions(-)

diff --git a/licenses.yaml b/licenses.yaml
index 777e1355261..ff8b0d5e5f1 100644
--- a/licenses.yaml
+++ b/licenses.yaml
@@ -5555,7 +5555,7 @@ license_category: binary
 module: web-console
 license_name: Apache License version 2.0
 copyright: Vadim Ogievetsky
-version: 1.2.0
+version: 1.2.1
 
 ---
 
diff --git a/web-console/package-lock.json b/web-console/package-lock.json
index 26db3a09974..fa00329611e 100644
--- a/web-console/package-lock.json
+++ b/web-console/package-lock.json
@@ -19,7 +19,7 @@
         "@internationalized/date": "^3.5.6",
         "ace-builds": "~1.5.3",
         "axios": "^1.7.7",
-        "chronoshift": "^1.2.0",
+        "chronoshift": "^1.2.1",
         "classnames": "^2.2.6",
         "copy-to-clipboard": "^3.3.3",
         "d3-array": "^3.2.4",
@@ -6007,9 +6007,9 @@
       }
     },
     "node_modules/chronoshift": {
-      "version": "1.2.0",
-      "resolved": 
"https://registry.npmjs.org/chronoshift/-/chronoshift-1.2.0.tgz";,
-      "integrity": 
"sha512-VRmMsk6N1X4q/6xBhzG31qhQP2cAQJXSAvXQIJPZi3ILAXjhvu0Lr0m5dpJKEEsEVGLCnPOQlk7UYwBd2u8lzQ==",
+      "version": "1.2.1",
+      "resolved": 
"https://registry.npmjs.org/chronoshift/-/chronoshift-1.2.1.tgz";,
+      "integrity": 
"sha512-pfHPuUjGb9ECw8dcuRzY0pKO1ohO6MIDTlNvzKVPrng8RUkwT4R9v3hHnVPu4gPKTciMQEZxclYENZMLwLwF4Q==",
       "license": "Apache-2.0",
       "dependencies": {
         "@internationalized/date": "^3.5.6",
@@ -22812,9 +22812,9 @@
       "dev": true
     },
     "chronoshift": {
-      "version": "1.2.0",
-      "resolved": 
"https://registry.npmjs.org/chronoshift/-/chronoshift-1.2.0.tgz";,
-      "integrity": 
"sha512-VRmMsk6N1X4q/6xBhzG31qhQP2cAQJXSAvXQIJPZi3ILAXjhvu0Lr0m5dpJKEEsEVGLCnPOQlk7UYwBd2u8lzQ==",
+      "version": "1.2.1",
+      "resolved": 
"https://registry.npmjs.org/chronoshift/-/chronoshift-1.2.1.tgz";,
+      "integrity": 
"sha512-pfHPuUjGb9ECw8dcuRzY0pKO1ohO6MIDTlNvzKVPrng8RUkwT4R9v3hHnVPu4gPKTciMQEZxclYENZMLwLwF4Q==",
       "requires": {
         "@internationalized/date": "^3.5.6",
         "tslib": "^2.8.1"
diff --git a/web-console/package.json b/web-console/package.json
index 6e08c95e7ea..370bf979c02 100644
--- a/web-console/package.json
+++ b/web-console/package.json
@@ -61,7 +61,7 @@
     "@internationalized/date": "^3.5.6",
     "ace-builds": "~1.5.3",
     "axios": "^1.7.7",
-    "chronoshift": "^1.2.0",
+    "chronoshift": "^1.2.1",
     "classnames": "^2.2.6",
     "copy-to-clipboard": "^3.3.3",
     "d3-array": "^3.2.4",
diff --git a/web-console/src/utils/general.spec.ts 
b/web-console/src/utils/general.spec.ts
index 02c47163260..2e863ca7d6f 100644
--- a/web-console/src/utils/general.spec.ts
+++ b/web-console/src/utils/general.spec.ts
@@ -104,6 +104,7 @@ describe('general', () => {
       expect(formatNumber(0)).toEqual('0');
       expect(formatNumber(5)).toEqual('5');
       expect(formatNumber(5.1)).toEqual('5.1');
+      expect(formatNumber(1 / 3)).toEqual('0.333');
     });
   });
 
diff --git a/web-console/src/utils/general.tsx 
b/web-console/src/utils/general.tsx
index 50ac0a43dd0..3547738ef80 100644
--- a/web-console/src/utils/general.tsx
+++ b/web-console/src/utils/general.tsx
@@ -277,7 +277,7 @@ export function formatInteger(n: NumberLike): string {
 }
 
 export function formatNumber(n: NumberLike): string {
-  return (n || 0).toLocaleString('en-US', { maximumFractionDigits: 20 });
+  return (n || 0).toLocaleString('en-US', { maximumFractionDigits: 3 });
 }
 
 export function formatNumberAbbreviated(n: NumberLike): string {
diff --git a/web-console/src/utils/ticks.ts b/web-console/src/utils/ticks.ts
index fbe4fc10e67..7e5ed27cffc 100644
--- a/web-console/src/utils/ticks.ts
+++ b/web-console/src/utils/ticks.ts
@@ -70,10 +70,15 @@ export function timezoneAwareTicks(
   count: number,
   timezone: Timezone,
 ): Date[] {
-  if (end < start) throw new Error('start must come before end end');
+  if (end < start) return [];
   const interval = tickInterval(start, end, count);
   if (!interval) return [];
-  return interval.materialize(start, end, timezone);
+  try {
+    return interval.materialize(start, end, timezone);
+  } catch {
+    // If there is some issue with materialization (maybe a strange duration, 
return nothing)
+    return [];
+  }
 }
 
 const durationSecond = new Duration('PT1S');
diff --git 
a/web-console/src/views/explore-view/components/error-boundary/error-boundary.scss
 
b/web-console/src/views/explore-view/components/error-boundary/error-boundary.scss
new file mode 100644
index 00000000000..5559bd17786
--- /dev/null
+++ 
b/web-console/src/views/explore-view/components/error-boundary/error-boundary.scss
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@import '../../../../variables';
+
+.error-boundary {
+  padding: 20px;
+  text-align: center;
+  color: $red3;
+
+  h3 {
+    margin-bottom: 10px;
+    color: $red5;
+  }
+
+  p {
+    margin: 0;
+  }
+}
diff --git 
a/web-console/src/views/explore-view/components/error-boundary/error-boundary.tsx
 
b/web-console/src/views/explore-view/components/error-boundary/error-boundary.tsx
new file mode 100644
index 00000000000..21172c1bd71
--- /dev/null
+++ 
b/web-console/src/views/explore-view/components/error-boundary/error-boundary.tsx
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+
+import './error-boundary.scss';
+
+interface ErrorBoundaryState {
+  error?: Error;
+}
+
+export class ErrorBoundary extends React.Component<
+  { children: React.ReactNode },
+  ErrorBoundaryState
+> {
+  constructor(props: { children: React.ReactNode }) {
+    super(props);
+    this.state = {};
+  }
+
+  static getDerivedStateFromError(error: Error): ErrorBoundaryState {
+    return { error };
+  }
+
+  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
+    console.log('Module content error:', error, errorInfo);
+  }
+
+  render() {
+    const { error } = this.state;
+    if (error) {
+      return (
+        <div className="error-boundary">
+          <h3>Error rendering module</h3>
+          <p>{error.message || 'An unexpected error occurred'}</p>
+        </div>
+      );
+    }
+
+    return this.props.children;
+  }
+}
diff --git 
a/web-console/src/views/explore-view/components/module-pane/module-pane.tsx 
b/web-console/src/views/explore-view/components/module-pane/module-pane.tsx
index 96ed6e8fe90..0f4d771d5d1 100644
--- a/web-console/src/views/explore-view/components/module-pane/module-pane.tsx
+++ b/web-console/src/views/explore-view/components/module-pane/module-pane.tsx
@@ -54,6 +54,7 @@ import { ModuleRepository } from 
'../../module-repository/module-repository';
 import { adjustTransferValue, normalizeType } from '../../utils';
 import { ControlPane } from '../control-pane/control-pane';
 import { DroppableContainer } from 
'../droppable-container/droppable-container';
+import { ErrorBoundary } from '../error-boundary/error-boundary';
 import { FilterPane } from '../filter-pane/filter-pane';
 import { Issue } from '../issue/issue';
 import { ModulePicker } from '../module-picker/module-picker';
@@ -338,7 +339,7 @@ export const ModulePane = function ModulePane(props: 
ModulePaneProps) {
           onDropColumn={onShowColumn}
           onDropMeasure={onShowMeasure}
         >
-          {content}
+          <ErrorBoundary>{content}</ErrorBoundary>
         </DroppableContainer>
       </ResizeSensor>
     </div>
diff --git a/web-console/src/views/explore-view/models/explore-state.ts 
b/web-console/src/views/explore-view/models/explore-state.ts
index 793e957cd4e..38f531bad9f 100644
--- a/web-console/src/views/explore-view/models/explore-state.ts
+++ b/web-console/src/views/explore-view/models/explore-state.ts
@@ -180,9 +180,10 @@ export class ExploreState {
       source: this.source,
       where: this.where,
       moduleStates: this.moduleStates,
-      layout: this.layout,
     };
+    if (this.layout) value.layout = this.layout;
     if (this.showSourceQuery) value.showSourceQuery = true;
+    if (this.timezone) value.timezone = this.timezone;
     if (this.hideResources) value.hideResources = true;
     if (this.helpers.length) value.helpers = this.helpers;
     if (this.hideHelpers) value.hideHelpers = true;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to