This is an automated email from the ASF dual-hosted git repository.
cwylie 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 a72cc28959 good stuff (#12435)
a72cc28959 is described below
commit a72cc28959a5dfa639d1bff069597a97ea5d4eba
Author: Vadim Ogievetsky <[email protected]>
AuthorDate: Thu Apr 14 00:23:06 2022 -0700
good stuff (#12435)
---
web-console/src/blueprint-overrides/_index.scss | 1 +
.../button/_button-group.scss} | 18 ++++++----
.../__snapshots__/header-bar.spec.tsx.snap | 10 ++++++
.../src/components/header-bar/header-bar.tsx | 6 ++++
.../src/druid-models/ingestion-spec.spec.ts | 22 ++++++++++--
web-console/src/druid-models/ingestion-spec.tsx | 22 +++++++++++-
web-console/src/druid-models/input-format.tsx | 40 +++++++++++++++++-----
web-console/src/druid-models/input-source.tsx | 4 +++
web-console/src/utils/capabilities.ts | 8 ++++-
web-console/src/utils/general.tsx | 19 ++++++++++
web-console/src/utils/sampler.ts | 6 ++--
web-console/src/variables.scss | 2 +-
.../src/views/datasource-view/datasource-view.tsx | 4 ++-
.../src/views/ingestion-view/ingestion-view.tsx | 11 ++++--
.../src/views/load-data-view/load-data-view.tsx | 2 +-
.../parse-data-table/parse-data-table.tsx | 5 ++-
.../src/views/lookups-view/lookups-view.tsx | 6 +++-
.../views/query-view/query-timer/query-timer.tsx | 4 ++-
web-console/src/views/query-view/query-view.tsx | 4 ++-
.../src/views/segments-view/segments-view.tsx | 6 +++-
.../src/views/services-view/services-view.tsx | 6 +++-
21 files changed, 173 insertions(+), 33 deletions(-)
diff --git a/web-console/src/blueprint-overrides/_index.scss
b/web-console/src/blueprint-overrides/_index.scss
index 821d8a395d..faffe22bbb 100644
--- a/web-console/src/blueprint-overrides/_index.scss
+++ b/web-console/src/blueprint-overrides/_index.scss
@@ -20,6 +20,7 @@
@import 'common/color-aliases';
@import 'common/variables';
@import 'components/button/common';
+@import 'components/button/button-group';
@import 'components/forms/common';
@import 'components/navbar/navbar';
@import 'components/card/card';
diff --git a/web-console/src/blueprint-overrides/_index.scss
b/web-console/src/blueprint-overrides/components/button/_button-group.scss
similarity index 65%
copy from web-console/src/blueprint-overrides/_index.scss
copy to web-console/src/blueprint-overrides/components/button/_button-group.scss
index 821d8a395d..9564e8d611 100644
--- a/web-console/src/blueprint-overrides/_index.scss
+++ b/web-console/src/blueprint-overrides/components/button/_button-group.scss
@@ -16,10 +16,14 @@
* limitations under the License.
*/
-@import 'common/colors';
-@import 'common/color-aliases';
-@import 'common/variables';
-@import 'components/button/common';
-@import 'components/forms/common';
-@import 'components/navbar/navbar';
-@import 'components/card/card';
+// Add body to make the selector more specific than what is in
+// node_modules/@blueprintjs/core/src/components/button/_button-group.scss
+body .#{$ns}-button-group {
+ &:not(.#{$ns}-minimal) {
+ > .#{$ns}-popover-wrapper:not(:last-child) .#{$ns}-button,
+ > .#{$ns}-button:not(:last-child) {
+ // Due to our flat styling this in needed to override the -1px that
blueprint tries to set
+ margin-right: 1px;
+ }
+ }
+}
diff --git
a/web-console/src/components/header-bar/__snapshots__/header-bar.spec.tsx.snap
b/web-console/src/components/header-bar/__snapshots__/header-bar.spec.tsx.snap
index f927f27c0b..bfd6aa4c3d 100644
---
a/web-console/src/components/header-bar/__snapshots__/header-bar.spec.tsx.snap
+++
b/web-console/src/components/header-bar/__snapshots__/header-bar.spec.tsx.snap
@@ -168,6 +168,16 @@ exports[`HeaderBar matches snapshot 1`] = `
shouldDismissPopover={true}
text="Force Overlord mode"
/>
+ <Blueprint4.MenuItem
+ active={false}
+ disabled={false}
+ multiline={false}
+ onClick={[Function]}
+ popoverProps={Object {}}
+ selected={false}
+ shouldDismissPopover={true}
+ text="Force no management proxy mode"
+ />
</React.Fragment>
</Blueprint4.MenuItem>
</Blueprint4.Menu>
diff --git a/web-console/src/components/header-bar/header-bar.tsx
b/web-console/src/components/header-bar/header-bar.tsx
index 390b49e5af..217ff80757 100644
--- a/web-console/src/components/header-bar/header-bar.tsx
+++ b/web-console/src/components/header-bar/header-bar.tsx
@@ -296,6 +296,12 @@ export const HeaderBar = React.memo(function
HeaderBar(props: HeaderBarProps) {
onClick={() => setForcedMode(Capabilities.OVERLORD)}
/>
)}
+ {capabilitiesMode !== 'no-proxy' && (
+ <MenuItem
+ text="Force no management proxy mode"
+ onClick={() => setForcedMode(Capabilities.NO_PROXY)}
+ />
+ )}
</>
)}
</MenuItem>
diff --git a/web-console/src/druid-models/ingestion-spec.spec.ts
b/web-console/src/druid-models/ingestion-spec.spec.ts
index 52efaed3a8..768a061fd9 100644
--- a/web-console/src/druid-models/ingestion-spec.spec.ts
+++ b/web-console/src/druid-models/ingestion-spec.spec.ts
@@ -545,8 +545,26 @@ describe('ingestion-spec', () => {
expect(guessInputFormat(['Obj1lol']).type).toEqual('regex');
});
- it('works for JSON', () => {
- expect(guessInputFormat(['{"a":1}']).type).toEqual('json');
+ it('works for JSON (strict)', () => {
+ expect(guessInputFormat(['{"a":1}'])).toEqual({ type: 'json' });
+ });
+
+ it('works for JSON (lax)', () => {
+ expect(guessInputFormat([`{hello:'world'}`])).toEqual({
+ type: 'json',
+ featureSpec: {
+ ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER: true,
+ ALLOW_COMMENTS: true,
+ ALLOW_MISSING_VALUES: true,
+ ALLOW_NON_NUMERIC_NUMBERS: true,
+ ALLOW_NUMERIC_LEADING_ZEROS: true,
+ ALLOW_SINGLE_QUOTES: true,
+ ALLOW_TRAILING_COMMA: true,
+ ALLOW_UNQUOTED_CONTROL_CHARS: true,
+ ALLOW_UNQUOTED_FIELD_NAMES: true,
+ ALLOW_YAML_COMMENTS: true,
+ },
+ });
});
it('works for CSV (with header)', () => {
diff --git a/web-console/src/druid-models/ingestion-spec.tsx
b/web-console/src/druid-models/ingestion-spec.tsx
index e58aeef320..fd7a92a1b4 100644
--- a/web-console/src/druid-models/ingestion-spec.tsx
+++ b/web-console/src/druid-models/ingestion-spec.tsx
@@ -2192,7 +2192,27 @@ export function guessInputFormat(sampleData: string[]):
InputFormat {
// If the string starts and ends with curly braces assume JSON
if (sampleDatum.startsWith('{') && sampleDatum.endsWith('}')) {
- return inputFormatFromType({ type: 'json' });
+ try {
+ JSON.parse(sampleDatum);
+ return { type: 'json' };
+ } catch {
+ // If the standard JSON parse does not parse then try setting a very
lax parsing style
+ return {
+ type: 'json',
+ featureSpec: {
+ ALLOW_COMMENTS: true,
+ ALLOW_YAML_COMMENTS: true,
+ ALLOW_UNQUOTED_FIELD_NAMES: true,
+ ALLOW_SINGLE_QUOTES: true,
+ ALLOW_UNQUOTED_CONTROL_CHARS: true,
+ ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER: true,
+ ALLOW_NUMERIC_LEADING_ZEROS: true,
+ ALLOW_NON_NUMERIC_NUMBERS: true,
+ ALLOW_MISSING_VALUES: true,
+ ALLOW_TRAILING_COMMA: true,
+ },
+ };
+ }
}
// Contains more than 3 tabs assume TSV
diff --git a/web-console/src/druid-models/input-format.tsx
b/web-console/src/druid-models/input-format.tsx
index f781a21f4c..90fb8b800d 100644
--- a/web-console/src/druid-models/input-format.tsx
+++ b/web-console/src/druid-models/input-format.tsx
@@ -34,7 +34,8 @@ export interface InputFormat {
readonly listDelimiter?: string;
readonly pattern?: string;
readonly function?: string;
- readonly flattenSpec?: FlattenSpec;
+ readonly flattenSpec?: FlattenSpec | null;
+ readonly featureSpec?: Record<string, boolean>;
readonly keepNullColumns?: boolean;
}
@@ -58,6 +59,35 @@ export const INPUT_FORMAT_FIELDS: Field<InputFormat>[] = [
</>
),
},
+ {
+ name: 'featureSpec',
+ label: 'JSON parser features',
+ type: 'json',
+ defined: typeIs('json'),
+ info: (
+ <>
+ <p>
+ <ExternalLink
href="https://github.com/FasterXML/jackson-core/wiki/JsonParser-Features">
+ JSON parser features
+ </ExternalLink>{' '}
+ supported by Jackson library. Those features will be applied when
parsing the input JSON
+ data.
+ </p>
+ <p>
+ Example:{' '}
+ <Code>{`{ "ALLOW_SINGLE_QUOTES": true, "ALLOW_UNQUOTED_FIELD_NAMES":
true }`}</Code>
+ </p>
+ </>
+ ),
+ },
+ {
+ name: 'delimiter',
+ type: 'string',
+ defaultValue: '\t',
+ suggestions: ['\t', ';', '|', '#'],
+ defined: typeIs('tsv'),
+ info: <>A custom delimiter for data values.</>,
+ },
{
name: 'pattern',
type: 'string',
@@ -110,14 +140,6 @@ export const INPUT_FORMAT_FIELDS: Field<InputFormat>[] = [
</>
),
},
- {
- name: 'delimiter',
- type: 'string',
- defaultValue: '\t',
- suggestions: ['\t', ';', '|', '#'],
- defined: typeIs('tsv'),
- info: <>A custom delimiter for data values.</>,
- },
{
name: 'listDelimiter',
type: 'string',
diff --git a/web-console/src/druid-models/input-source.tsx
b/web-console/src/druid-models/input-source.tsx
index 8c4302e28b..116ef48a83 100644
--- a/web-console/src/druid-models/input-source.tsx
+++ b/web-console/src/druid-models/input-source.tsx
@@ -41,6 +41,10 @@ export interface InputSource {
// hdfs
paths?: string;
+
+ // http
+ httpAuthenticationUsername?: any;
+ httpAuthenticationPassword?: any;
}
export function issueWithInputSource(inputSource: InputSource | undefined):
string | undefined {
diff --git a/web-console/src/utils/capabilities.ts
b/web-console/src/utils/capabilities.ts
index 4ad0dd2fb6..406115dfc9 100644
--- a/web-console/src/utils/capabilities.ts
+++ b/web-console/src/utils/capabilities.ts
@@ -45,6 +45,7 @@ export class Capabilities {
static COORDINATOR_OVERLORD: Capabilities;
static COORDINATOR: Capabilities;
static OVERLORD: Capabilities;
+ static NO_PROXY: Capabilities;
private readonly queryType: QueryType;
private readonly coordinator: boolean;
@@ -96,7 +97,7 @@ export class Capabilities {
static async detectNode(node: 'coordinator' | 'overlord'): Promise<boolean |
undefined> {
try {
- await Api.instance.get(`/druid/${node === 'overlord' ? 'indexer' :
node}/v1/isLeader`, {
+ await Api.instance.get(`/proxy/${node}/status`, {
timeout: Capabilities.STATUS_TIMEOUT,
});
} catch (e) {
@@ -218,3 +219,8 @@ Capabilities.OVERLORD = new Capabilities({
coordinator: false,
overlord: true,
});
+Capabilities.NO_PROXY = new Capabilities({
+ queryType: 'nativeAndSql',
+ coordinator: false,
+ overlord: false,
+});
diff --git a/web-console/src/utils/general.tsx
b/web-console/src/utils/general.tsx
index fb651e1829..e1c064a005 100644
--- a/web-console/src/utils/general.tsx
+++ b/web-console/src/utils/general.tsx
@@ -310,6 +310,21 @@ export function formatDurationWithMs(ms: NumberLike):
string {
);
}
+export function formatDurationHybrid(ms: NumberLike): string {
+ const n = Number(ms);
+ if (n < 600000) {
+ // anything that looks like 1:23.45 (max 9:59.99)
+ const timeInMin = Math.floor(n / 60000);
+ const timeInSec = Math.floor(n / 1000) % 60;
+ const timeInMs = Math.floor(n) % 1000;
+ return `${timeInMin ? `${timeInMin}:` : ''}${timeInMin ? pad2(timeInSec) :
timeInSec}.${pad3(
+ timeInMs,
+ ).substring(0, 2)}s`;
+ } else {
+ return formatDuration(n);
+ }
+}
+
export function pluralIfNeeded(n: NumberLike, singular: string, plural?:
string): string {
if (!plural) plural = singular + 's';
return `${formatInteger(n)} ${n === 1 ? singular : plural}`;
@@ -512,3 +527,7 @@ export function hashJoaat(str: string): number {
export function objectHash(obj: any): string {
return hashJoaat(JSONBig.stringify(obj)).toString(16).padStart(8);
}
+
+export function hasPopoverOpen(): boolean {
+ return Boolean(document.querySelector('.bp4-portal .bp4-overlay
.bp4-popover2'));
+}
diff --git a/web-console/src/utils/sampler.ts b/web-console/src/utils/sampler.ts
index a8619a5baf..5ebd49d67b 100644
--- a/web-console/src/utils/sampler.ts
+++ b/web-console/src/utils/sampler.ts
@@ -139,13 +139,15 @@ export interface HeaderFromSampleResponseOptions {
ignoreTimeColumn?: boolean;
columnOrder?: string[];
suffixColumnOrder?: string[];
+ useInput?: boolean;
}
export function headerFromSampleResponse(options:
HeaderFromSampleResponseOptions): string[] {
- const { sampleResponse, ignoreTimeColumn, columnOrder, suffixColumnOrder } =
options;
+ const { sampleResponse, ignoreTimeColumn, columnOrder, suffixColumnOrder,
useInput } = options;
+ const key = useInput ? 'input' : 'parsed';
let columns = arrangeWithPrefixSuffix(
- dedupe(sampleResponse.data.flatMap(s => (s.parsed ? Object.keys(s.parsed)
: []))),
+ dedupe(sampleResponse.data.flatMap(s => (s[key] ? Object.keys(s[key]!) :
[]))),
columnOrder || [TIME_COLUMN],
suffixColumnOrder || [],
);
diff --git a/web-console/src/variables.scss b/web-console/src/variables.scss
index d14c0b79a3..86528e1566 100644
--- a/web-console/src/variables.scss
+++ b/web-console/src/variables.scss
@@ -35,7 +35,7 @@ $druid-brand-background: #1c1c26;
background: $white;
border-radius: $pt-border-radius;
- .bp3-dark & {
+ .#{$bp-ns}-dark & {
background: $dark-gray3;
}
}
diff --git a/web-console/src/views/datasource-view/datasource-view.tsx
b/web-console/src/views/datasource-view/datasource-view.tsx
index d04c630b53..b894f7d91c 100644
--- a/web-console/src/views/datasource-view/datasource-view.tsx
+++ b/web-console/src/views/datasource-view/datasource-view.tsx
@@ -57,6 +57,7 @@ import {
formatMillions,
formatPercent,
getDruidErrorMessage,
+ hasPopoverOpen,
isNumberLikeNaN,
LocalStorageBackedVisibility,
LocalStorageKeys,
@@ -493,7 +494,8 @@ ORDER BY 1`;
});
}
- private readonly refresh = (auto: any): void => {
+ private readonly refresh = (auto: boolean): void => {
+ if (auto && hasPopoverOpen()) return;
this.datasourceQueryManager.rerunLastQuery(auto);
this.tiersQueryManager.rerunLastQuery(auto);
};
diff --git a/web-console/src/views/ingestion-view/ingestion-view.tsx
b/web-console/src/views/ingestion-view/ingestion-view.tsx
index 3071ebd4b6..ac4a8afe92 100644
--- a/web-console/src/views/ingestion-view/ingestion-view.tsx
+++ b/web-console/src/views/ingestion-view/ingestion-view.tsx
@@ -47,6 +47,7 @@ import {
deepGet,
formatDuration,
getDruidErrorMessage,
+ hasPopoverOpen,
LocalStorageBackedVisibility,
localStorageGet,
LocalStorageKeys,
@@ -1089,7 +1090,10 @@ ORDER BY "rank" DESC, "created_time" DESC`;
<ViewControlBar label="Supervisors">
<RefreshButton
localStorageKey={LocalStorageKeys.SUPERVISORS_REFRESH_RATE}
- onRefresh={auto =>
this.supervisorQueryManager.rerunLastQuery(auto)}
+ onRefresh={auto => {
+ if (auto && hasPopoverOpen()) return;
+ this.supervisorQueryManager.rerunLastQuery(auto);
+ }}
/>
{this.renderBulkSupervisorActions()}
<TableColumnSelector
@@ -1141,7 +1145,10 @@ ORDER BY "rank" DESC, "created_time" DESC`;
</ButtonGroup>
<RefreshButton
localStorageKey={LocalStorageKeys.TASKS_REFRESH_RATE}
- onRefresh={auto => this.taskQueryManager.rerunLastQuery(auto)}
+ onRefresh={auto => {
+ if (auto && hasPopoverOpen()) return;
+ this.taskQueryManager.rerunLastQuery(auto);
+ }}
/>
{this.renderBulkTasksActions()}
<TableColumnSelector
diff --git a/web-console/src/views/load-data-view/load-data-view.tsx
b/web-console/src/views/load-data-view/load-data-view.tsx
index f7665905f7..98d3fff812 100644
--- a/web-console/src/views/load-data-view/load-data-view.tsx
+++ b/web-console/src/views/load-data-view/load-data-view.tsx
@@ -1463,7 +1463,7 @@ export class LoadDataView extends
React.PureComponent<LoadDataViewProps, LoadDat
)}
</>
)}
- {this.renderFlattenControls()}
+ {canFlatten && this.renderFlattenControls()}
{suggestedFlattenFields && suggestedFlattenFields.length ? (
<FormGroup>
<Button
diff --git
a/web-console/src/views/load-data-view/parse-data-table/parse-data-table.tsx
b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.tsx
index 39d0f609ca..3ae077582e 100644
--- a/web-console/src/views/load-data-view/parse-data-table/parse-data-table.tsx
+++ b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.tsx
@@ -41,6 +41,7 @@ export interface ParseDataTableProps {
flattenedColumnsOnly: boolean;
flattenFields: FlattenField[];
onFlattenFieldSelect: (field: FlattenField, index: number) => void;
+ useInput?: boolean;
}
export const ParseDataTable = React.memo(function ParseDataTable(props:
ParseDataTableProps) {
@@ -51,8 +52,10 @@ export const ParseDataTable = React.memo(function
ParseDataTable(props: ParseDat
flattenedColumnsOnly,
flattenFields,
onFlattenFieldSelect,
+ useInput,
} = props;
+ const key = useInput ? 'input' : 'parsed';
return (
<ReactTable
className="parse-data-table -striped -highlight"
@@ -82,7 +85,7 @@ export const ParseDataTable = React.memo(function
ParseDataTable(props: ParseDat
</div>
),
id: String(i),
- accessor: (row: SampleEntry) => (row.parsed ? row.parsed[columnName]
: null),
+ accessor: (row: SampleEntry) => (row[key] ? row[key]![columnName] :
null),
Cell: function ParseDataTableCell(row) {
if (row.original.unparseable) {
return <TableCellUnparseable />;
diff --git a/web-console/src/views/lookups-view/lookups-view.tsx
b/web-console/src/views/lookups-view/lookups-view.tsx
index 441e76add3..9b5ea1160e 100644
--- a/web-console/src/views/lookups-view/lookups-view.tsx
+++ b/web-console/src/views/lookups-view/lookups-view.tsx
@@ -37,6 +37,7 @@ import { Api, AppToaster } from '../../singletons';
import {
deepGet,
getDruidErrorMessage,
+ hasPopoverOpen,
isLookupsUninitialized,
LocalStorageBackedVisibility,
LocalStorageKeys,
@@ -455,7 +456,10 @@ export class LookupsView extends
React.PureComponent<LookupsViewProps, LookupsVi
<div className="lookups-view app-view">
<ViewControlBar label="Lookups">
<RefreshButton
- onRefresh={auto => this.lookupsQueryManager.rerunLastQuery(auto)}
+ onRefresh={auto => {
+ if (auto && hasPopoverOpen()) return;
+ this.lookupsQueryManager.rerunLastQuery(auto);
+ }}
localStorageKey={LocalStorageKeys.LOOKUPS_REFRESH_RATE}
/>
{!lookupEntriesAndTiersState.isError() && (
diff --git a/web-console/src/views/query-view/query-timer/query-timer.tsx
b/web-console/src/views/query-view/query-timer/query-timer.tsx
index 8f5970a42c..46c6efa008 100644
--- a/web-console/src/views/query-view/query-timer/query-timer.tsx
+++ b/web-console/src/views/query-view/query-timer/query-timer.tsx
@@ -21,6 +21,7 @@ import { IconNames } from '@blueprintjs/icons';
import React, { useState } from 'react';
import { useInterval } from '../../../hooks';
+import { formatDurationHybrid } from '../../../utils';
import './query-timer.scss';
@@ -37,9 +38,10 @@ export const QueryTimer = React.memo(function QueryTimer() {
const elapsed = currentTime - startTime;
if (elapsed <= 0) return null;
+
return (
<div className="query-timer">
- {`${(elapsed / 1000).toFixed(2)}s`}
+ {formatDurationHybrid(elapsed)}
<Button icon={IconNames.STOPWATCH} minimal />
</div>
);
diff --git a/web-console/src/views/query-view/query-view.tsx
b/web-console/src/views/query-view/query-view.tsx
index 0c65c6f3c9..2221e97cd4 100644
--- a/web-console/src/views/query-view/query-view.tsx
+++ b/web-console/src/views/query-view/query-view.tsx
@@ -201,7 +201,9 @@ export class QueryView extends
React.PureComponent<QueryViewProps, QueryViewStat
},
});
- const queryRunner = new QueryRunner();
+ const queryRunner = new QueryRunner({
+ inflateDateStrategy: 'none',
+ });
this.queryManager = new QueryManager({
processQuery: async (
diff --git a/web-console/src/views/segments-view/segments-view.tsx
b/web-console/src/views/segments-view/segments-view.tsx
index 21ed68f2e0..644f8b4584 100644
--- a/web-console/src/views/segments-view/segments-view.tsx
+++ b/web-console/src/views/segments-view/segments-view.tsx
@@ -51,6 +51,7 @@ import {
formatBytes,
formatInteger,
getNeedleAndMode,
+ hasPopoverOpen,
isNumberLikeNaN,
LocalStorageBackedVisibility,
LocalStorageKeys,
@@ -893,7 +894,10 @@ END AS "time_span"`,
>
<ViewControlBar label="Segments">
<RefreshButton
- onRefresh={auto =>
this.segmentsQueryManager.rerunLastQuery(auto)}
+ onRefresh={auto => {
+ if (auto && hasPopoverOpen()) return;
+ this.segmentsQueryManager.rerunLastQuery(auto);
+ }}
localStorageKey={LocalStorageKeys.SEGMENTS_REFRESH_RATE}
/>
<Label>Group by</Label>
diff --git a/web-console/src/views/services-view/services-view.tsx
b/web-console/src/views/services-view/services-view.tsx
index e90a1096fb..05f3ac5982 100644
--- a/web-console/src/views/services-view/services-view.tsx
+++ b/web-console/src/views/services-view/services-view.tsx
@@ -41,6 +41,7 @@ import {
deepGet,
formatBytes,
formatBytesCompact,
+ hasPopoverOpen,
LocalStorageBackedVisibility,
LocalStorageKeys,
lookupBy,
@@ -718,7 +719,10 @@ ORDER BY
</Button>
</ButtonGroup>
<RefreshButton
- onRefresh={auto => this.serviceQueryManager.rerunLastQuery(auto)}
+ onRefresh={auto => {
+ if (auto && hasPopoverOpen()) return;
+ this.serviceQueryManager.rerunLastQuery(auto);
+ }}
localStorageKey={LocalStorageKeys.SERVICES_REFRESH_RATE}
/>
{this.renderBulkServicesActions()}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]