mirror of https://github.com/apache/druid.git
Added tslint to web console (#7280)
* added tslint to web console * added react linting and made rules stricter * order imports * update package-lock
This commit is contained in:
parent
1b6b40e511
commit
b6b1e6160c
|
@ -944,6 +944,65 @@
|
|||
"is-buffer": "^1.1.5"
|
||||
}
|
||||
},
|
||||
"babel-code-frame": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
||||
"integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^1.1.3",
|
||||
"esutils": "^2.0.2",
|
||||
"js-tokens": "^3.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
|
||||
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^2.2.1",
|
||||
"escape-string-regexp": "^1.0.2",
|
||||
"has-ansi": "^2.0.0",
|
||||
"strip-ansi": "^3.0.0",
|
||||
"supports-color": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
|
||||
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
|
||||
"dev": true
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
|
||||
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-jest": {
|
||||
"version": "24.1.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.1.0.tgz",
|
||||
|
@ -1372,6 +1431,12 @@
|
|||
"integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
|
||||
"dev": true
|
||||
},
|
||||
"builtin-modules": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
|
||||
"integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
|
||||
"dev": true
|
||||
},
|
||||
"builtin-status-codes": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
|
||||
|
@ -9636,6 +9701,58 @@
|
|||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
|
||||
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ=="
|
||||
},
|
||||
"tslint": {
|
||||
"version": "5.14.0",
|
||||
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.14.0.tgz",
|
||||
"integrity": "sha512-IUla/ieHVnB8Le7LdQFRGlVJid2T/gaJe5VkjzRVSRR6pA2ODYrnfR1hmxi+5+au9l50jBwpbBL34txgv4NnTQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-code-frame": "^6.22.0",
|
||||
"builtin-modules": "^1.1.1",
|
||||
"chalk": "^2.3.0",
|
||||
"commander": "^2.12.1",
|
||||
"diff": "^3.2.0",
|
||||
"glob": "^7.1.1",
|
||||
"js-yaml": "^3.7.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"mkdirp": "^0.5.1",
|
||||
"resolve": "^1.3.2",
|
||||
"semver": "^5.3.0",
|
||||
"tslib": "^1.8.0",
|
||||
"tsutils": "^2.29.0"
|
||||
}
|
||||
},
|
||||
"tslint-loader": {
|
||||
"version": "3.5.4",
|
||||
"resolved": "https://registry.npmjs.org/tslint-loader/-/tslint-loader-3.5.4.tgz",
|
||||
"integrity": "sha512-jBHNNppXut6SgZ7CsTBh+6oMwVum9n8azbmcYSeMlsABhWWoHwjq631vIFXef3VSd75cCdX3rc6kstsB7rSVVw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loader-utils": "^1.0.2",
|
||||
"mkdirp": "^0.5.1",
|
||||
"object-assign": "^4.1.1",
|
||||
"rimraf": "^2.4.4",
|
||||
"semver": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"tslint-react": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tslint-react/-/tslint-react-3.6.0.tgz",
|
||||
"integrity": "sha512-AIv1QcsSnj7e9pFir6cJ6vIncTqxfqeFF3Lzh8SuuBljueYzEAtByuB6zMaD27BL0xhMEqsZ9s5eHuCONydjBw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tsutils": "^2.13.1"
|
||||
}
|
||||
},
|
||||
"tsutils": {
|
||||
"version": "2.29.0",
|
||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
|
||||
"integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^1.8.1"
|
||||
}
|
||||
},
|
||||
"tty-browserify": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
|
||||
|
|
|
@ -70,6 +70,9 @@
|
|||
"ts-jest": "^23.10.5",
|
||||
"ts-loader": "^5.3.3",
|
||||
"ts-node": "^8.0.2",
|
||||
"tslint": "^5.14.0",
|
||||
"tslint-loader": "^3.5.4",
|
||||
"tslint-react": "^3.6.0",
|
||||
"typescript": "^3.2.4",
|
||||
"webpack": "^4.29.0",
|
||||
"webpack-cli": "^3.2.1",
|
||||
|
|
|
@ -21,8 +21,35 @@ writefile='lib/sql-function-doc.ts'
|
|||
|
||||
> "$writefile"
|
||||
|
||||
echo -e "// This file is auto generated and should not be modified\n" > "$writefile"
|
||||
echo -e 'export const SQLFunctionDoc: any[] = [' >> "$writefile"
|
||||
cat > "$writefile" <<- EOM
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// This file is auto generated and should not be modified
|
||||
|
||||
export interface FunctionDescription {
|
||||
syntax: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
/* tslint:disable */
|
||||
export const SQLFunctionDoc: FunctionDescription[] = [
|
||||
EOM
|
||||
|
||||
isFunction=false
|
||||
|
||||
|
@ -39,12 +66,12 @@ while read -r line; do
|
|||
description=$(echo $line | grep -o '`|.*.|')
|
||||
description=${description//\"/\'}
|
||||
description=${description:2:${#description}-4}
|
||||
echo -e " {" >> "$writefile"
|
||||
echo -e " syntax: \"$syntax\"," >> "$writefile"
|
||||
echo -e " description: \"$description\"" >> "$writefile"
|
||||
echo -e " }," >> "$writefile"
|
||||
echo -e " {" >> "$writefile"
|
||||
echo -e " syntax: \"$syntax\"," >> "$writefile"
|
||||
echo -e " description: \"$description\"" >> "$writefile"
|
||||
echo -e " }," >> "$writefile"
|
||||
fi
|
||||
fi
|
||||
done < "$readfile"
|
||||
|
||||
echo -e ']' >> "$writefile"
|
||||
echo -e '];' >> "$writefile"
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Trick blueprint 1.0.1 into accepting React 16 as React 15.
|
||||
// This is broken into its own file to make linting and import sorting easy
|
||||
// This file "a" to make sure it is imported before console-application in entry.ts
|
||||
|
||||
// tslint:disable
|
||||
import * as React from 'react';
|
||||
(React as any).PropTypes = require('prop-types');
|
|
@ -16,10 +16,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
import { Button } from "@blueprintjs/core";
|
||||
import * as React from 'react';
|
||||
import { Filter, ReactTableDefaults } from "react-table";
|
||||
import { Button } from "@blueprintjs/core";
|
||||
|
||||
import { Loader } from '../components/loader';
|
||||
import { countBy, makeTextFilter } from '../utils';
|
||||
|
|
@ -16,11 +16,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { resolveSrv } from 'dns';
|
||||
import * as React from 'react';
|
||||
import axios from 'axios';
|
||||
import { InputGroup } from "@blueprintjs/core";
|
||||
import { HTMLSelect, FormGroup, NumericInput, TagInput } from "../components/filler";
|
||||
import * as React from 'react';
|
||||
|
||||
import { FormGroup, HTMLSelect, NumericInput, TagInput } from "../components/filler";
|
||||
|
||||
interface Field {
|
||||
name: string;
|
||||
|
@ -31,8 +30,8 @@ interface Field {
|
|||
|
||||
export interface AutoFormProps<T> extends React.Props<any> {
|
||||
fields: Field[];
|
||||
model: T | null,
|
||||
onChange: (newValue: T) => void
|
||||
model: T | null;
|
||||
onChange: (newValue: T) => void;
|
||||
}
|
||||
|
||||
export interface AutoFormState<T> {
|
||||
|
@ -48,7 +47,7 @@ export class AutoForm<T> extends React.Component<AutoFormProps<T>, AutoFormState
|
|||
constructor(props: AutoFormProps<T>) {
|
||||
super(props);
|
||||
this.state = {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private renderNumberInput(field: Field): JSX.Element {
|
||||
|
@ -97,7 +96,7 @@ export class AutoForm<T> extends React.Component<AutoFormProps<T>, AutoFormState
|
|||
>
|
||||
<option value="True">True</option>
|
||||
<option value="False">False</option>
|
||||
</HTMLSelect>
|
||||
</HTMLSelect>;
|
||||
}
|
||||
|
||||
private renderStringArrayInput(field: Field): JSX.Element {
|
||||
|
@ -127,7 +126,7 @@ export class AutoForm<T> extends React.Component<AutoFormProps<T>, AutoFormState
|
|||
const label = field.label || AutoForm.makeLabelName(field.name);
|
||||
return <FormGroup label={label} key={field.name}>
|
||||
{this.renderFieldInput(field)}
|
||||
</FormGroup>
|
||||
</FormGroup>;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -135,6 +134,6 @@ export class AutoForm<T> extends React.Component<AutoFormProps<T>, AutoFormState
|
|||
|
||||
return <div className="auto-form">
|
||||
{model && fields.map(field => this.renderField(field))}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
*/
|
||||
|
||||
import { Button } from '@blueprintjs/core';
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import './filler.scss';
|
||||
import * as React from 'react';
|
||||
|
||||
import './filler.scss';
|
||||
|
||||
export const IconNames = {
|
||||
ERROR: "error" as "error",
|
||||
|
@ -103,16 +103,15 @@ export class FormGroup extends React.Component<{ className?: string, label?: str
|
|||
render() {
|
||||
const { className, label, children } = this.props;
|
||||
return <div className={classNames("form-group", className)}>
|
||||
{ label ? <Label>{label}</Label> : null }
|
||||
{label ? <Label>{label}</Label> : null}
|
||||
{children}
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const Alignment = {
|
||||
LEFT: "left" as "left",
|
||||
RIGHT: "right" as "right",
|
||||
RIGHT: "right" as "right"
|
||||
};
|
||||
export type Alignment = typeof Alignment[keyof typeof Alignment];
|
||||
|
||||
|
@ -166,7 +165,7 @@ export interface NumericInputProps {
|
|||
min?: number;
|
||||
max?: number;
|
||||
stepSize?: number;
|
||||
majorStepSize?: number
|
||||
majorStepSize?: number;
|
||||
}
|
||||
|
||||
export class NumericInput extends React.Component<NumericInputProps, { stringValue: string }> {
|
||||
|
@ -174,20 +173,20 @@ export class NumericInput extends React.Component<NumericInputProps, { stringVal
|
|||
static defaultProps = {
|
||||
stepSize: 1,
|
||||
majorStepSize: 10
|
||||
}
|
||||
};
|
||||
|
||||
constructor(props: NumericInputProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
stringValue: typeof props.value === 'number' ? String(props.value) : ''
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private constrain(n: number): number {
|
||||
const { min, max } = this.props;
|
||||
if (typeof min === 'number') n = Math.max(n, min);
|
||||
if (typeof max === 'number') n = Math.min(n, max);
|
||||
return n
|
||||
return n;
|
||||
}
|
||||
|
||||
private handleChange = (e: any) => {
|
||||
|
@ -236,13 +235,13 @@ export class TagInput extends React.Component<TagInputProps, { stringValue: stri
|
|||
super(props);
|
||||
this.state = {
|
||||
stringValue: Array.isArray(props.values) ? props.values.join(', ') : ''
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
handleChange = (e: any) => {
|
||||
let stringValue = e.target.value;
|
||||
let newValues = stringValue.split(',').map((v: string) => v.trim());
|
||||
let newValuesFiltered = newValues.filter(Boolean);
|
||||
const stringValue = e.target.value;
|
||||
const newValues = stringValue.split(',').map((v: string) => v.trim());
|
||||
const newValuesFiltered = newValues.filter(Boolean);
|
||||
this.setState({
|
||||
stringValue: newValues.length === newValuesFiltered.length ? newValues.join(', ') : stringValue
|
||||
});
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import { AnchorButton, Button, Classes, Menu, MenuItem, Popover, Position } from "@blueprintjs/core";
|
||||
import classNames from 'classnames';
|
||||
import { Button, Classes, AnchorButton, Popover, Position, Menu, MenuItem } from "@blueprintjs/core";
|
||||
import { IconNames, NavbarGroup, Alignment, NavbarDivider, Navbar } from "../components/filler";
|
||||
import * as React from 'react';
|
||||
|
||||
import { Alignment, IconNames, Navbar, NavbarDivider, NavbarGroup } from "../components/filler";
|
||||
import { AboutDialog } from "../dialogs/about-dialog";
|
||||
import { CoordinatorDynamicConfigDialog } from '../dialogs/coordinator-dynamic-config';
|
||||
import "./header-bar.scss";
|
||||
import {
|
||||
DRUID_DOCS,
|
||||
DRUID_GITHUB,
|
||||
|
@ -31,6 +31,8 @@ import {
|
|||
LEGACY_OVERLORD_CONSOLE
|
||||
} from '../variables';
|
||||
|
||||
import "./header-bar.scss";
|
||||
|
||||
export type HeaderActiveTab = null | 'datasources' | 'segments' | 'tasks' | 'servers' | 'sql' | 'lookups';
|
||||
|
||||
export interface HeaderBarProps extends React.Props<any> {
|
||||
|
@ -54,30 +56,48 @@ export class HeaderBar extends React.Component<HeaderBarProps, HeaderBarState> {
|
|||
renderLogo() {
|
||||
return <div className="logo">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 288 134">
|
||||
<path fill="#FFFFFF" d="M136.7,67.5c0.5-6.1,5-10.4,10.6-10.4c3.9,0,6.5,2,7.4,4.3l1.1-12.4c0-0.1,0.3-0.2,0.7-0.2
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M136.7,67.5c0.5-6.1,5-10.4,10.6-10.4c3.9,0,6.5,2,7.4,4.3l1.1-12.4c0-0.1,0.3-0.2,0.7-0.2
|
||||
c0.7,0,1.3,0.4,1.2,2l-2.3,25.9c-0.1,0.7-0.5,1-1,1h-0.2c-0.6,0-0.9-0.3-0.8-1l0.3-3.2c-1.7,2.7-4.5,4.5-8.3,4.5
|
||||
C139.9,77.9,136.2,73.7,136.7,67.5z M154,68.9l0.4-4.7c-0.9-3.3-3.3-5.4-7.2-5.4c-4.5,0-8.1,3.6-8.5,8.6
|
||||
c-0.4,5.1,2.5,8.7,6.9,8.7C150,76.1,153.7,72.9,154,68.9z"/>
|
||||
<path fill="#FFFFFF" d="M161.2,76.6l1.7-19.1c0,0,0.3-0.2,0.7-0.2c0.7,0,1.3,0.4,1.1,2l-0.2,2.5c1.1-3.3,3.3-4.8,6-4.8
|
||||
c-0.4,5.1,2.5,8.7,6.9,8.7C150,76.1,153.7,72.9,154,68.9z"
|
||||
/>
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M161.2,76.6l1.7-19.1c0,0,0.3-0.2,0.7-0.2c0.7,0,1.3,0.4,1.1,2l-0.2,2.5c1.1-3.3,3.3-4.8,6-4.8
|
||||
c1.6,0,2.7,0.7,2.6,1.7c-0.1,0.8-0.6,1.1-0.7,1.1c-0.5-0.5-1.3-0.8-2.3-0.8c-3.6,0-5.6,3.6-6.1,9l-0.8,8.7c-0.1,0.7-0.5,1-1,1
|
||||
h-0.2C161.5,77.6,161.2,77.4,161.2,76.6z"/>
|
||||
<path fill="#FFFFFF" d="M175.6,69l0.9-10.7c0.1-0.8,0.5-1,1-1h0.3c0.5,0,0.9,0.2,0.8,1l-0.9,10.5c-0.4,4.4,1.5,7.2,5.5,7.2
|
||||
h-0.2C161.5,77.6,161.2,77.4,161.2,76.6z"
|
||||
/>
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M175.6,69l0.9-10.7c0.1-0.8,0.5-1,1-1h0.3c0.5,0,0.9,0.2,0.8,1l-0.9,10.5c-0.4,4.4,1.5,7.2,5.5,7.2
|
||||
c3.3,0,6-1.9,7.5-4.7l1.1-13c0.1-0.8,0.5-1,1-1h0.3c0.5,0,0.9,0.2,0.8,1l-1.7,19.1c0,0-0.4,0.2-0.7,0.2c-0.7,0-1.2-0.4-1.1-2
|
||||
l0.2-1.8c-1.6,2.4-4.2,4.1-7.6,4.1C177.6,77.9,175.2,74.4,175.6,69z"/>
|
||||
<path fill="#FFFFFF" d="M200.1,50.7c0.1-1,0.6-1.4,1.6-1.4c0.9,0,1.4,0.5,1.3,1.4c-0.1,0.9-0.6,1.4-1.6,1.4
|
||||
l0.2-1.8c-1.6,2.4-4.2,4.1-7.6,4.1C177.6,77.9,175.2,74.4,175.6,69z"
|
||||
/>
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M200.1,50.7c0.1-1,0.6-1.4,1.6-1.4c0.9,0,1.4,0.5,1.3,1.4c-0.1,0.9-0.6,1.4-1.6,1.4
|
||||
C200.5,52.1,200,51.6,200.1,50.7z M198.2,76.6l1.6-18.3c0.1-0.8,0.5-1,1-1h0.3c0.5,0,0.9,0.2,0.8,1l-1.6,18.3
|
||||
c-0.1,0.8-0.5,1-1,1H199C198.5,77.6,198.2,77.4,198.2,76.6z"/>
|
||||
<path fill="#FFFFFF" d="M205.8,67.5c0.5-6.1,5-10.4,10.6-10.4c3.9,0,6.5,2,7.4,4.3l1.1-12.4c0-0.1,0.3-0.2,0.7-0.2
|
||||
c-0.1,0.8-0.5,1-1,1H199C198.5,77.6,198.2,77.4,198.2,76.6z"
|
||||
/>
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M205.8,67.5c0.5-6.1,5-10.4,10.6-10.4c3.9,0,6.5,2,7.4,4.3l1.1-12.4c0-0.1,0.3-0.2,0.7-0.2
|
||||
c0.7,0,1.3,0.4,1.2,2l-2.3,25.9c-0.1,0.7-0.5,1-1,1h-0.2c-0.5,0-0.9-0.3-0.8-1l0.3-3.2c-1.7,2.7-4.5,4.5-8.3,4.5
|
||||
C209,77.9,205.2,73.7,205.8,67.5z M223.1,68.9l0.4-4.7c-0.9-3.3-3.3-5.4-7.2-5.4c-4.5,0-8.1,3.6-8.5,8.6
|
||||
c-0.4,5.1,2.5,8.7,6.9,8.7C219,76.1,222.7,72.9,223.1,68.9z"/>
|
||||
<path fill="#2CEEFB" d="M96.2,89.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
|
||||
c-0.4,5.1,2.5,8.7,6.9,8.7C219,76.1,222.7,72.9,223.1,68.9z"
|
||||
/>
|
||||
<path
|
||||
fill="#2CEEFB"
|
||||
d="M96.2,89.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.8H80c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h23.6c5.3,0,10.1,1.9,13.6,5.3
|
||||
c3.5,3.4,5.4,8,5.4,13.1c0,6.6-2.3,13-6.3,17.7C111.5,86.8,104.5,89.8,96.2,89.8z M87.1,89.8h-5.8c-0.7,0-1.3-0.6-1.3-1.3
|
||||
c0-0.7,0.6-1.3,1.3-1.3h5.8c0.7,0,1.3,0.6,1.3,1.3C88.4,89.2,87.8,89.8,87.1,89.8z M97.7,79.5h-26c-0.7,0-1.3-0.6-1.3-1.3
|
||||
c0-0.7,0.6-1.3,1.3-1.3h26c7.5,0,11.5-5.8,11.5-11.5c0-4.2-3.2-7.3-7.7-7.3h-26c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3
|
||||
h26c5.9,0,10.3,4.3,10.3,9.9c0,3.7-1.3,7.2-3.7,9.8C105.5,78,101.9,79.5,97.7,79.5z M69.2,58h-6.3c-0.7,0-1.3-0.6-1.3-1.3
|
||||
c0-0.7,0.6-1.3,1.3-1.3h6.3c0.7,0,1.3,0.6,1.3,1.3C70.5,57.4,69.9,58,69.2,58z"/>
|
||||
c0-0.7,0.6-1.3,1.3-1.3h6.3c0.7,0,1.3,0.6,1.3,1.3C70.5,57.4,69.9,58,69.2,58z"
|
||||
/>
|
||||
</svg>
|
||||
</div>;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
import './loader.scss';
|
||||
|
||||
export interface LoaderProps extends React.Props<any> {
|
||||
|
@ -31,23 +32,35 @@ export class Loader extends React.Component<LoaderProps, LoaderState> {
|
|||
|
||||
render() {
|
||||
const { loadingText, loading } = this.props;
|
||||
if (loading === false) return null;
|
||||
if (!loading) return null;
|
||||
|
||||
return <div className="loader">
|
||||
<div className="loader-logo">
|
||||
<svg viewBox="0 0 100 100">
|
||||
<path className="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
|
||||
<path
|
||||
className="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 className="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,6.6-2.3,13-6.3,17.7C69.5,66.8,62.5,69.8,54.2,69.8z"
|
||||
/>
|
||||
<path
|
||||
className="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 className="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 className="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"/>
|
||||
C63.5,58,59.9,59.5,55.7,59.5z"
|
||||
/>
|
||||
<path
|
||||
className="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
|
||||
className="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>
|
||||
{loadingText ? <div className="label">{loadingText}</div> : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,10 +16,12 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import { Button, Collapse, InputGroup } from "@blueprintjs/core";
|
||||
import axios from 'axios';
|
||||
import { Button, InputGroup, Collapse } from "@blueprintjs/core";
|
||||
import { IconNames, FormGroup, HTMLSelect, Card, ControlGroup, NumericInput, TagInput } from "../components/filler";
|
||||
import * as React from 'react';
|
||||
|
||||
import { Card, ControlGroup, FormGroup, HTMLSelect, IconNames, NumericInput, TagInput } from "../components/filler";
|
||||
|
||||
import './rule-editor.scss';
|
||||
|
||||
export interface Rule {
|
||||
|
@ -107,7 +109,7 @@ export class RuleEditor extends React.Component<RuleEditorProps, RuleEditorState
|
|||
super(props);
|
||||
this.state = {
|
||||
isOpen: true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private removeTier = (key: string) => {
|
||||
|
@ -126,9 +128,9 @@ export class RuleEditor extends React.Component<RuleEditorProps, RuleEditorState
|
|||
let newTierName = tiers[0];
|
||||
|
||||
if (rule.tieredReplicants) {
|
||||
for (let i = 0; i < tiers.length; i++) {
|
||||
if (rule.tieredReplicants[tiers[i]] === undefined) {
|
||||
newTierName = tiers[i];
|
||||
for (const tier of tiers) {
|
||||
if (rule.tieredReplicants[tier] === undefined) {
|
||||
newTierName = tier;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -160,7 +162,7 @@ export class RuleEditor extends React.Component<RuleEditorProps, RuleEditorState
|
|||
/>
|
||||
<Button className="pt-minimal" style={{pointerEvents: 'none'}}>Tier:</Button>
|
||||
<HTMLSelect
|
||||
fill={true}
|
||||
fill
|
||||
value={tier}
|
||||
onChange={(e: any) => onChange(RuleEditor.changeTier(rule, tier, e.target.value))}
|
||||
>
|
||||
|
@ -194,7 +196,7 @@ export class RuleEditor extends React.Component<RuleEditorProps, RuleEditorState
|
|||
return <FormGroup label="Colocated datasources:">
|
||||
<TagInput
|
||||
values={rule.colocatedDataSources || []}
|
||||
onChange={(v: any) => onChange(RuleEditor.changeColocatedDataSources(rule, v)) }
|
||||
onChange={(v: any) => onChange(RuleEditor.changeColocatedDataSources(rule, v))}
|
||||
fill
|
||||
/>
|
||||
</FormGroup>;
|
||||
|
@ -240,21 +242,21 @@ export class RuleEditor extends React.Component<RuleEditorProps, RuleEditorState
|
|||
<option value="ByPeriod">by period</option>
|
||||
<option value="ByInterval">by interval</option>
|
||||
</HTMLSelect>
|
||||
{ ruleTimeType === 'ByPeriod' && <InputGroup value={rule.period || ''} onChange={(e: any) => onChange(RuleEditor.changePeriod(rule, e.target.value as any))}/>}
|
||||
{ ruleTimeType === 'ByInterval' && <InputGroup value={rule.interval || ''} onChange={(e: any) => onChange(RuleEditor.changeInterval(rule, e.target.value as any))}/>}
|
||||
{ruleTimeType === 'ByPeriod' && <InputGroup value={rule.period || ''} onChange={(e: any) => onChange(RuleEditor.changePeriod(rule, e.target.value as any))}/>}
|
||||
{ruleTimeType === 'ByInterval' && <InputGroup value={rule.interval || ''} onChange={(e: any) => onChange(RuleEditor.changeInterval(rule, e.target.value as any))}/>}
|
||||
</ControlGroup>
|
||||
</FormGroup>
|
||||
{
|
||||
ruleLoadType === 'load' &&
|
||||
<FormGroup>
|
||||
{ this.renderTiers() }
|
||||
{ this.renderTierAdder() }
|
||||
{this.renderTiers()}
|
||||
{this.renderTierAdder()}
|
||||
</FormGroup>
|
||||
}
|
||||
{
|
||||
ruleLoadType === 'broadcast' &&
|
||||
<FormGroup>
|
||||
{ this.renderColocatedDataSources() }
|
||||
{this.renderColocatedDataSources()}
|
||||
</FormGroup>
|
||||
}
|
||||
</Card>
|
||||
|
|
|
@ -16,21 +16,24 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as ReactDOMServer from 'react-dom/server';
|
||||
import { Button, Checkbox, Classes, Intent, Popover, Position } from "@blueprintjs/core";
|
||||
import axios from "axios";
|
||||
import * as classNames from 'classnames';
|
||||
import * as ace from 'brace'
|
||||
import AceEditor from "react-ace";
|
||||
import 'brace/mode/sql';
|
||||
import 'brace/mode/hjson';
|
||||
import 'brace/theme/solarized_dark';
|
||||
import * as ace from 'brace';
|
||||
import 'brace/ext/language_tools';
|
||||
import {Intent, Button, Popover, Checkbox, Classes, Position} from "@blueprintjs/core";
|
||||
import 'brace/mode/hjson';
|
||||
import 'brace/mode/sql';
|
||||
import 'brace/theme/solarized_dark';
|
||||
import * as classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
import AceEditor from "react-ace";
|
||||
import * as ReactDOMServer from 'react-dom/server';
|
||||
|
||||
import { SQLFunctionDoc } from "../../lib/sql-function-doc";
|
||||
import { AppToaster } from "../singletons/toaster";
|
||||
|
||||
import { IconNames } from './filler';
|
||||
import './sql-control.scss'
|
||||
import {AppToaster} from "../singletons/toaster";
|
||||
|
||||
import './sql-control.scss';
|
||||
|
||||
const langTools = ace.acequire('ace/ext/language_tools');
|
||||
|
||||
|
@ -55,9 +58,8 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
private addDatasourceAutoCompleter = async (): Promise<any> =>{
|
||||
const datasourceResp = await axios.post("/druid/v2/sql", { query: `SELECT datasource FROM sys.segments GROUP BY 1`})
|
||||
private addDatasourceAutoCompleter = async (): Promise<any> => {
|
||||
const datasourceResp = await axios.post("/druid/v2/sql", { query: `SELECT datasource FROM sys.segments GROUP BY 1`});
|
||||
const datasourceList: any[] = datasourceResp.data.map((d: any) => {
|
||||
const datasourceName: string = d.datasource;
|
||||
return {
|
||||
|
@ -68,7 +70,7 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
|||
});
|
||||
|
||||
const completer = {
|
||||
getCompletions: (editor:any , session: any, pos: any, prefix: any, callback: any) => {
|
||||
getCompletions: (editor: any, session: any, pos: any, prefix: any, callback: any) => {
|
||||
callback(null, datasourceList);
|
||||
}
|
||||
};
|
||||
|
@ -77,7 +79,7 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
|||
}
|
||||
|
||||
private addColumnNameAutoCompleter = async (): Promise<any> => {
|
||||
const columnNameResp = await axios.post("/druid/v2/sql", {query: `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'druid'`})
|
||||
const columnNameResp = await axios.post("/druid/v2/sql", {query: `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'druid'`});
|
||||
const columnNameList: any[] = columnNameResp.data.map((d: any) => {
|
||||
const columnName: string = d.COLUMN_NAME;
|
||||
return {
|
||||
|
@ -88,7 +90,7 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
|||
});
|
||||
|
||||
const completer = {
|
||||
getCompletions: (editor:any , session: any, pos: any, prefix: any, callback: any) => {
|
||||
getCompletions: (editor: any, session: any, pos: any, prefix: any, callback: any) => {
|
||||
callback(null, columnNameList);
|
||||
}
|
||||
};
|
||||
|
@ -97,9 +99,9 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
|||
}
|
||||
|
||||
private addFunctionAutoCompleter = (): void => {
|
||||
const functionList: any[]= SQLFunctionDoc.map((entry: any) => {
|
||||
let funcName: string = entry.syntax.replace(/\(.*\)/,"()");
|
||||
if (!funcName.includes("(")) funcName = funcName.substr(0,10);
|
||||
const functionList: any[] = SQLFunctionDoc.map((entry: any) => {
|
||||
let funcName: string = entry.syntax.replace(/\(.*\)/, "()");
|
||||
if (!funcName.includes("(")) funcName = funcName.substr(0, 10);
|
||||
return {
|
||||
value: funcName,
|
||||
score: 80,
|
||||
|
@ -107,22 +109,22 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
|||
syntax: entry.syntax,
|
||||
description: entry.description,
|
||||
completer: {
|
||||
insertMatch: (editor:any, data:any) => {
|
||||
insertMatch: (editor: any, data: any) => {
|
||||
editor.completer.insertMatch({value: data.caption});
|
||||
const pos = editor.getCursorPosition();
|
||||
editor.gotoLine(pos.row+1, pos.column-1);
|
||||
editor.gotoLine(pos.row + 1, pos.column - 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const completer = {
|
||||
getCompletions: (editor:any , session: any, pos: any, prefix: any, callback: any) => {
|
||||
getCompletions: (editor: any, session: any, pos: any, prefix: any, callback: any) => {
|
||||
callback(null, functionList);
|
||||
},
|
||||
getDocTooltip: (item: any) => {
|
||||
if (item.meta === "function") {
|
||||
const functionName = item.caption.slice(0,-2);
|
||||
const functionName = item.caption.slice(0, -2);
|
||||
item.docHTML = ReactDOMServer.renderToStaticMarkup((
|
||||
<div className={"function-doc"}>
|
||||
<div className={"function-doc-name"}><b>{functionName}</b></div>
|
||||
|
@ -133,7 +135,7 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
|||
<div><b>Description:</b></div>
|
||||
<div>{item.description}</div>
|
||||
</div>
|
||||
))
|
||||
));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -160,7 +162,7 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
|||
private handleChange = (newValue: string): void => {
|
||||
this.setState({
|
||||
query: newValue
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -186,7 +188,7 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
|||
theme="solarized_dark"
|
||||
name="ace-editor"
|
||||
onChange={this.handleChange}
|
||||
focus={true}
|
||||
focus
|
||||
fontSize={14}
|
||||
width={'100%'}
|
||||
height={"30vh"}
|
||||
|
@ -199,7 +201,7 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
|||
enableBasicAutocompletion: isRune ? false : autoCompleteOn,
|
||||
enableLiveAutocompletion: isRune ? false : autoCompleteOn,
|
||||
showLineNumbers: true,
|
||||
tabSize: 2,
|
||||
tabSize: 2
|
||||
}}
|
||||
/>
|
||||
<div className="buttons">
|
||||
|
@ -213,4 +215,3 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
|||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,22 +16,23 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import axios from 'axios';
|
||||
import * as React from 'react';
|
||||
import * as classNames from 'classnames';
|
||||
import { HashRouter, Route, Switch } from "react-router-dom";
|
||||
import { Intent } from "@blueprintjs/core";
|
||||
import axios from 'axios';
|
||||
import * as classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
import { HashRouter, Route, Switch } from "react-router-dom";
|
||||
|
||||
import { HeaderActiveTab, HeaderBar } from './components/header-bar';
|
||||
import { AppToaster } from './singletons/toaster';
|
||||
import { HeaderBar, HeaderActiveTab } from './components/header-bar';
|
||||
import { localStorageGet, localStorageSet } from './utils';
|
||||
import { DRUID_DOCS_SQL, LEGACY_COORDINATOR_CONSOLE, LEGACY_OVERLORD_CONSOLE } from './variables';
|
||||
import { HomeView } from './views/home-view';
|
||||
import { DatasourcesView } from './views/datasource-view';
|
||||
import { HomeView } from './views/home-view';
|
||||
import { LookupsView } from "./views/lookups-view";
|
||||
import { SegmentsView } from './views/segments-view';
|
||||
import { ServersView } from './views/servers-view';
|
||||
import { TasksView } from './views/tasks-view';
|
||||
import { SqlView } from './views/sql-view';
|
||||
import { LookupsView } from "./views/lookups-view";
|
||||
import { TasksView } from './views/tasks-view';
|
||||
|
||||
import "./console-application.scss";
|
||||
|
||||
export interface ConsoleApplicationProps extends React.Props<any> {
|
||||
|
@ -63,14 +64,16 @@ export class ConsoleApplication extends React.Component<ConsoleApplicationProps,
|
|||
iconName: 'error',
|
||||
intent: Intent.DANGER,
|
||||
timeout: 120000,
|
||||
/* tslint:disable:jsx-alignment */
|
||||
message: <>
|
||||
It appears that the SQL endpoint is disabled. Either <a
|
||||
href={DRUID_DOCS_SQL}>enable the SQL endpoint</a> or use the old <a
|
||||
href={LEGACY_COORDINATOR_CONSOLE}>coordinator</a> and <a
|
||||
href={LEGACY_OVERLORD_CONSOLE}>overlord</a> consoles that do not rely on the SQL endpoint.
|
||||
</>
|
||||
/* tslint:enable:jsx-alignment */
|
||||
});
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -142,30 +145,49 @@ export class ConsoleApplication extends React.Component<ConsoleApplicationProps,
|
|||
return <HashRouter hashType="noslash">
|
||||
<div className="console-application">
|
||||
<Switch>
|
||||
<Route path="/datasources" component={() => {
|
||||
return wrapInViewContainer('datasources', <DatasourcesView goToSql={this.goToSql} goToSegments={this.goToSegments}/>);
|
||||
}} />
|
||||
<Route path="/segments" component={() => {
|
||||
return wrapInViewContainer('segments', <SegmentsView datasource={this.datasource} onlyUnavailable={this.onlyUnavailable} goToSql={this.goToSql}/>);
|
||||
}} />
|
||||
<Route path="/tasks" component={() => {
|
||||
return wrapInViewContainer('tasks', <TasksView taskId={this.taskId} goToSql={this.goToSql} goToMiddleManager={this.goToMiddleManager}/>, true);
|
||||
}} />
|
||||
<Route path="/servers" component={() => {
|
||||
return wrapInViewContainer('servers', <ServersView middleManager={this.middleManager} goToSql={this.goToSql} goToTask={this.goToTask}/>, true);
|
||||
}} />
|
||||
<Route path="/sql" component={() => {
|
||||
return wrapInViewContainer('sql', <SqlView initSql={this.initSql}/>);
|
||||
}} />
|
||||
<Route path="/lookups" component={() => {
|
||||
return wrapInViewContainer('lookups', <LookupsView />);
|
||||
}} />
|
||||
<Route component={() => {
|
||||
return wrapInViewContainer(null, <HomeView/>)
|
||||
}} />
|
||||
<Route
|
||||
path="/datasources"
|
||||
component={() => {
|
||||
return wrapInViewContainer('datasources', <DatasourcesView goToSql={this.goToSql} goToSegments={this.goToSegments}/>);
|
||||
}}
|
||||
/>
|
||||
<Route
|
||||
path="/segments"
|
||||
component={() => {
|
||||
return wrapInViewContainer('segments', <SegmentsView datasource={this.datasource} onlyUnavailable={this.onlyUnavailable} goToSql={this.goToSql}/>);
|
||||
}}
|
||||
/>
|
||||
<Route
|
||||
path="/tasks"
|
||||
component={() => {
|
||||
return wrapInViewContainer('tasks', <TasksView taskId={this.taskId} goToSql={this.goToSql} goToMiddleManager={this.goToMiddleManager}/>, true);
|
||||
}}
|
||||
/>
|
||||
<Route
|
||||
path="/servers"
|
||||
component={() => {
|
||||
return wrapInViewContainer('servers', <ServersView middleManager={this.middleManager} goToSql={this.goToSql} goToTask={this.goToTask}/>, true);
|
||||
}}
|
||||
/>
|
||||
<Route
|
||||
path="/sql"
|
||||
component={() => {
|
||||
return wrapInViewContainer('sql', <SqlView initSql={this.initSql}/>);
|
||||
}}
|
||||
/>
|
||||
<Route
|
||||
path="/lookups"
|
||||
component={() => {
|
||||
return wrapInViewContainer('lookups', <LookupsView />);
|
||||
}}
|
||||
/>
|
||||
<Route
|
||||
component={() => {
|
||||
return wrapInViewContainer(null, <HomeView/>);
|
||||
}}
|
||||
/>
|
||||
</Switch>
|
||||
</div>
|
||||
</HashRouter>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,13 +16,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AnchorButton, Button, Classes, Dialog, Intent } from "@blueprintjs/core";
|
||||
import * as React from 'react';
|
||||
import { Button, Dialog, Classes, AnchorButton, Intent } from "@blueprintjs/core";
|
||||
|
||||
import { IconNames } from "../components/filler";
|
||||
import { DRUID_COMMUNITY, DRUID_DEVELOPER_GROUP, DRUID_USER_GROUP, DRUID_WEBSITE } from '../variables';
|
||||
|
||||
export interface AboutDialogProps extends React.Props<any> {
|
||||
onClose: () => void
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export interface AboutDialogState {
|
||||
|
@ -37,6 +38,7 @@ export class AboutDialog extends React.Component<AboutDialogProps, AboutDialogSt
|
|||
render() {
|
||||
const { onClose } = this.props;
|
||||
|
||||
/* tslint:disable:jsx-alignment */
|
||||
return <Dialog
|
||||
iconName={IconNames.GRAPH}
|
||||
onClose={onClose}
|
||||
|
@ -75,5 +77,6 @@ export class AboutDialog extends React.Component<AboutDialogProps, AboutDialogSt
|
|||
</div>
|
||||
</div>
|
||||
</Dialog>;
|
||||
/* tslint:enable:jsx-alignment */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,25 +16,25 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
import {
|
||||
Button,
|
||||
InputGroup,
|
||||
Dialog,
|
||||
Classes,
|
||||
Dialog,
|
||||
Intent,
|
||||
ProgressBar
|
||||
} from "@blueprintjs/core";
|
||||
import { Icon, FormGroup, ButtonGroup, NumericInput, TagInput } from '../components/filler';
|
||||
import classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
|
||||
import { ButtonGroup, FormGroup, Icon, NumericInput, TagInput } from '../components/filler';
|
||||
import { AppToaster } from '../singletons/toaster';
|
||||
|
||||
export interface AsyncAlertDialogProps extends React.Props<any> {
|
||||
action: null | (() => Promise<void>),
|
||||
onClose: (success: boolean) => void,
|
||||
action: null | (() => Promise<void>);
|
||||
onClose: (success: boolean) => void;
|
||||
confirmButtonText: string;
|
||||
cancelButtonText?: string;
|
||||
className?: string,
|
||||
className?: string;
|
||||
icon?: string;
|
||||
intent?: Intent;
|
||||
successText: string;
|
||||
|
@ -42,7 +42,7 @@ export interface AsyncAlertDialogProps extends React.Props<any> {
|
|||
}
|
||||
|
||||
export interface AsyncAlertDialogState {
|
||||
working: boolean
|
||||
working: boolean;
|
||||
}
|
||||
|
||||
export class AsyncActionDialog extends React.Component<AsyncAlertDialogProps, AsyncAlertDialogState> {
|
||||
|
@ -59,7 +59,7 @@ export class AsyncActionDialog extends React.Component<AsyncAlertDialogProps, As
|
|||
|
||||
this.setState({ working: true });
|
||||
try {
|
||||
await action()
|
||||
await action();
|
||||
} catch (e) {
|
||||
AppToaster.show({
|
||||
message: `${failText}: ${e.message}`,
|
||||
|
@ -92,8 +92,8 @@ export class AsyncActionDialog extends React.Component<AsyncAlertDialogProps, As
|
|||
onClose={handleClose}
|
||||
>
|
||||
<div className={Classes.ALERT_BODY}>
|
||||
{ icon && <Icon icon={icon} /> }
|
||||
{ !working && <div className={Classes.ALERT_CONTENTS}>{children}</div> }
|
||||
{icon && <Icon icon={icon} />}
|
||||
{!working && <div className={Classes.ALERT_CONTENTS}>{children}</div>}
|
||||
</div>
|
||||
{
|
||||
working ?
|
||||
|
@ -103,6 +103,6 @@ export class AsyncActionDialog extends React.Component<AsyncAlertDialogProps, As
|
|||
<Button text={cancelButtonText || 'Cancel'} onClick={handleClose}/>
|
||||
</div>
|
||||
}
|
||||
</Dialog>
|
||||
</Dialog>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,17 +17,20 @@
|
|||
*/
|
||||
|
||||
import { Intent } from '@blueprintjs/core';
|
||||
import * as React from 'react';
|
||||
import axios from 'axios';
|
||||
import { AppToaster } from '../singletons/toaster';
|
||||
import { IconNames } from '../components/filler';
|
||||
import * as React from 'react';
|
||||
|
||||
import { AutoForm } from '../components/auto-form';
|
||||
import { IconNames } from '../components/filler';
|
||||
import { AppToaster } from '../singletons/toaster';
|
||||
import { getDruidErrorMessage } from '../utils';
|
||||
|
||||
import { SnitchDialog } from './snitch-dialog';
|
||||
|
||||
import './coordinator-dynamic-config.scss';
|
||||
|
||||
export interface CoordinatorDynamicConfigDialogProps extends React.Props<any> {
|
||||
onClose: () => void
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export interface CoordinatorDynamicConfigDialogState {
|
||||
|
@ -39,7 +42,7 @@ export class CoordinatorDynamicConfigDialog extends React.Component<CoordinatorD
|
|||
super(props);
|
||||
this.state = {
|
||||
dynamicConfig: null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
|
@ -50,7 +53,7 @@ export class CoordinatorDynamicConfigDialog extends React.Component<CoordinatorD
|
|||
let config: Record<string, any> | null = null;
|
||||
try {
|
||||
const configResp = await axios.get("/druid/coordinator/v1/config");
|
||||
config = configResp.data
|
||||
config = configResp.data;
|
||||
} catch (e) {
|
||||
AppToaster.show({
|
||||
iconName: IconNames.ERROR,
|
||||
|
@ -66,7 +69,7 @@ export class CoordinatorDynamicConfigDialog extends React.Component<CoordinatorD
|
|||
|
||||
private saveClusterConfig = async (author: string, comment: string) => {
|
||||
const { onClose } = this.props;
|
||||
let newState: any = this.state.dynamicConfig;
|
||||
const newState: any = this.state.dynamicConfig;
|
||||
try {
|
||||
await axios.post("/druid/coordinator/v1/config", newState, {
|
||||
headers: {
|
||||
|
@ -158,6 +161,6 @@ export class CoordinatorDynamicConfigDialog extends React.Component<CoordinatorD
|
|||
model={dynamicConfig}
|
||||
onChange={m => this.setState({ dynamicConfig: m })}
|
||||
/>
|
||||
</SnitchDialog>
|
||||
</SnitchDialog>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,24 +16,26 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Button, Classes, Dialog, InputGroup, Intent } from "@blueprintjs/core";
|
||||
import * as React from "react";
|
||||
import {Button, Classes, Dialog, Intent, InputGroup } from "@blueprintjs/core";
|
||||
import "./lookup-edit-dialog.scss"
|
||||
import {validJson} from "../utils";
|
||||
import AceEditor from "react-ace";
|
||||
import {FormGroup} from "../components/filler";
|
||||
|
||||
import { FormGroup } from "../components/filler";
|
||||
import { validJson } from "../utils";
|
||||
|
||||
import "./lookup-edit-dialog.scss";
|
||||
|
||||
export interface LookupEditDialogProps extends React.Props<any> {
|
||||
isOpen: boolean,
|
||||
onClose: () => void,
|
||||
onSubmit: () => void,
|
||||
onChange: (field: string, value: string) => void
|
||||
lookupName: string,
|
||||
lookupTier: string,
|
||||
lookupVersion: string,
|
||||
lookupSpec: string,
|
||||
isEdit: boolean,
|
||||
allLookupTiers: string[]
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onSubmit: () => void;
|
||||
onChange: (field: string, value: string) => void;
|
||||
lookupName: string;
|
||||
lookupTier: string;
|
||||
lookupVersion: string;
|
||||
lookupSpec: string;
|
||||
isEdit: boolean;
|
||||
allLookupTiers: string[];
|
||||
}
|
||||
|
||||
export interface LookupEditDialogState {
|
||||
|
@ -45,7 +47,7 @@ export class LookupEditDialog extends React.Component<LookupEditDialogProps, Loo
|
|||
super(props);
|
||||
this.state = {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private addISOVersion = () => {
|
||||
|
@ -62,21 +64,21 @@ export class LookupEditDialog extends React.Component<LookupEditDialogProps, Loo
|
|||
<InputGroup
|
||||
value={lookupTier}
|
||||
onChange={(e: any) => onChange("lookupEditTier", e.target.value)}
|
||||
disabled={true}
|
||||
disabled
|
||||
/>
|
||||
</FormGroup>
|
||||
</FormGroup>;
|
||||
} else {
|
||||
return <FormGroup className={"lookup-label"} label={"Tier:"}>
|
||||
<div className="pt-select">
|
||||
<select disabled={isEdit} value={lookupTier} onChange={(e:any) => onChange("lookupEditTier", e.target.value)}>
|
||||
<select disabled={isEdit} value={lookupTier} onChange={(e: any) => onChange("lookupEditTier", e.target.value)}>
|
||||
{
|
||||
allLookupTiers.map(tier => {
|
||||
return <option key={tier} value={tier}>{tier}</option>
|
||||
return <option key={tier} value={tier}>{tier}</option>;
|
||||
})
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</FormGroup>
|
||||
</FormGroup>;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +103,7 @@ export class LookupEditDialog extends React.Component<LookupEditDialogProps, Loo
|
|||
/>
|
||||
</FormGroup>
|
||||
|
||||
{ this.renderTierInput() }
|
||||
{this.renderTierInput()}
|
||||
|
||||
<FormGroup className={"lookup-label"} label={"Version:"}>
|
||||
<InputGroup
|
||||
|
@ -131,7 +133,7 @@ export class LookupEditDialog extends React.Component<LookupEditDialogProps, Loo
|
|||
setOptions={{
|
||||
enableBasicAutocompletion: false,
|
||||
enableLiveAutocompletion: false,
|
||||
tabSize: 2,
|
||||
tabSize: 2
|
||||
}}
|
||||
/>
|
||||
|
||||
|
@ -151,4 +153,4 @@ export class LookupEditDialog extends React.Component<LookupEditDialogProps, Loo
|
|||
</div>
|
||||
</Dialog>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,17 +16,19 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import axios from 'axios';
|
||||
import { Button } from "@blueprintjs/core";
|
||||
import axios from 'axios';
|
||||
import * as React from 'react';
|
||||
|
||||
import { FormGroup, IconNames } from '../components/filler';
|
||||
import { RuleEditor, Rule } from '../components/rule-editor';
|
||||
import { Rule, RuleEditor } from '../components/rule-editor';
|
||||
|
||||
import { SnitchDialog } from './snitch-dialog';
|
||||
|
||||
import './retention-dialog.scss';
|
||||
|
||||
export function reorderArray<T>(items: T[], oldIndex: number, newIndex: number): T[] {
|
||||
let newItems = items.concat();
|
||||
const newItems = items.concat();
|
||||
|
||||
if (newIndex > oldIndex) newIndex--;
|
||||
|
||||
|
@ -111,7 +113,7 @@ export class RetentionDialog extends React.Component<RetentionDialogProps, Reten
|
|||
onDelete={() => this.onDeleteRule(index)}
|
||||
moveUp={index > 0 ? () => this.moveRule(index, -1) : null}
|
||||
moveDown={index < (currentRules || []).length - 1 ? () => this.moveRule(index, 2) : null}
|
||||
/>
|
||||
/>;
|
||||
}
|
||||
|
||||
reset = () => {
|
||||
|
|
|
@ -16,17 +16,17 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import {
|
||||
Button,
|
||||
InputGroup,
|
||||
Classes,
|
||||
Dialog,
|
||||
IDialogProps,
|
||||
Classes,
|
||||
Intent,
|
||||
InputGroup,
|
||||
Intent
|
||||
} from "@blueprintjs/core";
|
||||
import { IconNames, FormGroup } from '../components/filler';
|
||||
import * as React from 'react';
|
||||
|
||||
import { FormGroup, IconNames } from '../components/filler';
|
||||
|
||||
export interface SnitchDialogProps extends IDialogProps {
|
||||
onSave: (author: string, comment: string) => void;
|
||||
|
@ -50,7 +50,7 @@ export class SnitchDialog extends React.Component<SnitchDialogProps, SnitchDialo
|
|||
comment: "",
|
||||
author: "",
|
||||
saveDisabled: true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
save = () => {
|
||||
|
@ -136,7 +136,7 @@ export class SnitchDialog extends React.Component<SnitchDialogProps, SnitchDialo
|
|||
? <Button disabled={saveDisabled} text="Save" onClick={this.save} intent={Intent.PRIMARY as any} rightIconName={IconNames.TICK}/>
|
||||
: <Button disabled={saveDisabled} text="Next" onClick={this.goToFinalStep} intent={Intent.PRIMARY as any} rightIconName={IconNames.ARROW_RIGHT}/>
|
||||
}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -16,12 +16,13 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import { Button, Classes, Dialog, Intent } from "@blueprintjs/core";
|
||||
import "./spec-dialog.scss"
|
||||
import AceEditor from "react-ace";
|
||||
import "brace/mode/json";
|
||||
import "brace/theme/solarized_dark";
|
||||
import "brace/mode/json"
|
||||
import * as React from "react";
|
||||
import AceEditor from "react-ace";
|
||||
|
||||
import "./spec-dialog.scss";
|
||||
|
||||
export interface SpecDialogProps extends React.Props<any> {
|
||||
onSubmit: (spec: JSON) => void;
|
||||
|
@ -47,7 +48,7 @@ export class SpecDialog extends React.Component<SpecDialogProps, SpecDialogState
|
|||
super(props);
|
||||
this.state = {
|
||||
spec: ""
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private postSpec(): void {
|
||||
|
@ -72,11 +73,11 @@ export class SpecDialog extends React.Component<SpecDialogProps, SpecDialogState
|
|||
mode="json"
|
||||
theme="solarized_dark"
|
||||
className={"post-spec-dialog-textarea"}
|
||||
onChange={ (e) => {this.setState({ spec: e })} }
|
||||
onChange={(e) => { this.setState({ spec: e }); }}
|
||||
fontSize={12}
|
||||
showPrintMargin={false}
|
||||
showGutter={true}
|
||||
highlightActiveLine={true}
|
||||
showGutter
|
||||
highlightActiveLine
|
||||
value={spec}
|
||||
width={"100%"}
|
||||
setOptions={{
|
||||
|
@ -84,7 +85,7 @@ export class SpecDialog extends React.Component<SpecDialogProps, SpecDialogState
|
|||
enableLiveAutocompletion: true,
|
||||
showLineNumbers: true,
|
||||
enableSnippets: true,
|
||||
tabSize: 2,
|
||||
tabSize: 2
|
||||
}}
|
||||
/>
|
||||
<div className={Classes.DIALOG_FOOTER}>
|
||||
|
|
|
@ -19,13 +19,14 @@
|
|||
import 'es6-shim/es6-shim';
|
||||
import 'es7-shim'; // Webpack with automatically pick browser.js which does the shim()
|
||||
import * as React from 'react';
|
||||
(React as any).PropTypes = require('prop-types'); // Trick blueprint 1.0.1 into accepting React 16 as React 15.
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import "./singletons/react-table-defaults";
|
||||
import "./entry.scss";
|
||||
|
||||
import "./bootstrap/a-shim-for-react-props";
|
||||
import "./bootstrap/react-table-defaults";
|
||||
import { ConsoleApplication } from './console-application';
|
||||
|
||||
import "./entry.scss";
|
||||
|
||||
const container = document.getElementsByClassName('app-container')[0];
|
||||
if (!container) throw new Error('container not found');
|
||||
|
||||
|
|
|
@ -20,5 +20,5 @@ import { Position, Toaster } from "@blueprintjs/core";
|
|||
|
||||
export const AppToaster = Toaster.create({
|
||||
className: "recipe-toaster",
|
||||
position: Position.TOP,
|
||||
position: Position.TOP
|
||||
});
|
||||
|
|
|
@ -17,14 +17,14 @@
|
|||
*/
|
||||
|
||||
import { Button, InputGroup, Intent } from '@blueprintjs/core';
|
||||
import { IconNames, HTMLSelect } from "../components/filler";
|
||||
import * as numeral from "numeral";
|
||||
import * as React from 'react';
|
||||
import { Filter, FilterRender } from 'react-table';
|
||||
|
||||
import { HTMLSelect, IconNames } from "../components/filler";
|
||||
|
||||
export function addFilter(filters: Filter[], id: string, value: string): Filter[] {
|
||||
let currentFilter = filters.find(f => f.id === id);
|
||||
const currentFilter = filters.find(f => f.id === id);
|
||||
if (currentFilter) {
|
||||
filters = filters.filter(f => f.id !== id);
|
||||
if (currentFilter.value !== value) {
|
||||
|
@ -36,7 +36,7 @@ export function addFilter(filters: Filter[], id: string, value: string): Filter[
|
|||
return filters;
|
||||
}
|
||||
|
||||
export function makeTextFilter(placeholder: string = ''): FilterRender {
|
||||
export function makeTextFilter(placeholder = ''): FilterRender {
|
||||
return ({ filter, onChange, key }) => {
|
||||
const filterValue = filter ? filter.value : '';
|
||||
return <InputGroup
|
||||
|
@ -45,8 +45,8 @@ export function makeTextFilter(placeholder: string = ''): FilterRender {
|
|||
value={filterValue}
|
||||
rightElement={filterValue ? <Button iconName={IconNames.CROSS} className="pt-minimal" onClick={() => onChange('')} /> : undefined}
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
}
|
||||
/>;
|
||||
};
|
||||
}
|
||||
|
||||
export function makeBooleanFilter(): FilterRender {
|
||||
|
@ -57,13 +57,13 @@ export function makeBooleanFilter(): FilterRender {
|
|||
style={{ width: '100%' }}
|
||||
onChange={(event: any) => onChange(event.target.value)}
|
||||
value={filterValue || "all"}
|
||||
fill={true}
|
||||
fill
|
||||
>
|
||||
<option value="all">Show all</option>
|
||||
<option value="true">true</option>
|
||||
<option value="false">false</option>
|
||||
</HTMLSelect>;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
|
|
|
@ -74,7 +74,7 @@ export class QueryManager<Q, R> {
|
|||
private run() {
|
||||
this.lastQuery = this.nextQuery;
|
||||
this.currentQueryId++;
|
||||
let myQueryId = this.currentQueryId;
|
||||
const myQueryId = this.currentQueryId;
|
||||
|
||||
this.actuallyLoading = true;
|
||||
this.processQuery(this.lastQuery)
|
||||
|
@ -95,9 +95,9 @@ export class QueryManager<Q, R> {
|
|||
result: null,
|
||||
loading: false,
|
||||
error: e.message
|
||||
})
|
||||
});
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private trigger() {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
export interface HeaderRows {
|
||||
header: string[];
|
||||
rows: any[][];
|
||||
|
@ -86,7 +85,11 @@ export function decodeRune(runeQuery: any, runeResult: any[]): HeaderRows {
|
|||
throw new Error(`Unsupported query type in treatQueryTypeAs: '${treatQueryTypeAs}'`);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`Unsupported query type '${queryType}'. Supported query types are: '${SUPPORTED_QUERY_TYPES.join("', '")}'. If this is a custom query you can parse the result as a known query type by setting 'treatQueryTypeAs' in the context to one of the supported types.`);
|
||||
throw new Error([
|
||||
`Unsupported query type '${queryType}'.`,
|
||||
`Supported query types are: '${SUPPORTED_QUERY_TYPES.join("', '")}'.`,
|
||||
`If this is a custom query you can parse the result as a known query type by setting 'treatQueryTypeAs' in the context to one of the supported types.`
|
||||
].join(' '));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,25 +16,26 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Button, Intent, Switch } from "@blueprintjs/core";
|
||||
import axios from 'axios';
|
||||
import * as React from 'react';
|
||||
import * as classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
import ReactTable from "react-table";
|
||||
import { Filter } from "react-table";
|
||||
import { Button, Intent, Switch } from "@blueprintjs/core";
|
||||
|
||||
import { IconNames } from "../components/filler";
|
||||
import { AppToaster } from '../singletons/toaster';
|
||||
import { RuleEditor } from '../components/rule-editor';
|
||||
import { AsyncActionDialog } from '../dialogs/async-action-dialog';
|
||||
import { RetentionDialog } from '../dialogs/retention-dialog';
|
||||
import { AppToaster } from '../singletons/toaster';
|
||||
import {
|
||||
addFilter,
|
||||
formatNumber,
|
||||
formatBytes,
|
||||
countBy,
|
||||
formatBytes,
|
||||
formatNumber,
|
||||
getDruidErrorMessage,
|
||||
lookupBy,
|
||||
QueryManager,
|
||||
pluralIfNeeded, queryDruidSql, getDruidErrorMessage
|
||||
pluralIfNeeded, queryDruidSql, QueryManager
|
||||
} from "../utils";
|
||||
|
||||
import "./datasource-view.scss";
|
||||
|
@ -54,7 +55,7 @@ export interface DatasourcesViewState {
|
|||
datasourcesLoading: boolean;
|
||||
datasources: Datasource[] | null;
|
||||
tiers: string[];
|
||||
defaultRules: any[]
|
||||
defaultRules: any[];
|
||||
datasourcesError: string | null;
|
||||
datasourcesFilter: Filter[];
|
||||
|
||||
|
@ -73,7 +74,7 @@ export class DatasourcesView extends React.Component<DatasourcesViewProps, Datas
|
|||
static formatRules(rules: any[]): string {
|
||||
if (rules.length === 0) {
|
||||
return 'No rules';
|
||||
} if (rules.length <= 2) {
|
||||
} else if (rules.length <= 2) {
|
||||
return rules.map(RuleEditor.ruleToString).join(', ');
|
||||
} else {
|
||||
return `${RuleEditor.ruleToString(rules[0])} +${rules.length - 1} more rules`;
|
||||
|
@ -161,7 +162,7 @@ GROUP BY 1`);
|
|||
return <AsyncActionDialog
|
||||
action={
|
||||
dropDataDatasource ? async () => {
|
||||
const resp = await axios.delete(`/druid/coordinator/v1/datasources/${dropDataDatasource}`, {})
|
||||
const resp = await axios.delete(`/druid/coordinator/v1/datasources/${dropDataDatasource}`, {});
|
||||
return resp.data;
|
||||
} : null
|
||||
}
|
||||
|
@ -186,7 +187,7 @@ GROUP BY 1`);
|
|||
return <AsyncActionDialog
|
||||
action={
|
||||
enableDatasource ? async () => {
|
||||
const resp = await axios.post(`/druid/coordinator/v1/datasources/${enableDatasource}`, {})
|
||||
const resp = await axios.post(`/druid/coordinator/v1/datasources/${enableDatasource}`, {});
|
||||
return resp.data;
|
||||
} : null
|
||||
}
|
||||
|
@ -291,7 +292,7 @@ GROUP BY 1`);
|
|||
|
||||
let data = datasources || [];
|
||||
if (!showDisabled) {
|
||||
data = data.filter(d => !d.disabled)
|
||||
data = data.filter(d => !d.disabled);
|
||||
}
|
||||
|
||||
return <>
|
||||
|
@ -299,7 +300,7 @@ GROUP BY 1`);
|
|||
data={data}
|
||||
loading={datasourcesLoading}
|
||||
noDataText={!datasourcesLoading && datasources && !datasources.length ? 'No datasources' : (datasourcesError || '')}
|
||||
filterable={true}
|
||||
filterable
|
||||
filtered={datasourcesFilter}
|
||||
onFilteredChange={(filtered, column) => {
|
||||
this.setState({ datasourcesFilter: filtered });
|
||||
|
@ -311,7 +312,7 @@ GROUP BY 1`);
|
|||
width: 150,
|
||||
Cell: row => {
|
||||
const value = row.value;
|
||||
return <a onClick={() => { this.setState({ datasourcesFilter: addFilter(datasourcesFilter, 'datasource', value) }) }}>{value}</a>
|
||||
return <a onClick={() => { this.setState({ datasourcesFilter: addFilter(datasourcesFilter, 'datasource', value) }); }}>{value}</a>;
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -415,11 +416,11 @@ GROUP BY 1`);
|
|||
return <div>
|
||||
<a onClick={() => this.setState({ enableDatasource: datasource })}>Enable</a>
|
||||
<a onClick={() => this.setState({ killDatasource: datasource })}>Permanently delete</a>
|
||||
</div>
|
||||
</div>;
|
||||
} else {
|
||||
return <div>
|
||||
<a onClick={() => this.setState({ dropDataDatasource: datasource })}>Drop data</a>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -458,7 +459,6 @@ GROUP BY 1`);
|
|||
/>
|
||||
</div>
|
||||
{this.renderDatasourceTable()}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,10 +17,12 @@
|
|||
*/
|
||||
|
||||
import axios from 'axios';
|
||||
import * as React from 'react';
|
||||
import * as classNames from 'classnames';
|
||||
import { H5, Card, Icon, IconNames } from "../components/filler";
|
||||
import { QueryManager, pluralIfNeeded, queryDruidSql, getHeadProp } from '../utils';
|
||||
import * as React from 'react';
|
||||
|
||||
import { Card, H5, Icon, IconNames } from "../components/filler";
|
||||
import { getHeadProp, pluralIfNeeded, queryDruidSql, QueryManager } from '../utils';
|
||||
|
||||
import './home-view.scss';
|
||||
|
||||
export interface CardOptions {
|
||||
|
@ -164,14 +166,14 @@ export class HomeView extends React.Component<HomeViewProps, HomeViewState> {
|
|||
this.taskQueryManager = new QueryManager({
|
||||
processQuery: async (query) => {
|
||||
const taskCountsFromSql = await queryDruidSql({ query });
|
||||
let taskCounts = {
|
||||
const taskCounts = {
|
||||
successTaskCount: 0,
|
||||
failedTaskCount: 0,
|
||||
runningTaskCount: 0,
|
||||
waitingTaskCount: 0,
|
||||
pendingTaskCount: 0
|
||||
};
|
||||
for (let dataStatus of taskCountsFromSql) {
|
||||
for (const dataStatus of taskCountsFromSql) {
|
||||
if (dataStatus.status === "SUCCESS") {
|
||||
taskCounts.successTaskCount = dataStatus.count;
|
||||
} else if (dataStatus.status === "FAILED") {
|
||||
|
@ -254,7 +256,7 @@ GROUP BY 1`);
|
|||
|
||||
renderCard(cardOptions: CardOptions): JSX.Element {
|
||||
return <a href={cardOptions.href} target={cardOptions.href[0] === '/' ? '_blank' : undefined}>
|
||||
<Card interactive={true}>
|
||||
<Card interactive>
|
||||
<H5><Icon color="#bfccd5" icon={cardOptions.icon}/> {cardOptions.title}</H5>
|
||||
{cardOptions.loading ? <p>Loading...</p> : (cardOptions.error ? `Error: ${cardOptions.error}` : cardOptions.content)}
|
||||
</Card>
|
||||
|
@ -298,11 +300,11 @@ GROUP BY 1`);
|
|||
title: "Tasks",
|
||||
loading: state.taskCountLoading,
|
||||
content: <>
|
||||
{ Boolean(state.runningTaskCount) && <p>{pluralIfNeeded(state.runningTaskCount, 'running task')}</p> }
|
||||
{ Boolean(state.pendingTaskCount) && <p>{pluralIfNeeded(state.pendingTaskCount, 'pending task')}</p> }
|
||||
{ Boolean(state.successTaskCount) && <p>{pluralIfNeeded(state.successTaskCount, 'successful task')}</p> }
|
||||
{ Boolean(state.waitingTaskCount) && <p>{pluralIfNeeded(state.waitingTaskCount, 'waiting task')}</p> }
|
||||
{ Boolean(state.failedTaskCount) && <p>{pluralIfNeeded(state.failedTaskCount, 'failed task')}</p> }
|
||||
{Boolean(state.runningTaskCount) && <p>{pluralIfNeeded(state.runningTaskCount, 'running task')}</p>}
|
||||
{Boolean(state.pendingTaskCount) && <p>{pluralIfNeeded(state.pendingTaskCount, 'pending task')}</p>}
|
||||
{Boolean(state.successTaskCount) && <p>{pluralIfNeeded(state.successTaskCount, 'successful task')}</p>}
|
||||
{Boolean(state.waitingTaskCount) && <p>{pluralIfNeeded(state.waitingTaskCount, 'waiting task')}</p>}
|
||||
{Boolean(state.failedTaskCount) && <p>{pluralIfNeeded(state.failedTaskCount, 'failed task')}</p>}
|
||||
{ !(state.runningTaskCount + state.pendingTaskCount + state.successTaskCount + state.waitingTaskCount + state.failedTaskCount) &&
|
||||
<p>There are no tasks</p>
|
||||
}
|
||||
|
@ -321,7 +323,6 @@ GROUP BY 1`);
|
|||
</>,
|
||||
error: state.dataServerCountError
|
||||
})}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,15 +16,17 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Button, Intent } from "@blueprintjs/core";
|
||||
import axios from 'axios';
|
||||
import * as React from 'react';
|
||||
import * as classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
import ReactTable from "react-table";
|
||||
import { Filter } from "react-table";
|
||||
import { Button, Intent } from "@blueprintjs/core";
|
||||
import {getDruidErrorMessage, QueryManager} from "../utils";
|
||||
import {LookupEditDialog} from "../dialogs/lookup-edit-dialog";
|
||||
|
||||
import { LookupEditDialog } from "../dialogs/lookup-edit-dialog";
|
||||
import { AppToaster } from "../singletons/toaster";
|
||||
import { getDruidErrorMessage, QueryManager } from "../utils";
|
||||
|
||||
import "./lookups-view.scss";
|
||||
|
||||
export interface LookupsViewProps extends React.Props<any> {
|
||||
|
@ -32,16 +34,16 @@ export interface LookupsViewProps extends React.Props<any> {
|
|||
}
|
||||
|
||||
export interface LookupsViewState {
|
||||
lookups: {}[],
|
||||
loadingLookups: boolean,
|
||||
lookupsError: string | null,
|
||||
lookupEditDialogOpen: boolean,
|
||||
lookupEditName: string,
|
||||
lookupEditTier: string,
|
||||
lookupEditVersion: string,
|
||||
lookupEditSpec: string,
|
||||
isEdit: boolean,
|
||||
allLookupTiers: string[]
|
||||
lookups: {}[];
|
||||
loadingLookups: boolean;
|
||||
lookupsError: string | null;
|
||||
lookupEditDialogOpen: boolean;
|
||||
lookupEditName: string;
|
||||
lookupEditTier: string;
|
||||
lookupEditVersion: string;
|
||||
lookupEditSpec: string;
|
||||
isEdit: boolean;
|
||||
allLookupTiers: string[];
|
||||
}
|
||||
|
||||
export class LookupsView extends React.Component<LookupsViewProps, LookupsViewState> {
|
||||
|
@ -70,15 +72,15 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
|||
const tiersResp = await axios.get('/druid/coordinator/v1/tiers');
|
||||
const tiers = tiersResp.data;
|
||||
|
||||
let lookupEntries: {}[] = [];
|
||||
const lookupEntries: {}[] = [];
|
||||
const lookupResp = await axios.get("/druid/coordinator/v1/lookups/config/all");
|
||||
const lookupData = lookupResp.data;
|
||||
Object.keys(lookupData).map((tier: string) => {
|
||||
const lookupIds = lookupData[tier];
|
||||
Object.keys(lookupIds).map((id: string) => {
|
||||
lookupEntries.push({tier: tier, id: id, version:lookupData[tier][id].version, spec: lookupData[tier][id].lookupExtractorFactory},);
|
||||
})
|
||||
})
|
||||
lookupEntries.push({tier, id, version: lookupData[tier][id].version, spec: lookupData[tier][id].lookupExtractorFactory});
|
||||
});
|
||||
});
|
||||
return {
|
||||
lookupEntries,
|
||||
tiers
|
||||
|
@ -123,11 +125,11 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
|||
intent: Intent.DANGER,
|
||||
message: getDruidErrorMessage(e)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async openLookupEditDialog(tier:string, id: string) {
|
||||
private async openLookupEditDialog(tier: string, id: string) {
|
||||
const { lookups, allLookupTiers } = this.state;
|
||||
const target: any = lookups.find((lookupEntry: any) => {
|
||||
return lookupEntry.tier === tier && lookupEntry.id === id;
|
||||
|
@ -156,7 +158,7 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
|||
private changeLookup(field: string, value: string) {
|
||||
this.setState({
|
||||
[field]: value
|
||||
} as any)
|
||||
} as any);
|
||||
}
|
||||
|
||||
private async submitLookupEdit() {
|
||||
|
@ -184,20 +186,20 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
|||
await axios.post(endpoint, dataJSON);
|
||||
this.setState({
|
||||
lookupEditDialogOpen: false
|
||||
})
|
||||
});
|
||||
this.lookupsGetQueryManager.rerunLastQuery();
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
AppToaster.show(
|
||||
{
|
||||
iconName: 'error',
|
||||
intent: Intent.DANGER,
|
||||
message: getDruidErrorMessage(e)
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private deleteLookup(tier:string, name: string): void {
|
||||
private deleteLookup(tier: string, name: string): void {
|
||||
const url = `/druid/coordinator/v1/lookups/config/${tier}/${name}`;
|
||||
this.lookupDeleteQueryManager.runQuery(url);
|
||||
}
|
||||
|
@ -211,52 +213,52 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
|||
text="Initialize Lookup"
|
||||
onClick={() => this.initializeLookup()}
|
||||
/>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
return <>
|
||||
<ReactTable
|
||||
data={lookups}
|
||||
loading={loadingLookups}
|
||||
noDataText={!loadingLookups && lookups && !lookups.length ? 'No lookups' : (lookupsError || '')}
|
||||
filterable={true}
|
||||
filterable
|
||||
columns={[
|
||||
{
|
||||
Header: "Lookup Name",
|
||||
id: "lookup_name",
|
||||
accessor: (row: any) => row.id,
|
||||
filterable: true,
|
||||
filterable: true
|
||||
},
|
||||
{
|
||||
Header: "Tier",
|
||||
id: "tier",
|
||||
accessor: (row: any) => row.tier,
|
||||
filterable: true,
|
||||
filterable: true
|
||||
},
|
||||
{
|
||||
Header: "Type",
|
||||
id: "type",
|
||||
accessor: (row: any) => row.spec.type,
|
||||
filterable: true,
|
||||
filterable: true
|
||||
},
|
||||
{
|
||||
Header: "Version",
|
||||
id: "version",
|
||||
accessor: (row: any) => row.version,
|
||||
filterable: true,
|
||||
filterable: true
|
||||
},
|
||||
{
|
||||
Header: "Config",
|
||||
id: "config",
|
||||
accessor: row => {return {id: row.id, tier: row.tier};},
|
||||
accessor: row => ({id: row.id, tier: row.tier}),
|
||||
filterable: false,
|
||||
Cell: (row: any) => {
|
||||
const lookupId = row.value.id;
|
||||
const lookupTier = row.value.tier;
|
||||
return <div>
|
||||
<a onClick={() => this.openLookupEditDialog(lookupTier,lookupId)}>Edit</a>
|
||||
<a onClick={() => this.openLookupEditDialog(lookupTier, lookupId)}>Edit</a>
|
||||
|
||||
<a onClick={() => this.deleteLookup(lookupTier,lookupId)}>Delete</a>
|
||||
</div>
|
||||
<a onClick={() => this.deleteLookup(lookupTier, lookupId)}>Delete</a>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
]}
|
||||
|
@ -266,21 +268,21 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
|||
</>;
|
||||
}
|
||||
|
||||
renderLookupEditDialog () {
|
||||
const { lookupEditDialogOpen, allLookupTiers, lookupEditSpec, lookupEditTier, lookupEditName, lookupEditVersion, isEdit } = this.state
|
||||
renderLookupEditDialog() {
|
||||
const { lookupEditDialogOpen, allLookupTiers, lookupEditSpec, lookupEditTier, lookupEditName, lookupEditVersion, isEdit } = this.state;
|
||||
|
||||
return <LookupEditDialog
|
||||
isOpen={lookupEditDialogOpen}
|
||||
onClose={() => this.setState({ lookupEditDialogOpen: false })}
|
||||
onSubmit={() => this.submitLookupEdit()}
|
||||
onChange={(field: string, value: string) => this.changeLookup(field, value)}
|
||||
lookupSpec= {lookupEditSpec}
|
||||
lookupSpec={lookupEditSpec}
|
||||
lookupName={lookupEditName}
|
||||
lookupTier={lookupEditTier}
|
||||
lookupVersion = {lookupEditVersion}
|
||||
lookupVersion={lookupEditVersion}
|
||||
isEdit={isEdit}
|
||||
allLookupTiers={allLookupTiers}
|
||||
/>
|
||||
/>;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -301,6 +303,6 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
|||
</div>
|
||||
{this.renderLookupsTable()}
|
||||
{this.renderLookupEditDialog()}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,22 +16,24 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Button } from "@blueprintjs/core";
|
||||
import axios from 'axios';
|
||||
import * as React from 'react';
|
||||
import * as classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
import ReactTable from "react-table";
|
||||
import { Filter } from "react-table";
|
||||
import { Button } from "@blueprintjs/core";
|
||||
|
||||
import { H5, IconNames } from "../components/filler";
|
||||
import {
|
||||
addFilter,
|
||||
makeBooleanFilter,
|
||||
QueryManager,
|
||||
formatBytes,
|
||||
formatNumber,
|
||||
makeBooleanFilter,
|
||||
parseList,
|
||||
queryDruidSql
|
||||
queryDruidSql,
|
||||
QueryManager
|
||||
} from "../utils";
|
||||
|
||||
import "./segments-view.scss";
|
||||
|
||||
export interface SegmentsViewProps extends React.Props<any> {
|
||||
|
@ -88,7 +90,7 @@ export class SegmentsView extends React.Component<SegmentsViewProps, SegmentsVie
|
|||
segmentsError: error
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
|
@ -99,7 +101,7 @@ export class SegmentsView extends React.Component<SegmentsViewProps, SegmentsVie
|
|||
const { page, pageSize, filtered, sorted } = state;
|
||||
const totalQuerySize = (page + 1) * pageSize;
|
||||
|
||||
let queryParts = [
|
||||
const queryParts = [
|
||||
`SELECT "segment_id", "datasource", "start", "end", "size", "version", "partition_num", "num_replicas", "num_rows", "is_published", "is_available", "is_realtime", "payload"`,
|
||||
`FROM sys.segments`
|
||||
];
|
||||
|
@ -114,7 +116,7 @@ export class SegmentsView extends React.Component<SegmentsViewProps, SegmentsVie
|
|||
}).filter(Boolean);
|
||||
|
||||
if (whereParts.length) {
|
||||
queryParts.push('WHERE ' + whereParts.join(' AND '))
|
||||
queryParts.push('WHERE ' + whereParts.join(' AND '));
|
||||
}
|
||||
|
||||
if (sorted.length) {
|
||||
|
@ -160,7 +162,7 @@ export class SegmentsView extends React.Component<SegmentsViewProps, SegmentsVie
|
|||
accessor: "datasource",
|
||||
Cell: row => {
|
||||
const value = row.value;
|
||||
return <a onClick={() => { this.setState({ segmentFilter: addFilter(segmentFilter, 'datasource', value) }) }}>{value}</a>
|
||||
return <a onClick={() => { this.setState({ segmentFilter: addFilter(segmentFilter, 'datasource', value) }); }}>{value}</a>;
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -170,7 +172,7 @@ export class SegmentsView extends React.Component<SegmentsViewProps, SegmentsVie
|
|||
defaultSortDesc: true,
|
||||
Cell: row => {
|
||||
const value = row.value;
|
||||
return <a onClick={() => { this.setState({ segmentFilter: addFilter(segmentFilter, 'start', value) }) }}>{value}</a>
|
||||
return <a onClick={() => { this.setState({ segmentFilter: addFilter(segmentFilter, 'start', value) }); }}>{value}</a>;
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -180,14 +182,14 @@ export class SegmentsView extends React.Component<SegmentsViewProps, SegmentsVie
|
|||
width: 120,
|
||||
Cell: row => {
|
||||
const value = row.value;
|
||||
return <a onClick={() => { this.setState({ segmentFilter: addFilter(segmentFilter, 'end', value) }) }}>{value}</a>
|
||||
return <a onClick={() => { this.setState({ segmentFilter: addFilter(segmentFilter, 'end', value) }); }}>{value}</a>;
|
||||
}
|
||||
},
|
||||
{
|
||||
Header: "Version",
|
||||
accessor: "version",
|
||||
defaultSortDesc: true,
|
||||
width: 120,
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
Header: "Partition",
|
||||
|
@ -272,6 +274,6 @@ export class SegmentsView extends React.Component<SegmentsViewProps, SegmentsVie
|
|||
/>
|
||||
</div>
|
||||
{this.renderSegmentsTable()}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,19 +16,21 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Button, Switch } from "@blueprintjs/core";
|
||||
import axios from 'axios';
|
||||
import * as React from 'react';
|
||||
import * as classNames from 'classnames';
|
||||
import { sum } from "d3-array";
|
||||
import * as React from 'react';
|
||||
import ReactTable from "react-table";
|
||||
import { Filter } from "react-table";
|
||||
import { sum } from "d3-array";
|
||||
import { Button, Switch } from "@blueprintjs/core";
|
||||
|
||||
import { IconNames } from '../components/filler';
|
||||
import { addFilter, formatBytes, formatBytesCompact, QueryManager, queryDruidSql } from "../utils";
|
||||
import { addFilter, formatBytes, formatBytesCompact, queryDruidSql, QueryManager } from "../utils";
|
||||
|
||||
import "./servers-view.scss";
|
||||
|
||||
function formatQueues(segmentsToLoad: number, segmentsToLoadSize: number, segmentsToDrop: number, segmentsToDropSize: number): string {
|
||||
let queueParts: string[] = [];
|
||||
const queueParts: string[] = [];
|
||||
if (segmentsToLoad) {
|
||||
queueParts.push(`${segmentsToLoad} segments to load (${formatBytesCompact(segmentsToLoadSize)})`);
|
||||
}
|
||||
|
@ -73,7 +75,7 @@ export class ServersView extends React.Component<ServersViewProps, ServersViewSt
|
|||
middleManagersLoading: true,
|
||||
middleManagers: null,
|
||||
middleManagersError: null,
|
||||
middleManagerFilter: props.middleManager ? [{ id: 'host', value: props.middleManager }] : [],
|
||||
middleManagerFilter: props.middleManager ? [{ id: 'host', value: props.middleManager }] : []
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -82,7 +84,7 @@ export class ServersView extends React.Component<ServersViewProps, ServersViewSt
|
|||
processQuery: async (query: string) => {
|
||||
const servers = await queryDruidSql({ query });
|
||||
|
||||
let loadQueueResponse = await axios.get("/druid/coordinator/v1/loadqueue?simple");
|
||||
const loadQueueResponse = await axios.get("/druid/coordinator/v1/loadqueue?simple");
|
||||
const loadQueues = loadQueueResponse.data;
|
||||
|
||||
return servers.map((s: any) => {
|
||||
|
@ -143,7 +145,7 @@ WHERE "server_type" = 'historical'`);
|
|||
data={servers || []}
|
||||
loading={serversLoading}
|
||||
noDataText={!serversLoading && servers && !servers.length ? 'No historicals' : (serversError || '')}
|
||||
filterable={true}
|
||||
filterable
|
||||
filtered={serverFilter}
|
||||
onFilteredChange={(filtered, column) => {
|
||||
this.setState({ serverFilter: filtered });
|
||||
|
@ -161,7 +163,7 @@ WHERE "server_type" = 'historical'`);
|
|||
accessor: "tier",
|
||||
Cell: row => {
|
||||
const value = row.value;
|
||||
return <a onClick={() => { this.setState({ serverFilter: addFilter(serverFilter, 'tier', value) }) }}>{value}</a>
|
||||
return <a onClick={() => { this.setState({ serverFilter: addFilter(serverFilter, 'tier', value) }); }}>{value}</a>;
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -234,7 +236,7 @@ WHERE "server_type" = 'historical'`);
|
|||
const segmentsToDrop = sum(originals, s => s.segmentsToDrop);
|
||||
const segmentsToDropSize = sum(originals, s => s.segmentsToDropSize);
|
||||
return formatQueues(segmentsToLoad, segmentsToLoadSize, segmentsToDrop, segmentsToDropSize);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
Header: "Host",
|
||||
|
@ -245,7 +247,7 @@ WHERE "server_type" = 'historical'`);
|
|||
Header: "Port",
|
||||
id: 'port',
|
||||
accessor: (row) => {
|
||||
let ports: string[] = [];
|
||||
const ports: string[] = [];
|
||||
if (row.plaintext_port !== -1) {
|
||||
ports.push(`${row.plaintext_port} (plain)`);
|
||||
}
|
||||
|
@ -255,7 +257,7 @@ WHERE "server_type" = 'historical'`);
|
|||
return ports.join(', ') || 'No port';
|
||||
},
|
||||
Aggregated: () => ''
|
||||
},
|
||||
}
|
||||
]}
|
||||
defaultPageSize={10}
|
||||
className="-striped -highlight"
|
||||
|
@ -270,7 +272,7 @@ WHERE "server_type" = 'historical'`);
|
|||
data={middleManagers || []}
|
||||
loading={middleManagersLoading}
|
||||
noDataText={!middleManagersLoading && middleManagers && !middleManagers.length ? 'No MiddleManagers' : (middleManagersError || '')}
|
||||
filterable={true}
|
||||
filterable
|
||||
filtered={middleManagerFilter}
|
||||
onFilteredChange={(filtered, column) => {
|
||||
this.setState({ middleManagerFilter: filtered });
|
||||
|
@ -282,7 +284,7 @@ WHERE "server_type" = 'historical'`);
|
|||
accessor: (row) => row.worker.host,
|
||||
Cell: row => {
|
||||
const value = row.value;
|
||||
return <a onClick={() => { this.setState({ middleManagerFilter: addFilter(middleManagerFilter, 'host', value) }) }}>{value}</a>
|
||||
return <a onClick={() => { this.setState({ middleManagerFilter: addFilter(middleManagerFilter, 'host', value) }); }}>{value}</a>;
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -297,7 +299,7 @@ WHERE "server_type" = 'historical'`);
|
|||
id: "availabilityGroups",
|
||||
width: 60,
|
||||
accessor: (row) => row.availabilityGroups.length,
|
||||
filterable: false,
|
||||
filterable: false
|
||||
},
|
||||
{
|
||||
Header: "Last completed task time",
|
||||
|
@ -317,7 +319,7 @@ WHERE "server_type" = 'historical'`);
|
|||
runningTasks.length ?
|
||||
<>
|
||||
<span>Running tasks:</span>
|
||||
<ul>{ runningTasks.map((t: string) => <li key={t}>{t} <a onClick={() => goToTask(t)}>➚</a></li>) }</ul>
|
||||
<ul>{runningTasks.map((t: string) => <li key={t}>{t} <a onClick={() => goToTask(t)}>➚</a></li>)}</ul>
|
||||
</> :
|
||||
<span>No running tasks</span>
|
||||
}
|
||||
|
@ -362,7 +364,6 @@ WHERE "server_type" = 'historical'`);
|
|||
/>
|
||||
</div>
|
||||
{this.renderMiddleManagerTable()}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,19 +17,21 @@
|
|||
*/
|
||||
|
||||
import axios from 'axios';
|
||||
import * as React from 'react';
|
||||
import * as classNames from 'classnames';
|
||||
import ReactTable from "react-table";
|
||||
import * as Hjson from "hjson";
|
||||
import * as React from 'react';
|
||||
import ReactTable from "react-table";
|
||||
|
||||
import { SqlControl } from '../components/sql-control';
|
||||
import {
|
||||
QueryManager,
|
||||
localStorageSet,
|
||||
localStorageGet,
|
||||
decodeRune,
|
||||
HeaderRows,
|
||||
queryDruidRune, queryDruidSql
|
||||
localStorageGet,
|
||||
localStorageSet,
|
||||
queryDruidRune,
|
||||
queryDruidSql, QueryManager
|
||||
} from '../utils';
|
||||
|
||||
import "./sql-view.scss";
|
||||
|
||||
export interface SqlViewProps extends React.Props<any> {
|
||||
|
@ -84,7 +86,7 @@ export class SqlView extends React.Component<SqlViewProps, SqlViewState> {
|
|||
error
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
|
@ -117,7 +119,6 @@ export class SqlView extends React.Component<SqlViewProps, SqlViewState> {
|
|||
}}
|
||||
/>
|
||||
{this.renderResultTable()}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,17 +16,19 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Alert, Button, Intent } from "@blueprintjs/core";
|
||||
import axios from 'axios';
|
||||
import * as React from 'react';
|
||||
import * as classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
import ReactTable from "react-table";
|
||||
import { Filter } from "react-table";
|
||||
import { Button, Intent, Alert } from "@blueprintjs/core";
|
||||
import { ButtonGroup, Label, IconNames } from "../components/filler";
|
||||
import { addFilter, QueryManager, getDruidErrorMessage, countBy, formatDuration, queryDruidSql } from "../utils";
|
||||
|
||||
import { ButtonGroup, IconNames, Label } from "../components/filler";
|
||||
import { AsyncActionDialog } from "../dialogs/async-action-dialog";
|
||||
import { SpecDialog } from "../dialogs/spec-dialog";
|
||||
import { AppToaster } from '../singletons/toaster';
|
||||
import { addFilter, countBy, formatDuration, getDruidErrorMessage, queryDruidSql, QueryManager } from "../utils";
|
||||
|
||||
import "./tasks-view.scss";
|
||||
|
||||
export interface TasksViewProps extends React.Props<any> {
|
||||
|
@ -102,7 +104,7 @@ export class TasksView extends React.Component<TasksViewProps, TasksViewState> {
|
|||
componentDidMount(): void {
|
||||
this.supervisorQueryManager = new QueryManager({
|
||||
processQuery: async (query: string) => {
|
||||
const resp = await axios.get("/druid/indexer/v1/supervisor?full")
|
||||
const resp = await axios.get("/druid/indexer/v1/supervisor?full");
|
||||
return resp.data;
|
||||
},
|
||||
onStateChange: ({ result, loading, error }) => {
|
||||
|
@ -299,7 +301,7 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
|||
data={supervisors || []}
|
||||
loading={supervisorsLoading}
|
||||
noDataText={!supervisorsLoading && supervisors && !supervisors.length ? 'No supervisors' : (supervisorsError || '')}
|
||||
filterable={true}
|
||||
filterable
|
||||
columns={[
|
||||
{
|
||||
Header: "Datasource",
|
||||
|
@ -338,7 +340,9 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
|||
return <span>
|
||||
<span
|
||||
style={{ color: value === 'Suspended' ? '#d58512' : '#2167d5' }}
|
||||
>● </span>
|
||||
>
|
||||
●
|
||||
</span>
|
||||
{value}
|
||||
</span>;
|
||||
}
|
||||
|
@ -363,7 +367,7 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
|||
{suspendResume}
|
||||
<a onClick={() => this.setState({ resetSupervisorId: id })}>Reset</a>
|
||||
<a onClick={() => this.setState({ terminateSupervisorId: id })}>Terminate</a>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
]}
|
||||
|
@ -413,7 +417,7 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
|||
data={tasks || []}
|
||||
loading={tasksLoading}
|
||||
noDataText={!tasksLoading && tasks && !tasks.length ? 'No tasks' : (tasksError || '')}
|
||||
filterable={true}
|
||||
filterable
|
||||
filtered={taskFilter}
|
||||
onFilteredChange={(filtered, column) => {
|
||||
this.setState({ taskFilter: filtered });
|
||||
|
@ -432,7 +436,7 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
|||
accessor: "type",
|
||||
Cell: row => {
|
||||
const value = row.value;
|
||||
return <a onClick={() => { this.setState({ taskFilter: addFilter(taskFilter, 'type', value) }) }}>{value}</a>
|
||||
return <a onClick={() => { this.setState({ taskFilter: addFilter(taskFilter, 'type', value) }); }}>{value}</a>;
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -440,7 +444,7 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
|||
accessor: "datasource",
|
||||
Cell: row => {
|
||||
const value = row.value;
|
||||
return <a onClick={() => { this.setState({ taskFilter: addFilter(taskFilter, 'datasource', value) }) }}>{value}</a>
|
||||
return <a onClick={() => { this.setState({ taskFilter: addFilter(taskFilter, 'datasource', value) }); }}>{value}</a>;
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -462,10 +466,12 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
|||
return <span>
|
||||
<span
|
||||
style={{ color: statusToColor(status) }}
|
||||
>● </span>
|
||||
{ status }
|
||||
{ location && <a onClick={() => goToMiddleManager(locationHostname)} title={`Go to: ${locationHostname}`}> ➚</a> }
|
||||
{ errorMsg && <a onClick={() => this.setState({ alertErrorMsg: errorMsg })} title={errorMsg}> ?</a> }
|
||||
>
|
||||
●
|
||||
</span>
|
||||
{status}
|
||||
{location && <a onClick={() => goToMiddleManager(locationHostname)} title={`Go to: ${locationHostname}`}> ➚</a>}
|
||||
{errorMsg && <a onClick={() => this.setState({ alertErrorMsg: errorMsg })} title={errorMsg}> ?</a>}
|
||||
</span>;
|
||||
},
|
||||
PivotValue: (opt) => {
|
||||
|
@ -503,8 +509,8 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
|||
<a href={`/druid/indexer/v1/task/${id}/reports`} target="_blank">Reports</a>
|
||||
<a href={`/druid/indexer/v1/task/${id}/log`} target="_blank">Log (all)</a>
|
||||
<a href={`/druid/indexer/v1/task/${id}/log?offset=-8192`} target="_blank">Log (last 8kb)</a>
|
||||
{ (status === 'RUNNING' || status === 'WAITING' || status === 'PENDING') && <a onClick={() => this.setState({ killTaskId: id })}>Kill</a> }
|
||||
</div>
|
||||
{(status === 'RUNNING' || status === 'WAITING' || status === 'PENDING') && <a onClick={() => this.setState({ killTaskId: id })}>Kill</a>}
|
||||
</div>;
|
||||
},
|
||||
Aggregated: row => ''
|
||||
}
|
||||
|
@ -583,7 +589,6 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
|||
>
|
||||
<p>{alertErrorMsg}</p>
|
||||
</Alert>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
{
|
||||
"extends": [
|
||||
"tslint:recommended",
|
||||
"tslint-react"
|
||||
],
|
||||
"rules": {
|
||||
"align": true,
|
||||
"array-type": [true, "array"],
|
||||
"arrow-parens": false,
|
||||
"ban": [false,
|
||||
["_", "extend"],
|
||||
["_", "isNull"],
|
||||
["_", "isDefined"]
|
||||
],
|
||||
"comment-format": [false,
|
||||
"check-space"
|
||||
],
|
||||
"curly": [true, "ignore-same-line"],
|
||||
"file-header": [true, "Licensed to the Apache Software Foundation \\(ASF\\).+"],
|
||||
"forin": false,
|
||||
"indent": [true, "spaces", 2],
|
||||
"interface-name": [true, "never-prefix"],
|
||||
"jsdoc-format": true,
|
||||
"label-position": true,
|
||||
"max-line-length": [true, 200],
|
||||
"max-classes-per-file": false,
|
||||
"member-access": false,
|
||||
"member-ordering": [true,
|
||||
{
|
||||
"order": [
|
||||
"static-field",
|
||||
"static-method",
|
||||
"instance-field",
|
||||
"constructor",
|
||||
"instance-method"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-any": false,
|
||||
"no-arg": true,
|
||||
"no-console": [true,
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-empty": [true, "allow-empty-catch"],
|
||||
"no-empty-interface": false,
|
||||
"no-eval": true,
|
||||
"no-inferrable-types": true,
|
||||
"no-null-keyword": false,
|
||||
"no-parameter-properties": true,
|
||||
"no-require-imports": false,
|
||||
"no-shadowed-variable": false,
|
||||
"no-string-literal": false,
|
||||
"no-switch-case-fall-through": false,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unused-expression": false,
|
||||
"no-use-before-declare": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [true,
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-finally",
|
||||
"check-open-brace",
|
||||
"check-whitespace"
|
||||
],
|
||||
"ordered-imports": [
|
||||
true,
|
||||
{
|
||||
"import-sources-order": "case-insensitive",
|
||||
"grouped-imports": true,
|
||||
"groups": [
|
||||
{ "name": "parent directories", "match": "^\\.\\.", "order": 20 },
|
||||
{ "name": "styles", "match": ".scss$", "order": 40 },
|
||||
{ "name": "current directory", "match": "^\\.", "order": 30 },
|
||||
{ "name": "libraries", "match": ".*", "order": 10 }
|
||||
]
|
||||
}
|
||||
],
|
||||
"prefer-const": [true, {"destructuring": "all"}],
|
||||
"quotemark": [false, "double", "jsx-double", "avoid-escape"],
|
||||
"semicolon": true,
|
||||
"switch-default": false,
|
||||
"trailing-comma": [true, {
|
||||
"singleline": "never",
|
||||
"multiline": "never"
|
||||
}],
|
||||
"triple-equals": [true, "allow-null-check"],
|
||||
"typedef": false,
|
||||
"typedef-whitespace": [true, {
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}, {
|
||||
"call-signature": "onespace",
|
||||
"index-signature": "onespace",
|
||||
"parameter": "onespace",
|
||||
"property-declaration": "onespace",
|
||||
"variable-declaration": "onespace"
|
||||
}],
|
||||
"variable-name": false,
|
||||
"whitespace": [true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-module",
|
||||
"check-separator",
|
||||
"check-type",
|
||||
"check-type-operator"
|
||||
],
|
||||
"jsx-alignment": true,
|
||||
"jsx-boolean-value": [true, "never"],
|
||||
"jsx-curly-spacing": [true, "never"],
|
||||
"jsx-no-lambda": false,
|
||||
"jsx-no-multiline-js": false,
|
||||
"jsx-no-string-ref": true,
|
||||
"jsx-self-close": true,
|
||||
"jsx-space-before-trailing-slash": false,
|
||||
"jsx-wrap-multiline": false
|
||||
}
|
||||
}
|
|
@ -50,6 +50,20 @@ module.exports = (env) => {
|
|||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
enforce: 'pre',
|
||||
use: [
|
||||
{
|
||||
loader: 'tslint-loader',
|
||||
options: {
|
||||
configFile: 'tslint.json',
|
||||
emitErrors: true,
|
||||
fix: false // Set this to true to auto fix errors
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
|
|
Loading…
Reference in New Issue