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 6b899838449..61ae684d18a 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
@@ -15,6 +15,7 @@ exports[`header bar matches snapshot 1`] = `
diff --git a/web-console/src/components/header-bar/header-bar.spec.tsx b/web-console/src/components/header-bar/header-bar.spec.tsx
index 0e596c32e3a..8e79ddfd1df 100644
--- a/web-console/src/components/header-bar/header-bar.spec.tsx
+++ b/web-console/src/components/header-bar/header-bar.spec.tsx
@@ -23,7 +23,9 @@ import { HeaderBar } from './header-bar';
describe('header bar', () => {
it('matches snapshot', () => {
- const headerBar = shallow();
+ const headerBar = shallow(
+ ,
+ );
expect(headerBar).toMatchSnapshot();
});
});
diff --git a/web-console/src/components/header-bar/header-bar.tsx b/web-console/src/components/header-bar/header-bar.tsx
index 12b4a756c03..3a87b40812b 100644
--- a/web-console/src/components/header-bar/header-bar.tsx
+++ b/web-console/src/components/header-bar/header-bar.tsx
@@ -36,6 +36,7 @@ import { AboutDialog } from '../../dialogs/about-dialog/about-dialog';
import { CoordinatorDynamicConfigDialog } from '../../dialogs/coordinator-dynamic-config-dialog/coordinator-dynamic-config-dialog';
import { DoctorDialog } from '../../dialogs/doctor-dialog/doctor-dialog';
import { OverlordDynamicConfigDialog } from '../../dialogs/overlord-dynamic-config-dialog/overlord-dynamic-config-dialog';
+import { Capabilities } from '../../utils/capabilities';
import {
DRUID_ASF_SLACK,
DRUID_DOCS,
@@ -130,10 +131,11 @@ function LegacyMenu() {
export interface HeaderBarProps {
active: HeaderActiveTab;
hideLegacy: boolean;
+ capabilities: Capabilities;
}
export const HeaderBar = React.memo(function HeaderBar(props: HeaderBarProps) {
- const { active, hideLegacy } = props;
+ const { active, hideLegacy, capabilities } = props;
const [aboutDialogOpen, setAboutDialogOpen] = useState(false);
const [doctorDialogOpen, setDoctorDialogOpen] = useState(false);
const [coordinatorDynamicConfigDialogOpen, setCoordinatorDynamicConfigDialogOpen] = useState(
@@ -198,6 +200,7 @@ export const HeaderBar = React.memo(function HeaderBar(props: HeaderBarProps) {
href="#load-data"
minimal={!loadDataPrimary}
intent={loadDataPrimary ? Intent.PRIMARY : Intent.NONE}
+ disabled={capabilities === 'no-proxy'}
/>
@@ -241,12 +244,25 @@ export const HeaderBar = React.memo(function HeaderBar(props: HeaderBarProps) {
{!hideLegacy && (
- } position={Position.BOTTOM_RIGHT}>
-
+ }
+ position={Position.BOTTOM_RIGHT}
+ disabled={capabilities === 'no-proxy'}
+ >
+
)}
-
-
+
+
diff --git a/web-console/src/console-application.tsx b/web-console/src/console-application.tsx
index 110a99ec058..773ae136691 100644
--- a/web-console/src/console-application.tsx
+++ b/web-console/src/console-application.tsx
@@ -26,7 +26,8 @@ import { HashRouter, Route, Switch } from 'react-router-dom';
import { ExternalLink, HeaderActiveTab, HeaderBar, Loader } from './components';
import { AppToaster } from './singletons/toaster';
import { localStorageGet, LocalStorageKeys, QueryManager } from './utils';
-import { DRUID_DOCS_API, DRUID_DOCS_SQL } from './variables';
+import { Capabilities } from './utils/capabilities';
+import { DRUID_DOCS_API, DRUID_DOCS_SQL, DRUID_DOCS_VERSION } from './variables';
import {
DatasourcesView,
HomeView,
@@ -40,15 +41,13 @@ import {
import './console-application.scss';
-type Capabilities = 'working-with-sql' | 'working-without-sql' | 'broken';
-
export interface ConsoleApplicationProps {
hideLegacy: boolean;
exampleManifestsUrl?: string;
}
export interface ConsoleApplicationState {
- noSqlMode: boolean;
+ capabilities: Capabilities;
capabilitiesLoading: boolean;
}
@@ -64,6 +63,7 @@ export class ConsoleApplication extends React.PureComponent<
const capabilitiesOverride = localStorageGet(LocalStorageKeys.CAPABILITIES_OVERRIDE);
if (capabilitiesOverride) return capabilitiesOverride as Capabilities;
+ // Check SQL endpoint
try {
await axios.post(
'/druid/v2/sql',
@@ -73,7 +73,7 @@ export class ConsoleApplication extends React.PureComponent<
} catch (e) {
const { response } = e;
if (response.status !== 405 || response.statusText !== 'Method Not Allowed') {
- return 'working-with-sql'; // other failure
+ return 'full'; // other failure
}
try {
await axios.get('/status', { timeout: ConsoleApplication.STATUS_TIMEOUT });
@@ -81,27 +81,65 @@ export class ConsoleApplication extends React.PureComponent<
return 'broken'; // total failure
}
// Status works but SQL 405s => the SQL endpoint is disabled
- return 'working-without-sql';
+ return 'no-sql';
}
- return 'working-with-sql';
+
+ // Check proxy
+ try {
+ await axios.get('/proxy/coordinator/status', { timeout: ConsoleApplication.STATUS_TIMEOUT });
+ } catch (e) {
+ const { response } = e;
+ if (response.status !== 404) {
+ console.log('response.statusText', response.statusText);
+ return 'full'; // other failure
+ }
+ return 'no-proxy';
+ }
+
+ return 'full';
}
- static shownNotifications(capabilities: string) {
- let message: JSX.Element = <>>;
+ static shownNotifications(capabilities: Capabilities) {
+ let message: JSX.Element;
+ switch (capabilities) {
+ case 'no-sql':
+ message = (
+ <>
+ It appears that the SQL endpoint is disabled. The console will fall back to{' '}
+ native Druid APIs and will be limited
+ in functionality. Look at{' '}
+ the SQL docs to enable the SQL
+ endpoint.
+ >
+ );
+ break;
- if (capabilities === 'working-without-sql') {
- message = (
- <>
- It appears that the SQL endpoint is disabled. The console will fall back to{' '}
- native Druid APIs and will be limited
- in functionality. Look at the SQL docs{' '}
- to enable the SQL endpoint.
- >
- );
- } else if (capabilities === 'broken') {
- message = (
- <>It appears that the Druid is not responding. Data cannot be retrieved right now>
- );
+ case 'no-proxy':
+ message = (
+ <>
+ It appears that the management proxy is not enabled, the console will operate with
+ limited functionality. Look at{' '}
+
+ the console docs
+ {' '}
+ for more info on how to enable the management proxy.
+ >
+ );
+ break;
+
+ case 'broken':
+ message = (
+ <>
+ It appears that the the Router node is not responding. The console will not function at
+ the moment
+ >
+ );
+ break;
+
+ default:
+ return;
}
AppToaster.show({
@@ -123,21 +161,21 @@ export class ConsoleApplication extends React.PureComponent<
constructor(props: ConsoleApplicationProps, context: any) {
super(props, context);
this.state = {
- noSqlMode: false,
+ capabilities: 'full',
capabilitiesLoading: true,
};
this.capabilitiesQueryManager = new QueryManager({
processQuery: async () => {
const capabilities = await ConsoleApplication.discoverCapabilities();
- if (capabilities !== 'working-with-sql') {
+ if (capabilities !== 'full') {
ConsoleApplication.shownNotifications(capabilities);
}
return capabilities;
},
onStateChange: ({ result, loading }) => {
this.setState({
- noSqlMode: result !== 'working-with-sql',
+ capabilities: result || 'full',
capabilitiesLoading: loading,
});
},
@@ -216,18 +254,19 @@ export class ConsoleApplication extends React.PureComponent<
classType: 'normal' | 'narrow-pad' = 'normal',
) => {
const { hideLegacy } = this.props;
+ const { capabilities } = this.state;
return (
<>
-
+
{el}
>
);
};
private wrappedHomeView = () => {
- const { noSqlMode } = this.state;
- return this.wrapInViewContainer(null, );
+ const { capabilities } = this.state;
+ return this.wrapInViewContainer(null, );
};
private wrappedLoadDataView = () => {
@@ -250,7 +289,7 @@ export class ConsoleApplication extends React.PureComponent<
};
private wrappedDatasourcesView = () => {
- const { noSqlMode } = this.state;
+ const { capabilities } = this.state;
return this.wrapInViewContainer(
'datasources',
,
);
};
private wrappedSegmentsView = () => {
- const { noSqlMode } = this.state;
+ const { capabilities } = this.state;
return this.wrapInViewContainer(
'segments',
,
);
};
private wrappedTasksView = () => {
- const { noSqlMode } = this.state;
+ const { capabilities } = this.state;
return this.wrapInViewContainer(
'tasks',
,
);
};
private wrappedServersView = () => {
- const { noSqlMode } = this.state;
+ const { capabilities } = this.state;
return this.wrapInViewContainer(
'servers',
,
);
};
@@ -316,7 +355,7 @@ export class ConsoleApplication extends React.PureComponent<
if (capabilitiesLoading) {
return (
-
+
);
}
@@ -326,13 +365,14 @@ export class ConsoleApplication extends React.PureComponent<
-
+
+
diff --git a/web-console/src/utils/capabilities.ts b/web-console/src/utils/capabilities.ts
new file mode 100644
index 00000000000..a422752ec6e
--- /dev/null
+++ b/web-console/src/utils/capabilities.ts
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+export type Capabilities = 'full' | 'no-sql' | 'no-proxy' | 'broken';
diff --git a/web-console/src/views/datasource-view/datasource-view.spec.tsx b/web-console/src/views/datasource-view/datasource-view.spec.tsx
index 7bb670cf5e5..4b311461214 100644
--- a/web-console/src/views/datasource-view/datasource-view.spec.tsx
+++ b/web-console/src/views/datasource-view/datasource-view.spec.tsx
@@ -28,7 +28,7 @@ describe('data source view', () => {
goToQuery={() => {}}
goToTask={() => null}
goToSegments={() => {}}
- noSqlMode={false}
+ capabilities="full"
/>,
);
expect(dataSourceView).toMatchSnapshot();
diff --git a/web-console/src/views/datasource-view/datasource-view.tsx b/web-console/src/views/datasource-view/datasource-view.tsx
index 4c0936b64d6..27f9bf57b88 100644
--- a/web-console/src/views/datasource-view/datasource-view.tsx
+++ b/web-console/src/views/datasource-view/datasource-view.tsx
@@ -61,34 +61,48 @@ import {
QueryManager,
} from '../../utils';
import { BasicAction } from '../../utils/basic-action';
+import { Capabilities } from '../../utils/capabilities';
import { RuleUtil } from '../../utils/load-rule';
import { LocalStorageBackedArray } from '../../utils/local-storage-backed-array';
import { deepGet } from '../../utils/object-change';
import './datasource-view.scss';
-const tableColumns: string[] = [
- 'Datasource',
- 'Availability',
- 'Segment load/drop',
- 'Retention',
- 'Replicated size',
- 'Size',
- 'Compaction',
- 'Avg. segment size',
- 'Num rows',
- ACTION_COLUMN_LABEL,
-];
-const tableColumnsNoSql: string[] = [
- 'Datasource',
- 'Availability',
- 'Segment load/drop',
- 'Retention',
- 'Size',
- 'Compaction',
- 'Avg. segment size',
- ACTION_COLUMN_LABEL,
-];
+const tableColumns: Record
= {
+ full: [
+ 'Datasource',
+ 'Availability',
+ 'Segment load/drop',
+ 'Retention',
+ 'Replicated size',
+ 'Size',
+ 'Compaction',
+ 'Avg. segment size',
+ 'Num rows',
+ ACTION_COLUMN_LABEL,
+ ],
+ 'no-sql': [
+ 'Datasource',
+ 'Availability',
+ 'Segment load/drop',
+ 'Retention',
+ 'Size',
+ 'Compaction',
+ 'Avg. segment size',
+ ACTION_COLUMN_LABEL,
+ ],
+ 'no-proxy': [
+ 'Datasource',
+ 'Availability',
+ 'Segment load/drop',
+ 'Replicated size',
+ 'Size',
+ 'Avg. segment size',
+ 'Num rows',
+ ACTION_COLUMN_LABEL,
+ ],
+ broken: ['Datasource'],
+};
function formatLoadDrop(segmentsToLoad: number, segmentsToDrop: number): string {
const loadDrop: string[] = [];
@@ -133,7 +147,7 @@ export interface DatasourcesViewProps {
goToQuery: (initSql: string) => void;
goToTask: (datasource?: string, openDialog?: string) => void;
goToSegments: (datasource: string, onlyUnavailable?: boolean) => void;
- noSqlMode: boolean;
+ capabilities: Capabilities;
initDatasource?: string;
}
@@ -198,7 +212,7 @@ GROUP BY 1`;
}
private datasourceQueryManager: QueryManager<
- boolean,
+ Capabilities,
{ tiers: string[]; defaultRules: any[]; datasources: Datasource[] }
>;
@@ -231,9 +245,9 @@ GROUP BY 1`;
};
this.datasourceQueryManager = new QueryManager({
- processQuery: async noSqlMode => {
+ processQuery: async capabilities => {
let datasources: DatasourceQueryResultRow[];
- if (!noSqlMode) {
+ if (capabilities !== 'no-sql') {
datasources = await queryDruidSql({ query: DatasourcesView.DATASOURCE_SQL });
} else {
const datasourcesResp = await axios.get('/druid/coordinator/v1/datasources?simple');
@@ -260,6 +274,17 @@ GROUP BY 1`;
);
}
+ if (capabilities === 'no-proxy') {
+ datasources.forEach((ds: any) => {
+ ds.rules = [];
+ });
+ return {
+ datasources,
+ tiers: [],
+ defaultRules: [],
+ };
+ }
+
const seen = countBy(datasources, (x: any) => x.datasource);
let disabled: string[] = [];
@@ -320,8 +345,8 @@ GROUP BY 1`;
};
componentDidMount(): void {
- const { noSqlMode } = this.props;
- this.datasourceQueryManager.runQuery(noSqlMode);
+ const { capabilities } = this.props;
+ this.datasourceQueryManager.runQuery(capabilities);
window.addEventListener('resize', this.handleResize);
}
@@ -468,10 +493,10 @@ GROUP BY 1`;
}
renderBulkDatasourceActions() {
- const { goToQuery, noSqlMode } = this.props;
+ const { goToQuery, capabilities } = this.props;
const bulkDatasourceActionsMenu = (
diff --git a/web-console/src/views/home-view/datasources-card/datasources-card.spec.tsx b/web-console/src/views/home-view/datasources-card/datasources-card.spec.tsx
index edc4b9ec975..da5dd08f70a 100644
--- a/web-console/src/views/home-view/datasources-card/datasources-card.spec.tsx
+++ b/web-console/src/views/home-view/datasources-card/datasources-card.spec.tsx
@@ -23,7 +23,7 @@ import { DatasourcesCard } from './datasources-card';
describe('datasources card', () => {
it('matches snapshot', () => {
- const datasourcesCard = ;
+ const datasourcesCard = ;
const { container } = render(datasourcesCard);
expect(container.firstChild).toMatchSnapshot();
diff --git a/web-console/src/views/home-view/datasources-card/datasources-card.tsx b/web-console/src/views/home-view/datasources-card/datasources-card.tsx
index 34530c69167..4b888a68173 100644
--- a/web-console/src/views/home-view/datasources-card/datasources-card.tsx
+++ b/web-console/src/views/home-view/datasources-card/datasources-card.tsx
@@ -21,10 +21,11 @@ import axios from 'axios';
import React from 'react';
import { pluralIfNeeded, queryDruidSql, QueryManager } from '../../../utils';
+import { Capabilities } from '../../../utils/capabilities';
import { HomeViewCard } from '../home-view-card/home-view-card';
export interface DatasourcesCardProps {
- noSqlMode: boolean;
+ capabilities: Capabilities;
}
export interface DatasourcesCardState {
@@ -37,7 +38,7 @@ export class DatasourcesCard extends React.PureComponent<
DatasourcesCardProps,
DatasourcesCardState
> {
- private datasourceQueryManager: QueryManager;
+ private datasourceQueryManager: QueryManager;
constructor(props: DatasourcesCardProps, context: any) {
super(props, context);
@@ -47,9 +48,9 @@ export class DatasourcesCard extends React.PureComponent<
};
this.datasourceQueryManager = new QueryManager({
- processQuery: async noSqlMode => {
+ processQuery: async capabilities => {
let datasources: string[];
- if (!noSqlMode) {
+ if (capabilities !== 'no-sql') {
datasources = await queryDruidSql({
query: `SELECT datasource FROM sys.segments GROUP BY 1`,
});
@@ -70,9 +71,9 @@ export class DatasourcesCard extends React.PureComponent<
}
componentDidMount(): void {
- const { noSqlMode } = this.props;
+ const { capabilities } = this.props;
- this.datasourceQueryManager.runQuery(noSqlMode);
+ this.datasourceQueryManager.runQuery(capabilities);
}
componentWillUnmount(): void {
diff --git a/web-console/src/views/home-view/home-view.spec.tsx b/web-console/src/views/home-view/home-view.spec.tsx
index e67cd8ca770..5d6f1f1177b 100644
--- a/web-console/src/views/home-view/home-view.spec.tsx
+++ b/web-console/src/views/home-view/home-view.spec.tsx
@@ -23,7 +23,7 @@ import { HomeView } from './home-view';
describe('home view', () => {
it('matches snapshot', () => {
- const homeView = shallow();
+ const homeView = shallow();
expect(homeView).toMatchSnapshot();
});
});
diff --git a/web-console/src/views/home-view/home-view.tsx b/web-console/src/views/home-view/home-view.tsx
index 2e05dedeab3..afcf33d0ada 100644
--- a/web-console/src/views/home-view/home-view.tsx
+++ b/web-console/src/views/home-view/home-view.tsx
@@ -18,6 +18,8 @@
import React from 'react';
+import { Capabilities } from '../../utils/capabilities';
+
import { DatasourcesCard } from './datasources-card/datasources-card';
import { LookupsCard } from './lookups-card/lookups-card';
import { SegmentsCard } from './segments-card/segments-card';
@@ -29,20 +31,20 @@ import { TasksCard } from './tasks-card/tasks-card';
import './home-view.scss';
export interface HomeViewProps {
- noSqlMode: boolean;
+ capabilities: Capabilities;
}
export const HomeView = React.memo(function HomeView(props: HomeViewProps) {
- const { noSqlMode } = props;
+ const { capabilities } = props;
return (
-
-
-
-
-
+
+
+
+
+
);
diff --git a/web-console/src/views/home-view/segments-card/segments-card.spec.tsx b/web-console/src/views/home-view/segments-card/segments-card.spec.tsx
index 7bf98c6835d..87685dc0095 100644
--- a/web-console/src/views/home-view/segments-card/segments-card.spec.tsx
+++ b/web-console/src/views/home-view/segments-card/segments-card.spec.tsx
@@ -23,7 +23,7 @@ import { SegmentsCard } from './segments-card';
describe('segments card', () => {
it('matches snapshot', () => {
- const segmentsCard = ;
+ const segmentsCard = ;
const { container } = render(segmentsCard);
expect(container.firstChild).toMatchSnapshot();
diff --git a/web-console/src/views/home-view/segments-card/segments-card.tsx b/web-console/src/views/home-view/segments-card/segments-card.tsx
index 379d4cef028..1f81af18b6a 100644
--- a/web-console/src/views/home-view/segments-card/segments-card.tsx
+++ b/web-console/src/views/home-view/segments-card/segments-card.tsx
@@ -22,11 +22,12 @@ import { sum } from 'd3-array';
import React from 'react';
import { pluralIfNeeded, queryDruidSql, QueryManager } from '../../../utils';
+import { Capabilities } from '../../../utils/capabilities';
import { deepGet } from '../../../utils/object-change';
import { HomeViewCard } from '../home-view-card/home-view-card';
export interface SegmentsCardProps {
- noSqlMode: boolean;
+ capabilities: Capabilities;
}
export interface SegmentsCardState {
@@ -37,7 +38,7 @@ export interface SegmentsCardState {
}
export class SegmentsCard extends React.PureComponent {
- private segmentQueryManager: QueryManager;
+ private segmentQueryManager: QueryManager;
constructor(props: SegmentsCardProps, context: any) {
super(props, context);
@@ -48,8 +49,8 @@ export class SegmentsCard extends React.PureComponent {
- if (noSqlMode) {
+ processQuery: async capabilities => {
+ if (capabilities === 'no-sql') {
const loadstatusResp = await axios.get('/druid/coordinator/v1/loadstatus?simple');
const loadstatus = loadstatusResp.data;
const unavailableSegmentNum = sum(Object.keys(loadstatus), key => loadstatus[key]);
@@ -86,9 +87,9 @@ FROM sys.segments`,
}
componentDidMount(): void {
- const { noSqlMode } = this.props;
+ const { capabilities } = this.props;
- this.segmentQueryManager.runQuery(noSqlMode);
+ this.segmentQueryManager.runQuery(capabilities);
}
componentWillUnmount(): void {
diff --git a/web-console/src/views/home-view/servers-card/servers-card.spec.tsx b/web-console/src/views/home-view/servers-card/servers-card.spec.tsx
index b92fc2bb932..48ea6a981a6 100644
--- a/web-console/src/views/home-view/servers-card/servers-card.spec.tsx
+++ b/web-console/src/views/home-view/servers-card/servers-card.spec.tsx
@@ -23,7 +23,7 @@ import { ServersCard } from './servers-card';
describe('servers card', () => {
it('matches snapshot', () => {
- const serversCard = ;
+ const serversCard = ;
const { container } = render(serversCard);
expect(container.firstChild).toMatchSnapshot();
diff --git a/web-console/src/views/home-view/servers-card/servers-card.tsx b/web-console/src/views/home-view/servers-card/servers-card.tsx
index ee30b321cab..9c28390bd37 100644
--- a/web-console/src/views/home-view/servers-card/servers-card.tsx
+++ b/web-console/src/views/home-view/servers-card/servers-card.tsx
@@ -21,10 +21,11 @@ import axios from 'axios';
import React from 'react';
import { compact, lookupBy, pluralIfNeeded, queryDruidSql, QueryManager } from '../../../utils';
+import { Capabilities } from '../../../utils/capabilities';
import { HomeViewCard } from '../home-view-card/home-view-card';
export interface ServersCardProps {
- noSqlMode: boolean;
+ capabilities: Capabilities;
}
export interface ServersCardState {
@@ -55,7 +56,7 @@ export class ServersCard extends React.PureComponent{text}
;
}
- private serverQueryManager: QueryManager;
+ private serverQueryManager: QueryManager;
constructor(props: ServersCardProps, context: any) {
super(props, context);
@@ -72,8 +73,8 @@ export class ServersCard extends React.PureComponent {
- if (noSqlMode) {
+ processQuery: async capabilities => {
+ if (capabilities === 'no-sql') {
const serversResp = await axios.get('/druid/coordinator/v1/servers?simple');
const middleManagerResp = await axios.get('/druid/indexer/v1/workers');
return {
@@ -109,9 +110,9 @@ export class ServersCard extends React.PureComponent {
it('matches snapshot', () => {
- const supervisorsCard = ;
+ const supervisorsCard = ;
const { container } = render(supervisorsCard);
expect(container.firstChild).toMatchSnapshot();
diff --git a/web-console/src/views/home-view/supervisors-card/supervisors-card.tsx b/web-console/src/views/home-view/supervisors-card/supervisors-card.tsx
index 7bbe1d0632c..1b4358aa72c 100644
--- a/web-console/src/views/home-view/supervisors-card/supervisors-card.tsx
+++ b/web-console/src/views/home-view/supervisors-card/supervisors-card.tsx
@@ -20,10 +20,13 @@ import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import React from 'react';
-import { pluralIfNeeded, QueryManager } from '../../../utils';
+import { pluralIfNeeded, queryDruidSql, QueryManager } from '../../../utils';
+import { Capabilities } from '../../../utils/capabilities';
import { HomeViewCard } from '../home-view-card/home-view-card';
-export interface SupervisorsCardProps {}
+export interface SupervisorsCardProps {
+ capabilities: Capabilities;
+}
export interface SupervisorsCardState {
supervisorCountLoading: boolean;
@@ -36,7 +39,7 @@ export class SupervisorsCard extends React.PureComponent<
SupervisorsCardProps,
SupervisorsCardState
> {
- private supervisorQueryManager: QueryManager;
+ private supervisorQueryManager: QueryManager;
constructor(props: SupervisorsCardProps, context: any) {
super(props, context);
@@ -47,15 +50,25 @@ export class SupervisorsCard extends React.PureComponent<
};
this.supervisorQueryManager = new QueryManager({
- processQuery: async () => {
- const resp = await axios.get('/druid/indexer/v1/supervisor?full');
- const data = resp.data;
- const runningSupervisorCount = data.filter((d: any) => d.spec.suspended === false).length;
- const suspendedSupervisorCount = data.filter((d: any) => d.spec.suspended === true).length;
- return {
- runningSupervisorCount,
- suspendedSupervisorCount,
- };
+ processQuery: async capabilities => {
+ if (capabilities !== 'no-sql') {
+ return (await queryDruidSql({
+ query: `SELECT
+ COUNT(*) FILTER (WHERE "suspended" = 0) AS "runningSupervisorCount",
+ COUNT(*) FILTER (WHERE "suspended" = 1) AS "suspendedSupervisorCount"
+FROM sys.supervisors`,
+ }))[0];
+ } else {
+ const resp = await axios.get('/druid/indexer/v1/supervisor?full');
+ const data = resp.data;
+ const runningSupervisorCount = data.filter((d: any) => d.spec.suspended === false).length;
+ const suspendedSupervisorCount = data.filter((d: any) => d.spec.suspended === true)
+ .length;
+ return {
+ runningSupervisorCount,
+ suspendedSupervisorCount,
+ };
+ }
},
onStateChange: ({ result, loading, error }) => {
this.setState({
@@ -69,7 +82,9 @@ export class SupervisorsCard extends React.PureComponent<
}
componentDidMount(): void {
- this.supervisorQueryManager.runQuery(null);
+ const { capabilities } = this.props;
+
+ this.supervisorQueryManager.runQuery(capabilities);
}
componentWillUnmount(): void {
diff --git a/web-console/src/views/home-view/tasks-card/tasks-card.spec.tsx b/web-console/src/views/home-view/tasks-card/tasks-card.spec.tsx
index 14f1ea5d5e7..df830266c67 100644
--- a/web-console/src/views/home-view/tasks-card/tasks-card.spec.tsx
+++ b/web-console/src/views/home-view/tasks-card/tasks-card.spec.tsx
@@ -23,7 +23,7 @@ import { TasksCard } from './tasks-card';
describe('tasks card', () => {
it('matches snapshot', () => {
- const tasksCard = ;
+ const tasksCard = ;
const { container } = render(tasksCard);
expect(container.firstChild).toMatchSnapshot();
diff --git a/web-console/src/views/home-view/tasks-card/tasks-card.tsx b/web-console/src/views/home-view/tasks-card/tasks-card.tsx
index 375f106049d..044e79e2c6e 100644
--- a/web-console/src/views/home-view/tasks-card/tasks-card.tsx
+++ b/web-console/src/views/home-view/tasks-card/tasks-card.tsx
@@ -21,10 +21,11 @@ import axios from 'axios';
import React from 'react';
import { lookupBy, pluralIfNeeded, queryDruidSql, QueryManager } from '../../../utils';
+import { Capabilities } from '../../../utils/capabilities';
import { HomeViewCard } from '../home-view-card/home-view-card';
export interface TasksCardProps {
- noSqlMode: boolean;
+ capabilities: Capabilities;
}
export interface TasksCardState {
@@ -38,7 +39,7 @@ export interface TasksCardState {
}
export class TasksCard extends React.PureComponent {
- private taskQueryManager: QueryManager;
+ private taskQueryManager: QueryManager;
constructor(props: TasksCardProps, context: any) {
super(props, context);
@@ -52,8 +53,8 @@ export class TasksCard extends React.PureComponent {
- if (noSqlMode) {
+ processQuery: async capabilities => {
+ if (capabilities === 'no-sql') {
const completeTasksResp = await axios.get('/druid/indexer/v1/completeTasks');
const runningTasksResp = await axios.get('/druid/indexer/v1/runningTasks');
const pendingTasksResp = await axios.get('/druid/indexer/v1/pendingTasks');
@@ -91,9 +92,9 @@ GROUP BY 1`,
}
componentDidMount(): void {
- const { noSqlMode } = this.props;
+ const { capabilities } = this.props;
- this.taskQueryManager.runQuery(noSqlMode);
+ this.taskQueryManager.runQuery(capabilities);
}
componentWillUnmount(): void {
diff --git a/web-console/src/views/segments-view/segments-view.spec.tsx b/web-console/src/views/segments-view/segments-view.spec.tsx
index fc8b4d8631b..8dced7101a3 100644
--- a/web-console/src/views/segments-view/segments-view.spec.tsx
+++ b/web-console/src/views/segments-view/segments-view.spec.tsx
@@ -28,7 +28,7 @@ describe('segments-view', () => {
datasource={'test'}
onlyUnavailable={false}
goToQuery={() => {}}
- noSqlMode={false}
+ capabilities="full"
/>,
);
expect(segmentsView).toMatchSnapshot();
diff --git a/web-console/src/views/segments-view/segments-view.tsx b/web-console/src/views/segments-view/segments-view.tsx
index 743943c1500..ea39d77a79e 100644
--- a/web-console/src/views/segments-view/segments-view.tsx
+++ b/web-console/src/views/segments-view/segments-view.tsx
@@ -56,41 +56,61 @@ import {
sqlQueryCustomTableFilter,
} from '../../utils';
import { BasicAction } from '../../utils/basic-action';
+import { Capabilities } from '../../utils/capabilities';
import { LocalStorageBackedArray } from '../../utils/local-storage-backed-array';
import './segments-view.scss';
-const tableColumns: string[] = [
- 'Segment ID',
- 'Datasource',
- 'Start',
- 'End',
- 'Version',
- 'Partition',
- 'Size',
- 'Num rows',
- 'Replicas',
- 'Is published',
- 'Is realtime',
- 'Is available',
- 'Is overshadowed',
- ACTION_COLUMN_LABEL,
-];
-const tableColumnsNoSql: string[] = [
- 'Segment ID',
- 'Datasource',
- 'Start',
- 'End',
- 'Version',
- 'Partition',
- 'Size',
-];
+const tableColumns: Record = {
+ full: [
+ 'Segment ID',
+ 'Datasource',
+ 'Start',
+ 'End',
+ 'Version',
+ 'Partition',
+ 'Size',
+ 'Num rows',
+ 'Replicas',
+ 'Is published',
+ 'Is realtime',
+ 'Is available',
+ 'Is overshadowed',
+ ACTION_COLUMN_LABEL,
+ ],
+ 'no-sql': [
+ 'Segment ID',
+ 'Datasource',
+ 'Start',
+ 'End',
+ 'Version',
+ 'Partition',
+ 'Size',
+ ACTION_COLUMN_LABEL,
+ ],
+ 'no-proxy': [
+ 'Segment ID',
+ 'Datasource',
+ 'Start',
+ 'End',
+ 'Version',
+ 'Partition',
+ 'Size',
+ 'Num rows',
+ 'Replicas',
+ 'Is published',
+ 'Is realtime',
+ 'Is available',
+ 'Is overshadowed',
+ ],
+ broken: ['Segment ID'],
+};
export interface SegmentsViewProps {
goToQuery: (initSql: string) => void;
datasource: string | undefined;
onlyUnavailable: boolean | undefined;
- noSqlMode: boolean;
+ capabilities: Capabilities;
}
export interface SegmentsViewState {
@@ -318,8 +338,8 @@ export class SegmentsView extends React.PureComponent {
this.setState({
@@ -536,7 +556,7 @@ export class SegmentsView extends React.PureComponent (row.original.is_available ? formatNumber(row.value) : (unknown)),
- show: !noSqlMode && hiddenColumns.exists('Num rows'),
+ show: capabilities !== 'no-sql' && hiddenColumns.exists('Num rows'),
},
{
Header: 'Replicas',
@@ -544,35 +564,35 @@ export class SegmentsView extends React.PureComponent String(Boolean(row.is_published)),
Filter: makeBooleanFilter(),
- show: !noSqlMode && hiddenColumns.exists('Is published'),
+ show: capabilities !== 'no-sql' && hiddenColumns.exists('Is published'),
},
{
Header: 'Is realtime',
id: 'is_realtime',
accessor: row => String(Boolean(row.is_realtime)),
Filter: makeBooleanFilter(),
- show: !noSqlMode && hiddenColumns.exists('Is realtime'),
+ show: capabilities !== 'no-sql' && hiddenColumns.exists('Is realtime'),
},
{
Header: 'Is available',
id: 'is_available',
accessor: row => String(Boolean(row.is_available)),
Filter: makeBooleanFilter(),
- show: !noSqlMode && hiddenColumns.exists('Is available'),
+ show: capabilities !== 'no-sql' && hiddenColumns.exists('Is available'),
},
{
Header: 'Is overshadowed',
id: 'is_overshadowed',
accessor: row => String(Boolean(row.is_overshadowed)),
Filter: makeBooleanFilter(),
- show: !noSqlMode && hiddenColumns.exists('Is overshadowed'),
+ show: capabilities !== 'no-sql' && hiddenColumns.exists('Is overshadowed'),
},
{
Header: ACTION_COLUMN_LABEL,
@@ -598,7 +618,7 @@ export class SegmentsView extends React.PureComponent '',
- show: hiddenColumns.exists(ACTION_COLUMN_LABEL),
+ show: capabilities !== 'no-proxy' && hiddenColumns.exists(ACTION_COLUMN_LABEL),
},
]}
defaultPageSize={SegmentsView.PAGE_SIZE}
@@ -638,12 +658,12 @@ export class SegmentsView extends React.PureComponent
- {!noSqlMode && (
+ {capabilities !== 'no-sql' && (