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 1ca0edb8c9 Web console: Fixes query cancel NPE and more (#13786)
1ca0edb8c9 is described below

commit 1ca0edb8c9545b451ecc235ced5ea0188cbbf7d3
Author: Vadim Ogievetsky <[email protected]>
AuthorDate: Wed Feb 15 15:02:50 2023 -0800

    Web console: Fixes query cancel NPE and more (#13786)
    
    * add null icon
    
    * empty string table cell
    
    * enable views only if they will work
    
    * make sure method exists
    
    * use SQL compatible nulls for e2e tests
---
 web-console/script/druid                           |  1 +
 .../__snapshots__/table-cell.spec.tsx.snap         |  8 +++++
 .../src/components/table-cell/table-cell.scss      |  3 +-
 .../src/components/table-cell/table-cell.spec.tsx  |  7 +++++
 .../src/components/table-cell/table-cell.tsx       | 32 ++++++++++----------
 web-console/src/console-application.tsx            | 34 ++++++++++++++--------
 web-console/src/singletons/api.ts                  |  2 +-
 web-console/src/utils/types.ts                     |  3 ++
 8 files changed, 60 insertions(+), 30 deletions(-)

diff --git a/web-console/script/druid b/web-console/script/druid
index 18f10313d5..7ffbeeee2a 100755
--- a/web-console/script/druid
+++ b/web-console/script/druid
@@ -64,6 +64,7 @@ function _build_distribution() {
     && cp 
"$(_get_code_root)/extensions-core/testing-tools/target/druid-testing-tools-$(_get_druid_version).jar"
 extensions/druid-testing-tools/ \
     && echo -e "\n\ndruid.extensions.loadList=[\"druid-hdfs-storage\", 
\"druid-kafka-indexing-service\", \"druid-datasketches\", 
\"druid-multi-stage-query\", \"druid-testing-tools\"]" >> 
conf/druid/single-server/micro-quickstart/_common/common.runtime.properties \
     && echo -e "\n\ndruid.server.http.allowedHttpMethods=[\"HEAD\"]" >> 
conf/druid/single-server/micro-quickstart/_common/common.runtime.properties \
+    && echo -e "\n\ndruid.generic.useDefaultValueForNull=false" >> 
conf/druid/single-server/micro-quickstart/_common/common.runtime.properties \
   )
 }
 
diff --git 
a/web-console/src/components/table-cell/__snapshots__/table-cell.spec.tsx.snap 
b/web-console/src/components/table-cell/__snapshots__/table-cell.spec.tsx.snap
index 5ed0f31589..2f6b6f1298 100644
--- 
a/web-console/src/components/table-cell/__snapshots__/table-cell.spec.tsx.snap
+++ 
b/web-console/src/components/table-cell/__snapshots__/table-cell.spec.tsx.snap
@@ -65,6 +65,14 @@ exports[`TableCell matches snapshot array short 1`] = `
 </div>
 `;
 
+exports[`TableCell matches snapshot empty string 1`] = `
+<div
+  class="table-cell empty"
+>
+  empty
+</div>
+`;
+
 exports[`TableCell matches snapshot null 1`] = `
 <div
   class="table-cell null"
diff --git a/web-console/src/components/table-cell/table-cell.scss 
b/web-console/src/components/table-cell/table-cell.scss
index 3a7b4db695..62c80d4663 100644
--- a/web-console/src/components/table-cell/table-cell.scss
+++ b/web-console/src/components/table-cell/table-cell.scss
@@ -21,7 +21,8 @@
 .table-cell {
   padding: $table-cell-v-padding $table-cell-h-padding;
 
-  &.null {
+  &.null,
+  &.empty {
     font-style: italic;
   }
 
diff --git a/web-console/src/components/table-cell/table-cell.spec.tsx 
b/web-console/src/components/table-cell/table-cell.spec.tsx
index 74648dccb0..3aac5ac360 100644
--- a/web-console/src/components/table-cell/table-cell.spec.tsx
+++ b/web-console/src/components/table-cell/table-cell.spec.tsx
@@ -29,6 +29,13 @@ describe('TableCell', () => {
     expect(container.firstChild).toMatchSnapshot();
   });
 
+  it('matches snapshot empty string', () => {
+    const tableCell = <TableCell value="" />;
+
+    const { container } = render(tableCell);
+    expect(container.firstChild).toMatchSnapshot();
+  });
+
   it('matches snapshot simple', () => {
     const tableCell = <TableCell value="Hello World" />;
 
diff --git a/web-console/src/components/table-cell/table-cell.tsx 
b/web-console/src/components/table-cell/table-cell.tsx
index 78f080b306..9e390774ee 100644
--- a/web-console/src/components/table-cell/table-cell.tsx
+++ b/web-console/src/components/table-cell/table-cell.tsx
@@ -90,22 +90,22 @@ export const TableCell = React.memo(function 
TableCell(props: TableCellProps) {
     );
   }
 
-  if (value !== '' && value != null) {
-    if (value instanceof Date) {
-      const dateValue = value.valueOf();
-      return (
-        <div className="table-cell timestamp" title={String(value.valueOf())}>
-          {isNaN(dateValue) ? 'Unusable date' : value.toISOString()}
-        </div>
-      );
-    } else if (isSimpleArray(value)) {
-      return renderTruncated(`[${value.join(', ')}]`);
-    } else if (typeof value === 'object') {
-      return renderTruncated(JSONBig.stringify(value));
-    } else {
-      return renderTruncated(String(value));
-    }
-  } else {
+  if (value === '') {
+    return <div className="table-cell empty">empty</div>;
+  } else if (value == null) {
     return <div className="table-cell null">null</div>;
+  } else if (value instanceof Date) {
+    const dateValue = value.valueOf();
+    return (
+      <div className="table-cell timestamp" title={String(value.valueOf())}>
+        {isNaN(dateValue) ? 'Unusable date' : value.toISOString()}
+      </div>
+    );
+  } else if (isSimpleArray(value)) {
+    return renderTruncated(`[${value.join(', ')}]`);
+  } else if (typeof value === 'object') {
+    return renderTruncated(JSONBig.stringify(value));
+  } else {
+    return renderTruncated(String(value));
   }
 });
diff --git a/web-console/src/console-application.tsx 
b/web-console/src/console-application.tsx
index 1ddd3676b4..5683a101b5 100644
--- a/web-console/src/console-application.tsx
+++ b/web-console/src/console-application.tsx
@@ -356,7 +356,7 @@ export class ConsoleApplication extends React.PureComponent<
   };
 
   render(): JSX.Element {
-    const { capabilitiesLoading } = this.state;
+    const { capabilities, capabilitiesLoading } = this.state;
 
     if (capabilitiesLoading) {
       return (
@@ -371,15 +371,24 @@ export class ConsoleApplication extends 
React.PureComponent<
         <HashRouter hashType="noslash">
           <div className="console-application">
             <Switch>
-              <Route path="/data-loader" 
component={this.wrappedDataLoaderView} />
-              <Route
-                path="/streaming-data-loader"
-                component={this.wrappedStreamingDataLoaderView}
-              />
-              <Route
-                path="/classic-batch-data-loader"
-                component={this.wrappedClassicBatchDataLoaderView}
-              />
+              {capabilities.hasCoordinatorAccess() && (
+                <Route path="/data-loader" 
component={this.wrappedDataLoaderView} />
+              )}
+              {capabilities.hasCoordinatorAccess() && (
+                <Route
+                  path="/streaming-data-loader"
+                  component={this.wrappedStreamingDataLoaderView}
+                />
+              )}
+              {capabilities.hasCoordinatorAccess() && (
+                <Route
+                  path="/classic-batch-data-loader"
+                  component={this.wrappedClassicBatchDataLoaderView}
+                />
+              )}
+              {capabilities.hasCoordinatorAccess() && 
capabilities.hasMultiStageQuery() && (
+                <Route path="/sql-data-loader" 
component={this.wrappedSqlDataLoaderView} />
+              )}
 
               <Route path="/ingestion" component={this.wrappedIngestionView} />
               <Route path="/datasources" 
component={this.wrappedDatasourcesView} />
@@ -393,9 +402,10 @@ export class ConsoleApplication extends 
React.PureComponent<
                 path={['/workbench/:tabId', '/workbench']}
                 component={this.wrappedWorkbenchView}
               />
-              <Route path="/sql-data-loader" 
component={this.wrappedSqlDataLoaderView} />
 
-              <Route path="/lookups" component={this.wrappedLookupsView} />
+              {capabilities.hasCoordinatorAccess() && (
+                <Route path="/lookups" component={this.wrappedLookupsView} />
+              )}
               <Route component={this.wrappedHomeView} />
             </Switch>
           </div>
diff --git a/web-console/src/singletons/api.ts 
b/web-console/src/singletons/api.ts
index 6b49ac95a3..abc9eae69b 100644
--- a/web-console/src/singletons/api.ts
+++ b/web-console/src/singletons/api.ts
@@ -39,7 +39,7 @@ export class Api {
           return Promise.reject(new Error(message));
         }
 
-        if (error.config.method?.toLowerCase() === 'get' && 
nonEmptyString(responseData)) {
+        if (error.config?.method?.toLowerCase() === 'get' && 
nonEmptyString(responseData)) {
           return Promise.reject(new Error(responseData));
         }
 
diff --git a/web-console/src/utils/types.ts b/web-console/src/utils/types.ts
index d2c08525dc..4fb547ebdf 100644
--- a/web-console/src/utils/types.ts
+++ b/web-console/src/utils/types.ts
@@ -78,6 +78,9 @@ export function dataTypeToIcon(dataType: string): IconName {
     case 'COMPLEX<JSON>':
       return IconNames.DIAGRAM_TREE;
 
+    case 'NULL':
+      return IconNames.CIRCLE;
+
     default:
       if (typeUpper.startsWith('ARRAY')) return IconNames.ARRAY;
       if (typeUpper.startsWith('COMPLEX')) return IconNames.ASTERISK;


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

Reply via email to