mirror of https://github.com/apache/druid.git
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 <techdocsmith@gmail.com> * Update web-console/src/components/header-bar/header-bar.tsx Co-authored-by: Charles Smith <techdocsmith@gmail.com> * Update web-console/src/components/header-bar/restricted-mode/__snapshots__/restricted-mode.spec.tsx.snap Co-authored-by: Charles Smith <techdocsmith@gmail.com> * Update web-console/src/components/header-bar/restricted-mode/__snapshots__/restricted-mode.spec.tsx.snap Co-authored-by: Charles Smith <techdocsmith@gmail.com> * Update web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx Co-authored-by: Charles Smith <techdocsmith@gmail.com> * Update web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx Co-authored-by: Charles Smith <techdocsmith@gmail.com> * Update web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx Co-authored-by: Charles Smith <techdocsmith@gmail.com> * Update web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx Co-authored-by: Charles Smith <techdocsmith@gmail.com> * Update web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx Co-authored-by: Charles Smith <techdocsmith@gmail.com> * Update web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx Co-authored-by: Charles Smith <techdocsmith@gmail.com> * Update web-console/src/components/header-bar/restricted-mode/restricted-mode.tsx Co-authored-by: Charles Smith <techdocsmith@gmail.com> * reformat * forced => manual capability detection * typo * typo2 --------- Co-authored-by: Charles Smith <techdocsmith@gmail.com>
This commit is contained in:
parent
f4649fece9
commit
4ff7e2c6c9
|
@ -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>
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
`;
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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 React from 'react';
|
||||
|
||||
import { Capabilities } from '../../../helpers';
|
||||
import { shallow } from '../../../utils/shallow-renderer';
|
||||
|
||||
import { RestrictedMode } from './restricted-mode';
|
||||
|
||||
describe('RestrictedMode', () => {
|
||||
it('matches snapshot when in auto capability detection mode', () => {
|
||||
const headerBar = shallow(
|
||||
<RestrictedMode capabilities={Capabilities.COORDINATOR_OVERLORD} onUnrestrict={() => {}} />,
|
||||
);
|
||||
expect(headerBar).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('matches snapshot when in manual capability detection mode', () => {
|
||||
const headerBar = shallow(
|
||||
<RestrictedMode
|
||||
capabilities={Capabilities.COORDINATOR_OVERLORD}
|
||||
onUnrestrict={() => {}}
|
||||
onUseAutomaticCapabilityDetection={() => {}}
|
||||
/>,
|
||||
);
|
||||
expect(headerBar).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -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>
|
||||
);
|
||||
});
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -25,7 +25,6 @@ export async function getClusterCapacity(): Promise<CapacityInfo> {
|
|||
});
|
||||
|
||||
const usedTaskSlots = Number(workersResponse.data.usedClusterCapacity);
|
||||
|
||||
const totalTaskSlots = Number(workersResponse.data.currentClusterCapacity);
|
||||
|
||||
return {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue