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 4ff7e2c6c9c Web console: Better manual capabilities detection
indication (#16191)
4ff7e2c6c9c is described below
commit 4ff7e2c6c9c0048bb65913e6aad0199c6d68dad1
Author: Vadim Ogievetsky <[email protected]>
AuthorDate: Mon Apr 8 10:07:21 2024 -0700
Web console: Better manual capabilities detection indication (#16191)
* Better forced mode indication
* more robust
* Update web-console/src/components/header-bar/header-bar.tsx
Co-authored-by: Charles Smith <[email protected]>
* Update web-console/src/components/header-bar/header-bar.tsx
Co-authored-by: Charles Smith <[email protected]>
* Update
web-console/src/components/header-bar/restricted-mode/__snapshots__/restricted-mode.spec.tsx.snap
Co-authored-by: Charles Smith <[email protected]>
* Update
web-console/src/components/header-bar/restricted-mode/__snapshots__/restricted-mode.spec.tsx.snap
Co-authored-by: Charles Smith <[email protected]>
* Update
web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx
Co-authored-by: Charles Smith <[email protected]>
* Update
web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx
Co-authored-by: Charles Smith <[email protected]>
* Update
web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx
Co-authored-by: Charles Smith <[email protected]>
* Update
web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx
Co-authored-by: Charles Smith <[email protected]>
* Update
web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx
Co-authored-by: Charles Smith <[email protected]>
* Update
web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx
Co-authored-by: Charles Smith <[email protected]>
* Update
web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx
Co-authored-by: Charles Smith <[email protected]>
* reformat
* forced => manual capability detection
* typo
* typo2
---------
Co-authored-by: Charles Smith <[email protected]>
---
.../__snapshots__/header-bar.spec.tsx.snap | 86 ++++---
.../src/components/header-bar/header-bar.tsx | 251 +++++++--------------
.../__snapshots__/restricted-mode.spec.tsx.snap | 143 ++++++++++++
.../restricted-mode/restricted-mode.spec.tsx} | 44 ++--
.../header-bar/restricted-mode/restricted-mode.tsx | 184 +++++++++++++++
web-console/src/console-application.tsx | 3 +-
web-console/src/helpers/capabilities.ts | 10 +-
web-console/src/helpers/capacity.ts | 1 -
web-console/src/singletons/api.ts | 12 +-
9 files changed, 487 insertions(+), 247 deletions(-)
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 18a352dbbc6..6c7cf34cb70 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
@@ -267,55 +267,53 @@ exports[`HeaderBar matches snapshot 1`] = `
<Blueprint4.MenuItem
active={false}
disabled={false}
- icon="cog"
+ icon="high-priority"
multiline={false}
popoverProps={{}}
selected={false}
shouldDismissPopover={true}
- text="Console options"
+ text="Capabilty detection"
>
- <React.Fragment>
- <Blueprint4.MenuItem
- active={false}
- disabled={false}
- multiline={false}
- onClick={[Function]}
- popoverProps={{}}
- selected={false}
- shouldDismissPopover={true}
- text="Force Coordinator/Overlord mode"
- />
- <Blueprint4.MenuItem
- active={false}
- disabled={false}
- multiline={false}
- onClick={[Function]}
- popoverProps={{}}
- selected={false}
- shouldDismissPopover={true}
- text="Force Coordinator mode"
- />
- <Blueprint4.MenuItem
- active={false}
- disabled={false}
- multiline={false}
- onClick={[Function]}
- popoverProps={{}}
- selected={false}
- shouldDismissPopover={true}
- text="Force Overlord mode"
- />
- <Blueprint4.MenuItem
- active={false}
- disabled={false}
- multiline={false}
- onClick={[Function]}
- popoverProps={{}}
- selected={false}
- shouldDismissPopover={true}
- text="Force no management proxy mode"
- />
- </React.Fragment>
+ <Blueprint4.MenuItem
+ active={false}
+ disabled={false}
+ multiline={false}
+ onClick={[Function]}
+ popoverProps={{}}
+ selected={false}
+ shouldDismissPopover={true}
+ text="Manually set Coordinator/Overlord mode"
+ />
+ <Blueprint4.MenuItem
+ active={false}
+ disabled={false}
+ multiline={false}
+ onClick={[Function]}
+ popoverProps={{}}
+ selected={false}
+ shouldDismissPopover={true}
+ text="Manually set Coordinator mode"
+ />
+ <Blueprint4.MenuItem
+ active={false}
+ disabled={false}
+ multiline={false}
+ onClick={[Function]}
+ popoverProps={{}}
+ selected={false}
+ shouldDismissPopover={true}
+ text="Manually set Overlord mode"
+ />
+ <Blueprint4.MenuItem
+ active={false}
+ disabled={false}
+ multiline={false}
+ onClick={[Function]}
+ popoverProps={{}}
+ selected={false}
+ shouldDismissPopover={true}
+ text="Manually set Router with no management proxy mode"
+ />
</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 d3c58db6bb5..9a66dbaeace 100644
--- a/web-console/src/components/header-bar/header-bar.tsx
+++ b/web-console/src/components/header-bar/header-bar.tsx
@@ -32,7 +32,6 @@ import {
} from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import { Popover2 } from '@blueprintjs/popover2';
-import type { JSX } from 'react';
import React, { useState } from 'react';
import {
@@ -51,9 +50,10 @@ import {
localStorageSetJson,
oneOf,
} from '../../utils';
-import { ExternalLink } from '../external-link/external-link';
import { PopoverText } from '../popover-text/popover-text';
+import { RestrictedMode } from './restricted-mode/restricted-mode';
+
import './header-bar.scss';
const capabilitiesOverride =
localStorageGetJson(LocalStorageKeys.CAPABILITIES_OVERRIDE);
@@ -92,143 +92,6 @@ const DruidLogo = React.memo(function DruidLogo() {
);
});
-interface RestrictedModeProps {
- capabilities: Capabilities;
- onUnrestrict(capabilities: Capabilities): void;
-}
-
-const RestrictedMode = React.memo(function RestrictedMode(props:
RestrictedModeProps) {
- const { capabilities, onUnrestrict } = props;
- const mode = capabilities.getModeExtended();
-
- let label: string;
- let message: JSX.Element;
- switch (mode) {
- case 'full':
- return null; // Do not show anything
-
- case 'no-sql':
- label = 'No SQL mode';
- message = (
- <p>
- It appears that the SQL endpoint is disabled. The console will fall
back to{' '}
- <ExternalLink href={getLink('DOCS_API')}>native Druid
APIs</ExternalLink> and will be
- limited in functionality. Look at{' '}
- <ExternalLink href={getLink('DOCS_SQL')}>the SQL docs</ExternalLink>
to enable the SQL
- endpoint.
- </p>
- );
- break;
-
- case 'no-proxy':
- label = 'No management proxy mode';
- message = (
- <p>
- It appears that the management proxy is not enabled, the console
will operate with limited
- functionality.
- </p>
- );
- break;
-
- case 'no-sql-no-proxy':
- label = 'No SQL mode';
- message = (
- <p>
- It appears that the SQL endpoint and management proxy are disabled.
The console can only
- be used to make queries.
- </p>
- );
- break;
-
- case 'coordinator-overlord':
- label = 'Coordinator/Overlord mode';
- message = (
- <p>
- It appears that you are accessing the console on the
Coordinator/Overlord shared service.
- Due to the lack of access to some APIs on this service the console
will operate in a
- limited mode. The unrestricted version of the console can be
accessed on the Router
- service.
- </p>
- );
- break;
-
- case 'coordinator':
- label = 'Coordinator mode';
- message = (
- <p>
- It appears that you are accessing the console on the Coordinator
service. Due to the lack
- of access to some APIs on this service the console will operate in a
limited mode. The
- full version of the console can be accessed on the Router service.
- </p>
- );
- break;
-
- case 'overlord':
- label = 'Overlord mode';
- message = (
- <p>
- It appears that you are accessing the console on the Overlord
service. Due to the lack of
- access to some APIs on this service the console will operate in a
limited mode. The
- unrestricted version of the console can be accessed on the Router
service.
- </p>
- );
- break;
-
- default:
- label = 'Restricted mode';
- message = (
- <p>
- Due to the lack of access to some APIs on this service the console
will operate in a
- limited mode. The unrestricted version of the console can be
accessed on the Router
- service.
- </p>
- );
- break;
- }
-
- return (
- <Popover2
- content={
- <PopoverText>
- <p>The console is running in restricted mode.</p>
- {message}
- <p>
- For more info check out the{' '}
- <ExternalLink
href={`${getLink('DOCS')}/operations/web-console.html`}>
- web console documentation
- </ExternalLink>
- .
- </p>
- <p>
- It is possible that there is an issue with the capability
detection. You can enable the
- unrestricted console but certain features might not work if the
underlying APIs are not
- available.
- </p>
- <p>
- <Button
- icon={IconNames.WARNING_SIGN}
- text={`Temporarily unrestrict console${capabilities.hasSql() ?
'' : ' (with SQL)'}`}
- onClick={() => onUnrestrict(Capabilities.FULL)}
- />
- </p>
- {!capabilities.hasSql() && (
- <p>
- <Button
- icon={IconNames.WARNING_SIGN}
- text="Temporarily unrestrict console (without SQL)"
- onClick={() => onUnrestrict(Capabilities.NO_SQL)}
- />
- </p>
- )}
- </PopoverText>
- }
- position={Position.BOTTOM_RIGHT}
- >
- <Button icon={IconNames.WARNING_SIGN} text={label}
intent={Intent.WARNING} minimal />
- </Popover2>
- );
-});
-
export interface HeaderBarProps {
active: HeaderActiveTab;
capabilities: Capabilities;
@@ -324,7 +187,7 @@ export const HeaderBar = React.memo(function
HeaderBar(props: HeaderBarProps) {
</Menu>
);
- function setForcedMode(capabilities: Capabilities | undefined): void {
+ function setCapabilitiesOverride(capabilities: Capabilities | undefined):
void {
if (capabilities) {
localStorageSetJson(LocalStorageKeys.CAPABILITIES_OVERRIDE,
capabilities);
} else {
@@ -360,39 +223,46 @@ export const HeaderBar = React.memo(function
HeaderBar(props: HeaderBarProps) {
onClick={() => setCompactionDynamicConfigDialogOpen(true)}
disabled={!capabilities.hasCoordinatorAccess()}
/>
-
<MenuDivider />
- <MenuItem icon={IconNames.COG} text="Console options">
- {capabilitiesOverride ? (
- <MenuItem text="Clear forced mode" onClick={() =>
setForcedMode(undefined)} />
- ) : (
+ <MenuItem
+ icon={IconNames.HIGH_PRIORITY}
+ text="Capabilty detection"
+ intent={capabilitiesOverride ? Intent.DANGER : undefined}
+ >
+ {capabilitiesOverride && (
<>
- {capabilitiesMode !== 'coordinator-overlord' && (
- <MenuItem
- text="Force Coordinator/Overlord mode"
- onClick={() =>
setForcedMode(Capabilities.COORDINATOR_OVERLORD)}
- />
- )}
- {capabilitiesMode !== 'coordinator' && (
- <MenuItem
- text="Force Coordinator mode"
- onClick={() => setForcedMode(Capabilities.COORDINATOR)}
- />
- )}
- {capabilitiesMode !== 'overlord' && (
- <MenuItem
- text="Force Overlord mode"
- onClick={() => setForcedMode(Capabilities.OVERLORD)}
- />
- )}
- {capabilitiesMode !== 'no-proxy' && (
- <MenuItem
- text="Force no management proxy mode"
- onClick={() => setForcedMode(Capabilities.NO_PROXY)}
- />
- )}
+ <MenuItem
+ text="Use automatic capabilty detection"
+ onClick={() => setCapabilitiesOverride(undefined)}
+ intent={Intent.PRIMARY}
+ />
+ <MenuDivider />
</>
)}
+ {capabilitiesMode !== 'coordinator-overlord' && (
+ <MenuItem
+ text="Manually set Coordinator/Overlord mode"
+ onClick={() =>
setCapabilitiesOverride(Capabilities.COORDINATOR_OVERLORD)}
+ />
+ )}
+ {capabilitiesMode !== 'coordinator' && (
+ <MenuItem
+ text="Manually set Coordinator mode"
+ onClick={() => setCapabilitiesOverride(Capabilities.COORDINATOR)}
+ />
+ )}
+ {capabilitiesMode !== 'overlord' && (
+ <MenuItem
+ text="Manually set Overlord mode"
+ onClick={() => setCapabilitiesOverride(Capabilities.OVERLORD)}
+ />
+ )}
+ {capabilitiesMode !== 'no-proxy' && (
+ <MenuItem
+ text="Manually set Router with no management proxy mode"
+ onClick={() => setCapabilitiesOverride(Capabilities.NO_PROXY)}
+ />
+ )}
</MenuItem>
</Menu>
);
@@ -495,7 +365,48 @@ export const HeaderBar = React.memo(function
HeaderBar(props: HeaderBarProps) {
</Popover2>
</NavbarGroup>
<NavbarGroup align={Alignment.RIGHT}>
- <RestrictedMode capabilities={capabilities}
onUnrestrict={onUnrestrict} />
+ <RestrictedMode
+ capabilities={capabilities}
+ onUnrestrict={onUnrestrict}
+ onUseAutomaticCapabilityDetection={
+ capabilitiesOverride ? () => setCapabilitiesOverride(undefined) :
undefined
+ }
+ />
+ {capabilitiesOverride && (
+ <Popover2
+ content={
+ <PopoverText>
+ <p>
+ The console is running in a manual capability setting mode
that assumes a limited
+ set of capabilities rather than detecting all capabilities
for the cluster.
+ </p>
+ <p>
+ Manual capability setting mode is an advanced feature used
for testing and for
+ working around issues with the automatic capability
detecting logic.
+ </p>
+ <p>
+ If you are unsure why the console is in this mode, revert to
using automatic
+ capability detection.
+ </p>
+ <p>
+ <Button
+ text="Use automatic capability detection"
+ onClick={() => setCapabilitiesOverride(undefined)}
+ intent={Intent.PRIMARY}
+ />
+ </p>
+ </PopoverText>
+ }
+ position={Position.BOTTOM_RIGHT}
+ >
+ <Button
+ icon={IconNames.HIGH_PRIORITY}
+ text="Manual capabilty detection"
+ intent={Intent.DANGER}
+ minimal
+ />
+ </Popover2>
+ )}
<Popover2 content={configMenu} position={Position.BOTTOM_RIGHT}>
<Button className="header-entry" minimal icon={IconNames.COG} />
</Popover2>
diff --git
a/web-console/src/components/header-bar/restricted-mode/__snapshots__/restricted-mode.spec.tsx.snap
b/web-console/src/components/header-bar/restricted-mode/__snapshots__/restricted-mode.spec.tsx.snap
new file mode 100644
index 00000000000..ed352ecbf5f
--- /dev/null
+++
b/web-console/src/components/header-bar/restricted-mode/__snapshots__/restricted-mode.spec.tsx.snap
@@ -0,0 +1,143 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`RestrictedMode matches snapshot when in auto capability detection
mode 1`] = `
+<Blueprint4.Popover2
+ boundary="clippingParents"
+ captureDismiss={false}
+ className="restricted-mode"
+ content={
+ <Memo(PopoverText)>
+ <p>
+ The console is running in restricted mode.
+ </p>
+ <p>
+ You are accessing the console on the Coordinator/Overlord shared
service. Because this service lacks access to some APIs, the console will
operate in a limited mode. You can access the unrestricted version of the
console on the Router service.
+ </p>
+ <p>
+ For more info refer to the
+
+ <Memo(ExternalLink)
+
href="https://druid.apache.org/docs/latest/operations/web-console.html"
+ >
+ web console documentation
+ </Memo(ExternalLink)>
+ .
+ </p>
+ <React.Fragment>
+ <p>
+ It is possible that the console is experiencing an issue with the
capability detection. You can enable the unrestricted console, but certain
features might not work if the underlying APIs are not available.
+ </p>
+ <p>
+ <Blueprint4.Button
+ icon="warning-sign"
+ onClick={[Function]}
+ text="Temporarily unrestrict console (with SQL)"
+ />
+ </p>
+ </React.Fragment>
+ <p>
+ <Blueprint4.Button
+ icon="warning-sign"
+ onClick={[Function]}
+ text="Temporarily unrestrict console (without SQL)"
+ />
+ </p>
+ </Memo(PopoverText)>
+ }
+ defaultIsOpen={false}
+ disabled={false}
+ fill={false}
+ hasBackdrop={false}
+ hoverCloseDelay={300}
+ hoverOpenDelay={150}
+ inheritDarkTheme={true}
+ interactionKind="click"
+ matchTargetWidth={false}
+ minimal={false}
+ openOnTargetFocus={true}
+ position="bottom-right"
+ positioningStrategy="absolute"
+ shouldReturnFocusOnClose={false}
+ targetTagName="span"
+ transitionDuration={300}
+ usePortal={true}
+>
+ <Blueprint4.Button
+ icon="warning-sign"
+ intent="warning"
+ minimal={true}
+ text="Coordinator/Overlord mode"
+ />
+</Blueprint4.Popover2>
+`;
+
+exports[`RestrictedMode matches snapshot when in manual capability detection
mode 1`] = `
+<Blueprint4.Popover2
+ boundary="clippingParents"
+ captureDismiss={false}
+ className="restricted-mode"
+ content={
+ <Memo(PopoverText)>
+ <p>
+ The console is running in restricted mode.
+ </p>
+ <p>
+ You are accessing the console on the Coordinator/Overlord shared
service. Because this service lacks access to some APIs, the console will
operate in a limited mode. You can access the unrestricted version of the
console on the Router service.
+ </p>
+ <p>
+ For more info refer to the
+
+ <Memo(ExternalLink)
+
href="https://druid.apache.org/docs/latest/operations/web-console.html"
+ >
+ web console documentation
+ </Memo(ExternalLink)>
+ .
+ </p>
+ <React.Fragment>
+ <p>
+ The console did no perform its automatic capability detection
because it is running in manual capability detection mode.
+ </p>
+ <p>
+ <Blueprint4.Button
+ intent="primary"
+ onClick={[Function]}
+ text="Use to automatic capability detection"
+ />
+ </p>
+ </React.Fragment>
+ <p>
+ <Blueprint4.Button
+ icon="warning-sign"
+ onClick={[Function]}
+ text="Temporarily unrestrict console (without SQL)"
+ />
+ </p>
+ </Memo(PopoverText)>
+ }
+ defaultIsOpen={false}
+ disabled={false}
+ fill={false}
+ hasBackdrop={false}
+ hoverCloseDelay={300}
+ hoverOpenDelay={150}
+ inheritDarkTheme={true}
+ interactionKind="click"
+ matchTargetWidth={false}
+ minimal={false}
+ openOnTargetFocus={true}
+ position="bottom-right"
+ positioningStrategy="absolute"
+ shouldReturnFocusOnClose={false}
+ targetTagName="span"
+ transitionDuration={300}
+ usePortal={true}
+>
+ <Blueprint4.Button
+ icon="warning-sign"
+ intent="warning"
+ minimal={true}
+ text="Coordinator/Overlord mode"
+ />
+</Blueprint4.Popover2>
+`;
diff --git a/web-console/src/helpers/capacity.ts
b/web-console/src/components/header-bar/restricted-mode/restricted-mode.spec.tsx
similarity index 50%
copy from web-console/src/helpers/capacity.ts
copy to
web-console/src/components/header-bar/restricted-mode/restricted-mode.spec.tsx
index aa29efc68e9..2469c11f6ff 100644
--- a/web-console/src/helpers/capacity.ts
+++
b/web-console/src/components/header-bar/restricted-mode/restricted-mode.spec.tsx
@@ -16,29 +16,29 @@
* limitations under the License.
*/
-import type { CapacityInfo } from '../druid-models';
-import { Api } from '../singletons';
+import React from 'react';
-export async function getClusterCapacity(): Promise<CapacityInfo> {
- const workersResponse = await
Api.instance.get('/druid/indexer/v1/totalWorkerCapacity', {
- timeout: 5000,
- });
-
- const usedTaskSlots = Number(workersResponse.data.usedClusterCapacity);
+import { Capabilities } from '../../../helpers';
+import { shallow } from '../../../utils/shallow-renderer';
- const totalTaskSlots = Number(workersResponse.data.currentClusterCapacity);
+import { RestrictedMode } from './restricted-mode';
- return {
- availableTaskSlots: totalTaskSlots - usedTaskSlots,
- usedTaskSlots,
- totalTaskSlots,
- };
-}
+describe('RestrictedMode', () => {
+ it('matches snapshot when in auto capability detection mode', () => {
+ const headerBar = shallow(
+ <RestrictedMode capabilities={Capabilities.COORDINATOR_OVERLORD}
onUnrestrict={() => {}} />,
+ );
+ expect(headerBar).toMatchSnapshot();
+ });
-export async function maybeGetClusterCapacity(): Promise<CapacityInfo |
undefined> {
- try {
- return await getClusterCapacity();
- } catch {
- return;
- }
-}
+ it('matches snapshot when in manual capability detection mode', () => {
+ const headerBar = shallow(
+ <RestrictedMode
+ capabilities={Capabilities.COORDINATOR_OVERLORD}
+ onUnrestrict={() => {}}
+ onUseAutomaticCapabilityDetection={() => {}}
+ />,
+ );
+ expect(headerBar).toMatchSnapshot();
+ });
+});
diff --git
a/web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx
b/web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx
new file mode 100644
index 00000000000..072d5b10e58
--- /dev/null
+++ b/web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx
@@ -0,0 +1,184 @@
+/*
+ * 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 { Button, Intent, Position } from '@blueprintjs/core';
+import { IconNames } from '@blueprintjs/icons';
+import { Popover2 } from '@blueprintjs/popover2';
+import React, { type JSX } from 'react';
+
+import { Capabilities } from '../../../helpers';
+import { getLink } from '../../../links';
+import { ExternalLink } from '../../external-link/external-link';
+import { PopoverText } from '../../popover-text/popover-text';
+
+export interface RestrictedModeProps {
+ capabilities: Capabilities;
+ onUnrestrict(capabilities: Capabilities): void;
+ onUseAutomaticCapabilityDetection?: () => void;
+}
+
+export const RestrictedMode = React.memo(function RestrictedMode(props:
RestrictedModeProps) {
+ const { capabilities, onUnrestrict, onUseAutomaticCapabilityDetection } =
props;
+ const mode = capabilities.getModeExtended();
+
+ let label: string;
+ let message: JSX.Element;
+ switch (mode) {
+ case 'full':
+ return null; // Do not show anything
+
+ case 'no-sql':
+ label = 'No SQL mode';
+ message = (
+ <p>
+ The SQL endpoint is disabled. The console will fall back to{' '}
+ <ExternalLink href={getLink('DOCS_API')}>native Druid
APIs</ExternalLink> and will operate
+ with limited functionality. Refer to{' '}
+ <ExternalLink href={getLink('DOCS_SQL')}>the SQL docs</ExternalLink>
for instructions to
+ enable the SQL endpoint.
+ </p>
+ );
+ break;
+
+ case 'no-proxy':
+ label = 'No management proxy mode';
+ message = (
+ <p>
+ The management proxy is disabled, the console will operate with
limited functionality.
+ </p>
+ );
+ break;
+
+ case 'no-sql-no-proxy':
+ label = 'No SQL mode';
+ message = (
+ <p>
+ The SQL endpoint and management proxy are disabled. You can only use
the console to make
+ JSON-based queries.
+ </p>
+ );
+ break;
+
+ case 'coordinator-overlord':
+ label = 'Coordinator/Overlord mode';
+ message = (
+ <p>
+ You are accessing the console on the Coordinator/Overlord shared
service. Because this
+ service lacks access to some APIs, the console will operate in a
limited mode. You can
+ access the unrestricted version of the console on the Router service.
+ </p>
+ );
+ break;
+
+ case 'coordinator':
+ label = 'Coordinator mode';
+ message = (
+ <p>
+ You are accessing the console on the Coordinator service. Because
this service lacks
+ access to some APIs, the console will operate in a limited mode. You
can access the
+ unrestricted version of the console on the Router service.
+ </p>
+ );
+ break;
+
+ case 'overlord':
+ label = 'Overlord mode';
+ message = (
+ <p>
+ You are accessing the console on the Overlord service. Because this
service lacks access
+ to some APIs, the console will operate in a limited mode. You can
access the unrestricted
+ version of the console on the Router service.
+ </p>
+ );
+ break;
+
+ default:
+ label = 'Restricted mode';
+ message = (
+ <p>
+ Due to the lack of access to some APIs on this service, the console
will operate in a
+ limited mode. You can access the unrestricted version of the console
on the Router
+ service.
+ </p>
+ );
+ break;
+ }
+
+ return (
+ <Popover2
+ className="restricted-mode"
+ content={
+ <PopoverText>
+ <p>The console is running in restricted mode.</p>
+ {message}
+ <p>
+ For more info refer to the{' '}
+ <ExternalLink
href={`${getLink('DOCS')}/operations/web-console.html`}>
+ web console documentation
+ </ExternalLink>
+ .
+ </p>
+ {onUseAutomaticCapabilityDetection ? (
+ <>
+ <p>
+ The console did no perform its automatic capability detection
because it is running
+ in manual capability detection mode.
+ </p>
+ <p>
+ <Button
+ text="Use to automatic capability detection"
+ onClick={onUseAutomaticCapabilityDetection}
+ intent={Intent.PRIMARY}
+ />
+ </p>
+ </>
+ ) : (
+ <>
+ <p>
+ It is possible that the console is experiencing an issue with
the capability
+ detection. You can enable the unrestricted console, but
certain features might not
+ work if the underlying APIs are not available.
+ </p>
+ <p>
+ <Button
+ icon={IconNames.WARNING_SIGN}
+ text={`Temporarily unrestrict console${
+ capabilities.hasSql() ? '' : ' (with SQL)'
+ }`}
+ onClick={() => onUnrestrict(Capabilities.FULL)}
+ />
+ </p>
+ </>
+ )}
+ {!capabilities.hasSql() && (
+ <p>
+ <Button
+ icon={IconNames.WARNING_SIGN}
+ text="Temporarily unrestrict console (without SQL)"
+ onClick={() => onUnrestrict(Capabilities.NO_SQL)}
+ />
+ </p>
+ )}
+ </PopoverText>
+ }
+ position={Position.BOTTOM_RIGHT}
+ >
+ <Button icon={IconNames.WARNING_SIGN} text={label}
intent={Intent.WARNING} minimal />
+ </Popover2>
+ );
+});
diff --git a/web-console/src/console-application.tsx
b/web-console/src/console-application.tsx
index 8955b1c9051..08eaf74f4b7 100644
--- a/web-console/src/console-application.tsx
+++ b/web-console/src/console-application.tsx
@@ -122,7 +122,8 @@ export class ConsoleApplication extends React.PureComponent<
return await Capabilities.detectCapacity(capabilities);
},
- onStateChange: ({ data, loading }) => {
+ onStateChange: ({ data, loading, error }) => {
+ console.error('There was an error retrieving the capabilities', error);
this.setState({
capabilities: data || Capabilities.FULL,
capabilitiesLoading: loading,
diff --git a/web-console/src/helpers/capabilities.ts
b/web-console/src/helpers/capabilities.ts
index 4c5c9357cc1..ce8509072f2 100644
--- a/web-console/src/helpers/capabilities.ts
+++ b/web-console/src/helpers/capabilities.ts
@@ -65,8 +65,8 @@ export class Capabilities {
{ timeout: Capabilities.STATUS_TIMEOUT },
);
} catch (e) {
- const { response } = e;
- if (response.status !== 405 && response.status !== 404) {
+ const status = e.response?.status;
+ if (status !== 405 && status !== 404) {
return; // other failure
}
try {
@@ -87,7 +87,7 @@ export class Capabilities {
{ timeout: Capabilities.STATUS_TIMEOUT },
);
} catch (e) {
- if (response.status !== 405 && response.status !== 404) {
+ if (status !== 405 && status !== 404) {
return; // other failure
}
@@ -106,9 +106,9 @@ export class Capabilities {
timeout: Capabilities.STATUS_TIMEOUT,
});
} catch (e) {
- const { response } = e;
+ const status = e.response?.status;
// If we detect error code 400 the management proxy is enabled but just
does not know about the recently added /proxy/enabled route so treat this as a
win.
- return response.status === 400;
+ return status === 400;
}
return true;
diff --git a/web-console/src/helpers/capacity.ts
b/web-console/src/helpers/capacity.ts
index aa29efc68e9..c990149385f 100644
--- a/web-console/src/helpers/capacity.ts
+++ b/web-console/src/helpers/capacity.ts
@@ -25,7 +25,6 @@ export async function getClusterCapacity():
Promise<CapacityInfo> {
});
const usedTaskSlots = Number(workersResponse.data.usedClusterCapacity);
-
const totalTaskSlots = Number(workersResponse.data.currentClusterCapacity);
return {
diff --git a/web-console/src/singletons/api.ts
b/web-console/src/singletons/api.ts
index 6067dba39ae..c7b123df76c 100644
--- a/web-console/src/singletons/api.ts
+++ b/web-console/src/singletons/api.ts
@@ -16,8 +16,8 @@
* limitations under the License.
*/
-import type { AxiosError, AxiosInstance, CreateAxiosDefaults } from 'axios';
-import axios from 'axios';
+import type { AxiosInstance, CreateAxiosDefaults } from 'axios';
+import axios, { AxiosError } from 'axios';
import * as JSONBig from 'json-bigint-native';
import { nonEmptyString } from '../utils';
@@ -36,11 +36,15 @@ export class Api {
const responseData = error.response?.data;
const message = responseData?.message;
if (nonEmptyString(message)) {
- return Promise.reject(new Error(message));
+ return Promise.reject(
+ new AxiosError(message, error.code, error.config, error.request,
error.response),
+ );
}
if (error.config?.method?.toLowerCase() === 'get' &&
nonEmptyString(responseData)) {
- return Promise.reject(new Error(responseData));
+ return Promise.reject(
+ new AxiosError(responseData, error.code, error.config,
error.request, error.response),
+ );
}
return Promise.reject(error);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]