diff --git a/web-console/src/ace-modes/dsql.ts b/web-console/src/ace-modes/dsql.ts index e57d17d51e7c..38cc40124e2f 100644 --- a/web-console/src/ace-modes/dsql.ts +++ b/web-console/src/ace-modes/dsql.ts @@ -186,7 +186,10 @@ ace.define( this.$id = 'ace/mode/dsql'; this.lineCommentStart = '--'; - this.getCompletions = () => completions; + this.getCompletions = (_state: any, _session: any, _pos: any, prefix: string) => { + if (/^\d+$/.test(prefix)) return; // Don't start completing if the user is typing a number + return completions; + }; }; oop.inherits(Mode, TextMode); diff --git a/web-console/src/dialogs/index.ts b/web-console/src/dialogs/index.ts index f7e239b53f41..6a3c336831be 100644 --- a/web-console/src/dialogs/index.ts +++ b/web-console/src/dialogs/index.ts @@ -37,4 +37,5 @@ export * from './string-input-dialog/string-input-dialog'; export * from './supervisor-reset-offsets-dialog/supervisor-reset-offsets-dialog'; export * from './supervisor-table-action-dialog/supervisor-table-action-dialog'; export * from './table-action-dialog/table-action-dialog'; +export * from './task-group-handoff-dialog/task-group-handoff-dialog'; export * from './task-table-action-dialog/task-table-action-dialog'; diff --git a/web-console/src/dialogs/task-group-handoff-dialog/task-group-handoff-dialog.tsx b/web-console/src/dialogs/task-group-handoff-dialog/task-group-handoff-dialog.tsx new file mode 100644 index 000000000000..02e4b066af98 --- /dev/null +++ b/web-console/src/dialogs/task-group-handoff-dialog/task-group-handoff-dialog.tsx @@ -0,0 +1,65 @@ +/* + * 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 { FormGroup, Intent, Tag } from '@blueprintjs/core'; +import React, { useState } from 'react'; + +import { ArrayInput } from '../../components'; +import { Api } from '../../singletons'; +import { AsyncActionDialog } from '../async-action-dialog/async-action-dialog'; + +export interface TaskGroupHandoffDialogProps { + supervisorId: string; + onSuccess(): void; + onClose(): void; +} + +export function TaskGroupHandoffDialog(props: TaskGroupHandoffDialogProps) { + const { supervisorId, onSuccess, onClose } = props; + const [groupIds, setGroupIds] = useState([]); + + return ( + { + const resp = await Api.instance.post( + `/druid/indexer/v1/supervisor/${Api.encodePath(supervisorId)}/taskGroups/handoff`, + { taskGroupIds: groupIds.map(x => parseInt(x, 10)) }, + ); + return resp.data; + }} + confirmButtonText="Handoff task groups" + successText="Task group handoff has been initiated" + failText="Could not initiate handoff for the selected task groups" + intent={Intent.PRIMARY} + onClose={onClose} + onSuccess={onSuccess} + > +

+ Are you sure you want to initiate early handoff for the given task groups belonging to + supervisor {supervisorId}? +

+ + setGroupIds(v || [])} + placeholder="0, 1, 2, ..." + /> + +
+ ); +} diff --git a/web-console/src/views/supervisors-view/__snapshots__/supervisors-view.spec.tsx.snap b/web-console/src/views/supervisors-view/__snapshots__/supervisors-view.spec.tsx.snap index b20802ca4b84..9671213e3350 100644 --- a/web-console/src/views/supervisors-view/__snapshots__/supervisors-view.spec.tsx.snap +++ b/web-console/src/views/supervisors-view/__snapshots__/supervisors-view.spec.tsx.snap @@ -403,7 +403,7 @@ exports[`SupervisorsView matches snapshot 1`] = ` rowsText="rows" showPageJump={false} showPageSizeOptions={true} - showPagination={true} + showPagination={false} showPaginationBottom={true} showPaginationTop={false} sortable={true} diff --git a/web-console/src/views/supervisors-view/supervisors-view.tsx b/web-console/src/views/supervisors-view/supervisors-view.tsx index 68654cbce79d..bffcec674814 100644 --- a/web-console/src/views/supervisors-view/supervisors-view.tsx +++ b/web-console/src/views/supervisors-view/supervisors-view.tsx @@ -46,6 +46,7 @@ import { SupervisorTableActionDialog, } from '../../dialogs'; import { SupervisorResetOffsetsDialog } from '../../dialogs/supervisor-reset-offsets-dialog/supervisor-reset-offsets-dialog'; +import { TaskGroupHandoffDialog } from '../../dialogs/task-group-handoff-dialog/task-group-handoff-dialog'; import type { IngestionSpec, QueryWithContext, @@ -145,6 +146,7 @@ export interface SupervisorsViewState { resumeSupervisorId?: string; suspendSupervisorId?: string; + handoffSupervisorId?: string; resetOffsetsSupervisorInfo?: { id: string; type: string }; resetSupervisorId?: string; terminateSupervisorId?: string; @@ -426,15 +428,25 @@ export class SupervisorsView extends React.PureComponent< }, ); } + + actions.push({ + icon: supervisorSuspended ? IconNames.PLAY : IconNames.PAUSE, + title: supervisorSuspended ? 'Resume' : 'Suspend', + onAction: () => + supervisorSuspended + ? this.setState({ resumeSupervisorId: id }) + : this.setState({ suspendSupervisorId: id }), + }); + + if (!supervisorSuspended) { + actions.push({ + icon: IconNames.AUTOMATIC_UPDATES, + title: 'Handoff early', + onAction: () => this.setState({ handoffSupervisorId: id }), + }); + } + actions.push( - { - icon: supervisorSuspended ? IconNames.PLAY : IconNames.PAUSE, - title: supervisorSuspended ? 'Resume' : 'Suspend', - onAction: () => - supervisorSuspended - ? this.setState({ resumeSupervisorId: id }) - : this.setState({ suspendSupervisorId: id }), - }, { icon: IconNames.STEP_BACKWARD, title: `Set ${type === 'kinesis' ? 'sequence numbers' : 'offsets'}`, @@ -520,6 +532,23 @@ export class SupervisorsView extends React.PureComponent< ); } + renderTaskGroupHandoffAction() { + const { handoffSupervisorId } = this.state; + if (!handoffSupervisorId) return; + + return ( + { + this.setState({ handoffSupervisorId: undefined }); + }} + onSuccess={() => { + this.supervisorQueryManager.rerunLastQuery(); + }} + /> + ); + } + renderResetOffsetsSupervisorAction() { const { resetOffsetsSupervisorInfo } = this.state; if (!resetOffsetsSupervisorInfo) return; @@ -660,7 +689,7 @@ export class SupervisorsView extends React.PureComponent< ofText="" defaultPageSize={SMALL_TABLE_PAGE_SIZE} pageSizeOptions={SMALL_TABLE_PAGE_SIZE_OPTIONS} - showPagination + showPagination={supervisors.length > SMALL_TABLE_PAGE_SIZE} columns={[ { Header: twoLines('Supervisor ID', (datasource)), @@ -1061,6 +1090,7 @@ export class SupervisorsView extends React.PureComponent< {this.renderSupervisorTable()} {this.renderResumeSupervisorAction()} {this.renderSuspendSupervisorAction()} + {this.renderTaskGroupHandoffAction()} {this.renderResetOffsetsSupervisorAction()} {this.renderResetSupervisorAction()} {this.renderTerminateSupervisorAction()} diff --git a/web-console/src/views/workbench-view/flexible-query-input/flexible-query-input.tsx b/web-console/src/views/workbench-view/flexible-query-input/flexible-query-input.tsx index 7ba116e34b5d..fba74e521a44 100644 --- a/web-console/src/views/workbench-view/flexible-query-input/flexible-query-input.tsx +++ b/web-console/src/views/workbench-view/flexible-query-input/flexible-query-input.tsx @@ -82,6 +82,10 @@ export class FlexibleQueryInput extends React.PureComponent< // Local completions { getCompletions: (_state, session, pos, prefix, callback) => { + if (/^\d+$/.test(prefix)) { + callback(null, []); // Don't start completing if the user is typing a number + return; + } const charBeforePrefix = session.getLine(pos.row)[pos.column - prefix.length - 1]; callback( null,