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]