mirror of https://github.com/apache/druid.git
Web console: Remove support for IE11 and other older browsers (#11357)
* Use common browserlist and update to drop IE11 * Change TypeScript target to ES2016 * Update browserslist for "supports es6" support * Show a warning if accessed from an unsupported browser * Inline browser-update styles; detect SyntaxErrors too * Better wording * Upgrade to the latest Blueprint * Refactor RunButton to be FC, use useHotkeys * Remove dead license * Update snapshots * Address feedback * Wording Co-authored-by: Vadim Ogievetsky <vadimon@gmail.com> Co-authored-by: Vadim Ogievetsky <vadimon@gmail.com>
This commit is contained in:
parent
6b272c857f
commit
ac9b1f81b4
|
@ -4909,7 +4909,7 @@ license_category: binary
|
|||
module: web-console
|
||||
license_name: Apache License version 2.0
|
||||
copyright: Palantir Technologies
|
||||
version: 3.33.0
|
||||
version: 3.45.0
|
||||
|
||||
---
|
||||
|
||||
|
@ -4918,7 +4918,7 @@ license_category: binary
|
|||
module: web-console
|
||||
license_name: Apache License version 2.0
|
||||
copyright: Palantir Technologies
|
||||
version: 3.19.2
|
||||
version: 3.23.4
|
||||
|
||||
---
|
||||
|
||||
|
@ -4927,7 +4927,17 @@ license_category: binary
|
|||
module: web-console
|
||||
license_name: Apache License version 2.0
|
||||
copyright: Palantir Technologies
|
||||
version: 3.22.0
|
||||
version: 3.26.1
|
||||
|
||||
---
|
||||
|
||||
name: "@hypnosphi/create-react-context"
|
||||
license_category: binary
|
||||
module: web-console
|
||||
license_name: MIT License
|
||||
copyright: James Kyle
|
||||
version: 0.3.1
|
||||
license_file_path: licenses/bin/@hypnosphi-create-react-context.MIT
|
||||
|
||||
---
|
||||
|
||||
|
@ -4991,16 +5001,6 @@ license_file_path: licenses/bin/core-js.MIT
|
|||
|
||||
---
|
||||
|
||||
name: "create-react-context"
|
||||
license_category: binary
|
||||
module: web-console
|
||||
license_name: MIT License
|
||||
copyright: James Kyle
|
||||
version: 0.3.0
|
||||
license_file_path: licenses/bin/create-react-context.MIT
|
||||
|
||||
---
|
||||
|
||||
name: "d3-array"
|
||||
license_category: binary
|
||||
module: web-console
|
||||
|
@ -5135,7 +5135,7 @@ license_category: binary
|
|||
module: web-console
|
||||
license_name: MIT License
|
||||
copyright: Andrea Giammarchi
|
||||
version: 2.1.5
|
||||
version: 2.1.6
|
||||
license_file_path: licenses/bin/dom4.MIT
|
||||
|
||||
---
|
||||
|
@ -5483,7 +5483,7 @@ license_category: binary
|
|||
module: web-console
|
||||
license_name: MIT License
|
||||
copyright: Giampaolo Bellavite
|
||||
version: 7.4.8
|
||||
version: 7.4.9
|
||||
license_file_path: licenses/bin/react-day-picker.MIT
|
||||
|
||||
---
|
||||
|
@ -5523,7 +5523,7 @@ license_category: binary
|
|||
module: web-console
|
||||
license_name: MIT License
|
||||
copyright: Travis Arnold
|
||||
version: 1.3.7
|
||||
version: 1.3.11
|
||||
license_file_path: licenses/bin/react-popper.MIT
|
||||
|
||||
---
|
||||
|
|
|
@ -19,19 +19,7 @@
|
|||
module.exports = function (api) {
|
||||
api.cache(false);
|
||||
|
||||
const presets = [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
useBuiltIns: 'entry',
|
||||
corejs: 3,
|
||||
forceAllTransforms: true,
|
||||
targets: {
|
||||
ie: '11',
|
||||
},
|
||||
},
|
||||
],
|
||||
];
|
||||
const presets = [['@babel/preset-env', { useBuiltIns: 'entry', corejs: 3 }]];
|
||||
const plugins = [];
|
||||
|
||||
return {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -58,10 +58,17 @@
|
|||
"node": "14.16.1",
|
||||
"npm": "6.14.12"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1% and supports es6",
|
||||
"last 3 versions and supports es6",
|
||||
"Firefox ESR",
|
||||
"not dead",
|
||||
"not ie 11"
|
||||
],
|
||||
"dependencies": {
|
||||
"@blueprintjs/core": "^3.33.0",
|
||||
"@blueprintjs/datetime": "^3.19.2",
|
||||
"@blueprintjs/icons": "^3.22.0",
|
||||
"@blueprintjs/core": "^3.45.0",
|
||||
"@blueprintjs/datetime": "^3.23.4",
|
||||
"@blueprintjs/icons": "^3.26.1",
|
||||
"axios": "^0.21.1",
|
||||
"brace": "^0.11.1",
|
||||
"classnames": "^2.2.6",
|
||||
|
@ -95,8 +102,8 @@
|
|||
"@awesome-code-style/eslint-config": "^3.0.0",
|
||||
"@awesome-code-style/prettier-config": "^3.0.0",
|
||||
"@awesome-code-style/stylelint-config": "^3.0.0",
|
||||
"@babel/core": "^7.13.15",
|
||||
"@babel/preset-env": "^7.13.15",
|
||||
"@babel/core": "^7.14.3",
|
||||
"@babel/preset-env": "^7.14.4",
|
||||
"@testing-library/react": "^8.0.9",
|
||||
"@types/classnames": "^2.2.9",
|
||||
"@types/d3-array": "^2.0.0",
|
||||
|
@ -120,8 +127,9 @@
|
|||
"@types/react-table": "6.8.5",
|
||||
"@types/uuid": "^7.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^4.22.0",
|
||||
"autoprefixer": "^9.8.6",
|
||||
"autoprefixer": "^10.2.6",
|
||||
"babel-loader": "^8.2.2",
|
||||
"browserslist": "^4.16.6",
|
||||
"codecov": "^3.6.1",
|
||||
"css-loader": "^5.2.1",
|
||||
"enzyme": "^3.10.0",
|
||||
|
@ -142,8 +150,8 @@
|
|||
"license-checker": "^25.0.1",
|
||||
"node-sass": "^5.0.0",
|
||||
"playwright-chromium": "^1.10.0",
|
||||
"postcss": "^8.2.10",
|
||||
"postcss-loader": "^5.2.0",
|
||||
"postcss": "^8.3.0",
|
||||
"postcss-loader": "^5.3.0",
|
||||
"postcss-preset-env": "^6.7.0",
|
||||
"prettier": "^2.2.1",
|
||||
"sass-loader": "^11.0.1",
|
||||
|
|
|
@ -37,7 +37,6 @@ exports[`TimedButton matches snapshot 1`] = `
|
|||
minimal={false}
|
||||
modifiers={Object {}}
|
||||
openOnTargetFocus={true}
|
||||
position="auto"
|
||||
targetTagName="span"
|
||||
transitionDuration={300}
|
||||
usePortal={true}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import { HotkeysProvider, Intent } from '@blueprintjs/core';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
|
@ -279,23 +279,25 @@ export class ConsoleApplication extends React.PureComponent<
|
|||
}
|
||||
|
||||
return (
|
||||
<HashRouter hashType="noslash">
|
||||
<div className="console-application">
|
||||
<Switch>
|
||||
<Route path="/load-data" component={this.wrappedLoadDataView} />
|
||||
<HotkeysProvider>
|
||||
<HashRouter hashType="noslash">
|
||||
<div className="console-application">
|
||||
<Switch>
|
||||
<Route path="/load-data" component={this.wrappedLoadDataView} />
|
||||
|
||||
<Route path="/ingestion" component={this.wrappedIngestionView} />
|
||||
<Route path="/datasources" component={this.wrappedDatasourcesView} />
|
||||
<Route path="/segments" component={this.wrappedSegmentsView} />
|
||||
<Route path="/services" component={this.wrappedServicesView} />
|
||||
<Route path="/ingestion" component={this.wrappedIngestionView} />
|
||||
<Route path="/datasources" component={this.wrappedDatasourcesView} />
|
||||
<Route path="/segments" component={this.wrappedSegmentsView} />
|
||||
<Route path="/services" component={this.wrappedServicesView} />
|
||||
|
||||
<Route path="/query" component={this.wrappedQueryView} />
|
||||
<Route path="/query" component={this.wrappedQueryView} />
|
||||
|
||||
<Route path="/lookups" component={this.wrappedLookupsView} />
|
||||
<Route component={this.wrappedHomeView} />
|
||||
</Switch>
|
||||
</div>
|
||||
</HashRouter>
|
||||
<Route path="/lookups" component={this.wrappedLookupsView} />
|
||||
<Route component={this.wrappedHomeView} />
|
||||
</Switch>
|
||||
</div>
|
||||
</HashRouter>
|
||||
</HotkeysProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -597,6 +597,7 @@ exports[`tasks view matches snapshot 1`] = `
|
|||
icon="error"
|
||||
intent="primary"
|
||||
isOpen={false}
|
||||
loading={false}
|
||||
onConfirm={[Function]}
|
||||
>
|
||||
<p />
|
||||
|
|
|
@ -34,7 +34,7 @@ exports[`QueryView matches snapshot 1`] = `
|
|||
<div
|
||||
className="query-control-bar"
|
||||
>
|
||||
<HotkeysTarget(RunButton)
|
||||
<Memo(RunButton)
|
||||
loading={true}
|
||||
onEditContext={[Function]}
|
||||
onExplain={[Function]}
|
||||
|
@ -49,6 +49,7 @@ exports[`QueryView matches snapshot 1`] = `
|
|||
content="Automatically wrap the query with a limit to protect against queries with very large result sets."
|
||||
hoverCloseDelay={0}
|
||||
hoverOpenDelay={800}
|
||||
minimal={false}
|
||||
transitionDuration={100}
|
||||
>
|
||||
<Blueprint3.Switch
|
||||
|
@ -112,7 +113,7 @@ exports[`QueryView matches snapshot with query 1`] = `
|
|||
<div
|
||||
className="query-control-bar"
|
||||
>
|
||||
<HotkeysTarget(RunButton)
|
||||
<Memo(RunButton)
|
||||
loading={true}
|
||||
onEditContext={[Function]}
|
||||
onExplain={[Function]}
|
||||
|
@ -127,6 +128,7 @@ exports[`QueryView matches snapshot with query 1`] = `
|
|||
content="Automatically wrap the query with a limit to protect against queries with very large result sets."
|
||||
hoverCloseDelay={0}
|
||||
hoverOpenDelay={800}
|
||||
minimal={false}
|
||||
transitionDuration={100}
|
||||
>
|
||||
<Blueprint3.Switch
|
||||
|
|
|
@ -19,15 +19,13 @@
|
|||
import {
|
||||
Button,
|
||||
ButtonGroup,
|
||||
Hotkey,
|
||||
Hotkeys,
|
||||
HotkeysTarget,
|
||||
Intent,
|
||||
Menu,
|
||||
MenuDivider,
|
||||
MenuItem,
|
||||
Popover,
|
||||
Position,
|
||||
useHotkeys,
|
||||
} from '@blueprintjs/core';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
import React from 'react';
|
||||
|
@ -59,127 +57,123 @@ export interface RunButtonProps {
|
|||
onPrettier: () => void;
|
||||
}
|
||||
|
||||
@HotkeysTarget
|
||||
export class RunButton extends React.PureComponent<RunButtonProps> {
|
||||
public renderHotkeys() {
|
||||
return (
|
||||
<Hotkeys>
|
||||
<Hotkey
|
||||
allowInInput
|
||||
global
|
||||
combo="ctrl + enter"
|
||||
label="run on click"
|
||||
onKeyDown={this.handleRun}
|
||||
/>
|
||||
</Hotkeys>
|
||||
);
|
||||
}
|
||||
const RunButtonExtraMenu = (props: RunButtonProps) => {
|
||||
const {
|
||||
runeMode,
|
||||
onExplain,
|
||||
queryContext,
|
||||
onQueryContextChange,
|
||||
onEditContext,
|
||||
onHistory,
|
||||
onPrettier,
|
||||
} = props;
|
||||
|
||||
private readonly handleRun = () => {
|
||||
const { onRun } = this.props;
|
||||
const useCache = getUseCache(queryContext);
|
||||
const useApproximateCountDistinct = getUseApproximateCountDistinct(queryContext);
|
||||
const useApproximateTopN = getUseApproximateTopN(queryContext);
|
||||
const numContextKeys = Object.keys(queryContext).length;
|
||||
|
||||
return (
|
||||
<Menu>
|
||||
<MenuItem
|
||||
icon={IconNames.HELP}
|
||||
text={runeMode ? 'Native query documentation' : 'DruidSQL documentation'}
|
||||
href={getLink(runeMode ? 'DOCS_RUNE' : 'DOCS_SQL')}
|
||||
target="_blank"
|
||||
/>
|
||||
<MenuItem icon={IconNames.HISTORY} text="Query history" onClick={onHistory} />
|
||||
{!runeMode && onExplain && (
|
||||
<MenuItem icon={IconNames.CLEAN} text="Explain SQL query" onClick={onExplain} />
|
||||
)}
|
||||
{runeMode && (
|
||||
<MenuItem icon={IconNames.ALIGN_LEFT} text="Prettify JSON" onClick={onPrettier} />
|
||||
)}
|
||||
<MenuItem
|
||||
icon={IconNames.PROPERTIES}
|
||||
text="Edit context"
|
||||
onClick={onEditContext}
|
||||
label={numContextKeys ? pluralIfNeeded(numContextKeys, 'key') : undefined}
|
||||
/>
|
||||
<MenuDivider />
|
||||
{!runeMode && (
|
||||
<>
|
||||
<MenuCheckbox
|
||||
checked={useApproximateCountDistinct}
|
||||
text="Use approximate COUNT(DISTINCT)"
|
||||
onChange={() => {
|
||||
onQueryContextChange(
|
||||
setUseApproximateCountDistinct(queryContext, !useApproximateCountDistinct),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<MenuCheckbox
|
||||
checked={useApproximateTopN}
|
||||
text="Use approximate TopN"
|
||||
onChange={() => {
|
||||
onQueryContextChange(setUseApproximateTopN(queryContext, !useApproximateTopN));
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<MenuCheckbox
|
||||
checked={useCache}
|
||||
text="Use cache"
|
||||
onChange={() => {
|
||||
onQueryContextChange(setUseCache(queryContext, !useCache));
|
||||
}}
|
||||
/>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
||||
export const RunButton = React.memo(function RunButton(props: RunButtonProps) {
|
||||
const { runeMode, onRun, loading } = props;
|
||||
|
||||
const handleRun = React.useCallback(() => {
|
||||
if (!onRun) return;
|
||||
onRun();
|
||||
};
|
||||
}, [onRun]);
|
||||
|
||||
renderExtraMenu() {
|
||||
const {
|
||||
runeMode,
|
||||
onExplain,
|
||||
queryContext,
|
||||
onQueryContextChange,
|
||||
onEditContext,
|
||||
onHistory,
|
||||
onPrettier,
|
||||
} = this.props;
|
||||
const hotkeys = React.useMemo(() => {
|
||||
return [
|
||||
{
|
||||
allowInInput: true,
|
||||
global: true,
|
||||
combo: 'ctrl + enter',
|
||||
label: 'Runs the current query',
|
||||
onKeyDown: handleRun,
|
||||
},
|
||||
];
|
||||
}, [handleRun]);
|
||||
|
||||
const useCache = getUseCache(queryContext);
|
||||
const useApproximateCountDistinct = getUseApproximateCountDistinct(queryContext);
|
||||
const useApproximateTopN = getUseApproximateTopN(queryContext);
|
||||
const numContextKeys = Object.keys(queryContext).length;
|
||||
useHotkeys(hotkeys);
|
||||
|
||||
return (
|
||||
<Menu>
|
||||
<MenuItem
|
||||
icon={IconNames.HELP}
|
||||
text={runeMode ? 'Native query documentation' : 'DruidSQL documentation'}
|
||||
href={getLink(runeMode ? 'DOCS_RUNE' : 'DOCS_SQL')}
|
||||
target="_blank"
|
||||
return (
|
||||
<ButtonGroup className="run-button">
|
||||
{onRun ? (
|
||||
<Button
|
||||
className={runeMode ? 'rune-button' : undefined}
|
||||
disabled={loading}
|
||||
icon={IconNames.CARET_RIGHT}
|
||||
onClick={handleRun}
|
||||
text="Run"
|
||||
intent={Intent.PRIMARY}
|
||||
/>
|
||||
<MenuItem icon={IconNames.HISTORY} text="Query history" onClick={onHistory} />
|
||||
{!runeMode && onExplain && (
|
||||
<MenuItem icon={IconNames.CLEAN} text="Explain SQL query" onClick={onExplain} />
|
||||
)}
|
||||
{runeMode && (
|
||||
<MenuItem icon={IconNames.ALIGN_LEFT} text="Prettify JSON" onClick={onPrettier} />
|
||||
)}
|
||||
<MenuItem
|
||||
icon={IconNames.PROPERTIES}
|
||||
text="Edit context"
|
||||
onClick={onEditContext}
|
||||
label={numContextKeys ? pluralIfNeeded(numContextKeys, 'key') : undefined}
|
||||
) : (
|
||||
<Button
|
||||
className={runeMode ? 'rune-button' : undefined}
|
||||
icon={IconNames.CARET_RIGHT}
|
||||
text="Run"
|
||||
disabled
|
||||
/>
|
||||
<MenuDivider />
|
||||
{!runeMode && (
|
||||
<>
|
||||
<MenuCheckbox
|
||||
checked={useApproximateCountDistinct}
|
||||
text="Use approximate COUNT(DISTINCT)"
|
||||
onChange={() => {
|
||||
onQueryContextChange(
|
||||
setUseApproximateCountDistinct(queryContext, !useApproximateCountDistinct),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<MenuCheckbox
|
||||
checked={useApproximateTopN}
|
||||
text="Use approximate TopN"
|
||||
onChange={() => {
|
||||
onQueryContextChange(setUseApproximateTopN(queryContext, !useApproximateTopN));
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<MenuCheckbox
|
||||
checked={useCache}
|
||||
text="Use cache"
|
||||
onChange={() => {
|
||||
onQueryContextChange(setUseCache(queryContext, !useCache));
|
||||
}}
|
||||
)}
|
||||
<Popover position={Position.BOTTOM_LEFT} content={<RunButtonExtraMenu {...props} />}>
|
||||
<Button
|
||||
className={runeMode ? 'rune-button' : undefined}
|
||||
icon={IconNames.MORE}
|
||||
intent={onRun ? Intent.PRIMARY : undefined}
|
||||
/>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
const { runeMode, onRun, loading } = this.props;
|
||||
|
||||
return (
|
||||
<ButtonGroup className="run-button">
|
||||
{onRun ? (
|
||||
<Button
|
||||
className={runeMode ? 'rune-button' : undefined}
|
||||
disabled={loading}
|
||||
icon={IconNames.CARET_RIGHT}
|
||||
onClick={this.handleRun}
|
||||
text="Run"
|
||||
intent={Intent.PRIMARY}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
className={runeMode ? 'rune-button' : undefined}
|
||||
icon={IconNames.CARET_RIGHT}
|
||||
text="Run"
|
||||
disabled
|
||||
/>
|
||||
)}
|
||||
<Popover position={Position.BOTTOM_LEFT} content={this.renderExtraMenu()}>
|
||||
<Button
|
||||
className={runeMode ? 'rune-button' : undefined}
|
||||
icon={IconNames.MORE}
|
||||
intent={onRun ? Intent.PRIMARY : undefined}
|
||||
/>
|
||||
</Popover>
|
||||
</ButtonGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
</Popover>
|
||||
</ButtonGroup>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
"rootDirs": ["lib", "src"],
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"target": "es5",
|
||||
"target": "es2016"
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx", "e2e-tests/**/*.ts"]
|
||||
}
|
||||
|
|
|
@ -27,9 +27,49 @@
|
|||
<title>Apache Druid</title>
|
||||
<meta name="description" content="Apache Druid console" />
|
||||
<link rel="shortcut icon" href="favicon.png" />
|
||||
<style>
|
||||
body {
|
||||
background: #24283b;
|
||||
}
|
||||
#browser-update {
|
||||
background-color: #d9822b;
|
||||
border-radius: 3px;
|
||||
color: #ffffff;
|
||||
font-family: sans-serif;
|
||||
font-size: 13px;
|
||||
line-height: 1.2;
|
||||
padding: 13px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
z-index: 11;
|
||||
}
|
||||
#browser-update a {
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bp3-dark mouse-mode">
|
||||
<div class="app-container"></div>
|
||||
<div id="browser-update" style="display: none">
|
||||
You are using an unsupported browser. The console will not work properly.
|
||||
<a href="https://browser-update.org/update.html">Update to a supported browser.</a>
|
||||
</div>
|
||||
<script>
|
||||
function showUpdate() {
|
||||
document.getElementById('browser-update').style.display = 'block';
|
||||
}
|
||||
if (!('Proxy' in window)) showUpdate();
|
||||
window.onerror = function (message, source, lineno, colno, error) {
|
||||
if (error instanceof SyntaxError || message === 'Syntax error') {
|
||||
showUpdate();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
</script>
|
||||
<script src="console-config.js"></script>
|
||||
<script src="public/web-console-0.22.0.js"></script>
|
||||
</body>
|
||||
|
|
|
@ -119,7 +119,6 @@ module.exports = env => {
|
|||
plugins: {
|
||||
'postcss-preset-env': {
|
||||
autoprefixer: { grid: 'no-autoplace' },
|
||||
browsers: ['> 1%', 'last 3 versions', 'Firefox ESR', 'Opera 12.1', 'ie 11'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue