Web console: improve how code is imported, use API instance (#10597)

* fix imports

* clean up imports

* update DQT to fix escaping
This commit is contained in:
Vadim Ogievetsky 2020-12-01 13:16:14 -08:00 committed by GitHub
parent d47d6cf081
commit 5b06c7a3a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 306 additions and 215 deletions

View File

@ -4751,7 +4751,7 @@ license_category: binary
module: web-console
license_name: Apache License version 2.0
copyright: Imply Data
version: 0.9.15
version: 0.10.4
---

View File

@ -4265,11 +4265,18 @@
}
},
"druid-query-toolkit": {
"version": "0.9.15",
"resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.9.15.tgz",
"integrity": "sha512-HiJVqa6X6z/LeEU3GVxbkaP/X8JCn/9n8txoG1tSgk6edc1BZXj7F7hZpaNlAThVcZcFOYeE1gFOHzMMjK4U0A==",
"version": "0.10.4",
"resolved": "https://registry.npmjs.org/druid-query-toolkit/-/druid-query-toolkit-0.10.4.tgz",
"integrity": "sha512-feIRTC2paOkGpWvymseMs/wn+8XfbLjlcBsXJXKxgsJtqMKBYy3f8YiN3SV/xv6CQP9Vv4nBMEoa5q8OM5KHsg==",
"requires": {
"tslib": "^1.10.0"
"tslib": "^2.0.2"
},
"dependencies": {
"tslib": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
"integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
}
}
},
"duplexer": {

View File

@ -68,7 +68,7 @@
"d3-axis": "^1.0.12",
"d3-scale": "^3.2.0",
"d3-selection": "^1.4.0",
"druid-query-toolkit": "^0.9.15",
"druid-query-toolkit": "^0.10.4",
"file-saver": "^2.0.2",
"fontsource-open-sans": "^3.0.9",
"has-own-prop": "^2.0.0",

View File

@ -61,7 +61,7 @@ const readDoc = async () => {
);
}
// Make sure there are at least 5 data types for sanity
// Make sure there are at least 10 data types for sanity
if (dataTypeDocs.length < 10) {
throw new Error(
`Did not find enough data type entries did the structure of '${readfile}' change? (found ${dataTypeDocs.length})`,

View File

@ -0,0 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'brace'; // Import Ace editor and all the sub components used in the app
import 'brace/ext/language_tools';
import 'brace/theme/solarized_dark';
import '../ace-modes/dsql';
import '../ace-modes/hjson';

View File

@ -24,12 +24,13 @@ import { booleanCustomTableFilter, countBy, makeTextFilter } from '../utils';
import { ReactTableCustomPagination } from './react-table-custom-pagination';
export const NoData = React.memo(function NoData(props) {
const NoData = React.memo(function NoData(props) {
const { children } = props;
if (!children) return null;
return <div className="rt-noData">{children}</div>;
});
export function bootstrapReactTable() {
Object.assign(ReactTableDefaults, {
className: '-striped -highlight',
defaultFilterMethod: (filter: Filter, row: any) => {
@ -58,3 +59,4 @@ Object.assign(ReactTableDefaults, {
},
defaultPageSize: 20,
});
}

View File

@ -19,7 +19,7 @@
import { shallow } from 'enzyme';
import React from 'react';
import { Capabilities } from '../../utils/capabilities';
import { Capabilities } from '../../utils';
import { HeaderBar } from './header-bar';

View File

@ -39,7 +39,7 @@ import {
OverlordDynamicConfigDialog,
} from '../../dialogs';
import { getLink } from '../../links';
import { Capabilities } from '../../utils/capabilities';
import { Capabilities } from '../../utils';
import { ExternalLink } from '../external-link/external-link';
import { PopoverText } from '../popover-text/popover-text';

View File

@ -21,7 +21,7 @@ import { mount } from 'enzyme';
import React from 'react';
import { QueryManager } from '../../utils';
import { Capabilities } from '../../utils/capabilities';
import { Capabilities } from '../../utils';
import { SegmentTimeline } from './segment-timeline';

View File

@ -17,12 +17,12 @@
*/
import { FormGroup, HTMLSelect, Radio, RadioGroup } from '@blueprintjs/core';
import axios from 'axios';
import { AxisScale } from 'd3-axis';
import { scaleLinear, scaleTime } from 'd3-scale';
import React from 'react';
import { Capabilities } from '../../utils/capabilities';
import { Api } from '../../singletons';
import { Capabilities } from '../../utils';
import { formatBytes, queryDruidSql, QueryManager, uniq } from '../../utils/index';
import { StackedBarChart } from '../../visualization/stacked-bar-chart';
import { Loader } from '../loader/loader';
@ -266,10 +266,10 @@ ORDER BY "start" DESC`;
before.setMonth(before.getMonth() - timeSpan);
const beforeIso = before.toISOString();
datasources = (await axios.get(`/druid/coordinator/v1/datasources`)).data;
datasources = (await Api.instance.get(`/druid/coordinator/v1/datasources`)).data;
intervals = (await Promise.all(
datasources.map(async datasource => {
const intervalMap = (await axios.get(
const intervalMap = (await Api.instance.get(
`/druid/coordinator/v1/datasources/${datasource}/intervals?simple`,
)).data;

View File

@ -17,10 +17,10 @@
*/
import { Tab, Tabs } from '@blueprintjs/core';
import axios from 'axios';
import React from 'react';
import { useQueryManager } from '../../hooks';
import { Api } from '../../singletons';
import { Loader } from '../loader/loader';
import { ShowValue } from '../show-value/show-value';
@ -41,7 +41,7 @@ export const ShowHistory = React.memo(function ShowHistory(props: ShowHistoryPro
const [historyState] = useQueryManager<string, VersionSpec[]>({
processQuery: async (endpoint: string) => {
const resp = await axios.get(endpoint);
const resp = await Api.instance.get(endpoint);
return resp.data;
},
initQuery: endpoint,

View File

@ -17,13 +17,11 @@
*/
import { Button, ButtonGroup, Intent, TextArea } from '@blueprintjs/core';
import axios from 'axios';
import copy from 'copy-to-clipboard';
import React from 'react';
import { useQueryManager } from '../../hooks';
import { AppToaster } from '../../singletons/toaster';
import { UrlBaser } from '../../singletons/url-baser';
import { Api, AppToaster, UrlBaser } from '../../singletons';
import { downloadFile } from '../../utils';
import { Loader } from '../loader/loader';
@ -40,7 +38,7 @@ export const ShowJson = React.memo(function ShowJson(props: ShowJsonProps) {
const [jsonState] = useQueryManager<null, string>({
processQuery: async () => {
const resp = await axios.get(endpoint);
const resp = await Api.instance.get(endpoint);
let data = resp.data;
if (transform) data = transform(data);
return typeof data === 'string' ? data : JSON.stringify(data, undefined, 2);

View File

@ -17,13 +17,11 @@
*/
import { AnchorButton, Button, ButtonGroup, Intent, Switch } from '@blueprintjs/core';
import axios from 'axios';
import copy from 'copy-to-clipboard';
import React from 'react';
import { Loader } from '../../components';
import { AppToaster } from '../../singletons/toaster';
import { UrlBaser } from '../../singletons/url-baser';
import { Api, AppToaster, UrlBaser } from '../../singletons';
import { QueryManager, QueryState } from '../../utils';
import './show-log.scss';
@ -65,7 +63,9 @@ export class ShowLog extends React.PureComponent<ShowLogProps, ShowLogState> {
this.showLogQueryManager = new QueryManager({
processQuery: async () => {
const { endpoint, tailOffset } = this.props;
const resp = await axios.get(endpoint + (tailOffset ? `?offset=-${tailOffset}` : ''));
const resp = await Api.instance.get(
endpoint + (tailOffset ? `?offset=-${tailOffset}` : ''),
);
const data = resp.data;
let logValue = typeof data === 'string' ? data : JSON.stringify(data, undefined, 2);

View File

@ -19,7 +19,7 @@
import { Button, ButtonGroup, TextArea } from '@blueprintjs/core';
import React from 'react';
import { UrlBaser } from '../../singletons/url-baser';
import { UrlBaser } from '../../singletons';
import { downloadFile } from '../../utils';
import './show-value.scss';

View File

@ -17,12 +17,11 @@
*/
import { Button, ButtonGroup } from '@blueprintjs/core';
import axios from 'axios';
import React from 'react';
import ReactTable, { CellInfo, Column } from 'react-table';
import { useQueryManager } from '../../hooks';
import { UrlBaser } from '../../singletons/url-baser';
import { Api, UrlBaser } from '../../singletons';
import { deepGet } from '../../utils';
import { Loader } from '../loader/loader';
@ -65,7 +64,7 @@ export const SupervisorStatisticsTable = React.memo(function SupervisorStatistic
const [supervisorStatisticsState] = useQueryManager<null, SupervisorStatisticsTableRow[]>({
processQuery: async () => {
const resp = await axios.get(endpoint);
const resp = await Api.instance.get(endpoint);
return normalizeSupervisorStatisticsResults(resp.data);
},
initQuery: null,

View File

@ -23,9 +23,8 @@ import React from 'react';
import { HashRouter, Route, Switch } from 'react-router-dom';
import { HeaderActiveTab, HeaderBar, Loader } from './components';
import { AppToaster } from './singletons/toaster';
import { QueryManager } from './utils';
import { Capabilities } from './utils/capabilities';
import { AppToaster } from './singletons';
import { Capabilities, QueryManager } from './utils';
import {
DatasourcesView,
HomeView,

View File

@ -31,7 +31,7 @@ import classNames from 'classnames';
import React, { ReactNode, useState } from 'react';
import { WarningChecklist } from '../../components/warning-checklist/warning-checklist';
import { AppToaster } from '../../singletons/toaster';
import { AppToaster } from '../../singletons';
import './async-action-dialog.scss';

View File

@ -18,7 +18,6 @@
import { Intent } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import React, { useState } from 'react';
import { SnitchDialog } from '..';
@ -32,7 +31,7 @@ import {
import { COORDINATOR_DYNAMIC_CONFIG_FIELDS, CoordinatorDynamicConfig } from '../../druid-models';
import { useQueryManager } from '../../hooks';
import { getLink } from '../../links';
import { AppToaster } from '../../singletons/toaster';
import { Api, AppToaster } from '../../singletons';
import { getDruidErrorMessage } from '../../utils';
import './coordinator-dynamic-config-dialog.scss';
@ -50,7 +49,7 @@ export const CoordinatorDynamicConfigDialog = React.memo(function CoordinatorDyn
const [historyRecordsState] = useQueryManager<null, any[]>({
processQuery: async () => {
const historyResp = await axios(`/druid/coordinator/v1/config/history?count=100`);
const historyResp = await Api.instance.get(`/druid/coordinator/v1/config/history?count=100`);
return historyResp.data;
},
initQuery: null,
@ -59,7 +58,7 @@ export const CoordinatorDynamicConfigDialog = React.memo(function CoordinatorDyn
useQueryManager<null, Record<string, any>>({
processQuery: async () => {
try {
const configResp = await axios.get('/druid/coordinator/v1/config');
const configResp = await Api.instance.get('/druid/coordinator/v1/config');
setDynamicConfig(configResp.data || {});
} catch (e) {
AppToaster.show({
@ -77,7 +76,7 @@ export const CoordinatorDynamicConfigDialog = React.memo(function CoordinatorDyn
async function saveConfig(comment: string) {
try {
await axios.post('/druid/coordinator/v1/config', dynamicConfig, {
await Api.instance.post('/druid/coordinator/v1/config', dynamicConfig, {
headers: {
'X-Druid-Author': 'console',
'X-Druid-Comment': comment,

View File

@ -16,8 +16,7 @@
* limitations under the License.
*/
import axios from 'axios';
import { Api } from '../../singletons';
import { deepGet, pluralIfNeeded, queryDruidSql } from '../../utils';
import { postToSampler } from '../../utils/sampler';
@ -56,7 +55,7 @@ export const DOCTOR_CHECKS: DoctorCheck[] = [
// Make sure that the router responds to /status and gives some valid info back
let status: any;
try {
status = (await axios.get(`/status`)).data;
status = (await Api.instance.get(`/status`)).data;
} catch (e) {
controls.addIssue(
`Did not get a /status response from the Router service. Try confirming that it is running and accessible. Got: ${e.message}`,
@ -76,7 +75,7 @@ export const DOCTOR_CHECKS: DoctorCheck[] = [
// Make sure that everything in /status/properties is above board
let properties: Record<string, string>;
try {
properties = (await axios.get(`/status/properties`)).data;
properties = (await Api.instance.get(`/status/properties`)).data;
} catch (e) {
controls.addIssue(
`Did not get a /status/properties response from the Router. Message: ${e.message}`,
@ -126,14 +125,14 @@ export const DOCTOR_CHECKS: DoctorCheck[] = [
// Make sure that everything in Coordinator's /status is good
let myStatus: any;
try {
myStatus = (await axios.get(`/status`)).data;
myStatus = (await Api.instance.get(`/status`)).data;
} catch {
return;
}
let coordinatorStatus: any;
try {
coordinatorStatus = (await axios.get(`/proxy/coordinator/status`)).data;
coordinatorStatus = (await Api.instance.get(`/proxy/coordinator/status`)).data;
} catch (e) {
controls.addIssue(
'Did not get a /status response from the Coordinator service. Try confirming that it is running and accessible.',
@ -143,7 +142,7 @@ export const DOCTOR_CHECKS: DoctorCheck[] = [
let overlordStatus: any;
try {
overlordStatus = (await axios.get(`/proxy/overlord/status`)).data;
overlordStatus = (await Api.instance.get(`/proxy/overlord/status`)).data;
} catch (e) {
controls.addIssue(
'Did not get a /status response from the Overlord service. Try confirming that it is running and accessible.',
@ -170,14 +169,15 @@ export const DOCTOR_CHECKS: DoctorCheck[] = [
// Make sure that everything in coordinator and overlord /status/properties is good and matches where needed
let myProperties: Record<string, string>;
try {
myProperties = (await axios.get(`/status/properties`)).data;
myProperties = (await Api.instance.get(`/status/properties`)).data;
} catch {
return;
}
let coordinatorProperties: Record<string, string>;
try {
coordinatorProperties = (await axios.get(`/proxy/coordinator/status/properties`)).data;
coordinatorProperties = (await Api.instance.get(`/proxy/coordinator/status/properties`))
.data;
} catch (e) {
controls.addIssue(
'Did not get a /status response from the coordinator. Try confirming that it is running and accessible.',
@ -187,7 +187,7 @@ export const DOCTOR_CHECKS: DoctorCheck[] = [
let overlordProperties: Record<string, string>;
try {
overlordProperties = (await axios.get(`/proxy/overlord/status/properties`)).data;
overlordProperties = (await Api.instance.get(`/proxy/overlord/status/properties`)).data;
} catch (e) {
controls.addIssue(
'Did not get a /status response from the overlord. Try confirming that it is running and accessible.',
@ -384,7 +384,8 @@ ORDER BY "num_bad_time_chunks"`,
// Grab the auto-compaction definitions and ignore dataSources that already have auto-compaction
let compactionResult: any;
try {
compactionResult = (await axios.get('/druid/coordinator/v1/config/compaction')).data;
compactionResult = (await Api.instance.get('/druid/coordinator/v1/config/compaction'))
.data;
} catch (e) {
controls.addIssue(`Could not get compaction config. Something is wrong.`);
return;

View File

@ -18,7 +18,6 @@
import { Intent } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import React, { useState } from 'react';
import { SnitchDialog } from '..';
@ -26,7 +25,7 @@ import { AutoForm, ExternalLink } from '../../components';
import { OVERLORD_DYNAMIC_CONFIG_FIELDS, OverlordDynamicConfig } from '../../druid-models';
import { useQueryManager } from '../../hooks';
import { getLink } from '../../links';
import { AppToaster } from '../../singletons/toaster';
import { Api, AppToaster } from '../../singletons';
import { getDruidErrorMessage } from '../../utils';
import './overlord-dynamic-config-dialog.scss';
@ -43,7 +42,7 @@ export const OverlordDynamicConfigDialog = React.memo(function OverlordDynamicCo
const [historyRecordsState] = useQueryManager<null, any[]>({
processQuery: async () => {
const historyResp = await axios(`/druid/indexer/v1/worker/history?count=100`);
const historyResp = await Api.instance.get(`/druid/indexer/v1/worker/history?count=100`);
return historyResp.data;
},
initQuery: null,
@ -52,7 +51,7 @@ export const OverlordDynamicConfigDialog = React.memo(function OverlordDynamicCo
useQueryManager<null, Record<string, any>>({
processQuery: async () => {
try {
const configResp = await axios(`/druid/indexer/v1/worker`);
const configResp = await Api.instance.get(`/druid/indexer/v1/worker`);
setDynamicConfig(configResp.data || {});
} catch (e) {
AppToaster.show({
@ -70,7 +69,7 @@ export const OverlordDynamicConfigDialog = React.memo(function OverlordDynamicCo
async function saveConfig(comment: string) {
try {
await axios.post('/druid/indexer/v1/worker', dynamicConfig, {
await Api.instance.post('/druid/indexer/v1/worker', dynamicConfig, {
headers: {
'X-Druid-Author': 'console',
'X-Druid-Comment': comment,

View File

@ -18,13 +18,13 @@
import { Button, Divider, FormGroup } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import React, { useState } from 'react';
import { SnitchDialog } from '..';
import { ExternalLink, RuleEditor } from '../../components';
import { useQueryManager } from '../../hooks';
import { getLink } from '../../links';
import { Api } from '../../singletons';
import { swapElements } from '../../utils';
import { Rule, RuleUtil } from '../../utils/load-rule';
@ -46,7 +46,9 @@ export const RetentionDialog = React.memo(function RetentionDialog(props: Retent
const [historyQueryState] = useQueryManager<string, any[]>({
processQuery: async datasource => {
const historyResp = await axios(`/druid/coordinator/v1/rules/${datasource}/history`);
const historyResp = await Api.instance.get(
`/druid/coordinator/v1/rules/${datasource}/history`,
);
return historyResp.data;
},
initQuery: props.datasource,

View File

@ -21,7 +21,7 @@ import { IconNames } from '@blueprintjs/icons';
import copy from 'copy-to-clipboard';
import React from 'react';
import { AppToaster } from '../../singletons/toaster';
import { AppToaster } from '../../singletons';
import './show-value-dialog.scss';

View File

@ -17,13 +17,12 @@
*/
import { Button, Classes, Dialog, Intent } from '@blueprintjs/core';
import axios from 'axios';
import React from 'react';
import ReactTable, { Filter } from 'react-table';
import { Loader } from '../../components';
import { useQueryManager } from '../../hooks';
import { UrlBaser } from '../../singletons/url-baser';
import { Api, UrlBaser } from '../../singletons';
import './status-dialog.scss';
@ -50,7 +49,7 @@ export const StatusDialog = React.memo(function StatusDialog(props: StatusDialog
const { onClose } = props;
const [responseState] = useQueryManager<null, StatusResponse>({
processQuery: async () => {
const resp = await axios.get(`/status`);
const resp = await Api.instance.get(`/status`);
return resp.data;
},
initQuery: null,

View File

@ -16,24 +16,22 @@
* limitations under the License.
*/
import axios from 'axios';
import 'brace'; // Import Ace editor and all the sub components used in the app
import 'brace/ext/language_tools';
import 'brace/theme/solarized_dark';
import { AxiosRequestConfig } from 'axios';
import 'core-js/stable';
import React from 'react';
import ReactDOM from 'react-dom';
import 'regenerator-runtime/runtime';
import './ace-modes/dsql';
import './ace-modes/hjson';
import './bootstrap/react-table-defaults';
import './bootstrap/ace';
import { bootstrapReactTable } from './bootstrap/react-table-defaults';
import { ConsoleApplication } from './console-application';
import { Links, setLinkOverrides } from './links';
import { UrlBaser } from './singletons/url-baser';
import { Api, UrlBaser } from './singletons';
import './entry.scss';
bootstrapReactTable();
const container = document.getElementsByClassName('app-container')[0];
if (!container) throw new Error('container not found');
@ -69,16 +67,23 @@ if (typeof consoleConfig.title === 'string') {
window.document.title = consoleConfig.title;
}
const apiConfig: AxiosRequestConfig = {
headers: {},
};
if (consoleConfig.baseURL) {
axios.defaults.baseURL = consoleConfig.baseURL;
apiConfig.baseURL = consoleConfig.baseURL;
UrlBaser.baseUrl = consoleConfig.baseURL;
}
if (consoleConfig.customHeaderName && consoleConfig.customHeaderValue) {
axios.defaults.headers.common[consoleConfig.customHeaderName] = consoleConfig.customHeaderValue;
apiConfig.headers.common[consoleConfig.customHeaderName] = consoleConfig.customHeaderValue;
}
if (consoleConfig.customHeaders) {
Object.assign(axios.defaults.headers, consoleConfig.customHeaders);
Object.assign(apiConfig.headers, consoleConfig.customHeaders);
}
Api.initialize(apiConfig);
if (consoleConfig.linkOverrides) {
setLinkOverrides(consoleConfig.linkOverrides);
}

View File

@ -20,7 +20,7 @@ import 'core-js/stable';
import { configure } from 'enzyme';
import enzymeAdapterReact16 from 'enzyme-adapter-react-16';
import { UrlBaser } from './singletons/url-baser';
import { UrlBaser } from './singletons';
configure({ adapter: new (enzymeAdapterReact16 as any)() });

View File

@ -0,0 +1,27 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
export class Api {
static instance: AxiosInstance;
static initialize(config?: AxiosRequestConfig): void {
Api.instance = axios.create(config);
}
}

View File

@ -0,0 +1,21 @@
/*
* 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.
*/
export * from './api';
export * from './toaster';
export * from './url-baser';

View File

@ -16,7 +16,7 @@
* limitations under the License.
*/
import axios from 'axios';
import { Api } from '../singletons';
import { localStorageGetJson, LocalStorageKeys } from './local-storage-keys';
@ -51,7 +51,7 @@ export class Capabilities {
static async detectQueryType(): Promise<QueryType | undefined> {
// Check SQL endpoint
try {
await axios.post(
await Api.instance.post(
'/druid/v2/sql',
{ query: 'SELECT 1337', context: { timeout: Capabilities.STATUS_TIMEOUT } },
{ timeout: Capabilities.STATUS_TIMEOUT },
@ -62,14 +62,14 @@ export class Capabilities {
return; // other failure
}
try {
await axios.get('/status', { timeout: Capabilities.STATUS_TIMEOUT });
await Api.instance.get('/status', { timeout: Capabilities.STATUS_TIMEOUT });
} catch (e) {
return; // total failure
}
// Status works but SQL 405s => the SQL endpoint is disabled
try {
await axios.post(
await Api.instance.post(
'/druid/v2',
{
queryType: 'dataSourceMetadata',
@ -94,7 +94,7 @@ export class Capabilities {
static async detectNode(node: 'coordinator' | 'overlord'): Promise<boolean | undefined> {
try {
await axios.get(`/druid/${node === 'overlord' ? 'indexer' : node}/v1/isLeader`, {
await Api.instance.get(`/druid/${node === 'overlord' ? 'indexer' : node}/v1/isLeader`, {
timeout: Capabilities.STATUS_TIMEOUT,
});
} catch (e) {

View File

@ -16,8 +16,9 @@
* limitations under the License.
*/
import axios from 'axios';
import { AxiosResponse } from 'axios';
import axios, { AxiosResponse } from 'axios';
import { Api } from '../singletons';
import { assemble } from './general';
import { RowColumn } from './query-cursor';
@ -213,7 +214,7 @@ export class DruidError extends Error {
export async function queryDruidRune(runeQuery: Record<string, any>): Promise<any> {
let runeResultResp: AxiosResponse<any>;
try {
runeResultResp = await axios.post('/druid/v2', runeQuery);
runeResultResp = await Api.instance.post('/druid/v2', runeQuery);
} catch (e) {
throw new Error(getDruidErrorMessage(e));
}
@ -223,7 +224,7 @@ export async function queryDruidRune(runeQuery: Record<string, any>): Promise<an
export async function queryDruidSql<T = any>(sqlQueryPayload: Record<string, any>): Promise<T[]> {
let sqlResultResp: AxiosResponse<any>;
try {
sqlResultResp = await axios.post('/druid/v2/sql', sqlQueryPayload);
sqlResultResp = await Api.instance.post('/druid/v2/sql', sqlQueryPayload);
} catch (e) {
throw new Error(getDruidErrorMessage(e));
}

View File

@ -26,7 +26,7 @@ import numeral from 'numeral';
import React from 'react';
import { Filter, FilterRender } from 'react-table';
import { AppToaster } from '../singletons/toaster';
import { AppToaster } from '../singletons';
// These constants are used to make sure that they are not constantly recreated thrashing the pure components
export const EMPTY_OBJECT: any = {};

View File

@ -16,8 +16,6 @@
* limitations under the License.
*/
import axios from 'axios';
import {
DimensionsSpec,
getSpecType,
@ -34,6 +32,7 @@ import {
TransformSpec,
upgradeSpec,
} from '../druid-models';
import { Api } from '../singletons';
import { getDruidErrorMessage, queryDruidRune } from './druid-query';
import {
@ -181,7 +180,7 @@ export function headerAndRowsFromSampleResponse(
export async function getProxyOverlordModules(): Promise<string[]> {
let statusResp: any;
try {
statusResp = await axios.get(`/proxy/overlord/status`);
statusResp = await Api.instance.get(`/proxy/overlord/status`);
} catch (e) {
throw new Error(getDruidErrorMessage(e));
}
@ -197,7 +196,7 @@ export async function postToSampler(
let sampleResp: any;
try {
sampleResp = await axios.post(`${SAMPLER_URL}?for=${forStr}`, sampleSpec);
sampleResp = await Api.instance.post(`${SAMPLER_URL}?for=${forStr}`, sampleSpec);
} catch (e) {
throw new Error(getDruidErrorMessage(e));
}

View File

@ -19,7 +19,7 @@
import { shallow } from 'enzyme';
import React from 'react';
import { Capabilities } from '../../utils/capabilities';
import { Capabilities } from '../../utils';
import { DatasourcesView } from './datasource-view';

View File

@ -18,7 +18,6 @@
import { FormGroup, InputGroup, Intent, MenuItem, Switch } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import classNames from 'classnames';
import { SqlQuery, SqlRef } from 'druid-query-toolkit';
import React from 'react';
@ -45,7 +44,7 @@ import {
formatCompactionConfigAndStatus,
zeroCompactionStatus,
} from '../../druid-models';
import { AppToaster } from '../../singletons/toaster';
import { Api, AppToaster } from '../../singletons';
import {
addFilter,
Capabilities,
@ -317,8 +316,10 @@ GROUP BY 1`;
if (capabilities.hasSql()) {
datasources = await queryDruidSql({ query: DatasourcesView.DATASOURCE_SQL });
} else if (capabilities.hasCoordinatorAccess()) {
const datasourcesResp = await axios.get('/druid/coordinator/v1/datasources?simple');
const loadstatusResp = await axios.get('/druid/coordinator/v1/loadstatus?simple');
const datasourcesResp = await Api.instance.get(
'/druid/coordinator/v1/datasources?simple',
);
const loadstatusResp = await Api.instance.get('/druid/coordinator/v1/loadstatus?simple');
const loadstatus = loadstatusResp.data;
datasources = datasourcesResp.data.map(
(d: any): DatasourceQueryResultRow => {
@ -367,22 +368,26 @@ GROUP BY 1`;
if (this.state.showUnused) {
// Using 'includeDisabled' parameter for compatibility.
// Should be changed to 'includeUnused' in Druid 0.17
const unusedResp = await axios.get(
const unusedResp = await Api.instance.get(
'/druid/coordinator/v1/metadata/datasources?includeDisabled',
);
unused = unusedResp.data.filter((d: string) => !seen[d]);
}
const rulesResp = await axios.get('/druid/coordinator/v1/rules');
const rulesResp = await Api.instance.get('/druid/coordinator/v1/rules');
const rules = rulesResp.data;
const compactionConfigsResp = await axios.get('/druid/coordinator/v1/config/compaction');
const compactionConfigsResp = await Api.instance.get(
'/druid/coordinator/v1/config/compaction',
);
const compactionConfigs = lookupBy(
compactionConfigsResp.data.compactionConfigs || [],
(c: CompactionConfig) => c.dataSource,
);
const compactionStatusesResp = await axios.get('/druid/coordinator/v1/compaction/status');
const compactionStatusesResp = await Api.instance.get(
'/druid/coordinator/v1/compaction/status',
);
const compactionStatuses = lookupBy(
compactionStatusesResp.data.latestStatus || [],
(c: CompactionStatus) => c.dataSource,
@ -412,7 +417,7 @@ GROUP BY 1`;
this.tiersQueryManager = new QueryManager({
processQuery: async capabilities => {
if (capabilities.hasCoordinatorAccess()) {
const tiersResp = await axios.get('/druid/coordinator/v1/tiers');
const tiersResp = await Api.instance.get('/druid/coordinator/v1/tiers');
return tiersResp.data;
} else {
throw new Error(`must have coordinator access`);
@ -455,7 +460,7 @@ GROUP BY 1`;
return (
<AsyncActionDialog
action={async () => {
const resp = await axios.delete(
const resp = await Api.instance.delete(
`/druid/coordinator/v1/datasources/${datasourceToMarkAsUnusedAllSegmentsIn}`,
{},
);
@ -486,7 +491,7 @@ GROUP BY 1`;
return (
<AsyncActionDialog
action={async () => {
const resp = await axios.post(
const resp = await Api.instance.post(
`/druid/coordinator/v1/datasources/${datasourceToMarkAllNonOvershadowedSegmentsAsUsedIn}`,
{},
);
@ -518,7 +523,7 @@ GROUP BY 1`;
action={async () => {
if (!useUnuseInterval) return;
const param = isUse ? 'markUsed' : 'markUnused';
const resp = await axios.post(
const resp = await Api.instance.post(
`/druid/coordinator/v1/datasources/${datasourceToMarkSegmentsByIntervalIn}/${param}`,
{
interval: useUnuseInterval,
@ -560,7 +565,7 @@ GROUP BY 1`;
return (
<AsyncActionDialog
action={async () => {
const resp = await axios.delete(
const resp = await Api.instance.delete(
`/druid/coordinator/v1/datasources/${killDatasource}?kill=true&interval=1000/3000`,
{},
);
@ -628,7 +633,7 @@ GROUP BY 1`;
return (
<AsyncActionDialog
action={async () => {
const resp = await axios.post(`/druid/coordinator/v1/compaction/compact`, {});
const resp = await Api.instance.post(`/druid/coordinator/v1/compaction/compact`, {});
return resp.data;
}}
confirmButtonText="Force compaction run"
@ -648,7 +653,7 @@ GROUP BY 1`;
private saveRules = async (datasource: string, rules: Rule[], comment: string) => {
try {
await axios.post(`/druid/coordinator/v1/rules/${datasource}`, rules, {
await Api.instance.post(`/druid/coordinator/v1/rules/${datasource}`, rules, {
headers: {
'X-Druid-Author': 'console',
'X-Druid-Comment': comment,
@ -689,7 +694,7 @@ GROUP BY 1`;
private saveCompaction = async (compactionConfig: any) => {
if (!compactionConfig) return;
try {
await axios.post(`/druid/coordinator/v1/config/compaction`, compactionConfig);
await Api.instance.post(`/druid/coordinator/v1/config/compaction`, compactionConfig);
this.setState({ compactionDialogOpenOn: undefined });
this.datasourceQueryManager.rerunLastQuery();
} catch (e) {
@ -711,7 +716,7 @@ GROUP BY 1`;
text: 'Confirm',
onClick: async () => {
try {
await axios.delete(`/druid/coordinator/v1/config/compaction/${datasource}`);
await Api.instance.delete(`/druid/coordinator/v1/config/compaction/${datasource}`);
this.setState({ compactionDialogOpenOn: undefined }, () =>
this.datasourceQueryManager.rerunLastQuery(),
);

View File

@ -19,7 +19,7 @@
import { render } from '@testing-library/react';
import React from 'react';
import { Capabilities } from '../../../utils/capabilities';
import { Capabilities } from '../../../utils';
import { DatasourcesCard } from './datasources-card';

View File

@ -17,12 +17,12 @@
*/
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import React from 'react';
import { useQueryManager } from '../../../hooks';
import { Api } from '../../../singletons';
import { pluralIfNeeded, queryDruidSql } from '../../../utils';
import { Capabilities } from '../../../utils/capabilities';
import { Capabilities } from '../../../utils';
import { HomeViewCard } from '../home-view-card/home-view-card';
export interface DatasourcesCardProps {
@ -38,7 +38,7 @@ export const DatasourcesCard = React.memo(function DatasourcesCard(props: Dataso
query: `SELECT datasource FROM sys.segments GROUP BY 1`,
});
} else if (capabilities.hasCoordinatorAccess()) {
const datasourcesResp = await axios.get('/druid/coordinator/v1/datasources');
const datasourcesResp = await Api.instance.get('/druid/coordinator/v1/datasources');
datasources = datasourcesResp.data;
} else {
throw new Error(`must have SQL or coordinator access`);

View File

@ -19,7 +19,7 @@
import { shallow } from 'enzyme';
import React from 'react';
import { Capabilities } from '../../utils/capabilities';
import { Capabilities } from '../../utils';
import { HomeView } from './home-view';

View File

@ -18,7 +18,7 @@
import React from 'react';
import { Capabilities } from '../../utils/capabilities';
import { Capabilities } from '../../utils';
import { DatasourcesCard } from './datasources-card/datasources-card';
import { LookupsCard } from './lookups-card/lookups-card';

View File

@ -19,7 +19,7 @@
import { render } from '@testing-library/react';
import React from 'react';
import { Capabilities } from '../../../utils/capabilities';
import { Capabilities } from '../../../utils';
import { LookupsCard } from './lookups-card';

View File

@ -17,13 +17,13 @@
*/
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import { sum } from 'd3-array';
import React from 'react';
import { useQueryManager } from '../../../hooks';
import { Api } from '../../../singletons';
import { isLookupsUninitialized, pluralIfNeeded } from '../../../utils';
import { Capabilities } from '../../../utils/capabilities';
import { Capabilities } from '../../../utils';
import { HomeViewCard } from '../home-view-card/home-view-card';
export interface LookupsCardProps {
@ -34,7 +34,7 @@ export const LookupsCard = React.memo(function LookupsCard(props: LookupsCardPro
const [lookupsCountState] = useQueryManager<Capabilities, number>({
processQuery: async capabilities => {
if (capabilities.hasCoordinatorAccess()) {
const resp = await axios.get('/druid/coordinator/v1/lookups/status');
const resp = await Api.instance.get('/druid/coordinator/v1/lookups/status');
const data = resp.data;
return sum(Object.keys(data).map(k => Object.keys(data[k]).length));
} else {

View File

@ -19,7 +19,7 @@
import { render } from '@testing-library/react';
import React from 'react';
import { Capabilities } from '../../../utils/capabilities';
import { Capabilities } from '../../../utils';
import { SegmentsCard } from './segments-card';

View File

@ -17,11 +17,11 @@
*/
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import { sum } from 'd3-array';
import React from 'react';
import { useQueryManager } from '../../../hooks';
import { Api } from '../../../singletons';
import { Capabilities, deepGet, pluralIfNeeded, queryDruidSql } from '../../../utils';
import { HomeViewCard } from '../home-view-card/home-view-card';
@ -46,11 +46,13 @@ FROM sys.segments`,
});
return segments.length === 1 ? segments[0] : null;
} else if (capabilities.hasCoordinatorAccess()) {
const loadstatusResp = await axios.get('/druid/coordinator/v1/loadstatus?simple');
const loadstatusResp = await Api.instance.get('/druid/coordinator/v1/loadstatus?simple');
const loadstatus = loadstatusResp.data;
const unavailableSegmentNum = sum(Object.keys(loadstatus), key => loadstatus[key]);
const datasourcesMetaResp = await axios.get('/druid/coordinator/v1/datasources?simple');
const datasourcesMetaResp = await Api.instance.get(
'/druid/coordinator/v1/datasources?simple',
);
const datasourcesMeta = datasourcesMetaResp.data;
const availableSegmentNum = sum(datasourcesMeta, (curr: any) =>
deepGet(curr, 'properties.segments.count'),

View File

@ -19,7 +19,7 @@
import { render } from '@testing-library/react';
import React from 'react';
import { Capabilities } from '../../../utils/capabilities';
import { Capabilities } from '../../../utils';
import { ServicesCard } from './services-card';

View File

@ -17,13 +17,13 @@
*/
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import React from 'react';
import { PluralPairIfNeeded } from '../../../components/plural-pair-if-needed/plural-pair-if-needed';
import { useQueryManager } from '../../../hooks';
import { Api } from '../../../singletons';
import { lookupBy, queryDruidSql } from '../../../utils';
import { Capabilities } from '../../../utils/capabilities';
import { Capabilities } from '../../../utils';
import { HomeViewCard } from '../home-view-card/home-view-card';
export interface ServiceCounts {
@ -53,10 +53,10 @@ export const ServicesCard = React.memo(function ServicesCard(props: ServicesCard
});
return lookupBy(serviceCountsFromQuery, x => x.service_type, x => x.count);
} else if (capabilities.hasCoordinatorAccess()) {
const services = (await axios.get('/druid/coordinator/v1/servers?simple')).data;
const services = (await Api.instance.get('/druid/coordinator/v1/servers?simple')).data;
const middleManager = capabilities.hasOverlordAccess()
? (await axios.get('/druid/indexer/v1/workers')).data
? (await Api.instance.get('/druid/indexer/v1/workers')).data
: [];
return {

View File

@ -17,11 +17,11 @@
*/
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import React, { useState } from 'react';
import { StatusDialog } from '../../../dialogs/status-dialog/status-dialog';
import { useQueryManager } from '../../../hooks';
import { Api } from '../../../singletons';
import { pluralIfNeeded } from '../../../utils';
import { HomeViewCard } from '../home-view-card/home-view-card';
@ -36,7 +36,7 @@ export const StatusCard = React.memo(function StatusCard(_props: StatusCardProps
const [showStatusDialog, setShowStatusDialog] = useState(false);
const [statusSummaryState] = useQueryManager<null, StatusSummary>({
processQuery: async () => {
const statusResp = await axios.get('/status');
const statusResp = await Api.instance.get('/status');
return {
version: statusResp.data.version,
extensionCount: statusResp.data.modules.length,

View File

@ -19,7 +19,7 @@
import { render } from '@testing-library/react';
import React from 'react';
import { Capabilities } from '../../../utils/capabilities';
import { Capabilities } from '../../../utils';
import { SupervisorsCard } from './supervisors-card';

View File

@ -17,12 +17,12 @@
*/
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import React from 'react';
import { useQueryManager } from '../../../hooks';
import { Api } from '../../../singletons';
import { pluralIfNeeded, queryDruidSql } from '../../../utils';
import { Capabilities } from '../../../utils/capabilities';
import { Capabilities } from '../../../utils';
import { HomeViewCard } from '../home-view-card/home-view-card';
export interface SupervisorCounts {
@ -45,7 +45,7 @@ export const SupervisorsCard = React.memo(function SupervisorsCard(props: Superv
FROM sys.supervisors`,
}))[0];
} else if (capabilities.hasOverlordAccess()) {
const resp = await axios.get('/druid/indexer/v1/supervisor?full');
const resp = await Api.instance.get('/druid/indexer/v1/supervisor?full');
const data = resp.data;
return {
running: data.filter((d: any) => d.spec.suspended === false).length,

View File

@ -19,7 +19,7 @@
import { render } from '@testing-library/react';
import React from 'react';
import { Capabilities } from '../../../utils/capabilities';
import { Capabilities } from '../../../utils';
import { TasksCard } from './tasks-card';

View File

@ -17,13 +17,13 @@
*/
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import React from 'react';
import { PluralPairIfNeeded } from '../../../components/plural-pair-if-needed/plural-pair-if-needed';
import { useQueryManager } from '../../../hooks';
import { Api } from '../../../singletons';
import { lookupBy, pluralIfNeeded, queryDruidSql } from '../../../utils';
import { Capabilities } from '../../../utils/capabilities';
import { Capabilities } from '../../../utils';
import { HomeViewCard } from '../home-view-card/home-view-card';
function getTaskStatus(d: any) {
@ -55,7 +55,7 @@ GROUP BY 1`,
});
return lookupBy(taskCountsFromQuery, x => x.status, x => x.count);
} else if (capabilities.hasOverlordAccess()) {
const tasks: any[] = (await axios.get('/druid/indexer/v1/tasks')).data;
const tasks: any[] = (await Api.instance.get('/druid/indexer/v1/tasks')).data;
return {
SUCCESS: tasks.filter(d => getTaskStatus(d) === 'SUCCESS').length,
FAILED: tasks.filter(d => getTaskStatus(d) === 'FAILED').length,

View File

@ -19,7 +19,7 @@
import { shallow } from 'enzyme';
import React from 'react';
import { Capabilities } from '../../utils/capabilities';
import { Capabilities } from '../../utils';
import { IngestionView } from './ingestion-view';

View File

@ -18,7 +18,6 @@
import { Alert, Button, ButtonGroup, Intent, Label, MenuItem } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import React from 'react';
import SplitterLayout from 'react-splitter-layout';
import ReactTable from 'react-table';
@ -40,7 +39,7 @@ import {
SupervisorTableActionDialog,
TaskTableActionDialog,
} from '../../dialogs';
import { AppToaster } from '../../singletons/toaster';
import { Api, AppToaster } from '../../singletons';
import {
addFilter,
addFilterRaw,
@ -56,8 +55,8 @@ import {
QueryManager,
QueryState,
} from '../../utils';
import { Capabilities } from '../../utils';
import { BasicAction } from '../../utils/basic-action';
import { Capabilities } from '../../utils/capabilities';
import { LocalStorageBackedArray } from '../../utils/local-storage-backed-array';
import './ingestion-view.scss';
@ -251,7 +250,7 @@ ORDER BY "rank" DESC, "created_time" DESC`;
query: IngestionView.SUPERVISOR_SQL,
});
} else if (capabilities.hasOverlordAccess()) {
const supervisors = (await axios.get('/druid/indexer/v1/supervisor?full')).data;
const supervisors = (await Api.instance.get('/druid/indexer/v1/supervisor?full')).data;
if (!Array.isArray(supervisors)) throw new Error(`Unexpected results`);
return supervisors.map((sup: any) => {
return {
@ -284,7 +283,7 @@ ORDER BY "rank" DESC, "created_time" DESC`;
query: IngestionView.TASK_SQL,
});
} else if (capabilities.hasOverlordAccess()) {
const resp = await axios.get(`/druid/indexer/v1/tasks`);
const resp = await Api.instance.get(`/druid/indexer/v1/tasks`);
return IngestionView.parseTasks(resp.data);
} else {
throw new Error(`must have SQL or overlord access`);
@ -343,7 +342,7 @@ ORDER BY "rank" DESC, "created_time" DESC`;
private submitSupervisor = async (spec: JSON) => {
try {
await axios.post('/druid/indexer/v1/supervisor', spec);
await Api.instance.post('/druid/indexer/v1/supervisor', spec);
} catch (e) {
AppToaster.show({
message: `Failed to submit supervisor: ${getDruidErrorMessage(e)}`,
@ -361,7 +360,7 @@ ORDER BY "rank" DESC, "created_time" DESC`;
private submitTask = async (spec: JSON) => {
try {
await axios.post('/druid/indexer/v1/task', spec);
await Api.instance.post('/druid/indexer/v1/task', spec);
} catch (e) {
AppToaster.show({
message: `Failed to submit task: ${getDruidErrorMessage(e)}`,
@ -431,7 +430,7 @@ ORDER BY "rank" DESC, "created_time" DESC`;
return (
<AsyncActionDialog
action={async () => {
const resp = await axios.post(
const resp = await Api.instance.post(
`/druid/indexer/v1/supervisor/${resumeSupervisorId}/resume`,
{},
);
@ -460,7 +459,7 @@ ORDER BY "rank" DESC, "created_time" DESC`;
return (
<AsyncActionDialog
action={async () => {
const resp = await axios.post(
const resp = await Api.instance.post(
`/druid/indexer/v1/supervisor/${suspendSupervisorId}/suspend`,
{},
);
@ -489,7 +488,7 @@ ORDER BY "rank" DESC, "created_time" DESC`;
return (
<AsyncActionDialog
action={async () => {
const resp = await axios.post(
const resp = await Api.instance.post(
`/druid/indexer/v1/supervisor/${resetSupervisorId}/reset`,
{},
);
@ -527,7 +526,7 @@ ORDER BY "rank" DESC, "created_time" DESC`;
return (
<AsyncActionDialog
action={async () => {
const resp = await axios.post(
const resp = await Api.instance.post(
`/druid/indexer/v1/supervisor/${terminateSupervisorId}/terminate`,
{},
);
@ -684,7 +683,7 @@ ORDER BY "rank" DESC, "created_time" DESC`;
return (
<AsyncActionDialog
action={async () => {
const resp = await axios.post(`/druid/indexer/v1/task/${killTaskId}/shutdown`, {});
const resp = await Api.instance.post(`/druid/indexer/v1/task/${killTaskId}/shutdown`, {});
return resp.data;
}}
confirmButtonText="Kill task"
@ -945,7 +944,7 @@ ORDER BY "rank" DESC, "created_time" DESC`;
return (
<AsyncActionDialog
action={async () => {
const resp = await axios.post(`/druid/indexer/v1/supervisor/resumeAll`, {});
const resp = await Api.instance.post(`/druid/indexer/v1/supervisor/resumeAll`, {});
return resp.data;
}}
confirmButtonText="Resume all supervisors"
@ -971,7 +970,7 @@ ORDER BY "rank" DESC, "created_time" DESC`;
return (
<AsyncActionDialog
action={async () => {
const resp = await axios.post(`/druid/indexer/v1/supervisor/suspendAll`, {});
const resp = await Api.instance.post(`/druid/indexer/v1/supervisor/suspendAll`, {});
return resp.data;
}}
confirmButtonText="Suspend all supervisors"
@ -997,7 +996,7 @@ ORDER BY "rank" DESC, "created_time" DESC`;
return (
<AsyncActionDialog
action={async () => {
const resp = await axios.post(`/druid/indexer/v1/supervisor/terminateAll`, {});
const resp = await Api.instance.post(`/druid/indexer/v1/supervisor/terminateAll`, {});
return resp.data;
}}
confirmButtonText="Terminate all supervisors"

View File

@ -39,7 +39,6 @@ import {
TextArea,
} from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import classNames from 'classnames';
import memoize from 'memoize-one';
import React from 'react';
@ -121,8 +120,7 @@ import {
upgradeSpec,
} from '../../druid-models';
import { getLink } from '../../links';
import { AppToaster } from '../../singletons/toaster';
import { UrlBaser } from '../../singletons/url-baser';
import { Api, AppToaster, UrlBaser } from '../../singletons';
import {
deepDelete,
deepGet,
@ -3220,7 +3218,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
const { initSupervisorId } = this.props;
try {
const resp = await axios.get(`/druid/indexer/v1/supervisor/${initSupervisorId}`);
const resp = await Api.instance.get(`/druid/indexer/v1/supervisor/${initSupervisorId}`);
this.updateSpec(cleanSpec(resp.data));
this.setState({ continueToSpec: true });
this.updateStep('spec');
@ -3236,7 +3234,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
const { initTaskId } = this.props;
try {
const resp = await axios.get(`/druid/indexer/v1/task/${initTaskId}`);
const resp = await Api.instance.get(`/druid/indexer/v1/task/${initTaskId}`);
this.updateSpec(cleanSpec(resp.data.payload));
this.setState({ continueToSpec: true });
this.updateStep('spec');
@ -3302,7 +3300,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
if (isTask(spec)) {
let taskResp: any;
try {
taskResp = await axios.post('/druid/indexer/v1/task', spec);
taskResp = await Api.instance.post('/druid/indexer/v1/task', spec);
} catch (e) {
AppToaster.show({
message: `Failed to submit task: ${getDruidErrorMessage(e)}`,
@ -3322,7 +3320,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
}, 1000);
} else {
try {
await axios.post('/druid/indexer/v1/supervisor', spec);
await Api.instance.post('/druid/indexer/v1/supervisor', spec);
} catch (e) {
AppToaster.show({
message: `Failed to submit supervisor: ${getDruidErrorMessage(e)}`,

View File

@ -18,7 +18,6 @@
import { Button, Intent } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import React from 'react';
import ReactTable from 'react-table';
@ -34,7 +33,7 @@ import {
import { AsyncActionDialog, LookupEditDialog } from '../../dialogs/';
import { LookupTableActionDialog } from '../../dialogs/lookup-table-action-dialog/lookup-table-action-dialog';
import { LookupSpec } from '../../druid-models';
import { AppToaster } from '../../singletons/toaster';
import { Api, AppToaster } from '../../singletons';
import {
getDruidErrorMessage,
isLookupsUninitialized,
@ -107,14 +106,16 @@ export class LookupsView extends React.PureComponent<LookupsViewProps, LookupsVi
this.lookupsQueryManager = new QueryManager({
processQuery: async () => {
const tiersResp = await axios.get('/druid/coordinator/v1/lookups/config?discover=true');
const tiersResp = await Api.instance.get(
'/druid/coordinator/v1/lookups/config?discover=true',
);
const tiers =
tiersResp.data && tiersResp.data.length > 0
? tiersResp.data.sort(tierNameCompare)
: [DEFAULT_LOOKUP_TIER];
const lookupEntries: {}[] = [];
const lookupResp = await axios.get('/druid/coordinator/v1/lookups/config/all');
const lookupResp = await Api.instance.get('/druid/coordinator/v1/lookups/config/all');
const lookupData = lookupResp.data;
Object.keys(lookupData).map((tier: string) => {
const lookupIds = lookupData[tier];
@ -151,7 +152,7 @@ export class LookupsView extends React.PureComponent<LookupsViewProps, LookupsVi
private async initializeLookup() {
try {
await axios.post(`/druid/coordinator/v1/lookups/config`, {});
await Api.instance.post(`/druid/coordinator/v1/lookups/config`, {});
this.lookupsQueryManager.rerunLastQuery();
} catch (e) {
AppToaster.show({
@ -228,7 +229,7 @@ export class LookupsView extends React.PureComponent<LookupsViewProps, LookupsVi
};
}
try {
await axios.post(endpoint, dataJson);
await Api.instance.post(endpoint, dataJson);
this.setState({
lookupEdit: undefined,
});
@ -265,7 +266,7 @@ export class LookupsView extends React.PureComponent<LookupsViewProps, LookupsVi
return (
<AsyncActionDialog
action={async () => {
await axios.delete(
await Api.instance.delete(
`/druid/coordinator/v1/lookups/config/${deleteLookupTier}/${deleteLookupName}`,
);
}}

View File

@ -32,7 +32,7 @@ exports[`sql view matches snapshot 1`] = `
runeMode={false}
/>
<div
className="control-bar"
className="query-control-bar"
>
<HotkeysTarget(RunButton)
loading={true}
@ -109,7 +109,7 @@ exports[`sql view matches snapshot with query 1`] = `
runeMode={false}
/>
<div
className="control-bar"
className="query-control-bar"
>
<HotkeysTarget(RunButton)
loading={true}

View File

@ -94,7 +94,7 @@ function handleColumnClick(options: HandleColumnClickOptions): void {
let newSelectExpressions = query.selectExpressions;
for (const aggregate of aggregates) {
newSelectExpressions = newSelectExpressions.addLast(aggregate);
newSelectExpressions = newSelectExpressions.append(aggregate);
}
onQueryChange(
@ -339,7 +339,7 @@ export class ColumnTree extends React.PureComponent<ColumnTreeProps, ColumnTreeS
}}
/>
{parsedQuery &&
oneOf(columnData.DATA_TYPE, 'BIGINT', 'FLOAT') && (
oneOf(columnData.DATA_TYPE, 'BIGINT', 'FLOAT', 'DOUBLE') && (
<NumberMenuItems
table={tableName}
schema={schemaName}

View File

@ -31,7 +31,7 @@ import copy from 'copy-to-clipboard';
import { QueryResult } from 'druid-query-toolkit';
import React from 'react';
import { AppToaster } from '../../../singletons/toaster';
import { AppToaster } from '../../../singletons';
import { pluralIfNeeded } from '../../../utils';
import './query-extra-info.scss';

View File

@ -27,6 +27,7 @@ export function dataTypeToIcon(dataType: string): IconName {
return IconNames.FONT;
case 'BIGINT':
case 'FLOAT':
case 'DOUBLE':
return IconNames.NUMERICAL;
default:
return IconNames.HELP;

View File

@ -57,7 +57,7 @@ $nav-width: 250px;
overflow: hidden;
}
.control-bar {
.query-control-bar {
position: absolute;
bottom: 0;
width: 100%;

View File

@ -17,7 +17,6 @@
*/
import { Code, Intent, Switch, Tooltip } from '@blueprintjs/core';
import axios from 'axios';
import classNames from 'classnames';
import { QueryResult, QueryRunner, SqlQuery } from 'druid-query-toolkit';
import Hjson from 'hjson';
@ -29,7 +28,7 @@ import { Loader } from '../../components';
import { QueryPlanDialog } from '../../dialogs';
import { EditContextDialog } from '../../dialogs/edit-context-dialog/edit-context-dialog';
import { QueryHistoryDialog } from '../../dialogs/query-history-dialog/query-history-dialog';
import { AppToaster } from '../../singletons/toaster';
import { Api, AppToaster } from '../../singletons';
import {
BasicQueryExplanation,
ColumnMetadata,
@ -225,7 +224,7 @@ export class QueryView extends React.PureComponent<QueryViewProps, QueryViewStat
});
const queryRunner = new QueryRunner((payload, isSql, cancelToken) => {
return axios.post(`/druid/v2${isSql ? '/sql' : ''}`, payload, { cancelToken });
return Api.instance.post(`/druid/v2${isSql ? '/sql' : ''}`, payload, { cancelToken });
});
this.queryManager = new QueryManager({
@ -482,7 +481,7 @@ export class QueryView extends React.PureComponent<QueryViewProps, QueryViewStat
runeMode={runeMode}
columnMetadata={columnMetadataState.data}
/>
<div className="control-bar">
<div className="query-control-bar">
<RunButton
onEditContext={() => this.setState({ editContextDialogOpen: true })}
runeMode={runeMode}

View File

@ -19,7 +19,7 @@
import { shallow } from 'enzyme';
import React from 'react';
import { Capabilities } from '../../utils/capabilities';
import { Capabilities } from '../../utils';
import { SegmentsView } from '../segments-view/segments-view';
describe('segments-view', () => {

View File

@ -18,7 +18,6 @@
import { Button, ButtonGroup, Intent, Label, MenuItem } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import { SqlExpression, SqlRef } from 'druid-query-toolkit';
import React from 'react';
import ReactTable, { Filter } from 'react-table';
@ -36,6 +35,7 @@ import {
} from '../../components';
import { AsyncActionDialog } from '../../dialogs';
import { SegmentTableActionDialog } from '../../dialogs/segments-table-action-dialog/segment-table-action-dialog';
import { Api } from '../../singletons';
import {
addFilter,
compact,
@ -50,8 +50,8 @@ import {
QueryState,
sqlQueryCustomTableFilter,
} from '../../utils';
import { Capabilities, CapabilitiesMode } from '../../utils';
import { BasicAction } from '../../utils/basic-action';
import { Capabilities, CapabilitiesMode } from '../../utils/capabilities';
import { LocalStorageBackedArray } from '../../utils/local-storage-backed-array';
import './segments-view.scss';
@ -295,11 +295,13 @@ export class SegmentsView extends React.PureComponent<SegmentsViewProps, Segment
this.segmentsNoSqlQueryManager = new QueryManager({
processQuery: async () => {
const datasourceList = (await axios.get('/druid/coordinator/v1/metadata/datasources')).data;
const datasourceList = (await Api.instance.get(
'/druid/coordinator/v1/metadata/datasources',
)).data;
const nestedResults: SegmentQueryResultRow[][] = await Promise.all(
datasourceList.map(async (d: string) => {
const segments = (await axios.get(`/druid/coordinator/v1/datasources/${d}?full`)).data
.segments;
const segments = (await Api.instance.get(`/druid/coordinator/v1/datasources/${d}?full`))
.data.segments;
return segments.map(
(segment: any): SegmentQueryResultRow => {
@ -634,7 +636,7 @@ export class SegmentsView extends React.PureComponent<SegmentsViewProps, Segment
return (
<AsyncActionDialog
action={async () => {
const resp = await axios.delete(
const resp = await Api.instance.delete(
`/druid/coordinator/v1/datasources/${terminateDatasourceId}/segments/${terminateSegmentId}`,
{},
);

View File

@ -19,7 +19,7 @@
import { shallow } from 'enzyme';
import React from 'react';
import { Capabilities } from '../../utils/capabilities';
import { Capabilities } from '../../utils';
import { ServicesView } from './services-view';

View File

@ -18,7 +18,6 @@
import { Button, ButtonGroup, Intent, Label, MenuItem } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import axios from 'axios';
import { sum } from 'd3-array';
import React from 'react';
import ReactTable from 'react-table';
@ -35,6 +34,7 @@ import {
ViewControlBar,
} from '../../components';
import { AsyncActionDialog } from '../../dialogs';
import { Api } from '../../singletons';
import {
addFilter,
Capabilities,
@ -182,7 +182,7 @@ FROM sys.servers
ORDER BY "rank" DESC, "service" DESC`;
static async getServices(): Promise<ServiceQueryResultRow[]> {
const allServiceResp = await axios.get('/druid/coordinator/v1/servers?simple');
const allServiceResp = await Api.instance.get('/druid/coordinator/v1/servers?simple');
const allServices = allServiceResp.data;
return allServices.map((s: any) => {
return {
@ -221,7 +221,9 @@ ORDER BY "rank" DESC, "service" DESC`;
}
if (capabilities.hasCoordinatorAccess()) {
const loadQueueResponse = await axios.get('/druid/coordinator/v1/loadqueue?simple');
const loadQueueResponse = await Api.instance.get(
'/druid/coordinator/v1/loadqueue?simple',
);
const loadQueues: Record<string, LoadQueueStatus> = loadQueueResponse.data;
services = services.map(s => {
const loadQueueInfo = loadQueues[s.service];
@ -235,7 +237,7 @@ ORDER BY "rank" DESC, "service" DESC`;
if (capabilities.hasOverlordAccess()) {
let middleManagers: MiddleManagerQueryResultRow[];
try {
const middleManagerResponse = await axios.get('/druid/indexer/v1/workers');
const middleManagerResponse = await Api.instance.get('/druid/indexer/v1/workers');
middleManagers = middleManagerResponse.data;
} catch (e) {
if (
@ -589,7 +591,7 @@ ORDER BY "rank" DESC, "service" DESC`;
return (
<AsyncActionDialog
action={async () => {
const resp = await axios.post(
const resp = await Api.instance.post(
`/druid/indexer/v1/worker/${middleManagerDisableWorkerHost}/disable`,
{},
);
@ -618,7 +620,7 @@ ORDER BY "rank" DESC, "service" DESC`;
return (
<AsyncActionDialog
action={async () => {
const resp = await axios.post(
const resp = await Api.instance.post(
`/druid/indexer/v1/worker/${middleManagerEnableWorkerHost}/enable`,
{},
);