mirror of
https://github.com/apache/druid.git
synced 2025-02-22 10:16:12 +00:00
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
This commit is contained in:
parent
460d8b8a2a
commit
1ca0edb8c9
@ -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 \
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
@ -21,7 +21,8 @@
|
||||
.table-cell {
|
||||
padding: $table-cell-v-padding $table-cell-h-padding;
|
||||
|
||||
&.null {
|
||||
&.null,
|
||||
&.empty {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
|
@ -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" />;
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
});
|
||||
|
@ -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>
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user