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"
|
"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": {
|
"babel-jest": {
|
||||||
"version": "24.1.0",
|
"version": "24.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.1.0.tgz",
|
||||||
|
@ -1372,6 +1431,12 @@
|
||||||
"integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
|
"integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
|
||||||
"dev": true
|
"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": {
|
"builtin-status-codes": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
|
||||||
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ=="
|
"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": {
|
"tty-browserify": {
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
|
||||||
|
|
|
@ -70,6 +70,9 @@
|
||||||
"ts-jest": "^23.10.5",
|
"ts-jest": "^23.10.5",
|
||||||
"ts-loader": "^5.3.3",
|
"ts-loader": "^5.3.3",
|
||||||
"ts-node": "^8.0.2",
|
"ts-node": "^8.0.2",
|
||||||
|
"tslint": "^5.14.0",
|
||||||
|
"tslint-loader": "^3.5.4",
|
||||||
|
"tslint-react": "^3.6.0",
|
||||||
"typescript": "^3.2.4",
|
"typescript": "^3.2.4",
|
||||||
"webpack": "^4.29.0",
|
"webpack": "^4.29.0",
|
||||||
"webpack-cli": "^3.2.1",
|
"webpack-cli": "^3.2.1",
|
||||||
|
|
|
@ -21,8 +21,35 @@ writefile='lib/sql-function-doc.ts'
|
||||||
|
|
||||||
> "$writefile"
|
> "$writefile"
|
||||||
|
|
||||||
echo -e "// This file is auto generated and should not be modified\n" > "$writefile"
|
cat > "$writefile" <<- EOM
|
||||||
echo -e 'export const SQLFunctionDoc: any[] = [' >> "$writefile"
|
/*
|
||||||
|
* 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
|
isFunction=false
|
||||||
|
|
||||||
|
@ -47,4 +74,4 @@ while read -r line; do
|
||||||
fi
|
fi
|
||||||
done < "$readfile"
|
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.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Button } from "@blueprintjs/core";
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Filter, ReactTableDefaults } from "react-table";
|
import { Filter, ReactTableDefaults } from "react-table";
|
||||||
import { Button } from "@blueprintjs/core";
|
|
||||||
import { Loader } from '../components/loader';
|
import { Loader } from '../components/loader';
|
||||||
import { countBy, makeTextFilter } from '../utils';
|
import { countBy, makeTextFilter } from '../utils';
|
||||||
|
|
|
@ -16,11 +16,10 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { resolveSrv } from 'dns';
|
|
||||||
import * as React from 'react';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { InputGroup } from "@blueprintjs/core";
|
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 {
|
interface Field {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -31,8 +30,8 @@ interface Field {
|
||||||
|
|
||||||
export interface AutoFormProps<T> extends React.Props<any> {
|
export interface AutoFormProps<T> extends React.Props<any> {
|
||||||
fields: Field[];
|
fields: Field[];
|
||||||
model: T | null,
|
model: T | null;
|
||||||
onChange: (newValue: T) => void
|
onChange: (newValue: T) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AutoFormState<T> {
|
export interface AutoFormState<T> {
|
||||||
|
@ -48,7 +47,7 @@ export class AutoForm<T> extends React.Component<AutoFormProps<T>, AutoFormState
|
||||||
constructor(props: AutoFormProps<T>) {
|
constructor(props: AutoFormProps<T>) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderNumberInput(field: Field): JSX.Element {
|
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="True">True</option>
|
||||||
<option value="False">False</option>
|
<option value="False">False</option>
|
||||||
</HTMLSelect>
|
</HTMLSelect>;
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderStringArrayInput(field: Field): JSX.Element {
|
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);
|
const label = field.label || AutoForm.makeLabelName(field.name);
|
||||||
return <FormGroup label={label} key={field.name}>
|
return <FormGroup label={label} key={field.name}>
|
||||||
{this.renderFieldInput(field)}
|
{this.renderFieldInput(field)}
|
||||||
</FormGroup>
|
</FormGroup>;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -135,6 +134,6 @@ export class AutoForm<T> extends React.Component<AutoFormProps<T>, AutoFormState
|
||||||
|
|
||||||
return <div className="auto-form">
|
return <div className="auto-form">
|
||||||
{model && fields.map(field => this.renderField(field))}
|
{model && fields.map(field => this.renderField(field))}
|
||||||
</div>
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Button } from '@blueprintjs/core';
|
import { Button } from '@blueprintjs/core';
|
||||||
import * as React from 'react';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import './filler.scss';
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import './filler.scss';
|
||||||
|
|
||||||
export const IconNames = {
|
export const IconNames = {
|
||||||
ERROR: "error" as "error",
|
ERROR: "error" as "error",
|
||||||
|
@ -109,10 +109,9 @@ export class FormGroup extends React.Component<{ className?: string, label?: str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const Alignment = {
|
export const Alignment = {
|
||||||
LEFT: "left" as "left",
|
LEFT: "left" as "left",
|
||||||
RIGHT: "right" as "right",
|
RIGHT: "right" as "right"
|
||||||
};
|
};
|
||||||
export type Alignment = typeof Alignment[keyof typeof Alignment];
|
export type Alignment = typeof Alignment[keyof typeof Alignment];
|
||||||
|
|
||||||
|
@ -166,7 +165,7 @@ export interface NumericInputProps {
|
||||||
min?: number;
|
min?: number;
|
||||||
max?: number;
|
max?: number;
|
||||||
stepSize?: number;
|
stepSize?: number;
|
||||||
majorStepSize?: number
|
majorStepSize?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NumericInput extends React.Component<NumericInputProps, { stringValue: string }> {
|
export class NumericInput extends React.Component<NumericInputProps, { stringValue: string }> {
|
||||||
|
@ -174,20 +173,20 @@ export class NumericInput extends React.Component<NumericInputProps, { stringVal
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
stepSize: 1,
|
stepSize: 1,
|
||||||
majorStepSize: 10
|
majorStepSize: 10
|
||||||
}
|
};
|
||||||
|
|
||||||
constructor(props: NumericInputProps) {
|
constructor(props: NumericInputProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
stringValue: typeof props.value === 'number' ? String(props.value) : ''
|
stringValue: typeof props.value === 'number' ? String(props.value) : ''
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private constrain(n: number): number {
|
private constrain(n: number): number {
|
||||||
const { min, max } = this.props;
|
const { min, max } = this.props;
|
||||||
if (typeof min === 'number') n = Math.max(n, min);
|
if (typeof min === 'number') n = Math.max(n, min);
|
||||||
if (typeof max === 'number') n = Math.min(n, max);
|
if (typeof max === 'number') n = Math.min(n, max);
|
||||||
return n
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleChange = (e: any) => {
|
private handleChange = (e: any) => {
|
||||||
|
@ -236,13 +235,13 @@ export class TagInput extends React.Component<TagInputProps, { stringValue: stri
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
stringValue: Array.isArray(props.values) ? props.values.join(', ') : ''
|
stringValue: Array.isArray(props.values) ? props.values.join(', ') : ''
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChange = (e: any) => {
|
handleChange = (e: any) => {
|
||||||
let stringValue = e.target.value;
|
const stringValue = e.target.value;
|
||||||
let newValues = stringValue.split(',').map((v: string) => v.trim());
|
const newValues = stringValue.split(',').map((v: string) => v.trim());
|
||||||
let newValuesFiltered = newValues.filter(Boolean);
|
const newValuesFiltered = newValues.filter(Boolean);
|
||||||
this.setState({
|
this.setState({
|
||||||
stringValue: newValues.length === newValuesFiltered.length ? newValues.join(', ') : stringValue
|
stringValue: newValues.length === newValuesFiltered.length ? newValues.join(', ') : stringValue
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,13 +16,13 @@
|
||||||
* limitations under the License.
|
* 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 classNames from 'classnames';
|
||||||
import { Button, Classes, AnchorButton, Popover, Position, Menu, MenuItem } from "@blueprintjs/core";
|
import * as React from 'react';
|
||||||
import { IconNames, NavbarGroup, Alignment, NavbarDivider, Navbar } from "../components/filler";
|
|
||||||
|
import { Alignment, IconNames, Navbar, NavbarDivider, NavbarGroup } from "../components/filler";
|
||||||
import { AboutDialog } from "../dialogs/about-dialog";
|
import { AboutDialog } from "../dialogs/about-dialog";
|
||||||
import { CoordinatorDynamicConfigDialog } from '../dialogs/coordinator-dynamic-config';
|
import { CoordinatorDynamicConfigDialog } from '../dialogs/coordinator-dynamic-config';
|
||||||
import "./header-bar.scss";
|
|
||||||
import {
|
import {
|
||||||
DRUID_DOCS,
|
DRUID_DOCS,
|
||||||
DRUID_GITHUB,
|
DRUID_GITHUB,
|
||||||
|
@ -31,6 +31,8 @@ import {
|
||||||
LEGACY_OVERLORD_CONSOLE
|
LEGACY_OVERLORD_CONSOLE
|
||||||
} from '../variables';
|
} from '../variables';
|
||||||
|
|
||||||
|
import "./header-bar.scss";
|
||||||
|
|
||||||
export type HeaderActiveTab = null | 'datasources' | 'segments' | 'tasks' | 'servers' | 'sql' | 'lookups';
|
export type HeaderActiveTab = null | 'datasources' | 'segments' | 'tasks' | 'servers' | 'sql' | 'lookups';
|
||||||
|
|
||||||
export interface HeaderBarProps extends React.Props<any> {
|
export interface HeaderBarProps extends React.Props<any> {
|
||||||
|
@ -54,30 +56,48 @@ export class HeaderBar extends React.Component<HeaderBarProps, HeaderBarState> {
|
||||||
renderLogo() {
|
renderLogo() {
|
||||||
return <div className="logo">
|
return <div className="logo">
|
||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 288 134">
|
<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
|
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
|
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"/>
|
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
|
/>
|
||||||
|
<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
|
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"/>
|
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
|
/>
|
||||||
|
<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
|
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"/>
|
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
|
/>
|
||||||
|
<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
|
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"/>
|
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
|
/>
|
||||||
|
<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
|
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
|
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"/>
|
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
|
/>
|
||||||
|
<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
|
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
|
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.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
|
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
|
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>
|
</svg>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import './loader.scss';
|
import './loader.scss';
|
||||||
|
|
||||||
export interface LoaderProps extends React.Props<any> {
|
export interface LoaderProps extends React.Props<any> {
|
||||||
|
@ -31,23 +32,35 @@ export class Loader extends React.Component<LoaderProps, LoaderState> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { loadingText, loading } = this.props;
|
const { loadingText, loading } = this.props;
|
||||||
if (loading === false) return null;
|
if (!loading) return null;
|
||||||
|
|
||||||
return <div className="loader">
|
return <div className="loader">
|
||||||
<div className="loader-logo">
|
<div className="loader-logo">
|
||||||
<svg viewBox="0 0 100 100">
|
<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-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"/>
|
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
|
/>
|
||||||
|
<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
|
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"/>
|
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
|
<path
|
||||||
C46.4,69.2,45.8,69.8,45.1,69.8z"/>
|
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>
|
</svg>
|
||||||
{loadingText ? <div className="label">{loadingText}</div> : null}
|
{loadingText ? <div className="label">{loadingText}</div> : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,12 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from 'react';
|
import { Button, Collapse, InputGroup } from "@blueprintjs/core";
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { Button, InputGroup, Collapse } from "@blueprintjs/core";
|
import * as React from 'react';
|
||||||
import { IconNames, FormGroup, HTMLSelect, Card, ControlGroup, NumericInput, TagInput } from "../components/filler";
|
|
||||||
|
import { Card, ControlGroup, FormGroup, HTMLSelect, IconNames, NumericInput, TagInput } from "../components/filler";
|
||||||
|
|
||||||
import './rule-editor.scss';
|
import './rule-editor.scss';
|
||||||
|
|
||||||
export interface Rule {
|
export interface Rule {
|
||||||
|
@ -107,7 +109,7 @@ export class RuleEditor extends React.Component<RuleEditorProps, RuleEditorState
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
isOpen: true
|
isOpen: true
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private removeTier = (key: string) => {
|
private removeTier = (key: string) => {
|
||||||
|
@ -126,9 +128,9 @@ export class RuleEditor extends React.Component<RuleEditorProps, RuleEditorState
|
||||||
let newTierName = tiers[0];
|
let newTierName = tiers[0];
|
||||||
|
|
||||||
if (rule.tieredReplicants) {
|
if (rule.tieredReplicants) {
|
||||||
for (let i = 0; i < tiers.length; i++) {
|
for (const tier of tiers) {
|
||||||
if (rule.tieredReplicants[tiers[i]] === undefined) {
|
if (rule.tieredReplicants[tier] === undefined) {
|
||||||
newTierName = tiers[i];
|
newTierName = tier;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,7 +162,7 @@ export class RuleEditor extends React.Component<RuleEditorProps, RuleEditorState
|
||||||
/>
|
/>
|
||||||
<Button className="pt-minimal" style={{pointerEvents: 'none'}}>Tier:</Button>
|
<Button className="pt-minimal" style={{pointerEvents: 'none'}}>Tier:</Button>
|
||||||
<HTMLSelect
|
<HTMLSelect
|
||||||
fill={true}
|
fill
|
||||||
value={tier}
|
value={tier}
|
||||||
onChange={(e: any) => onChange(RuleEditor.changeTier(rule, tier, e.target.value))}
|
onChange={(e: any) => onChange(RuleEditor.changeTier(rule, tier, e.target.value))}
|
||||||
>
|
>
|
||||||
|
|
|
@ -16,22 +16,25 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from 'react';
|
import { Button, Checkbox, Classes, Intent, Popover, Position } from "@blueprintjs/core";
|
||||||
import * as ReactDOMServer from 'react-dom/server';
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import * as classNames from 'classnames';
|
import * as ace from 'brace';
|
||||||
import * as ace from 'brace'
|
|
||||||
import AceEditor from "react-ace";
|
|
||||||
import 'brace/mode/sql';
|
|
||||||
import 'brace/mode/hjson';
|
|
||||||
import 'brace/theme/solarized_dark';
|
|
||||||
import 'brace/ext/language_tools';
|
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 { SQLFunctionDoc } from "../../lib/sql-function-doc";
|
||||||
import { IconNames } from './filler';
|
|
||||||
import './sql-control.scss'
|
|
||||||
import { AppToaster } from "../singletons/toaster";
|
import { AppToaster } from "../singletons/toaster";
|
||||||
|
|
||||||
|
import { IconNames } from './filler';
|
||||||
|
|
||||||
|
import './sql-control.scss';
|
||||||
|
|
||||||
const langTools = ace.acequire('ace/ext/language_tools');
|
const langTools = ace.acequire('ace/ext/language_tools');
|
||||||
|
|
||||||
export interface SqlControlProps extends React.Props<any> {
|
export interface SqlControlProps extends React.Props<any> {
|
||||||
|
@ -55,9 +58,8 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private addDatasourceAutoCompleter = async (): Promise<any> => {
|
private addDatasourceAutoCompleter = async (): Promise<any> => {
|
||||||
const datasourceResp = await axios.post("/druid/v2/sql", { query: `SELECT datasource FROM sys.segments GROUP BY 1`})
|
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 datasourceList: any[] = datasourceResp.data.map((d: any) => {
|
||||||
const datasourceName: string = d.datasource;
|
const datasourceName: string = d.datasource;
|
||||||
return {
|
return {
|
||||||
|
@ -77,7 +79,7 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
||||||
}
|
}
|
||||||
|
|
||||||
private addColumnNameAutoCompleter = async (): Promise<any> => {
|
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 columnNameList: any[] = columnNameResp.data.map((d: any) => {
|
||||||
const columnName: string = d.COLUMN_NAME;
|
const columnName: string = d.COLUMN_NAME;
|
||||||
return {
|
return {
|
||||||
|
@ -133,7 +135,7 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
||||||
<div><b>Description:</b></div>
|
<div><b>Description:</b></div>
|
||||||
<div>{item.description}</div>
|
<div>{item.description}</div>
|
||||||
</div>
|
</div>
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -160,7 +162,7 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
||||||
private handleChange = (newValue: string): void => {
|
private handleChange = (newValue: string): void => {
|
||||||
this.setState({
|
this.setState({
|
||||||
query: newValue
|
query: newValue
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -186,7 +188,7 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
||||||
theme="solarized_dark"
|
theme="solarized_dark"
|
||||||
name="ace-editor"
|
name="ace-editor"
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
focus={true}
|
focus
|
||||||
fontSize={14}
|
fontSize={14}
|
||||||
width={'100%'}
|
width={'100%'}
|
||||||
height={"30vh"}
|
height={"30vh"}
|
||||||
|
@ -199,7 +201,7 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
||||||
enableBasicAutocompletion: isRune ? false : autoCompleteOn,
|
enableBasicAutocompletion: isRune ? false : autoCompleteOn,
|
||||||
enableLiveAutocompletion: isRune ? false : autoCompleteOn,
|
enableLiveAutocompletion: isRune ? false : autoCompleteOn,
|
||||||
showLineNumbers: true,
|
showLineNumbers: true,
|
||||||
tabSize: 2,
|
tabSize: 2
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="buttons">
|
<div className="buttons">
|
||||||
|
@ -213,4 +215,3 @@ export class SqlControl extends React.Component<SqlControlProps, SqlControlState
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,22 +16,23 @@
|
||||||
* limitations under the License.
|
* 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 { 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 { 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 { DRUID_DOCS_SQL, LEGACY_COORDINATOR_CONSOLE, LEGACY_OVERLORD_CONSOLE } from './variables';
|
||||||
import { HomeView } from './views/home-view';
|
|
||||||
import { DatasourcesView } from './views/datasource-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 { SegmentsView } from './views/segments-view';
|
||||||
import { ServersView } from './views/servers-view';
|
import { ServersView } from './views/servers-view';
|
||||||
import { TasksView } from './views/tasks-view';
|
|
||||||
import { SqlView } from './views/sql-view';
|
import { SqlView } from './views/sql-view';
|
||||||
import { LookupsView } from "./views/lookups-view";
|
import { TasksView } from './views/tasks-view';
|
||||||
|
|
||||||
import "./console-application.scss";
|
import "./console-application.scss";
|
||||||
|
|
||||||
export interface ConsoleApplicationProps extends React.Props<any> {
|
export interface ConsoleApplicationProps extends React.Props<any> {
|
||||||
|
@ -63,14 +64,16 @@ export class ConsoleApplication extends React.Component<ConsoleApplicationProps,
|
||||||
iconName: 'error',
|
iconName: 'error',
|
||||||
intent: Intent.DANGER,
|
intent: Intent.DANGER,
|
||||||
timeout: 120000,
|
timeout: 120000,
|
||||||
|
/* tslint:disable:jsx-alignment */
|
||||||
message: <>
|
message: <>
|
||||||
It appears that the SQL endpoint is disabled. Either <a
|
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={DRUID_DOCS_SQL}>enable the SQL endpoint</a> or use the old <a
|
||||||
href={LEGACY_COORDINATOR_CONSOLE}>coordinator</a> and <a
|
href={LEGACY_COORDINATOR_CONSOLE}>coordinator</a> and <a
|
||||||
href={LEGACY_OVERLORD_CONSOLE}>overlord</a> consoles that do not rely on the SQL endpoint.
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -142,30 +145,49 @@ export class ConsoleApplication extends React.Component<ConsoleApplicationProps,
|
||||||
return <HashRouter hashType="noslash">
|
return <HashRouter hashType="noslash">
|
||||||
<div className="console-application">
|
<div className="console-application">
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/datasources" component={() => {
|
<Route
|
||||||
|
path="/datasources"
|
||||||
|
component={() => {
|
||||||
return wrapInViewContainer('datasources', <DatasourcesView goToSql={this.goToSql} goToSegments={this.goToSegments}/>);
|
return wrapInViewContainer('datasources', <DatasourcesView goToSql={this.goToSql} goToSegments={this.goToSegments}/>);
|
||||||
}} />
|
}}
|
||||||
<Route path="/segments" component={() => {
|
/>
|
||||||
|
<Route
|
||||||
|
path="/segments"
|
||||||
|
component={() => {
|
||||||
return wrapInViewContainer('segments', <SegmentsView datasource={this.datasource} onlyUnavailable={this.onlyUnavailable} goToSql={this.goToSql}/>);
|
return wrapInViewContainer('segments', <SegmentsView datasource={this.datasource} onlyUnavailable={this.onlyUnavailable} goToSql={this.goToSql}/>);
|
||||||
}} />
|
}}
|
||||||
<Route path="/tasks" component={() => {
|
/>
|
||||||
|
<Route
|
||||||
|
path="/tasks"
|
||||||
|
component={() => {
|
||||||
return wrapInViewContainer('tasks', <TasksView taskId={this.taskId} goToSql={this.goToSql} goToMiddleManager={this.goToMiddleManager}/>, true);
|
return wrapInViewContainer('tasks', <TasksView taskId={this.taskId} goToSql={this.goToSql} goToMiddleManager={this.goToMiddleManager}/>, true);
|
||||||
}} />
|
}}
|
||||||
<Route path="/servers" component={() => {
|
/>
|
||||||
|
<Route
|
||||||
|
path="/servers"
|
||||||
|
component={() => {
|
||||||
return wrapInViewContainer('servers', <ServersView middleManager={this.middleManager} goToSql={this.goToSql} goToTask={this.goToTask}/>, true);
|
return wrapInViewContainer('servers', <ServersView middleManager={this.middleManager} goToSql={this.goToSql} goToTask={this.goToTask}/>, true);
|
||||||
}} />
|
}}
|
||||||
<Route path="/sql" component={() => {
|
/>
|
||||||
|
<Route
|
||||||
|
path="/sql"
|
||||||
|
component={() => {
|
||||||
return wrapInViewContainer('sql', <SqlView initSql={this.initSql}/>);
|
return wrapInViewContainer('sql', <SqlView initSql={this.initSql}/>);
|
||||||
}} />
|
}}
|
||||||
<Route path="/lookups" component={() => {
|
/>
|
||||||
|
<Route
|
||||||
|
path="/lookups"
|
||||||
|
component={() => {
|
||||||
return wrapInViewContainer('lookups', <LookupsView />);
|
return wrapInViewContainer('lookups', <LookupsView />);
|
||||||
}} />
|
}}
|
||||||
<Route component={() => {
|
/>
|
||||||
return wrapInViewContainer(null, <HomeView/>)
|
<Route
|
||||||
}} />
|
component={() => {
|
||||||
|
return wrapInViewContainer(null, <HomeView/>);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
</HashRouter>;
|
</HashRouter>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,13 +16,14 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { AnchorButton, Button, Classes, Dialog, Intent } from "@blueprintjs/core";
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Button, Dialog, Classes, AnchorButton, Intent } from "@blueprintjs/core";
|
|
||||||
import { IconNames } from "../components/filler";
|
import { IconNames } from "../components/filler";
|
||||||
import { DRUID_COMMUNITY, DRUID_DEVELOPER_GROUP, DRUID_USER_GROUP, DRUID_WEBSITE } from '../variables';
|
import { DRUID_COMMUNITY, DRUID_DEVELOPER_GROUP, DRUID_USER_GROUP, DRUID_WEBSITE } from '../variables';
|
||||||
|
|
||||||
export interface AboutDialogProps extends React.Props<any> {
|
export interface AboutDialogProps extends React.Props<any> {
|
||||||
onClose: () => void
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AboutDialogState {
|
export interface AboutDialogState {
|
||||||
|
@ -37,6 +38,7 @@ export class AboutDialog extends React.Component<AboutDialogProps, AboutDialogSt
|
||||||
render() {
|
render() {
|
||||||
const { onClose } = this.props;
|
const { onClose } = this.props;
|
||||||
|
|
||||||
|
/* tslint:disable:jsx-alignment */
|
||||||
return <Dialog
|
return <Dialog
|
||||||
iconName={IconNames.GRAPH}
|
iconName={IconNames.GRAPH}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
|
@ -75,5 +77,6 @@ export class AboutDialog extends React.Component<AboutDialogProps, AboutDialogSt
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>;
|
</Dialog>;
|
||||||
|
/* tslint:enable:jsx-alignment */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,25 +16,25 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import * as React from 'react';
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
InputGroup,
|
|
||||||
Dialog,
|
|
||||||
Classes,
|
Classes,
|
||||||
|
Dialog,
|
||||||
Intent,
|
Intent,
|
||||||
ProgressBar
|
ProgressBar
|
||||||
} from "@blueprintjs/core";
|
} 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';
|
import { AppToaster } from '../singletons/toaster';
|
||||||
|
|
||||||
export interface AsyncAlertDialogProps extends React.Props<any> {
|
export interface AsyncAlertDialogProps extends React.Props<any> {
|
||||||
action: null | (() => Promise<void>),
|
action: null | (() => Promise<void>);
|
||||||
onClose: (success: boolean) => void,
|
onClose: (success: boolean) => void;
|
||||||
confirmButtonText: string;
|
confirmButtonText: string;
|
||||||
cancelButtonText?: string;
|
cancelButtonText?: string;
|
||||||
className?: string,
|
className?: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
intent?: Intent;
|
intent?: Intent;
|
||||||
successText: string;
|
successText: string;
|
||||||
|
@ -42,7 +42,7 @@ export interface AsyncAlertDialogProps extends React.Props<any> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AsyncAlertDialogState {
|
export interface AsyncAlertDialogState {
|
||||||
working: boolean
|
working: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AsyncActionDialog extends React.Component<AsyncAlertDialogProps, AsyncAlertDialogState> {
|
export class AsyncActionDialog extends React.Component<AsyncAlertDialogProps, AsyncAlertDialogState> {
|
||||||
|
@ -59,7 +59,7 @@ export class AsyncActionDialog extends React.Component<AsyncAlertDialogProps, As
|
||||||
|
|
||||||
this.setState({ working: true });
|
this.setState({ working: true });
|
||||||
try {
|
try {
|
||||||
await action()
|
await action();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
AppToaster.show({
|
AppToaster.show({
|
||||||
message: `${failText}: ${e.message}`,
|
message: `${failText}: ${e.message}`,
|
||||||
|
@ -103,6 +103,6 @@ export class AsyncActionDialog extends React.Component<AsyncAlertDialogProps, As
|
||||||
<Button text={cancelButtonText || 'Cancel'} onClick={handleClose}/>
|
<Button text={cancelButtonText || 'Cancel'} onClick={handleClose}/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</Dialog>
|
</Dialog>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,17 +17,20 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Intent } from '@blueprintjs/core';
|
import { Intent } from '@blueprintjs/core';
|
||||||
import * as React from 'react';
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { AppToaster } from '../singletons/toaster';
|
import * as React from 'react';
|
||||||
import { IconNames } from '../components/filler';
|
|
||||||
import { AutoForm } from '../components/auto-form';
|
import { AutoForm } from '../components/auto-form';
|
||||||
|
import { IconNames } from '../components/filler';
|
||||||
|
import { AppToaster } from '../singletons/toaster';
|
||||||
import { getDruidErrorMessage } from '../utils';
|
import { getDruidErrorMessage } from '../utils';
|
||||||
|
|
||||||
import { SnitchDialog } from './snitch-dialog';
|
import { SnitchDialog } from './snitch-dialog';
|
||||||
|
|
||||||
import './coordinator-dynamic-config.scss';
|
import './coordinator-dynamic-config.scss';
|
||||||
|
|
||||||
export interface CoordinatorDynamicConfigDialogProps extends React.Props<any> {
|
export interface CoordinatorDynamicConfigDialogProps extends React.Props<any> {
|
||||||
onClose: () => void
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CoordinatorDynamicConfigDialogState {
|
export interface CoordinatorDynamicConfigDialogState {
|
||||||
|
@ -39,7 +42,7 @@ export class CoordinatorDynamicConfigDialog extends React.Component<CoordinatorD
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
dynamicConfig: null
|
dynamicConfig: null
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
|
@ -50,7 +53,7 @@ export class CoordinatorDynamicConfigDialog extends React.Component<CoordinatorD
|
||||||
let config: Record<string, any> | null = null;
|
let config: Record<string, any> | null = null;
|
||||||
try {
|
try {
|
||||||
const configResp = await axios.get("/druid/coordinator/v1/config");
|
const configResp = await axios.get("/druid/coordinator/v1/config");
|
||||||
config = configResp.data
|
config = configResp.data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
AppToaster.show({
|
AppToaster.show({
|
||||||
iconName: IconNames.ERROR,
|
iconName: IconNames.ERROR,
|
||||||
|
@ -66,7 +69,7 @@ export class CoordinatorDynamicConfigDialog extends React.Component<CoordinatorD
|
||||||
|
|
||||||
private saveClusterConfig = async (author: string, comment: string) => {
|
private saveClusterConfig = async (author: string, comment: string) => {
|
||||||
const { onClose } = this.props;
|
const { onClose } = this.props;
|
||||||
let newState: any = this.state.dynamicConfig;
|
const newState: any = this.state.dynamicConfig;
|
||||||
try {
|
try {
|
||||||
await axios.post("/druid/coordinator/v1/config", newState, {
|
await axios.post("/druid/coordinator/v1/config", newState, {
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -158,6 +161,6 @@ export class CoordinatorDynamicConfigDialog extends React.Component<CoordinatorD
|
||||||
model={dynamicConfig}
|
model={dynamicConfig}
|
||||||
onChange={m => this.setState({ dynamicConfig: m })}
|
onChange={m => this.setState({ dynamicConfig: m })}
|
||||||
/>
|
/>
|
||||||
</SnitchDialog>
|
</SnitchDialog>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,24 +16,26 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Button, Classes, Dialog, InputGroup, Intent } from "@blueprintjs/core";
|
||||||
import * as React from "react";
|
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 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> {
|
export interface LookupEditDialogProps extends React.Props<any> {
|
||||||
isOpen: boolean,
|
isOpen: boolean;
|
||||||
onClose: () => void,
|
onClose: () => void;
|
||||||
onSubmit: () => void,
|
onSubmit: () => void;
|
||||||
onChange: (field: string, value: string) => void
|
onChange: (field: string, value: string) => void;
|
||||||
lookupName: string,
|
lookupName: string;
|
||||||
lookupTier: string,
|
lookupTier: string;
|
||||||
lookupVersion: string,
|
lookupVersion: string;
|
||||||
lookupSpec: string,
|
lookupSpec: string;
|
||||||
isEdit: boolean,
|
isEdit: boolean;
|
||||||
allLookupTiers: string[]
|
allLookupTiers: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LookupEditDialogState {
|
export interface LookupEditDialogState {
|
||||||
|
@ -45,7 +47,7 @@ export class LookupEditDialog extends React.Component<LookupEditDialogProps, Loo
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
|
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private addISOVersion = () => {
|
private addISOVersion = () => {
|
||||||
|
@ -62,21 +64,21 @@ export class LookupEditDialog extends React.Component<LookupEditDialogProps, Loo
|
||||||
<InputGroup
|
<InputGroup
|
||||||
value={lookupTier}
|
value={lookupTier}
|
||||||
onChange={(e: any) => onChange("lookupEditTier", e.target.value)}
|
onChange={(e: any) => onChange("lookupEditTier", e.target.value)}
|
||||||
disabled={true}
|
disabled
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>;
|
||||||
} else {
|
} else {
|
||||||
return <FormGroup className={"lookup-label"} label={"Tier:"}>
|
return <FormGroup className={"lookup-label"} label={"Tier:"}>
|
||||||
<div className="pt-select">
|
<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 => {
|
allLookupTiers.map(tier => {
|
||||||
return <option key={tier} value={tier}>{tier}</option>
|
return <option key={tier} value={tier}>{tier}</option>;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</FormGroup>
|
</FormGroup>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +133,7 @@ export class LookupEditDialog extends React.Component<LookupEditDialogProps, Loo
|
||||||
setOptions={{
|
setOptions={{
|
||||||
enableBasicAutocompletion: false,
|
enableBasicAutocompletion: false,
|
||||||
enableLiveAutocompletion: false,
|
enableLiveAutocompletion: false,
|
||||||
tabSize: 2,
|
tabSize: 2
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -16,17 +16,19 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from 'react';
|
|
||||||
import axios from 'axios';
|
|
||||||
import { Button } from "@blueprintjs/core";
|
import { Button } from "@blueprintjs/core";
|
||||||
|
import axios from 'axios';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
import { FormGroup, IconNames } from '../components/filler';
|
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 { SnitchDialog } from './snitch-dialog';
|
||||||
|
|
||||||
import './retention-dialog.scss';
|
import './retention-dialog.scss';
|
||||||
|
|
||||||
export function reorderArray<T>(items: T[], oldIndex: number, newIndex: number): T[] {
|
export function reorderArray<T>(items: T[], oldIndex: number, newIndex: number): T[] {
|
||||||
let newItems = items.concat();
|
const newItems = items.concat();
|
||||||
|
|
||||||
if (newIndex > oldIndex) newIndex--;
|
if (newIndex > oldIndex) newIndex--;
|
||||||
|
|
||||||
|
@ -111,7 +113,7 @@ export class RetentionDialog extends React.Component<RetentionDialogProps, Reten
|
||||||
onDelete={() => this.onDeleteRule(index)}
|
onDelete={() => this.onDeleteRule(index)}
|
||||||
moveUp={index > 0 ? () => this.moveRule(index, -1) : null}
|
moveUp={index > 0 ? () => this.moveRule(index, -1) : null}
|
||||||
moveDown={index < (currentRules || []).length - 1 ? () => this.moveRule(index, 2) : null}
|
moveDown={index < (currentRules || []).length - 1 ? () => this.moveRule(index, 2) : null}
|
||||||
/>
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
reset = () => {
|
reset = () => {
|
||||||
|
|
|
@ -16,17 +16,17 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from 'react';
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
InputGroup,
|
Classes,
|
||||||
Dialog,
|
Dialog,
|
||||||
IDialogProps,
|
IDialogProps,
|
||||||
Classes,
|
InputGroup,
|
||||||
Intent,
|
Intent
|
||||||
} from "@blueprintjs/core";
|
} 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 {
|
export interface SnitchDialogProps extends IDialogProps {
|
||||||
onSave: (author: string, comment: string) => void;
|
onSave: (author: string, comment: string) => void;
|
||||||
|
@ -50,7 +50,7 @@ export class SnitchDialog extends React.Component<SnitchDialogProps, SnitchDialo
|
||||||
comment: "",
|
comment: "",
|
||||||
author: "",
|
author: "",
|
||||||
saveDisabled: true
|
saveDisabled: true
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
save = () => {
|
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="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}/>
|
: <Button disabled={saveDisabled} text="Next" onClick={this.goToFinalStep} intent={Intent.PRIMARY as any} rightIconName={IconNames.ARROW_RIGHT}/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -16,12 +16,13 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { Button, Classes, Dialog, Intent } from "@blueprintjs/core";
|
import { Button, Classes, Dialog, Intent } from "@blueprintjs/core";
|
||||||
import "./spec-dialog.scss"
|
import "brace/mode/json";
|
||||||
import AceEditor from "react-ace";
|
|
||||||
import "brace/theme/solarized_dark";
|
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> {
|
export interface SpecDialogProps extends React.Props<any> {
|
||||||
onSubmit: (spec: JSON) => void;
|
onSubmit: (spec: JSON) => void;
|
||||||
|
@ -47,7 +48,7 @@ export class SpecDialog extends React.Component<SpecDialogProps, SpecDialogState
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
spec: ""
|
spec: ""
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private postSpec(): void {
|
private postSpec(): void {
|
||||||
|
@ -72,11 +73,11 @@ export class SpecDialog extends React.Component<SpecDialogProps, SpecDialogState
|
||||||
mode="json"
|
mode="json"
|
||||||
theme="solarized_dark"
|
theme="solarized_dark"
|
||||||
className={"post-spec-dialog-textarea"}
|
className={"post-spec-dialog-textarea"}
|
||||||
onChange={ (e) => {this.setState({ spec: e })} }
|
onChange={(e) => { this.setState({ spec: e }); }}
|
||||||
fontSize={12}
|
fontSize={12}
|
||||||
showPrintMargin={false}
|
showPrintMargin={false}
|
||||||
showGutter={true}
|
showGutter
|
||||||
highlightActiveLine={true}
|
highlightActiveLine
|
||||||
value={spec}
|
value={spec}
|
||||||
width={"100%"}
|
width={"100%"}
|
||||||
setOptions={{
|
setOptions={{
|
||||||
|
@ -84,7 +85,7 @@ export class SpecDialog extends React.Component<SpecDialogProps, SpecDialogState
|
||||||
enableLiveAutocompletion: true,
|
enableLiveAutocompletion: true,
|
||||||
showLineNumbers: true,
|
showLineNumbers: true,
|
||||||
enableSnippets: true,
|
enableSnippets: true,
|
||||||
tabSize: 2,
|
tabSize: 2
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className={Classes.DIALOG_FOOTER}>
|
<div className={Classes.DIALOG_FOOTER}>
|
||||||
|
|
|
@ -19,13 +19,14 @@
|
||||||
import 'es6-shim/es6-shim';
|
import 'es6-shim/es6-shim';
|
||||||
import 'es7-shim'; // Webpack with automatically pick browser.js which does the shim()
|
import 'es7-shim'; // Webpack with automatically pick browser.js which does the shim()
|
||||||
import * as React from 'react';
|
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 * 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 { ConsoleApplication } from './console-application';
|
||||||
|
|
||||||
|
import "./entry.scss";
|
||||||
|
|
||||||
const container = document.getElementsByClassName('app-container')[0];
|
const container = document.getElementsByClassName('app-container')[0];
|
||||||
if (!container) throw new Error('container not found');
|
if (!container) throw new Error('container not found');
|
||||||
|
|
||||||
|
|
|
@ -20,5 +20,5 @@ import { Position, Toaster } from "@blueprintjs/core";
|
||||||
|
|
||||||
export const AppToaster = Toaster.create({
|
export const AppToaster = Toaster.create({
|
||||||
className: "recipe-toaster",
|
className: "recipe-toaster",
|
||||||
position: Position.TOP,
|
position: Position.TOP
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,14 +17,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Button, InputGroup, Intent } from '@blueprintjs/core';
|
import { Button, InputGroup, Intent } from '@blueprintjs/core';
|
||||||
import { IconNames, HTMLSelect } from "../components/filler";
|
|
||||||
import * as numeral from "numeral";
|
import * as numeral from "numeral";
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Filter, FilterRender } from 'react-table';
|
import { Filter, FilterRender } from 'react-table';
|
||||||
|
|
||||||
|
import { HTMLSelect, IconNames } from "../components/filler";
|
||||||
|
|
||||||
export function addFilter(filters: Filter[], id: string, value: string): Filter[] {
|
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) {
|
if (currentFilter) {
|
||||||
filters = filters.filter(f => f.id !== id);
|
filters = filters.filter(f => f.id !== id);
|
||||||
if (currentFilter.value !== value) {
|
if (currentFilter.value !== value) {
|
||||||
|
@ -36,7 +36,7 @@ export function addFilter(filters: Filter[], id: string, value: string): Filter[
|
||||||
return filters;
|
return filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeTextFilter(placeholder: string = ''): FilterRender {
|
export function makeTextFilter(placeholder = ''): FilterRender {
|
||||||
return ({ filter, onChange, key }) => {
|
return ({ filter, onChange, key }) => {
|
||||||
const filterValue = filter ? filter.value : '';
|
const filterValue = filter ? filter.value : '';
|
||||||
return <InputGroup
|
return <InputGroup
|
||||||
|
@ -45,8 +45,8 @@ export function makeTextFilter(placeholder: string = ''): FilterRender {
|
||||||
value={filterValue}
|
value={filterValue}
|
||||||
rightElement={filterValue ? <Button iconName={IconNames.CROSS} className="pt-minimal" onClick={() => onChange('')} /> : undefined}
|
rightElement={filterValue ? <Button iconName={IconNames.CROSS} className="pt-minimal" onClick={() => onChange('')} /> : undefined}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
/>
|
/>;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeBooleanFilter(): FilterRender {
|
export function makeBooleanFilter(): FilterRender {
|
||||||
|
@ -57,13 +57,13 @@ export function makeBooleanFilter(): FilterRender {
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
onChange={(event: any) => onChange(event.target.value)}
|
onChange={(event: any) => onChange(event.target.value)}
|
||||||
value={filterValue || "all"}
|
value={filterValue || "all"}
|
||||||
fill={true}
|
fill
|
||||||
>
|
>
|
||||||
<option value="all">Show all</option>
|
<option value="all">Show all</option>
|
||||||
<option value="true">true</option>
|
<option value="true">true</option>
|
||||||
<option value="false">false</option>
|
<option value="false">false</option>
|
||||||
</HTMLSelect>;
|
</HTMLSelect>;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------
|
// ----------------------------
|
||||||
|
|
|
@ -74,7 +74,7 @@ export class QueryManager<Q, R> {
|
||||||
private run() {
|
private run() {
|
||||||
this.lastQuery = this.nextQuery;
|
this.lastQuery = this.nextQuery;
|
||||||
this.currentQueryId++;
|
this.currentQueryId++;
|
||||||
let myQueryId = this.currentQueryId;
|
const myQueryId = this.currentQueryId;
|
||||||
|
|
||||||
this.actuallyLoading = true;
|
this.actuallyLoading = true;
|
||||||
this.processQuery(this.lastQuery)
|
this.processQuery(this.lastQuery)
|
||||||
|
@ -95,9 +95,9 @@ export class QueryManager<Q, R> {
|
||||||
result: null,
|
result: null,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: e.message
|
error: e.message
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private trigger() {
|
private trigger() {
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
export interface HeaderRows {
|
export interface HeaderRows {
|
||||||
header: string[];
|
header: string[];
|
||||||
rows: any[][];
|
rows: any[][];
|
||||||
|
@ -86,7 +85,11 @@ export function decodeRune(runeQuery: any, runeResult: any[]): HeaderRows {
|
||||||
throw new Error(`Unsupported query type in treatQueryTypeAs: '${treatQueryTypeAs}'`);
|
throw new Error(`Unsupported query type in treatQueryTypeAs: '${treatQueryTypeAs}'`);
|
||||||
}
|
}
|
||||||
} else {
|
} 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.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Button, Intent, Switch } from "@blueprintjs/core";
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import * as React from 'react';
|
|
||||||
import * as classNames from 'classnames';
|
import * as classNames from 'classnames';
|
||||||
|
import * as React from 'react';
|
||||||
import ReactTable from "react-table";
|
import ReactTable from "react-table";
|
||||||
import { Filter } from "react-table";
|
import { Filter } from "react-table";
|
||||||
import { Button, Intent, Switch } from "@blueprintjs/core";
|
|
||||||
import { IconNames } from "../components/filler";
|
import { IconNames } from "../components/filler";
|
||||||
import { AppToaster } from '../singletons/toaster';
|
|
||||||
import { RuleEditor } from '../components/rule-editor';
|
import { RuleEditor } from '../components/rule-editor';
|
||||||
import { AsyncActionDialog } from '../dialogs/async-action-dialog';
|
import { AsyncActionDialog } from '../dialogs/async-action-dialog';
|
||||||
import { RetentionDialog } from '../dialogs/retention-dialog';
|
import { RetentionDialog } from '../dialogs/retention-dialog';
|
||||||
|
import { AppToaster } from '../singletons/toaster';
|
||||||
import {
|
import {
|
||||||
addFilter,
|
addFilter,
|
||||||
formatNumber,
|
|
||||||
formatBytes,
|
|
||||||
countBy,
|
countBy,
|
||||||
|
formatBytes,
|
||||||
|
formatNumber,
|
||||||
|
getDruidErrorMessage,
|
||||||
lookupBy,
|
lookupBy,
|
||||||
QueryManager,
|
pluralIfNeeded, queryDruidSql, QueryManager
|
||||||
pluralIfNeeded, queryDruidSql, getDruidErrorMessage
|
|
||||||
} from "../utils";
|
} from "../utils";
|
||||||
|
|
||||||
import "./datasource-view.scss";
|
import "./datasource-view.scss";
|
||||||
|
@ -54,7 +55,7 @@ export interface DatasourcesViewState {
|
||||||
datasourcesLoading: boolean;
|
datasourcesLoading: boolean;
|
||||||
datasources: Datasource[] | null;
|
datasources: Datasource[] | null;
|
||||||
tiers: string[];
|
tiers: string[];
|
||||||
defaultRules: any[]
|
defaultRules: any[];
|
||||||
datasourcesError: string | null;
|
datasourcesError: string | null;
|
||||||
datasourcesFilter: Filter[];
|
datasourcesFilter: Filter[];
|
||||||
|
|
||||||
|
@ -73,7 +74,7 @@ export class DatasourcesView extends React.Component<DatasourcesViewProps, Datas
|
||||||
static formatRules(rules: any[]): string {
|
static formatRules(rules: any[]): string {
|
||||||
if (rules.length === 0) {
|
if (rules.length === 0) {
|
||||||
return 'No rules';
|
return 'No rules';
|
||||||
} if (rules.length <= 2) {
|
} else if (rules.length <= 2) {
|
||||||
return rules.map(RuleEditor.ruleToString).join(', ');
|
return rules.map(RuleEditor.ruleToString).join(', ');
|
||||||
} else {
|
} else {
|
||||||
return `${RuleEditor.ruleToString(rules[0])} +${rules.length - 1} more rules`;
|
return `${RuleEditor.ruleToString(rules[0])} +${rules.length - 1} more rules`;
|
||||||
|
@ -161,7 +162,7 @@ GROUP BY 1`);
|
||||||
return <AsyncActionDialog
|
return <AsyncActionDialog
|
||||||
action={
|
action={
|
||||||
dropDataDatasource ? async () => {
|
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;
|
return resp.data;
|
||||||
} : null
|
} : null
|
||||||
}
|
}
|
||||||
|
@ -186,7 +187,7 @@ GROUP BY 1`);
|
||||||
return <AsyncActionDialog
|
return <AsyncActionDialog
|
||||||
action={
|
action={
|
||||||
enableDatasource ? async () => {
|
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;
|
return resp.data;
|
||||||
} : null
|
} : null
|
||||||
}
|
}
|
||||||
|
@ -291,7 +292,7 @@ GROUP BY 1`);
|
||||||
|
|
||||||
let data = datasources || [];
|
let data = datasources || [];
|
||||||
if (!showDisabled) {
|
if (!showDisabled) {
|
||||||
data = data.filter(d => !d.disabled)
|
data = data.filter(d => !d.disabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
|
@ -299,7 +300,7 @@ GROUP BY 1`);
|
||||||
data={data}
|
data={data}
|
||||||
loading={datasourcesLoading}
|
loading={datasourcesLoading}
|
||||||
noDataText={!datasourcesLoading && datasources && !datasources.length ? 'No datasources' : (datasourcesError || '')}
|
noDataText={!datasourcesLoading && datasources && !datasources.length ? 'No datasources' : (datasourcesError || '')}
|
||||||
filterable={true}
|
filterable
|
||||||
filtered={datasourcesFilter}
|
filtered={datasourcesFilter}
|
||||||
onFilteredChange={(filtered, column) => {
|
onFilteredChange={(filtered, column) => {
|
||||||
this.setState({ datasourcesFilter: filtered });
|
this.setState({ datasourcesFilter: filtered });
|
||||||
|
@ -311,7 +312,7 @@ GROUP BY 1`);
|
||||||
width: 150,
|
width: 150,
|
||||||
Cell: row => {
|
Cell: row => {
|
||||||
const value = row.value;
|
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>
|
return <div>
|
||||||
<a onClick={() => this.setState({ enableDatasource: datasource })}>Enable</a>
|
<a onClick={() => this.setState({ enableDatasource: datasource })}>Enable</a>
|
||||||
<a onClick={() => this.setState({ killDatasource: datasource })}>Permanently delete</a>
|
<a onClick={() => this.setState({ killDatasource: datasource })}>Permanently delete</a>
|
||||||
</div>
|
</div>;
|
||||||
} else {
|
} else {
|
||||||
return <div>
|
return <div>
|
||||||
<a onClick={() => this.setState({ dropDataDatasource: datasource })}>Drop data</a>
|
<a onClick={() => this.setState({ dropDataDatasource: datasource })}>Drop data</a>
|
||||||
</div>
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -458,7 +459,6 @@ GROUP BY 1`);
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{this.renderDatasourceTable()}
|
{this.renderDatasourceTable()}
|
||||||
</div>
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import * as React from 'react';
|
|
||||||
import * as classNames from 'classnames';
|
import * as classNames from 'classnames';
|
||||||
import { H5, Card, Icon, IconNames } from "../components/filler";
|
import * as React from 'react';
|
||||||
import { QueryManager, pluralIfNeeded, queryDruidSql, getHeadProp } from '../utils';
|
|
||||||
|
import { Card, H5, Icon, IconNames } from "../components/filler";
|
||||||
|
import { getHeadProp, pluralIfNeeded, queryDruidSql, QueryManager } from '../utils';
|
||||||
|
|
||||||
import './home-view.scss';
|
import './home-view.scss';
|
||||||
|
|
||||||
export interface CardOptions {
|
export interface CardOptions {
|
||||||
|
@ -164,14 +166,14 @@ export class HomeView extends React.Component<HomeViewProps, HomeViewState> {
|
||||||
this.taskQueryManager = new QueryManager({
|
this.taskQueryManager = new QueryManager({
|
||||||
processQuery: async (query) => {
|
processQuery: async (query) => {
|
||||||
const taskCountsFromSql = await queryDruidSql({ query });
|
const taskCountsFromSql = await queryDruidSql({ query });
|
||||||
let taskCounts = {
|
const taskCounts = {
|
||||||
successTaskCount: 0,
|
successTaskCount: 0,
|
||||||
failedTaskCount: 0,
|
failedTaskCount: 0,
|
||||||
runningTaskCount: 0,
|
runningTaskCount: 0,
|
||||||
waitingTaskCount: 0,
|
waitingTaskCount: 0,
|
||||||
pendingTaskCount: 0
|
pendingTaskCount: 0
|
||||||
};
|
};
|
||||||
for (let dataStatus of taskCountsFromSql) {
|
for (const dataStatus of taskCountsFromSql) {
|
||||||
if (dataStatus.status === "SUCCESS") {
|
if (dataStatus.status === "SUCCESS") {
|
||||||
taskCounts.successTaskCount = dataStatus.count;
|
taskCounts.successTaskCount = dataStatus.count;
|
||||||
} else if (dataStatus.status === "FAILED") {
|
} else if (dataStatus.status === "FAILED") {
|
||||||
|
@ -254,7 +256,7 @@ GROUP BY 1`);
|
||||||
|
|
||||||
renderCard(cardOptions: CardOptions): JSX.Element {
|
renderCard(cardOptions: CardOptions): JSX.Element {
|
||||||
return <a href={cardOptions.href} target={cardOptions.href[0] === '/' ? '_blank' : undefined}>
|
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>
|
<H5><Icon color="#bfccd5" icon={cardOptions.icon}/> {cardOptions.title}</H5>
|
||||||
{cardOptions.loading ? <p>Loading...</p> : (cardOptions.error ? `Error: ${cardOptions.error}` : cardOptions.content)}
|
{cardOptions.loading ? <p>Loading...</p> : (cardOptions.error ? `Error: ${cardOptions.error}` : cardOptions.content)}
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -321,7 +323,6 @@ GROUP BY 1`);
|
||||||
</>,
|
</>,
|
||||||
error: state.dataServerCountError
|
error: state.dataServerCountError
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,15 +16,17 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Button, Intent } from "@blueprintjs/core";
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import * as React from 'react';
|
|
||||||
import * as classNames from 'classnames';
|
import * as classNames from 'classnames';
|
||||||
|
import * as React from 'react';
|
||||||
import ReactTable from "react-table";
|
import ReactTable from "react-table";
|
||||||
import { Filter } 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 { AppToaster } from "../singletons/toaster";
|
||||||
|
import { getDruidErrorMessage, QueryManager } from "../utils";
|
||||||
|
|
||||||
import "./lookups-view.scss";
|
import "./lookups-view.scss";
|
||||||
|
|
||||||
export interface LookupsViewProps extends React.Props<any> {
|
export interface LookupsViewProps extends React.Props<any> {
|
||||||
|
@ -32,16 +34,16 @@ export interface LookupsViewProps extends React.Props<any> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LookupsViewState {
|
export interface LookupsViewState {
|
||||||
lookups: {}[],
|
lookups: {}[];
|
||||||
loadingLookups: boolean,
|
loadingLookups: boolean;
|
||||||
lookupsError: string | null,
|
lookupsError: string | null;
|
||||||
lookupEditDialogOpen: boolean,
|
lookupEditDialogOpen: boolean;
|
||||||
lookupEditName: string,
|
lookupEditName: string;
|
||||||
lookupEditTier: string,
|
lookupEditTier: string;
|
||||||
lookupEditVersion: string,
|
lookupEditVersion: string;
|
||||||
lookupEditSpec: string,
|
lookupEditSpec: string;
|
||||||
isEdit: boolean,
|
isEdit: boolean;
|
||||||
allLookupTiers: string[]
|
allLookupTiers: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LookupsView extends React.Component<LookupsViewProps, LookupsViewState> {
|
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 tiersResp = await axios.get('/druid/coordinator/v1/tiers');
|
||||||
const tiers = tiersResp.data;
|
const tiers = tiersResp.data;
|
||||||
|
|
||||||
let lookupEntries: {}[] = [];
|
const lookupEntries: {}[] = [];
|
||||||
const lookupResp = await axios.get("/druid/coordinator/v1/lookups/config/all");
|
const lookupResp = await axios.get("/druid/coordinator/v1/lookups/config/all");
|
||||||
const lookupData = lookupResp.data;
|
const lookupData = lookupResp.data;
|
||||||
Object.keys(lookupData).map((tier: string) => {
|
Object.keys(lookupData).map((tier: string) => {
|
||||||
const lookupIds = lookupData[tier];
|
const lookupIds = lookupData[tier];
|
||||||
Object.keys(lookupIds).map((id: string) => {
|
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 {
|
return {
|
||||||
lookupEntries,
|
lookupEntries,
|
||||||
tiers
|
tiers
|
||||||
|
@ -123,7 +125,7 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
||||||
intent: Intent.DANGER,
|
intent: Intent.DANGER,
|
||||||
message: getDruidErrorMessage(e)
|
message: getDruidErrorMessage(e)
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +158,7 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
||||||
private changeLookup(field: string, value: string) {
|
private changeLookup(field: string, value: string) {
|
||||||
this.setState({
|
this.setState({
|
||||||
[field]: value
|
[field]: value
|
||||||
} as any)
|
} as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async submitLookupEdit() {
|
private async submitLookupEdit() {
|
||||||
|
@ -184,7 +186,7 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
||||||
await axios.post(endpoint, dataJSON);
|
await axios.post(endpoint, dataJSON);
|
||||||
this.setState({
|
this.setState({
|
||||||
lookupEditDialogOpen: false
|
lookupEditDialogOpen: false
|
||||||
})
|
});
|
||||||
this.lookupsGetQueryManager.rerunLastQuery();
|
this.lookupsGetQueryManager.rerunLastQuery();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
AppToaster.show(
|
AppToaster.show(
|
||||||
|
@ -193,7 +195,7 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
||||||
intent: Intent.DANGER,
|
intent: Intent.DANGER,
|
||||||
message: getDruidErrorMessage(e)
|
message: getDruidErrorMessage(e)
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,43 +213,43 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
||||||
text="Initialize Lookup"
|
text="Initialize Lookup"
|
||||||
onClick={() => this.initializeLookup()}
|
onClick={() => this.initializeLookup()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>;
|
||||||
}
|
}
|
||||||
return <>
|
return <>
|
||||||
<ReactTable
|
<ReactTable
|
||||||
data={lookups}
|
data={lookups}
|
||||||
loading={loadingLookups}
|
loading={loadingLookups}
|
||||||
noDataText={!loadingLookups && lookups && !lookups.length ? 'No lookups' : (lookupsError || '')}
|
noDataText={!loadingLookups && lookups && !lookups.length ? 'No lookups' : (lookupsError || '')}
|
||||||
filterable={true}
|
filterable
|
||||||
columns={[
|
columns={[
|
||||||
{
|
{
|
||||||
Header: "Lookup Name",
|
Header: "Lookup Name",
|
||||||
id: "lookup_name",
|
id: "lookup_name",
|
||||||
accessor: (row: any) => row.id,
|
accessor: (row: any) => row.id,
|
||||||
filterable: true,
|
filterable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: "Tier",
|
Header: "Tier",
|
||||||
id: "tier",
|
id: "tier",
|
||||||
accessor: (row: any) => row.tier,
|
accessor: (row: any) => row.tier,
|
||||||
filterable: true,
|
filterable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: "Type",
|
Header: "Type",
|
||||||
id: "type",
|
id: "type",
|
||||||
accessor: (row: any) => row.spec.type,
|
accessor: (row: any) => row.spec.type,
|
||||||
filterable: true,
|
filterable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: "Version",
|
Header: "Version",
|
||||||
id: "version",
|
id: "version",
|
||||||
accessor: (row: any) => row.version,
|
accessor: (row: any) => row.version,
|
||||||
filterable: true,
|
filterable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: "Config",
|
Header: "Config",
|
||||||
id: "config",
|
id: "config",
|
||||||
accessor: row => {return {id: row.id, tier: row.tier};},
|
accessor: row => ({id: row.id, tier: row.tier}),
|
||||||
filterable: false,
|
filterable: false,
|
||||||
Cell: (row: any) => {
|
Cell: (row: any) => {
|
||||||
const lookupId = row.value.id;
|
const lookupId = row.value.id;
|
||||||
|
@ -256,7 +258,7 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
||||||
<a onClick={() => this.openLookupEditDialog(lookupTier, lookupId)}>Edit</a>
|
<a onClick={() => this.openLookupEditDialog(lookupTier, lookupId)}>Edit</a>
|
||||||
|
|
||||||
<a onClick={() => this.deleteLookup(lookupTier, lookupId)}>Delete</a>
|
<a onClick={() => this.deleteLookup(lookupTier, lookupId)}>Delete</a>
|
||||||
</div>
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
|
@ -267,7 +269,7 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLookupEditDialog() {
|
renderLookupEditDialog() {
|
||||||
const { lookupEditDialogOpen, allLookupTiers, lookupEditSpec, lookupEditTier, lookupEditName, lookupEditVersion, isEdit } = this.state
|
const { lookupEditDialogOpen, allLookupTiers, lookupEditSpec, lookupEditTier, lookupEditName, lookupEditVersion, isEdit } = this.state;
|
||||||
|
|
||||||
return <LookupEditDialog
|
return <LookupEditDialog
|
||||||
isOpen={lookupEditDialogOpen}
|
isOpen={lookupEditDialogOpen}
|
||||||
|
@ -280,7 +282,7 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
||||||
lookupVersion={lookupEditVersion}
|
lookupVersion={lookupEditVersion}
|
||||||
isEdit={isEdit}
|
isEdit={isEdit}
|
||||||
allLookupTiers={allLookupTiers}
|
allLookupTiers={allLookupTiers}
|
||||||
/>
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -301,6 +303,6 @@ export class LookupsView extends React.Component<LookupsViewProps, LookupsViewSt
|
||||||
</div>
|
</div>
|
||||||
{this.renderLookupsTable()}
|
{this.renderLookupsTable()}
|
||||||
{this.renderLookupEditDialog()}
|
{this.renderLookupEditDialog()}
|
||||||
</div>
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,22 +16,24 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Button } from "@blueprintjs/core";
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import * as React from 'react';
|
|
||||||
import * as classNames from 'classnames';
|
import * as classNames from 'classnames';
|
||||||
|
import * as React from 'react';
|
||||||
import ReactTable from "react-table";
|
import ReactTable from "react-table";
|
||||||
import { Filter } from "react-table";
|
import { Filter } from "react-table";
|
||||||
import { Button } from "@blueprintjs/core";
|
|
||||||
import { H5, IconNames } from "../components/filler";
|
import { H5, IconNames } from "../components/filler";
|
||||||
import {
|
import {
|
||||||
addFilter,
|
addFilter,
|
||||||
makeBooleanFilter,
|
|
||||||
QueryManager,
|
|
||||||
formatBytes,
|
formatBytes,
|
||||||
formatNumber,
|
formatNumber,
|
||||||
|
makeBooleanFilter,
|
||||||
parseList,
|
parseList,
|
||||||
queryDruidSql
|
queryDruidSql,
|
||||||
|
QueryManager
|
||||||
} from "../utils";
|
} from "../utils";
|
||||||
|
|
||||||
import "./segments-view.scss";
|
import "./segments-view.scss";
|
||||||
|
|
||||||
export interface SegmentsViewProps extends React.Props<any> {
|
export interface SegmentsViewProps extends React.Props<any> {
|
||||||
|
@ -88,7 +90,7 @@ export class SegmentsView extends React.Component<SegmentsViewProps, SegmentsVie
|
||||||
segmentsError: error
|
segmentsError: error
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount(): void {
|
componentWillUnmount(): void {
|
||||||
|
@ -99,7 +101,7 @@ export class SegmentsView extends React.Component<SegmentsViewProps, SegmentsVie
|
||||||
const { page, pageSize, filtered, sorted } = state;
|
const { page, pageSize, filtered, sorted } = state;
|
||||||
const totalQuerySize = (page + 1) * pageSize;
|
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"`,
|
`SELECT "segment_id", "datasource", "start", "end", "size", "version", "partition_num", "num_replicas", "num_rows", "is_published", "is_available", "is_realtime", "payload"`,
|
||||||
`FROM sys.segments`
|
`FROM sys.segments`
|
||||||
];
|
];
|
||||||
|
@ -114,7 +116,7 @@ export class SegmentsView extends React.Component<SegmentsViewProps, SegmentsVie
|
||||||
}).filter(Boolean);
|
}).filter(Boolean);
|
||||||
|
|
||||||
if (whereParts.length) {
|
if (whereParts.length) {
|
||||||
queryParts.push('WHERE ' + whereParts.join(' AND '))
|
queryParts.push('WHERE ' + whereParts.join(' AND '));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sorted.length) {
|
if (sorted.length) {
|
||||||
|
@ -160,7 +162,7 @@ export class SegmentsView extends React.Component<SegmentsViewProps, SegmentsVie
|
||||||
accessor: "datasource",
|
accessor: "datasource",
|
||||||
Cell: row => {
|
Cell: row => {
|
||||||
const value = row.value;
|
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,
|
defaultSortDesc: true,
|
||||||
Cell: row => {
|
Cell: row => {
|
||||||
const value = row.value;
|
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,
|
width: 120,
|
||||||
Cell: row => {
|
Cell: row => {
|
||||||
const value = row.value;
|
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",
|
Header: "Version",
|
||||||
accessor: "version",
|
accessor: "version",
|
||||||
defaultSortDesc: true,
|
defaultSortDesc: true,
|
||||||
width: 120,
|
width: 120
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: "Partition",
|
Header: "Partition",
|
||||||
|
@ -272,6 +274,6 @@ export class SegmentsView extends React.Component<SegmentsViewProps, SegmentsVie
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{this.renderSegmentsTable()}
|
{this.renderSegmentsTable()}
|
||||||
</div>
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,19 +16,21 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Button, Switch } from "@blueprintjs/core";
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import * as React from 'react';
|
|
||||||
import * as classNames from 'classnames';
|
import * as classNames from 'classnames';
|
||||||
|
import { sum } from "d3-array";
|
||||||
|
import * as React from 'react';
|
||||||
import ReactTable from "react-table";
|
import ReactTable from "react-table";
|
||||||
import { Filter } 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 { IconNames } from '../components/filler';
|
||||||
import { addFilter, formatBytes, formatBytesCompact, QueryManager, queryDruidSql } from "../utils";
|
import { addFilter, formatBytes, formatBytesCompact, queryDruidSql, QueryManager } from "../utils";
|
||||||
|
|
||||||
import "./servers-view.scss";
|
import "./servers-view.scss";
|
||||||
|
|
||||||
function formatQueues(segmentsToLoad: number, segmentsToLoadSize: number, segmentsToDrop: number, segmentsToDropSize: number): string {
|
function formatQueues(segmentsToLoad: number, segmentsToLoadSize: number, segmentsToDrop: number, segmentsToDropSize: number): string {
|
||||||
let queueParts: string[] = [];
|
const queueParts: string[] = [];
|
||||||
if (segmentsToLoad) {
|
if (segmentsToLoad) {
|
||||||
queueParts.push(`${segmentsToLoad} segments to load (${formatBytesCompact(segmentsToLoadSize)})`);
|
queueParts.push(`${segmentsToLoad} segments to load (${formatBytesCompact(segmentsToLoadSize)})`);
|
||||||
}
|
}
|
||||||
|
@ -73,7 +75,7 @@ export class ServersView extends React.Component<ServersViewProps, ServersViewSt
|
||||||
middleManagersLoading: true,
|
middleManagersLoading: true,
|
||||||
middleManagers: null,
|
middleManagers: null,
|
||||||
middleManagersError: 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) => {
|
processQuery: async (query: string) => {
|
||||||
const servers = await queryDruidSql({ query });
|
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;
|
const loadQueues = loadQueueResponse.data;
|
||||||
|
|
||||||
return servers.map((s: any) => {
|
return servers.map((s: any) => {
|
||||||
|
@ -143,7 +145,7 @@ WHERE "server_type" = 'historical'`);
|
||||||
data={servers || []}
|
data={servers || []}
|
||||||
loading={serversLoading}
|
loading={serversLoading}
|
||||||
noDataText={!serversLoading && servers && !servers.length ? 'No historicals' : (serversError || '')}
|
noDataText={!serversLoading && servers && !servers.length ? 'No historicals' : (serversError || '')}
|
||||||
filterable={true}
|
filterable
|
||||||
filtered={serverFilter}
|
filtered={serverFilter}
|
||||||
onFilteredChange={(filtered, column) => {
|
onFilteredChange={(filtered, column) => {
|
||||||
this.setState({ serverFilter: filtered });
|
this.setState({ serverFilter: filtered });
|
||||||
|
@ -161,7 +163,7 @@ WHERE "server_type" = 'historical'`);
|
||||||
accessor: "tier",
|
accessor: "tier",
|
||||||
Cell: row => {
|
Cell: row => {
|
||||||
const value = row.value;
|
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 segmentsToDrop = sum(originals, s => s.segmentsToDrop);
|
||||||
const segmentsToDropSize = sum(originals, s => s.segmentsToDropSize);
|
const segmentsToDropSize = sum(originals, s => s.segmentsToDropSize);
|
||||||
return formatQueues(segmentsToLoad, segmentsToLoadSize, segmentsToDrop, segmentsToDropSize);
|
return formatQueues(segmentsToLoad, segmentsToLoadSize, segmentsToDrop, segmentsToDropSize);
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: "Host",
|
Header: "Host",
|
||||||
|
@ -245,7 +247,7 @@ WHERE "server_type" = 'historical'`);
|
||||||
Header: "Port",
|
Header: "Port",
|
||||||
id: 'port',
|
id: 'port',
|
||||||
accessor: (row) => {
|
accessor: (row) => {
|
||||||
let ports: string[] = [];
|
const ports: string[] = [];
|
||||||
if (row.plaintext_port !== -1) {
|
if (row.plaintext_port !== -1) {
|
||||||
ports.push(`${row.plaintext_port} (plain)`);
|
ports.push(`${row.plaintext_port} (plain)`);
|
||||||
}
|
}
|
||||||
|
@ -255,7 +257,7 @@ WHERE "server_type" = 'historical'`);
|
||||||
return ports.join(', ') || 'No port';
|
return ports.join(', ') || 'No port';
|
||||||
},
|
},
|
||||||
Aggregated: () => ''
|
Aggregated: () => ''
|
||||||
},
|
}
|
||||||
]}
|
]}
|
||||||
defaultPageSize={10}
|
defaultPageSize={10}
|
||||||
className="-striped -highlight"
|
className="-striped -highlight"
|
||||||
|
@ -270,7 +272,7 @@ WHERE "server_type" = 'historical'`);
|
||||||
data={middleManagers || []}
|
data={middleManagers || []}
|
||||||
loading={middleManagersLoading}
|
loading={middleManagersLoading}
|
||||||
noDataText={!middleManagersLoading && middleManagers && !middleManagers.length ? 'No MiddleManagers' : (middleManagersError || '')}
|
noDataText={!middleManagersLoading && middleManagers && !middleManagers.length ? 'No MiddleManagers' : (middleManagersError || '')}
|
||||||
filterable={true}
|
filterable
|
||||||
filtered={middleManagerFilter}
|
filtered={middleManagerFilter}
|
||||||
onFilteredChange={(filtered, column) => {
|
onFilteredChange={(filtered, column) => {
|
||||||
this.setState({ middleManagerFilter: filtered });
|
this.setState({ middleManagerFilter: filtered });
|
||||||
|
@ -282,7 +284,7 @@ WHERE "server_type" = 'historical'`);
|
||||||
accessor: (row) => row.worker.host,
|
accessor: (row) => row.worker.host,
|
||||||
Cell: row => {
|
Cell: row => {
|
||||||
const value = row.value;
|
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",
|
id: "availabilityGroups",
|
||||||
width: 60,
|
width: 60,
|
||||||
accessor: (row) => row.availabilityGroups.length,
|
accessor: (row) => row.availabilityGroups.length,
|
||||||
filterable: false,
|
filterable: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: "Last completed task time",
|
Header: "Last completed task time",
|
||||||
|
@ -362,7 +364,6 @@ WHERE "server_type" = 'historical'`);
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{this.renderMiddleManagerTable()}
|
{this.renderMiddleManagerTable()}
|
||||||
</div>
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,19 +17,21 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import * as React from 'react';
|
|
||||||
import * as classNames from 'classnames';
|
import * as classNames from 'classnames';
|
||||||
import ReactTable from "react-table";
|
|
||||||
import * as Hjson from "hjson";
|
import * as Hjson from "hjson";
|
||||||
|
import * as React from 'react';
|
||||||
|
import ReactTable from "react-table";
|
||||||
|
|
||||||
import { SqlControl } from '../components/sql-control';
|
import { SqlControl } from '../components/sql-control';
|
||||||
import {
|
import {
|
||||||
QueryManager,
|
|
||||||
localStorageSet,
|
|
||||||
localStorageGet,
|
|
||||||
decodeRune,
|
decodeRune,
|
||||||
HeaderRows,
|
HeaderRows,
|
||||||
queryDruidRune, queryDruidSql
|
localStorageGet,
|
||||||
|
localStorageSet,
|
||||||
|
queryDruidRune,
|
||||||
|
queryDruidSql, QueryManager
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
|
|
||||||
import "./sql-view.scss";
|
import "./sql-view.scss";
|
||||||
|
|
||||||
export interface SqlViewProps extends React.Props<any> {
|
export interface SqlViewProps extends React.Props<any> {
|
||||||
|
@ -84,7 +86,7 @@ export class SqlView extends React.Component<SqlViewProps, SqlViewState> {
|
||||||
error
|
error
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount(): void {
|
componentWillUnmount(): void {
|
||||||
|
@ -117,7 +119,6 @@ export class SqlView extends React.Component<SqlViewProps, SqlViewState> {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{this.renderResultTable()}
|
{this.renderResultTable()}
|
||||||
</div>
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,17 +16,19 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Alert, Button, Intent } from "@blueprintjs/core";
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import * as React from 'react';
|
|
||||||
import * as classNames from 'classnames';
|
import * as classNames from 'classnames';
|
||||||
|
import * as React from 'react';
|
||||||
import ReactTable from "react-table";
|
import ReactTable from "react-table";
|
||||||
import { Filter } from "react-table";
|
import { Filter } from "react-table";
|
||||||
import { Button, Intent, Alert } from "@blueprintjs/core";
|
|
||||||
import { ButtonGroup, Label, IconNames } from "../components/filler";
|
import { ButtonGroup, IconNames, Label } from "../components/filler";
|
||||||
import { addFilter, QueryManager, getDruidErrorMessage, countBy, formatDuration, queryDruidSql } from "../utils";
|
|
||||||
import { AsyncActionDialog } from "../dialogs/async-action-dialog";
|
import { AsyncActionDialog } from "../dialogs/async-action-dialog";
|
||||||
import { SpecDialog } from "../dialogs/spec-dialog";
|
import { SpecDialog } from "../dialogs/spec-dialog";
|
||||||
import { AppToaster } from '../singletons/toaster';
|
import { AppToaster } from '../singletons/toaster';
|
||||||
|
import { addFilter, countBy, formatDuration, getDruidErrorMessage, queryDruidSql, QueryManager } from "../utils";
|
||||||
|
|
||||||
import "./tasks-view.scss";
|
import "./tasks-view.scss";
|
||||||
|
|
||||||
export interface TasksViewProps extends React.Props<any> {
|
export interface TasksViewProps extends React.Props<any> {
|
||||||
|
@ -102,7 +104,7 @@ export class TasksView extends React.Component<TasksViewProps, TasksViewState> {
|
||||||
componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
this.supervisorQueryManager = new QueryManager({
|
this.supervisorQueryManager = new QueryManager({
|
||||||
processQuery: async (query: string) => {
|
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;
|
return resp.data;
|
||||||
},
|
},
|
||||||
onStateChange: ({ result, loading, error }) => {
|
onStateChange: ({ result, loading, error }) => {
|
||||||
|
@ -299,7 +301,7 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
||||||
data={supervisors || []}
|
data={supervisors || []}
|
||||||
loading={supervisorsLoading}
|
loading={supervisorsLoading}
|
||||||
noDataText={!supervisorsLoading && supervisors && !supervisors.length ? 'No supervisors' : (supervisorsError || '')}
|
noDataText={!supervisorsLoading && supervisors && !supervisors.length ? 'No supervisors' : (supervisorsError || '')}
|
||||||
filterable={true}
|
filterable
|
||||||
columns={[
|
columns={[
|
||||||
{
|
{
|
||||||
Header: "Datasource",
|
Header: "Datasource",
|
||||||
|
@ -338,7 +340,9 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
||||||
return <span>
|
return <span>
|
||||||
<span
|
<span
|
||||||
style={{ color: value === 'Suspended' ? '#d58512' : '#2167d5' }}
|
style={{ color: value === 'Suspended' ? '#d58512' : '#2167d5' }}
|
||||||
>● </span>
|
>
|
||||||
|
●
|
||||||
|
</span>
|
||||||
{value}
|
{value}
|
||||||
</span>;
|
</span>;
|
||||||
}
|
}
|
||||||
|
@ -363,7 +367,7 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
||||||
{suspendResume}
|
{suspendResume}
|
||||||
<a onClick={() => this.setState({ resetSupervisorId: id })}>Reset</a>
|
<a onClick={() => this.setState({ resetSupervisorId: id })}>Reset</a>
|
||||||
<a onClick={() => this.setState({ terminateSupervisorId: id })}>Terminate</a>
|
<a onClick={() => this.setState({ terminateSupervisorId: id })}>Terminate</a>
|
||||||
</div>
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
|
@ -413,7 +417,7 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
||||||
data={tasks || []}
|
data={tasks || []}
|
||||||
loading={tasksLoading}
|
loading={tasksLoading}
|
||||||
noDataText={!tasksLoading && tasks && !tasks.length ? 'No tasks' : (tasksError || '')}
|
noDataText={!tasksLoading && tasks && !tasks.length ? 'No tasks' : (tasksError || '')}
|
||||||
filterable={true}
|
filterable
|
||||||
filtered={taskFilter}
|
filtered={taskFilter}
|
||||||
onFilteredChange={(filtered, column) => {
|
onFilteredChange={(filtered, column) => {
|
||||||
this.setState({ taskFilter: filtered });
|
this.setState({ taskFilter: filtered });
|
||||||
|
@ -432,7 +436,7 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
||||||
accessor: "type",
|
accessor: "type",
|
||||||
Cell: row => {
|
Cell: row => {
|
||||||
const value = row.value;
|
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",
|
accessor: "datasource",
|
||||||
Cell: row => {
|
Cell: row => {
|
||||||
const value = row.value;
|
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,7 +466,9 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
||||||
return <span>
|
return <span>
|
||||||
<span
|
<span
|
||||||
style={{ color: statusToColor(status) }}
|
style={{ color: statusToColor(status) }}
|
||||||
>● </span>
|
>
|
||||||
|
●
|
||||||
|
</span>
|
||||||
{status}
|
{status}
|
||||||
{location && <a onClick={() => goToMiddleManager(locationHostname)} title={`Go to: ${locationHostname}`}> ➚</a>}
|
{location && <a onClick={() => goToMiddleManager(locationHostname)} title={`Go to: ${locationHostname}`}> ➚</a>}
|
||||||
{errorMsg && <a onClick={() => this.setState({ alertErrorMsg: errorMsg })} title={errorMsg}> ?</a>}
|
{errorMsg && <a onClick={() => this.setState({ alertErrorMsg: errorMsg })} title={errorMsg}> ?</a>}
|
||||||
|
@ -504,7 +510,7 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
||||||
<a href={`/druid/indexer/v1/task/${id}/log`} target="_blank">Log (all)</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>
|
<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>}
|
{(status === 'RUNNING' || status === 'WAITING' || status === 'PENDING') && <a onClick={() => this.setState({ killTaskId: id })}>Kill</a>}
|
||||||
</div>
|
</div>;
|
||||||
},
|
},
|
||||||
Aggregated: row => ''
|
Aggregated: row => ''
|
||||||
}
|
}
|
||||||
|
@ -583,7 +589,6 @@ ORDER BY "rank" DESC, "created_time" DESC`);
|
||||||
>
|
>
|
||||||
<p>{alertErrorMsg}</p>
|
<p>{alertErrorMsg}</p>
|
||||||
</Alert>
|
</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: {
|
module: {
|
||||||
rules: [
|
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?$/,
|
test: /\.tsx?$/,
|
||||||
use: 'ts-loader',
|
use: 'ts-loader',
|
||||||
|
|
Loading…
Reference in New Issue