Web-console: fix alerts from lgtm (#8346)

* fix alerts from lgtm

* remove unordered imports

* fix introduced alert

* move getExpanded to renderSchemaSelector

* use getDerivedStateFromProps

* use prevState

* add semi colons, remove unused imports

* fixes
This commit is contained in:
mcbrewster 2019-08-20 21:40:47 -06:00 committed by Clint Wylie
parent c87b68d2a4
commit e4aa7fb268
26 changed files with 225 additions and 201 deletions

View File

@ -28,7 +28,7 @@ This is the unified Druid web console that servers as a data management layer fo
3. Run `npm start` will start in development mode and will proxy druid requests to `localhost:8888`
**Note:** you can provide an environment variable to proxy to a different Druid host like so: `druid_host=1.2.3.4:8888 npm start`
**Note:** you can provide an environment variable use webpack-bundle-analyzer as a plugin in the build script or like so: `BUNDLE_ANALYZER_PLUGIN='TRUE' npm start`
## Description of the directory structure
@ -50,7 +50,6 @@ Generated/copied dynamically
- `pages/` - The files for the older coordinator console
- `coordinator-console/` - Files for the coordinator console
## List of non SQL data reading APIs used
```

View File

@ -29,6 +29,7 @@ PATH="./target/node:$PATH" ./script/create-sql-function-doc.js
echo "Transpiling ReactTable CSS..."
PATH="./target/node:$PATH" ./node_modules/.bin/stylus lib/react-table.styl -o lib/react-table.css
# add BUNDLE_ANALYZER_PLUGIN='TRUE' here to enable webpack-bundle-analyzer as a plugin
echo "Webpacking everything..."
PATH="./target/node:$PATH" NODE_ENV=production ./node_modules/.bin/webpack -c webpack.config.js

View File

@ -60,24 +60,24 @@ function injectConsoleLicenses(consoleLicenses) {
// Write out the new file
fs.writeFileSync(
LICENSES_FILE,
[
beforeLines.join('\n'),
consoleLicenses.join(SEPARATOR),
afterLines.join('\n')
].join('\n')
[beforeLines.join('\n'), consoleLicenses.join(SEPARATOR), afterLines.join('\n')].join('\n'),
);
}
checker.init({
checker.init(
{
start: '.',
production: true
}, function(err, packages) {
production: true,
},
function(err, packages) {
if (err) {
console.log('err', err);
return;
}
const mapped = Object.keys(packages).sort().map(p => {
const mapped = Object.keys(packages)
.sort()
.map(p => {
const m = p.match(/^(.+)@(\d+\.\d+\.\d+.*)$/);
if (!m) throw new Error(`Malformed name@version`);
const name = m[1];
@ -111,7 +111,7 @@ checker.init({
}
const simpleName = name.replace('/', '-');
const licenseDest = `licenses/bin/${simpleName}.${licenseExt}`
const licenseDest = `licenses/bin/${simpleName}.${licenseExt}`;
let hasLicense = false;
if (licenseExt !== 'A2') {
@ -137,7 +137,9 @@ checker.init({
if (!publisher && hasLicense) {
// Extract copyright from license
const licenseText = fs.readFileSync(`../${licenseDest}`, 'utf-8');
const m = licenseText.match(/(?:^|\n)\s*Copyright(?: (?:\(c\)|©))?(?: 2[0-9]{3}(?:-\w+)?,?)? ([^0-9][^\n]*)\n/m);
const m = licenseText.match(
/(?:^|\n)\s*Copyright(?: (?:\(c\)|©))?(?: 2[0-9]{3}(?:-\w+)?,?)? ([^0-9][^\n]*)\n/m,
);
if (m) {
publisher = m[1]
.replace(/All rights reserved./i, '')
@ -148,8 +150,8 @@ checker.init({
if (!publisher) {
// Hand coded copyrights
if (name === 'asap') publisher = 'Contributors'
if (name === 'diff-match-patch') publisher = 'Google'
if (name === 'asap') publisher = 'Contributors';
if (name === 'diff-match-patch') publisher = 'Google';
}
if (!publisher) {
@ -168,8 +170,9 @@ checker.init({
];
return lines.filter(Boolean).join('\n');
}).filter(Boolean);
})
.filter(Boolean);
injectConsoleLicenses(mapped);
});
},
);

View File

@ -105,7 +105,7 @@ export class DatasourceColumnsTable extends React.PureComponent<
return (
<div className="datasource-columns-table">
<div className="main-area">
{loading ? <Loader loadingText="" loading /> : !loading && this.renderTable()}
{loading ? <Loader loadingText="" loading /> : this.renderTable()}
</div>
</div>
);

View File

@ -3,6 +3,7 @@
exports[`external link matches snapshot 1`] = `
<a
href="http://test/"
rel="noopener noreferrer"
target="_blank"
>
<div>

View File

@ -27,7 +27,7 @@ export class ExternalLink extends React.PureComponent<ExternalLinkProps> {
const { href, children } = this.props;
return (
<a href={href} target="_blank">
<a href={href} target="_blank" rel="noopener noreferrer">
{children}
</a>
);

View File

@ -71,7 +71,7 @@ export class ShowHistory extends React.PureComponent<ShowHistoryProps, ShowHisto
render(): JSX.Element | null {
const { downloadFilename, endpoint } = this.props;
const { data, loading } = this.state;
const { data, loading, error } = this.state;
if (loading) return <Loader />;
if (!data) return null;
@ -82,7 +82,9 @@ export class ShowHistory extends React.PureComponent<ShowHistoryProps, ShowHisto
title={pastSupervisor.version}
panel={
<ShowValue
jsonValue={JSON.stringify(pastSupervisor.spec, undefined, 2)}
jsonValue={
pastSupervisor.spec ? JSON.stringify(pastSupervisor.spec, undefined, 2) : error
}
downloadFilename={`version-${pastSupervisor.version}-${downloadFilename}`}
endpoint={endpoint}
/>

View File

@ -60,10 +60,39 @@ exports[`show log describe show log 1`] = `
<div
class="main-area"
>
<textarea
class="bp3-input"
readonly=""
<div
class="loader"
>
<div
class="loader-logo"
>
<svg
viewBox="0 0 100 100"
>
<path
class="one"
d="M54.2,69.8h-2.7c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h2.7c11.5,0,23.8-7.4,23.8-23.7
c0-9.1-6.9-15.8-16.4-15.8H38c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h23.6c5.3,0,10.1,1.9,13.6,5.3c3.5,3.4,5.4,8,5.4,13.1
c0,6.6-2.3,13-6.3,17.7C69.5,66.8,62.5,69.8,54.2,69.8z"
/>
<path
class="two"
d="M55.7,59.5h-26c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h26c7.5,0,11.5-5.8,11.5-11.5
c0-4.2-3.2-7.3-7.7-7.3h-26c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h26c5.9,0,10.3,4.3,10.3,9.9c0,3.7-1.3,7.2-3.7,9.8
C63.5,58,59.9,59.5,55.7,59.5z"
/>
<path
class="three"
d="M27.2,38h-6.3c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h6.3c0.7,0,1.3,0.6,1.3,1.3S27.9,38,27.2,38z"
/>
<path
class="four"
d="M45.1,69.8h-5.8c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h5.8c0.7,0,1.3,0.6,1.3,1.3
C46.4,69.2,45.8,69.8,45.1,69.8z"
/>
</svg>
</div>
</div>
</div>
</div>
`;

View File

@ -21,6 +21,7 @@ import axios from 'axios';
import copy from 'copy-to-clipboard';
import React from 'react';
import { Loader } from '../../components';
import { AppToaster } from '../../singletons/toaster';
import { UrlBaser } from '../../singletons/url-baser';
import { QueryManager } from '../../utils';
@ -109,7 +110,7 @@ export class ShowLog extends React.PureComponent<ShowLogProps, ShowLogState> {
render(): JSX.Element {
const { endpoint, downloadFilename, status } = this.props;
const { logValue, error } = this.state;
const { logValue, error, loading } = this.state;
return (
<div className="show-log">
@ -144,12 +145,16 @@ export class ShowLog extends React.PureComponent<ShowLogProps, ShowLogState> {
</ButtonGroup>
</div>
<div className="main-area">
{loading ? (
<Loader loadingText="" loading />
) : (
<textarea
className="bp3-input"
readOnly
value={logValue ? logValue : error}
ref={this.log}
/>
)}
</div>
</div>
);

View File

@ -170,7 +170,7 @@ export class SupervisorStatisticsTable extends React.PureComponent<
</ButtonGroup>
</div>
<div className="main-area">
{loading ? <Loader loadingText="" loading /> : !loading && this.renderTable(error)}
{loading ? <Loader loadingText="" loading /> : this.renderTable(error)}
</div>
</div>
);

View File

@ -48,7 +48,6 @@ export interface ConsoleApplicationProps {
}
export interface ConsoleApplicationState {
aboutDialogOpen: boolean;
noSqlMode: boolean;
capabilitiesLoading: boolean;
}
@ -124,7 +123,6 @@ export class ConsoleApplication extends React.PureComponent<
constructor(props: ConsoleApplicationProps, context: any) {
super(props, context);
this.state = {
aboutDialogOpen: false,
noSqlMode: false,
capabilitiesLoading: true,
};

View File

@ -84,6 +84,7 @@ exports[`about dialog matches snapshot 1`] = `
<a
href="https://druid.apache.org/community/"
rel="noopener noreferrer"
target="_blank"
>
community page
@ -92,6 +93,7 @@ exports[`about dialog matches snapshot 1`] = `
<a
href="https://groups.google.com/forum/#!forum/druid-user"
rel="noopener noreferrer"
target="_blank"
>
user groups
@ -103,6 +105,7 @@ exports[`about dialog matches snapshot 1`] = `
<a
href="https://lists.apache.org/list.html?dev@druid.apache.org"
rel="noopener noreferrer"
target="_blank"
>
developer group

View File

@ -60,6 +60,7 @@ exports[`coordinator dynamic config matches snapshot 1`] = `
<a
href="https://druid.apache.org/docs/latest/configuration/index.html#dynamic-configuration"
rel="noopener noreferrer"
target="_blank"
>
documentation

View File

@ -20,9 +20,7 @@ import { IDialogProps } from '@blueprintjs/core';
import React from 'react';
import { DatasourceColumnsTable } from '../../components/datasource-columns-table/datasource-columns-table';
import { queryDruidSql, QueryManager } from '../../utils';
import { BasicAction } from '../../utils/basic-action';
import { ColumnMetadata } from '../../utils/column-metadata';
import { SideButtonMetaData, TableActionDialog } from '../table-action-dialog/table-action-dialog';
interface DatasourceTableActionDialogProps extends IDialogProps {
@ -33,40 +31,17 @@ interface DatasourceTableActionDialogProps extends IDialogProps {
interface DatasourceTableActionDialogState {
activeTab: 'columns';
dimensions?: string;
error?: string;
}
export class DatasourceTableActionDialog extends React.PureComponent<
DatasourceTableActionDialogProps,
DatasourceTableActionDialogState
> {
private dimensionsQueryManager: QueryManager<null, string>;
constructor(props: DatasourceTableActionDialogProps) {
super(props);
this.state = {
activeTab: 'columns',
};
/// This should be a table
this.dimensionsQueryManager = new QueryManager({
processQuery: async () => {
const { datasourceId } = this.props;
const resp = await queryDruidSql<ColumnMetadata>({
query: `SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'druid' AND TABLE_NAME = '${datasourceId}'`,
});
const dimensionArray = resp.map(object => object.COLUMN_NAME);
return JSON.stringify(dimensionArray, undefined, 2);
},
onStateChange: ({ result, error }) => {
this.setState({ dimensions: result, error });
},
});
}
componentDidMount(): void {
this.dimensionsQueryManager.runQuery(null);
}
render(): React.ReactNode {

View File

@ -60,6 +60,7 @@ exports[`overload dynamic config matches snapshot 1`] = `
<a
href="https://druid.apache.org/docs/latest/configuration/index.html#overlord-dynamic-configuration"
rel="noopener noreferrer"
target="_blank"
>
documentation

View File

@ -306,13 +306,13 @@ GROUP BY 1`;
this.datasourceQueryManager.rerunLastQuery(auto);
// this looks ugly, but it forces the chart to re-render when refresh is clicked
this.setState(
{
showChart: !this.state.showChart,
},
() =>
this.setState({
showChart: !this.state.showChart,
prevState => ({
showChart: !prevState.showChart,
}),
() =>
this.setState(prevState => ({
showChart: !prevState.showChart,
})),
);
};
@ -989,7 +989,11 @@ GROUP BY 1`;
/>
<TableColumnSelector
columns={noSqlMode ? tableColumnsNoSql : tableColumns}
onChange={column => this.setState({ hiddenColumns: hiddenColumns.toggle(column) })}
onChange={column =>
this.setState(prevState => ({
hiddenColumns: prevState.hiddenColumns.toggle(column),
}))
}
tableColumnsHidden={hiddenColumns.storedArray}
/>
</ViewControlBar>

View File

@ -266,7 +266,6 @@ export interface LoadDataViewState {
parserQueryState: QueryState<HeaderAndRows>;
// for flatten
flattenQueryState: QueryState<HeaderAndRows>;
selectedFlattenFieldIndex: number;
selectedFlattenField?: FlattenField;
@ -328,7 +327,6 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
parserQueryState: QueryState.INIT,
// for flatten
flattenQueryState: QueryState.INIT,
selectedFlattenFieldIndex: -1,
// for timestamp

View File

@ -138,21 +138,21 @@ export class LookupsView extends React.PureComponent<LookupsViewProps, LookupsVi
}
private async openLookupEditDialog(tier: string, id: string) {
const { lookups, allLookupTiers } = this.state;
const { lookups } = this.state;
if (!lookups) return;
const target: any = lookups.find((lookupEntry: any) => {
return lookupEntry.tier === tier && lookupEntry.id === id;
});
if (id === '') {
this.setState({
this.setState(prevState => ({
lookupEditName: '',
lookupEditTier: allLookupTiers[0],
lookupEditTier: prevState.allLookupTiers[0],
lookupEditDialogOpen: true,
lookupEditSpec: '',
lookupEditVersion: new Date().toISOString(),
isEdit: false,
});
}));
} else {
this.setState({
lookupEditName: id,

View File

@ -143,8 +143,8 @@ export interface ColumnTreeProps {
export interface ColumnTreeState {
prevColumnMetadata?: readonly ColumnMetadata[];
prevGroupByStatus?: boolean;
columnTree?: ITreeNode[];
currentSchemaSubtree?: ITreeNode[];
selectedTreeIndex: number;
expandedNode: number;
}
@ -317,12 +317,21 @@ export class ColumnTree extends React.PureComponent<ColumnTreeProps, ColumnTreeS
}
}
if (!columnTree) return null;
const currentSchemaSubtree =
columnTree[selectedTreeIndex > -1 ? selectedTreeIndex : 0].childNodes;
if (!currentSchemaSubtree) return null;
if (expandedNode > -1) {
currentSchemaSubtree[expandedNode].isExpanded = true;
}
return {
prevColumnMetadata: columnMetadata,
columnTree,
selectedTreeIndex,
expandedNode,
prevGroupByStatus: props.hasGroupBy,
currentSchemaSubtree,
};
}
return null;
@ -377,6 +386,8 @@ export class ColumnTree extends React.PureComponent<ColumnTreeProps, ColumnTreeS
render(): JSX.Element | null {
const { columnMetadataLoading } = this.props;
const { currentSchemaSubtree } = this.state;
if (columnMetadataLoading) {
return (
<div className="column-tree">
@ -385,15 +396,8 @@ export class ColumnTree extends React.PureComponent<ColumnTreeProps, ColumnTreeS
);
}
const { columnTree, selectedTreeIndex, expandedNode } = this.state;
if (!columnTree) return null;
const currentSchemaSubtree =
columnTree[selectedTreeIndex > -1 ? selectedTreeIndex : 0].childNodes;
if (!currentSchemaSubtree) return null;
if (expandedNode > -1) {
currentSchemaSubtree[expandedNode].isExpanded = true;
}
return (
<div className="column-tree">
{this.renderSchemaSelector()}
@ -423,6 +427,8 @@ export class ColumnTree extends React.PureComponent<ColumnTreeProps, ColumnTreeS
bounceState() {
const { columnTree } = this.state;
if (!columnTree) return;
this.setState({ columnTree: columnTree.slice() });
this.setState(prevState => ({
columnTree: prevState.columnTree ? prevState.columnTree.slice() : undefined,
}));
}
}

View File

@ -617,11 +617,9 @@ export class QueryView extends React.PureComponent<QueryViewProps, QueryViewStat
if (!queryAst) return;
let modifiedAst: SqlQuery = queryAst;
if (queryAst) {
for (const filter of filters) {
modifiedAst = modifiedAst.filterRow(filter.header, filter.row, filter.operator);
}
}
this.handleQueryStringChange(modifiedAst.toString(), preferablyRun);
};

View File

@ -61,9 +61,6 @@ export interface RunButtonProps {
export class RunButton extends React.PureComponent<RunButtonProps> {
constructor(props: RunButtonProps, context: any) {
super(props, context);
this.state = {
wrapQuery: true,
};
}
public renderHotkeys() {

View File

@ -97,7 +97,6 @@ export interface SegmentsViewState {
terminateSegmentId?: string;
terminateDatasourceId?: string;
hiddenColumns: LocalStorageBackedArray<string>;
loaded: boolean;
groupByInterval: boolean;
// table state
@ -157,7 +156,6 @@ export class SegmentsView extends React.PureComponent<SegmentsViewProps, Segment
hiddenColumns: new LocalStorageBackedArray<string>(
LocalStorageKeys.SEGMENT_TABLE_COLUMN_SELECTION,
),
loaded: false,
groupByInterval: false,
// Table state
@ -696,7 +694,11 @@ export class SegmentsView extends React.PureComponent<SegmentsViewProps, Segment
{this.renderBulkSegmentsActions()}
<TableColumnSelector
columns={noSqlMode ? tableColumnsNoSql : tableColumns}
onChange={column => this.setState({ hiddenColumns: hiddenColumns.toggle(column) })}
onChange={column =>
this.setState(prevState => ({
hiddenColumns: prevState.hiddenColumns.toggle(column),
}))
}
tableColumnsHidden={hiddenColumns.storedArray}
/>
</ViewControlBar>

View File

@ -677,7 +677,11 @@ ORDER BY "rank" DESC, "server" DESC`;
{this.renderBulkServersActions()}
<TableColumnSelector
columns={serverTableColumns}
onChange={column => this.setState({ hiddenColumns: hiddenColumns.toggle(column) })}
onChange={column =>
this.setState(prevState => ({
hiddenColumns: prevState.hiddenColumns.toggle(column),
}))
}
tableColumnsHidden={hiddenColumns.storedArray}
/>
</ViewControlBar>

View File

@ -1106,7 +1106,9 @@ ORDER BY "rank" DESC, "created_time" DESC`;
<TableColumnSelector
columns={supervisorTableColumns}
onChange={column =>
this.setState({ hiddenSupervisorColumns: hiddenSupervisorColumns.toggle(column) })
this.setState(prevState => ({
hiddenSupervisorColumns: prevState.hiddenSupervisorColumns.toggle(column),
}))
}
tableColumnsHidden={hiddenSupervisorColumns.storedArray}
/>
@ -1153,7 +1155,9 @@ ORDER BY "rank" DESC, "created_time" DESC`;
<TableColumnSelector
columns={taskTableColumns}
onChange={column =>
this.setState({ hiddenTaskColumns: hiddenTaskColumns.toggle(column) })
this.setState(prevState => ({
hiddenTaskColumns: prevState.hiddenTaskColumns.toggle(column),
}))
}
tableColumnsHidden={hiddenTaskColumns.storedArray}
/>

View File

@ -57,21 +57,16 @@ export interface HoveredBarInfo {
}
export class StackedBarChart extends React.Component<StackedBarChartProps, StackedBarChartState> {
constructor(props: StackedBarChartProps) {
super(props);
this.state = {
width: this.props.svgWidth - this.props.margin.left - this.props.margin.right,
height: this.props.svgHeight - this.props.margin.bottom - this.props.margin.top,
static getDerivedStateFromProps(props: StackedBarChartProps) {
const width = props.svgWidth - props.margin.left - props.margin.right;
const height = props.svgHeight - props.margin.bottom - props.margin.top;
return {
width,
height,
};
}
componentWillReceiveProps(nextProps: StackedBarChartProps): void {
if (nextProps !== this.props) {
this.setState({
width: nextProps.svgWidth - this.props.margin.left - this.props.margin.right,
height: nextProps.svgHeight - this.props.margin.bottom - this.props.margin.top,
});
}
constructor(props: StackedBarChartProps) {
super(props);
}
renderBarChart() {

View File

@ -97,10 +97,10 @@ module.exports = env => {
],
},
{
test: (ALWAYS_BABEL || mode === 'production') ? /\.m?js$/ : /^xxx$/,
test: ALWAYS_BABEL || mode === 'production' ? /\.m?js$/ : /^xxx$/,
use: {
loader: 'babel-loader'
}
loader: 'babel-loader',
},
},
{
test: /\.s?css$/,
@ -124,10 +124,8 @@ module.exports = env => {
],
},
performance: {
hints: false
hints: false,
},
plugins: [
// new BundleAnalyzerPlugin()
],
plugins: process.env.BUNDLE_ANALYZER_PLUGIN === 'TRUE' ? [new BundleAnalyzerPlugin()] : [],
};
};