mirror of https://github.com/apache/druid.git
Web console: added bulk supervisor actions (#8028)
* added bulk supervisor actions to the web console * improve async action dialog * fix tests
This commit is contained in:
parent
3353da2974
commit
8493bd5c1c
|
@ -33,7 +33,6 @@
|
|||
"endOfLine": "lf"
|
||||
},
|
||||
"scripts": {
|
||||
"watch": "./script/watch",
|
||||
"compile": "./script/build",
|
||||
"pretest": "./script/build",
|
||||
"run": "./script/run",
|
||||
|
|
|
@ -62,7 +62,7 @@ export class ConsoleApplication extends React.PureComponent<
|
|||
> {
|
||||
static MESSAGE_KEY = 'druid-console-message';
|
||||
static MESSAGE_DISMISSED = 'dismissed';
|
||||
private capabilitiesQueryManager: QueryManager<string, Capabilities>;
|
||||
private capabilitiesQueryManager: QueryManager<null, Capabilities>;
|
||||
|
||||
static async discoverCapabilities(): Promise<Capabilities> {
|
||||
try {
|
||||
|
@ -151,7 +151,7 @@ export class ConsoleApplication extends React.PureComponent<
|
|||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this.capabilitiesQueryManager.runQuery('dummy');
|
||||
this.capabilitiesQueryManager.runQuery(null);
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
|
|
|
@ -16,7 +16,7 @@ exports[`async action dialog matches snapshot 1`] = `
|
|||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="bp3-dialog bp3-alert async-alert-dialog"
|
||||
class="bp3-dialog bp3-alert async-action-dialog"
|
||||
>
|
||||
<div
|
||||
class="bp3-alert-body"
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.async-action-dialog {
|
||||
.progress-group {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
|
@ -16,16 +16,28 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Button, Classes, Dialog, Icon, Intent, ProgressBar } from '@blueprintjs/core';
|
||||
import { IconName } from '@blueprintjs/icons';
|
||||
import {
|
||||
Button,
|
||||
Classes,
|
||||
Dialog,
|
||||
FormGroup,
|
||||
Icon,
|
||||
IconName,
|
||||
Intent,
|
||||
ProgressBar,
|
||||
} from '@blueprintjs/core';
|
||||
import { IconNames } from '@blueprintjs/icons';
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
|
||||
import { AppToaster } from '../../singletons/toaster';
|
||||
|
||||
export interface AsyncAlertDialogProps {
|
||||
action: null | (() => Promise<void>);
|
||||
onClose: (success: boolean) => void;
|
||||
import './async-action-dialog.scss';
|
||||
|
||||
export interface AsyncActionDialogProps {
|
||||
action: () => Promise<void>;
|
||||
onClose: () => void;
|
||||
onSuccess?: () => void;
|
||||
confirmButtonText: string;
|
||||
confirmButtonDisabled?: boolean;
|
||||
cancelButtonText?: string;
|
||||
|
@ -36,24 +48,33 @@ export interface AsyncAlertDialogProps {
|
|||
failText: string;
|
||||
}
|
||||
|
||||
export interface AsyncAlertDialogState {
|
||||
export interface AsyncActionDialogState {
|
||||
working: boolean;
|
||||
}
|
||||
|
||||
export class AsyncActionDialog extends React.PureComponent<
|
||||
AsyncAlertDialogProps,
|
||||
AsyncAlertDialogState
|
||||
AsyncActionDialogProps,
|
||||
AsyncActionDialogState
|
||||
> {
|
||||
constructor(props: AsyncAlertDialogProps) {
|
||||
private mounted = false;
|
||||
|
||||
constructor(props: AsyncActionDialogProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
working: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this.mounted = true;
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
this.mounted = false;
|
||||
}
|
||||
|
||||
private handleConfirm = async () => {
|
||||
const { action, onClose, successText, failText } = this.props;
|
||||
if (!action) throw new Error('should never get here');
|
||||
const { action, onClose, onSuccess, successText, failText } = this.props;
|
||||
|
||||
this.setState({ working: true });
|
||||
try {
|
||||
|
@ -63,22 +84,30 @@ export class AsyncActionDialog extends React.PureComponent<
|
|||
message: `${failText}: ${e.message}`,
|
||||
intent: Intent.DANGER,
|
||||
});
|
||||
this.setState({ working: false });
|
||||
onClose(false);
|
||||
if (this.mounted) {
|
||||
this.setState({ working: false });
|
||||
onClose();
|
||||
}
|
||||
return;
|
||||
}
|
||||
AppToaster.show({
|
||||
message: successText,
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
this.setState({ working: false });
|
||||
onClose(true);
|
||||
if (this.mounted) {
|
||||
this.setState({ working: false });
|
||||
}
|
||||
if (onSuccess) onSuccess();
|
||||
onClose();
|
||||
};
|
||||
|
||||
private handleClose = () => {
|
||||
const { onClose } = this.props;
|
||||
onClose();
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
action,
|
||||
onClose,
|
||||
className,
|
||||
icon,
|
||||
intent,
|
||||
|
@ -88,34 +117,41 @@ export class AsyncActionDialog extends React.PureComponent<
|
|||
children,
|
||||
} = this.props;
|
||||
const { working } = this.state;
|
||||
if (!action) return null;
|
||||
|
||||
const handleClose = () => onClose(false);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
isOpen
|
||||
className={classNames(Classes.ALERT, 'async-alert-dialog', className)}
|
||||
className={classNames(Classes.ALERT, 'async-action-dialog', className)}
|
||||
canEscapeKeyClose={!working}
|
||||
onClose={handleClose}
|
||||
onClose={this.handleClose}
|
||||
>
|
||||
<div className={Classes.ALERT_BODY}>
|
||||
{icon && <Icon icon={icon} />}
|
||||
{!working && <div className={Classes.ALERT_CONTENTS}>{children}</div>}
|
||||
{working ? (
|
||||
<FormGroup className="progress-group" label="Processing action...">
|
||||
<ProgressBar intent={intent || Intent.PRIMARY} />
|
||||
</FormGroup>
|
||||
) : (
|
||||
<>
|
||||
{icon && <Icon icon={icon} />}
|
||||
<div className={Classes.ALERT_CONTENTS}>{children}</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className={Classes.ALERT_FOOTER}>
|
||||
{working ? (
|
||||
<Button icon={IconNames.EYE_OFF} text="Run in background" onClick={this.handleClose} />
|
||||
) : (
|
||||
<>
|
||||
<Button
|
||||
intent={intent}
|
||||
text={confirmButtonText}
|
||||
onClick={this.handleConfirm}
|
||||
disabled={confirmButtonDisabled}
|
||||
/>
|
||||
<Button text={cancelButtonText || 'Cancel'} onClick={this.handleClose} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{working ? (
|
||||
<ProgressBar />
|
||||
) : (
|
||||
<div className={Classes.ALERT_FOOTER}>
|
||||
<Button
|
||||
intent={intent}
|
||||
text={confirmButtonText}
|
||||
onClick={this.handleConfirm}
|
||||
disabled={confirmButtonDisabled}
|
||||
/>
|
||||
<Button text={cancelButtonText || 'Cancel'} onClick={handleClose} />
|
||||
</div>
|
||||
)}
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,12 @@ import numeral from 'numeral';
|
|||
import React from 'react';
|
||||
import { Filter, FilterRender } from 'react-table';
|
||||
|
||||
export function wait(ms: number): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
||||
|
||||
export function addFilter(filters: Filter[], id: string, value: string): Filter[] {
|
||||
value = `"${value}"`;
|
||||
const currentFilter = filters.find(f => f.id === id);
|
||||
|
|
|
@ -117,18 +117,15 @@ export class QueryManager<Q, R> {
|
|||
}
|
||||
|
||||
public runQuery(query: Q): void {
|
||||
if (this.terminated) return;
|
||||
this.nextQuery = query;
|
||||
this.trigger();
|
||||
}
|
||||
|
||||
public rerunLastQuery(): void {
|
||||
public rerunLastQuery(runInBackground = false): void {
|
||||
if (this.terminated) return;
|
||||
this.nextQuery = this.lastQuery;
|
||||
this.trigger();
|
||||
}
|
||||
|
||||
public rerunLastQueryInBackground(auto: boolean): void {
|
||||
this.nextQuery = this.lastQuery;
|
||||
if (auto) {
|
||||
if (runInBackground) {
|
||||
this.runWhenIdle();
|
||||
} else {
|
||||
this.trigger();
|
||||
|
|
|
@ -246,64 +246,5 @@ exports[`data source view matches snapshot 1`] = `
|
|||
style={Object {}}
|
||||
subRowsKey="_subRows"
|
||||
/>
|
||||
<AsyncActionDialog
|
||||
action={null}
|
||||
confirmButtonText="Drop data"
|
||||
failText="Could not drop data"
|
||||
intent="danger"
|
||||
onClose={[Function]}
|
||||
successText="Data drop request acknowledged, next time the coordinator runs data will be dropped"
|
||||
>
|
||||
<p>
|
||||
Are you sure you want to drop all the data for datasource 'null'?
|
||||
</p>
|
||||
</AsyncActionDialog>
|
||||
<AsyncActionDialog
|
||||
action={null}
|
||||
confirmButtonText="Enable datasource"
|
||||
failText="Could not enable datasource"
|
||||
intent="primary"
|
||||
onClose={[Function]}
|
||||
successText="Datasource has been enabled"
|
||||
>
|
||||
<p>
|
||||
Are you sure you want to enable datasource 'null'?
|
||||
</p>
|
||||
</AsyncActionDialog>
|
||||
<AsyncActionDialog
|
||||
action={null}
|
||||
confirmButtonDisabled={true}
|
||||
confirmButtonText="Drop selected data"
|
||||
failText="Could not drop data"
|
||||
intent="primary"
|
||||
onClose={[Function]}
|
||||
successText="Drop request submitted"
|
||||
>
|
||||
<p>
|
||||
Please select the interval that you want to drop?
|
||||
</p>
|
||||
<Blueprint3.FormGroup>
|
||||
<Blueprint3.InputGroup
|
||||
onChange={[Function]}
|
||||
placeholder="2018-01-01T00:00:00/2018-01-03T00:00:00"
|
||||
value=""
|
||||
/>
|
||||
</Blueprint3.FormGroup>
|
||||
</AsyncActionDialog>
|
||||
<AsyncActionDialog
|
||||
action={null}
|
||||
confirmButtonText="Permanently delete data"
|
||||
failText="Could not submit kill task"
|
||||
intent="danger"
|
||||
onClose={[Function]}
|
||||
successText="Kill task was issued. Datasource will be deleted"
|
||||
>
|
||||
<p>
|
||||
Are you sure you want to permanently delete the data in datasource 'null'?
|
||||
</p>
|
||||
<p>
|
||||
This action can not be undone.
|
||||
</p>
|
||||
</AsyncActionDialog>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -266,27 +266,26 @@ GROUP BY 1`;
|
|||
|
||||
renderDropDataAction() {
|
||||
const { dropDataDatasource } = this.state;
|
||||
if (!dropDataDatasource) return;
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={
|
||||
dropDataDatasource
|
||||
? async () => {
|
||||
const resp = await axios.delete(
|
||||
`/druid/coordinator/v1/datasources/${dropDataDatasource}`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}
|
||||
: null
|
||||
}
|
||||
action={async () => {
|
||||
const resp = await axios.delete(
|
||||
`/druid/coordinator/v1/datasources/${dropDataDatasource}`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}}
|
||||
confirmButtonText="Drop data"
|
||||
successText="Data drop request acknowledged, next time the coordinator runs data will be dropped"
|
||||
failText="Could not drop data"
|
||||
intent={Intent.DANGER}
|
||||
onClose={success => {
|
||||
onClose={() => {
|
||||
this.setState({ dropDataDatasource: null });
|
||||
if (success) this.datasourceQueryManager.rerunLastQuery();
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.datasourceQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>
|
||||
|
@ -298,27 +297,26 @@ GROUP BY 1`;
|
|||
|
||||
renderEnableAction() {
|
||||
const { enableDatasource } = this.state;
|
||||
if (!enableDatasource) return;
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={
|
||||
enableDatasource
|
||||
? async () => {
|
||||
const resp = await axios.post(
|
||||
`/druid/coordinator/v1/datasources/${enableDatasource}`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}
|
||||
: null
|
||||
}
|
||||
action={async () => {
|
||||
const resp = await axios.post(
|
||||
`/druid/coordinator/v1/datasources/${enableDatasource}`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}}
|
||||
confirmButtonText="Enable datasource"
|
||||
successText="Datasource has been enabled"
|
||||
failText="Could not enable datasource"
|
||||
intent={Intent.PRIMARY}
|
||||
onClose={success => {
|
||||
onClose={() => {
|
||||
this.setState({ enableDatasource: null });
|
||||
if (success) this.datasourceQueryManager.rerunLastQuery();
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.datasourceQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>{`Are you sure you want to enable datasource '${enableDatasource}'?`}</p>
|
||||
|
@ -328,34 +326,33 @@ GROUP BY 1`;
|
|||
|
||||
renderDropReloadAction() {
|
||||
const { dropReloadDatasource, dropReloadAction, dropReloadInterval } = this.state;
|
||||
if (!dropReloadDatasource) return;
|
||||
const isDrop = dropReloadAction === 'drop';
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={
|
||||
dropReloadDatasource
|
||||
? async () => {
|
||||
if (!dropReloadInterval) return;
|
||||
const resp = await axios.post(
|
||||
`/druid/coordinator/v1/datasources/${dropReloadDatasource}/${
|
||||
isDrop ? 'markUnused' : 'markUsed'
|
||||
}`,
|
||||
{
|
||||
interval: dropReloadInterval,
|
||||
},
|
||||
);
|
||||
return resp.data;
|
||||
}
|
||||
: null
|
||||
}
|
||||
action={async () => {
|
||||
if (!dropReloadInterval) return;
|
||||
const resp = await axios.post(
|
||||
`/druid/coordinator/v1/datasources/${dropReloadDatasource}/${
|
||||
isDrop ? 'markUnused' : 'markUsed'
|
||||
}`,
|
||||
{
|
||||
interval: dropReloadInterval,
|
||||
},
|
||||
);
|
||||
return resp.data;
|
||||
}}
|
||||
confirmButtonText={`${isDrop ? 'Drop' : 'Reload'} selected data`}
|
||||
confirmButtonDisabled={!/.\/./.test(dropReloadInterval)}
|
||||
successText={`${isDrop ? 'Drop' : 'Reload'} request submitted`}
|
||||
failText={`Could not ${isDrop ? 'drop' : 'reload'} data`}
|
||||
intent={Intent.PRIMARY}
|
||||
onClose={success => {
|
||||
onClose={() => {
|
||||
this.setState({ dropReloadDatasource: null });
|
||||
if (success) this.datasourceQueryManager.rerunLastQuery();
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.datasourceQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>{`Please select the interval that you want to ${isDrop ? 'drop' : 'reload'}?`}</p>
|
||||
|
@ -375,27 +372,26 @@ GROUP BY 1`;
|
|||
|
||||
renderKillAction() {
|
||||
const { killDatasource } = this.state;
|
||||
if (!killDatasource) return;
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={
|
||||
killDatasource
|
||||
? async () => {
|
||||
const resp = await axios.delete(
|
||||
`/druid/coordinator/v1/datasources/${killDatasource}?kill=true&interval=1000/3000`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}
|
||||
: null
|
||||
}
|
||||
action={async () => {
|
||||
const resp = await axios.delete(
|
||||
`/druid/coordinator/v1/datasources/${killDatasource}?kill=true&interval=1000/3000`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}}
|
||||
confirmButtonText="Permanently delete data"
|
||||
successText="Kill task was issued. Datasource will be deleted"
|
||||
failText="Could not submit kill task"
|
||||
intent={Intent.DANGER}
|
||||
onClose={success => {
|
||||
onClose={() => {
|
||||
this.setState({ killDatasource: null });
|
||||
if (success) this.datasourceQueryManager.rerunLastQuery();
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.datasourceQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>
|
||||
|
@ -808,7 +804,7 @@ GROUP BY 1`;
|
|||
<div className="data-sources-view app-view">
|
||||
<ViewControlBar label="Datasources">
|
||||
<RefreshButton
|
||||
onRefresh={auto => this.datasourceQueryManager.rerunLastQueryInBackground(auto)}
|
||||
onRefresh={auto => this.datasourceQueryManager.rerunLastQuery(auto)}
|
||||
localStorageKey={LocalStorageKeys.DATASOURCES_REFRESH_RATE}
|
||||
/>
|
||||
{!noSqlMode && (
|
||||
|
|
|
@ -220,17 +220,5 @@ exports[`lookups view matches snapshot 1`] = `
|
|||
onClose={[Function]}
|
||||
onSubmit={[Function]}
|
||||
/>
|
||||
<AsyncActionDialog
|
||||
action={null}
|
||||
confirmButtonText="Delete lookup"
|
||||
failText="Could not delete lookup"
|
||||
intent="danger"
|
||||
onClose={[Function]}
|
||||
successText="Lookup was deleted"
|
||||
>
|
||||
<p>
|
||||
Are you sure you want to delete the lookup 'null'?
|
||||
</p>
|
||||
</AsyncActionDialog>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -235,25 +235,24 @@ export class LookupsView extends React.PureComponent<LookupsViewProps, LookupsVi
|
|||
|
||||
renderDeleteLookupAction() {
|
||||
const { deleteLookupTier, deleteLookupName } = this.state;
|
||||
if (!deleteLookupTier) return;
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={
|
||||
deleteLookupTier
|
||||
? async () => {
|
||||
await axios.delete(
|
||||
`/druid/coordinator/v1/lookups/config/${deleteLookupTier}/${deleteLookupName}`,
|
||||
);
|
||||
}
|
||||
: null
|
||||
}
|
||||
action={async () => {
|
||||
await axios.delete(
|
||||
`/druid/coordinator/v1/lookups/config/${deleteLookupTier}/${deleteLookupName}`,
|
||||
);
|
||||
}}
|
||||
confirmButtonText="Delete lookup"
|
||||
successText="Lookup was deleted"
|
||||
failText="Could not delete lookup"
|
||||
intent={Intent.DANGER}
|
||||
onClose={success => {
|
||||
onClose={() => {
|
||||
this.setState({ deleteLookupTier: null, deleteLookupName: null });
|
||||
if (success) this.lookupsQueryManager.rerunLastQuery();
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.lookupsQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>{`Are you sure you want to delete the lookup '${deleteLookupName}'?`}</p>
|
||||
|
|
|
@ -305,20 +305,5 @@ exports[`segments-view matches snapshot 1`] = `
|
|||
subRowsKey="_subRows"
|
||||
/>
|
||||
</div>
|
||||
<AsyncActionDialog
|
||||
action={null}
|
||||
confirmButtonText="Drop Segment"
|
||||
failText="Could not drop segment"
|
||||
intent="danger"
|
||||
onClose={[Function]}
|
||||
successText="Segment drop request acknowledged, next time the coordinator runs segment will be dropped"
|
||||
>
|
||||
<p>
|
||||
Are you sure you want to drop segment 'null'?
|
||||
</p>
|
||||
<p>
|
||||
This action is not reversible.
|
||||
</p>
|
||||
</AsyncActionDialog>
|
||||
</Fragment>
|
||||
`;
|
||||
|
|
|
@ -479,30 +479,27 @@ export class SegmentsView extends React.PureComponent<SegmentsViewProps, Segment
|
|||
|
||||
renderTerminateSegmentAction() {
|
||||
const { terminateSegmentId, terminateDatasourceId } = this.state;
|
||||
if (!terminateDatasourceId || !terminateSegmentId) return;
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={
|
||||
terminateSegmentId
|
||||
? async () => {
|
||||
const resp = await axios.delete(
|
||||
`/druid/coordinator/v1/datasources/${terminateDatasourceId}/segments/${terminateSegmentId}`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}
|
||||
: null
|
||||
}
|
||||
action={async () => {
|
||||
const resp = await axios.delete(
|
||||
`/druid/coordinator/v1/datasources/${terminateDatasourceId}/segments/${terminateSegmentId}`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}}
|
||||
confirmButtonText="Drop Segment"
|
||||
successText="Segment drop request acknowledged, next time the coordinator runs segment will be dropped"
|
||||
failText="Could not drop segment"
|
||||
intent={Intent.DANGER}
|
||||
onClose={success => {
|
||||
onClose={() => {
|
||||
this.setState({ terminateSegmentId: null });
|
||||
if (success) {
|
||||
this.segmentsNoSqlQueryManager.rerunLastQuery();
|
||||
this.segmentsSqlQueryManager.rerunLastQuery();
|
||||
}
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.segmentsNoSqlQueryManager.rerunLastQuery();
|
||||
this.segmentsSqlQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>{`Are you sure you want to drop segment '${terminateSegmentId}'?`}</p>
|
||||
|
@ -528,8 +525,8 @@ export class SegmentsView extends React.PureComponent<SegmentsViewProps, Segment
|
|||
<RefreshButton
|
||||
onRefresh={auto =>
|
||||
noSqlMode
|
||||
? this.segmentsNoSqlQueryManager.rerunLastQueryInBackground(auto)
|
||||
: this.segmentsSqlQueryManager.rerunLastQueryInBackground(auto)
|
||||
? this.segmentsNoSqlQueryManager.rerunLastQuery(auto)
|
||||
: this.segmentsSqlQueryManager.rerunLastQuery(auto)
|
||||
}
|
||||
localStorageKey={LocalStorageKeys.SEGMENTS_REFRESH_RATE}
|
||||
/>
|
||||
|
|
|
@ -284,29 +284,5 @@ exports[`servers view action servers view 1`] = `
|
|||
style={Object {}}
|
||||
subRowsKey="_subRows"
|
||||
/>
|
||||
<AsyncActionDialog
|
||||
action={null}
|
||||
confirmButtonText="Disable worker"
|
||||
failText="Could not disable worker"
|
||||
intent="danger"
|
||||
onClose={[Function]}
|
||||
successText="Worker has been disabled"
|
||||
>
|
||||
<p>
|
||||
Are you sure you want to disable worker 'null'?
|
||||
</p>
|
||||
</AsyncActionDialog>
|
||||
<AsyncActionDialog
|
||||
action={null}
|
||||
confirmButtonText="Enable worker"
|
||||
failText="Could not enable worker"
|
||||
intent="primary"
|
||||
onClose={[Function]}
|
||||
successText="Worker has been enabled"
|
||||
>
|
||||
<p>
|
||||
Are you sure you want to enable worker 'null'?
|
||||
</p>
|
||||
</AsyncActionDialog>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -560,27 +560,26 @@ ORDER BY "rank" DESC, "server" DESC`;
|
|||
|
||||
renderDisableWorkerAction() {
|
||||
const { middleManagerDisableWorkerHost } = this.state;
|
||||
if (!middleManagerDisableWorkerHost) return;
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={
|
||||
middleManagerDisableWorkerHost
|
||||
? async () => {
|
||||
const resp = await axios.post(
|
||||
`/druid/indexer/v1/worker/${middleManagerDisableWorkerHost}/disable`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}
|
||||
: null
|
||||
}
|
||||
action={async () => {
|
||||
const resp = await axios.post(
|
||||
`/druid/indexer/v1/worker/${middleManagerDisableWorkerHost}/disable`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}}
|
||||
confirmButtonText="Disable worker"
|
||||
successText="Worker has been disabled"
|
||||
failText="Could not disable worker"
|
||||
intent={Intent.DANGER}
|
||||
onClose={success => {
|
||||
onClose={() => {
|
||||
this.setState({ middleManagerDisableWorkerHost: null });
|
||||
if (success) this.serverQueryManager.rerunLastQuery();
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.serverQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>{`Are you sure you want to disable worker '${middleManagerDisableWorkerHost}'?`}</p>
|
||||
|
@ -590,27 +589,26 @@ ORDER BY "rank" DESC, "server" DESC`;
|
|||
|
||||
renderEnableWorkerAction() {
|
||||
const { middleManagerEnableWorkerHost } = this.state;
|
||||
if (!middleManagerEnableWorkerHost) return;
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={
|
||||
middleManagerEnableWorkerHost
|
||||
? async () => {
|
||||
const resp = await axios.post(
|
||||
`/druid/indexer/v1/worker/${middleManagerEnableWorkerHost}/enable`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}
|
||||
: null
|
||||
}
|
||||
action={async () => {
|
||||
const resp = await axios.post(
|
||||
`/druid/indexer/v1/worker/${middleManagerEnableWorkerHost}/enable`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}}
|
||||
confirmButtonText="Enable worker"
|
||||
successText="Worker has been enabled"
|
||||
failText="Could not enable worker"
|
||||
intent={Intent.PRIMARY}
|
||||
onClose={success => {
|
||||
onClose={() => {
|
||||
this.setState({ middleManagerEnableWorkerHost: null });
|
||||
if (success) this.serverQueryManager.rerunLastQuery();
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.serverQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>{`Are you sure you want to enable worker '${middleManagerEnableWorkerHost}'?`}</p>
|
||||
|
@ -647,7 +645,7 @@ ORDER BY "rank" DESC, "server" DESC`;
|
|||
</Button>
|
||||
</ButtonGroup>
|
||||
<RefreshButton
|
||||
onRefresh={auto => this.serverQueryManager.rerunLastQueryInBackground(auto)}
|
||||
onRefresh={auto => this.serverQueryManager.rerunLastQuery(auto)}
|
||||
localStorageKey={LocalStorageKeys.SERVERS_REFRESH_RATE}
|
||||
/>
|
||||
{!noSqlMode && (
|
||||
|
|
|
@ -70,6 +70,61 @@ exports[`tasks view matches snapshot 1`] = `
|
|||
text="Submit supervisor"
|
||||
/>
|
||||
</Blueprint3.Popover>
|
||||
<Blueprint3.Popover
|
||||
boundary="scrollParent"
|
||||
captureDismiss={false}
|
||||
content={
|
||||
<Blueprint3.Menu>
|
||||
<Blueprint3.MenuItem
|
||||
disabled={false}
|
||||
icon="play"
|
||||
multiline={false}
|
||||
onClick={[Function]}
|
||||
popoverProps={Object {}}
|
||||
shouldDismissPopover={true}
|
||||
text="Resume all supervisors"
|
||||
/>
|
||||
<Blueprint3.MenuItem
|
||||
disabled={false}
|
||||
icon="pause"
|
||||
multiline={false}
|
||||
onClick={[Function]}
|
||||
popoverProps={Object {}}
|
||||
shouldDismissPopover={true}
|
||||
text="Suspend all supervisors"
|
||||
/>
|
||||
<Blueprint3.MenuItem
|
||||
disabled={false}
|
||||
icon="cross"
|
||||
intent="danger"
|
||||
multiline={false}
|
||||
onClick={[Function]}
|
||||
popoverProps={Object {}}
|
||||
shouldDismissPopover={true}
|
||||
text="Terminate all supervisors"
|
||||
/>
|
||||
</Blueprint3.Menu>
|
||||
}
|
||||
defaultIsOpen={false}
|
||||
disabled={false}
|
||||
hasBackdrop={false}
|
||||
hoverCloseDelay={300}
|
||||
hoverOpenDelay={150}
|
||||
inheritDarkTheme={true}
|
||||
interactionKind="click"
|
||||
minimal={false}
|
||||
modifiers={Object {}}
|
||||
openOnTargetFocus={true}
|
||||
position="bottom-left"
|
||||
targetTagName="span"
|
||||
transitionDuration={300}
|
||||
usePortal={true}
|
||||
wrapperTagName="span"
|
||||
>
|
||||
<Blueprint3.Button
|
||||
icon="more"
|
||||
/>
|
||||
</Blueprint3.Popover>
|
||||
<TableColumnSelector
|
||||
columns={
|
||||
Array [
|
||||
|
@ -261,57 +316,6 @@ exports[`tasks view matches snapshot 1`] = `
|
|||
style={Object {}}
|
||||
subRowsKey="_subRows"
|
||||
/>
|
||||
<AsyncActionDialog
|
||||
action={null}
|
||||
confirmButtonText="Resume supervisor"
|
||||
failText="Could not resume supervisor"
|
||||
intent="primary"
|
||||
onClose={[Function]}
|
||||
successText="Supervisor has been resumed"
|
||||
>
|
||||
<p>
|
||||
Are you sure you want to resume supervisor 'null'?
|
||||
</p>
|
||||
</AsyncActionDialog>
|
||||
<AsyncActionDialog
|
||||
action={null}
|
||||
confirmButtonText="Suspend supervisor"
|
||||
failText="Could not suspend supervisor"
|
||||
intent="danger"
|
||||
onClose={[Function]}
|
||||
successText="Supervisor has been suspended"
|
||||
>
|
||||
<p>
|
||||
Are you sure you want to suspend supervisor 'null'?
|
||||
</p>
|
||||
</AsyncActionDialog>
|
||||
<AsyncActionDialog
|
||||
action={null}
|
||||
confirmButtonText="Reset supervisor"
|
||||
failText="Could not reset supervisor"
|
||||
intent="danger"
|
||||
onClose={[Function]}
|
||||
successText="Supervisor has been reset"
|
||||
>
|
||||
<p>
|
||||
Are you sure you want to reset supervisor 'null'?
|
||||
</p>
|
||||
</AsyncActionDialog>
|
||||
<AsyncActionDialog
|
||||
action={null}
|
||||
confirmButtonText="Terminate supervisor"
|
||||
failText="Could not terminate supervisor"
|
||||
intent="danger"
|
||||
onClose={[Function]}
|
||||
successText="Supervisor has been terminated"
|
||||
>
|
||||
<p>
|
||||
Are you sure you want to terminate supervisor 'null'?
|
||||
</p>
|
||||
<p>
|
||||
This action is not reversible.
|
||||
</p>
|
||||
</AsyncActionDialog>
|
||||
</div>
|
||||
<div
|
||||
className="bottom-pane"
|
||||
|
@ -639,18 +643,6 @@ exports[`tasks view matches snapshot 1`] = `
|
|||
style={Object {}}
|
||||
subRowsKey="_subRows"
|
||||
/>
|
||||
<AsyncActionDialog
|
||||
action={null}
|
||||
confirmButtonText="Kill task"
|
||||
failText="Could not kill task"
|
||||
intent="danger"
|
||||
onClose={[Function]}
|
||||
successText="Task was killed"
|
||||
>
|
||||
<p>
|
||||
Are you sure you want to kill task 'null'?
|
||||
</p>
|
||||
</AsyncActionDialog>
|
||||
</div>
|
||||
</t>
|
||||
<Blueprint3.Alert
|
||||
|
|
|
@ -95,6 +95,10 @@ export interface TasksViewState {
|
|||
resetSupervisorId: string | null;
|
||||
terminateSupervisorId: string | null;
|
||||
|
||||
showResumeAllSupervisors: boolean;
|
||||
showSuspendAllSupervisors: boolean;
|
||||
showTerminateAllSupervisors: boolean;
|
||||
|
||||
tasksLoading: boolean;
|
||||
tasks: any[] | null;
|
||||
tasksError: string | null;
|
||||
|
@ -206,6 +210,10 @@ ORDER BY "rank" DESC, "created_time" DESC`;
|
|||
supervisorTableActionDialogId: null,
|
||||
terminateSupervisorId: null,
|
||||
|
||||
showResumeAllSupervisors: false,
|
||||
showSuspendAllSupervisors: false,
|
||||
showTerminateAllSupervisors: false,
|
||||
|
||||
tasksLoading: true,
|
||||
tasks: null,
|
||||
tasksError: null,
|
||||
|
@ -394,27 +402,26 @@ ORDER BY "rank" DESC, "created_time" DESC`;
|
|||
|
||||
renderResumeSupervisorAction() {
|
||||
const { resumeSupervisorId } = this.state;
|
||||
if (!resumeSupervisorId) return;
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={
|
||||
resumeSupervisorId
|
||||
? async () => {
|
||||
const resp = await axios.post(
|
||||
`/druid/indexer/v1/supervisor/${resumeSupervisorId}/resume`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}
|
||||
: null
|
||||
}
|
||||
action={async () => {
|
||||
const resp = await axios.post(
|
||||
`/druid/indexer/v1/supervisor/${resumeSupervisorId}/resume`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}}
|
||||
confirmButtonText="Resume supervisor"
|
||||
successText="Supervisor has been resumed"
|
||||
failText="Could not resume supervisor"
|
||||
intent={Intent.PRIMARY}
|
||||
onClose={success => {
|
||||
onClose={() => {
|
||||
this.setState({ resumeSupervisorId: null });
|
||||
if (success) this.supervisorQueryManager.rerunLastQuery();
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.supervisorQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>{`Are you sure you want to resume supervisor '${resumeSupervisorId}'?`}</p>
|
||||
|
@ -424,27 +431,26 @@ ORDER BY "rank" DESC, "created_time" DESC`;
|
|||
|
||||
renderSuspendSupervisorAction() {
|
||||
const { suspendSupervisorId } = this.state;
|
||||
if (!suspendSupervisorId) return;
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={
|
||||
suspendSupervisorId
|
||||
? async () => {
|
||||
const resp = await axios.post(
|
||||
`/druid/indexer/v1/supervisor/${suspendSupervisorId}/suspend`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}
|
||||
: null
|
||||
}
|
||||
action={async () => {
|
||||
const resp = await axios.post(
|
||||
`/druid/indexer/v1/supervisor/${suspendSupervisorId}/suspend`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}}
|
||||
confirmButtonText="Suspend supervisor"
|
||||
successText="Supervisor has been suspended"
|
||||
failText="Could not suspend supervisor"
|
||||
intent={Intent.DANGER}
|
||||
onClose={success => {
|
||||
onClose={() => {
|
||||
this.setState({ suspendSupervisorId: null });
|
||||
if (success) this.supervisorQueryManager.rerunLastQuery();
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.supervisorQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>{`Are you sure you want to suspend supervisor '${suspendSupervisorId}'?`}</p>
|
||||
|
@ -454,27 +460,26 @@ ORDER BY "rank" DESC, "created_time" DESC`;
|
|||
|
||||
renderResetSupervisorAction() {
|
||||
const { resetSupervisorId } = this.state;
|
||||
if (!resetSupervisorId) return;
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={
|
||||
resetSupervisorId
|
||||
? async () => {
|
||||
const resp = await axios.post(
|
||||
`/druid/indexer/v1/supervisor/${resetSupervisorId}/reset`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}
|
||||
: null
|
||||
}
|
||||
action={async () => {
|
||||
const resp = await axios.post(
|
||||
`/druid/indexer/v1/supervisor/${resetSupervisorId}/reset`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}}
|
||||
confirmButtonText="Reset supervisor"
|
||||
successText="Supervisor has been reset"
|
||||
failText="Could not reset supervisor"
|
||||
intent={Intent.DANGER}
|
||||
onClose={success => {
|
||||
onClose={() => {
|
||||
this.setState({ resetSupervisorId: null });
|
||||
if (success) this.supervisorQueryManager.rerunLastQuery();
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.supervisorQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>{`Are you sure you want to reset supervisor '${resetSupervisorId}'?`}</p>
|
||||
|
@ -484,27 +489,26 @@ ORDER BY "rank" DESC, "created_time" DESC`;
|
|||
|
||||
renderTerminateSupervisorAction() {
|
||||
const { terminateSupervisorId } = this.state;
|
||||
if (!terminateSupervisorId) return;
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={
|
||||
terminateSupervisorId
|
||||
? async () => {
|
||||
const resp = await axios.post(
|
||||
`/druid/indexer/v1/supervisor/${terminateSupervisorId}/terminate`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}
|
||||
: null
|
||||
}
|
||||
action={async () => {
|
||||
const resp = await axios.post(
|
||||
`/druid/indexer/v1/supervisor/${terminateSupervisorId}/terminate`,
|
||||
{},
|
||||
);
|
||||
return resp.data;
|
||||
}}
|
||||
confirmButtonText="Terminate supervisor"
|
||||
successText="Supervisor has been terminated"
|
||||
failText="Could not terminate supervisor"
|
||||
intent={Intent.DANGER}
|
||||
onClose={success => {
|
||||
onClose={() => {
|
||||
this.setState({ terminateSupervisorId: null });
|
||||
if (success) this.supervisorQueryManager.rerunLastQuery();
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.supervisorQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>{`Are you sure you want to terminate supervisor '${terminateSupervisorId}'?`}</p>
|
||||
|
@ -638,24 +642,23 @@ ORDER BY "rank" DESC, "created_time" DESC`;
|
|||
|
||||
renderKillTaskAction() {
|
||||
const { killTaskId } = this.state;
|
||||
if (!killTaskId) return;
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={
|
||||
killTaskId
|
||||
? async () => {
|
||||
const resp = await axios.post(`/druid/indexer/v1/task/${killTaskId}/shutdown`, {});
|
||||
return resp.data;
|
||||
}
|
||||
: null
|
||||
}
|
||||
action={async () => {
|
||||
const resp = await axios.post(`/druid/indexer/v1/task/${killTaskId}/shutdown`, {});
|
||||
return resp.data;
|
||||
}}
|
||||
confirmButtonText="Kill task"
|
||||
successText="Task was killed"
|
||||
failText="Could not kill task"
|
||||
intent={Intent.DANGER}
|
||||
onClose={success => {
|
||||
onClose={() => {
|
||||
this.setState({ killTaskId: null });
|
||||
if (success) this.taskQueryManager.rerunLastQuery();
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.taskQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>{`Are you sure you want to kill task '${killTaskId}'?`}</p>
|
||||
|
@ -849,6 +852,118 @@ ORDER BY "rank" DESC, "created_time" DESC`;
|
|||
);
|
||||
}
|
||||
|
||||
renderBulkSupervisorActions() {
|
||||
const bulkSupervisorActionsMenu = (
|
||||
<Menu>
|
||||
<MenuItem
|
||||
icon={IconNames.PLAY}
|
||||
text="Resume all supervisors"
|
||||
onClick={() => this.setState({ showResumeAllSupervisors: true })}
|
||||
/>
|
||||
<MenuItem
|
||||
icon={IconNames.PAUSE}
|
||||
text="Suspend all supervisors"
|
||||
onClick={() => this.setState({ showSuspendAllSupervisors: true })}
|
||||
/>
|
||||
<MenuItem
|
||||
icon={IconNames.CROSS}
|
||||
text="Terminate all supervisors"
|
||||
intent={Intent.DANGER}
|
||||
onClick={() => this.setState({ showTerminateAllSupervisors: true })}
|
||||
/>
|
||||
</Menu>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Popover content={bulkSupervisorActionsMenu} position={Position.BOTTOM_LEFT}>
|
||||
<Button icon={IconNames.MORE} />
|
||||
</Popover>
|
||||
{this.renderResumeAllSupervisorAction()}
|
||||
{this.renderSuspendAllSupervisorAction()}
|
||||
{this.renderTerminateAllSupervisorAction()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
renderResumeAllSupervisorAction() {
|
||||
const { showResumeAllSupervisors } = this.state;
|
||||
if (!showResumeAllSupervisors) return;
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={async () => {
|
||||
const resp = await axios.post(`/druid/indexer/v1/supervisor/resumeAll`, {});
|
||||
return resp.data;
|
||||
}}
|
||||
confirmButtonText="Resume all supervisors"
|
||||
successText="All supervisors have been resumed"
|
||||
failText="Could not resume all supervisors"
|
||||
intent={Intent.PRIMARY}
|
||||
onClose={() => {
|
||||
this.setState({ showResumeAllSupervisors: false });
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.supervisorQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>Are you sure you want to resume all the supervisors?</p>
|
||||
</AsyncActionDialog>
|
||||
);
|
||||
}
|
||||
|
||||
renderSuspendAllSupervisorAction() {
|
||||
const { showSuspendAllSupervisors } = this.state;
|
||||
if (!showSuspendAllSupervisors) return;
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={async () => {
|
||||
const resp = await axios.post(`/druid/indexer/v1/supervisor/suspendAll`, {});
|
||||
return resp.data;
|
||||
}}
|
||||
confirmButtonText="Suspend all supervisors"
|
||||
successText="All supervisors have been suspended"
|
||||
failText="Could not suspend all supervisors"
|
||||
intent={Intent.DANGER}
|
||||
onClose={() => {
|
||||
this.setState({ showSuspendAllSupervisors: false });
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.supervisorQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>Are you sure you want to suspend all the supervisors?</p>
|
||||
</AsyncActionDialog>
|
||||
);
|
||||
}
|
||||
|
||||
renderTerminateAllSupervisorAction() {
|
||||
const { showTerminateAllSupervisors } = this.state;
|
||||
if (!showTerminateAllSupervisors) return;
|
||||
|
||||
return (
|
||||
<AsyncActionDialog
|
||||
action={async () => {
|
||||
const resp = await axios.post(`/druid/indexer/v1/supervisor/terminateAll`, {});
|
||||
return resp.data;
|
||||
}}
|
||||
confirmButtonText="Terminate all supervisors"
|
||||
successText="All supervisors have been terminated"
|
||||
failText="Could not terminate all supervisors"
|
||||
intent={Intent.DANGER}
|
||||
onClose={() => {
|
||||
this.setState({ showTerminateAllSupervisors: false });
|
||||
}}
|
||||
onSuccess={() => {
|
||||
this.supervisorQueryManager.rerunLastQuery();
|
||||
}}
|
||||
>
|
||||
<p>Are you sure you want to terminate all the supervisors?</p>
|
||||
</AsyncActionDialog>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { goToQuery, goToLoadDataView, noSqlMode } = this.props;
|
||||
const {
|
||||
|
@ -912,11 +1027,12 @@ ORDER BY "rank" DESC, "created_time" DESC`;
|
|||
<ViewControlBar label="Supervisors">
|
||||
<RefreshButton
|
||||
localStorageKey={LocalStorageKeys.SUPERVISORS_REFRESH_RATE}
|
||||
onRefresh={auto => this.supervisorQueryManager.rerunLastQueryInBackground(auto)}
|
||||
onRefresh={auto => this.supervisorQueryManager.rerunLastQuery(auto)}
|
||||
/>
|
||||
<Popover content={submitSupervisorMenu} position={Position.BOTTOM_LEFT}>
|
||||
<Button icon={IconNames.PLUS} text="Submit supervisor" />
|
||||
</Popover>
|
||||
{this.renderBulkSupervisorActions()}
|
||||
<TableColumnSelector
|
||||
columns={supervisorTableColumns}
|
||||
onChange={column =>
|
||||
|
@ -958,7 +1074,7 @@ ORDER BY "rank" DESC, "created_time" DESC`;
|
|||
</ButtonGroup>
|
||||
<RefreshButton
|
||||
localStorageKey={LocalStorageKeys.TASKS_REFRESH_RATE}
|
||||
onRefresh={auto => this.taskQueryManager.rerunLastQueryInBackground(auto)}
|
||||
onRefresh={auto => this.taskQueryManager.rerunLastQuery(auto)}
|
||||
/>
|
||||
{!noSqlMode && (
|
||||
<Button
|
||||
|
|
Loading…
Reference in New Issue