Web console: Reset to specific offsets dialog (#14863)

* add dialog

* copy changes
This commit is contained in:
Vadim Ogievetsky 2023-08-17 15:38:56 -07:00 committed by GitHub
parent 59415ba9b2
commit 7e147ee905
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 147 additions and 1 deletions

View File

@ -34,6 +34,7 @@ export * from './retention-dialog/retention-dialog';
export * from './snitch-dialog/snitch-dialog';
export * from './spec-dialog/spec-dialog';
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-table-action-dialog/task-table-action-dialog';

View File

@ -0,0 +1,122 @@
/*
* 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 { Button, Classes, Code, ControlGroup, Dialog, FormGroup, Intent } from '@blueprintjs/core';
import React, { useState } from 'react';
import { FancyNumericInput } from '../../components/fancy-numeric-input/fancy-numeric-input';
import { useQueryManager } from '../../hooks';
import { Api, AppToaster } from '../../singletons';
import { deepGet, getDruidErrorMessage } from '../../utils';
type OffsetMap = Record<string, number>;
interface SupervisorResetOffsetsDialogProps {
supervisorId: string;
supervisorType: string;
onClose: () => void;
}
export const SupervisorResetOffsetsDialog = React.memo(function SupervisorResetOffsetsDialog(
props: SupervisorResetOffsetsDialogProps,
) {
const { supervisorId, supervisorType, onClose } = props;
const [offsetsToResetTo, setOffsetsToResetTo] = useState<OffsetMap>({});
const [statusResp] = useQueryManager<string, OffsetMap>({
initQuery: supervisorId,
processQuery: async supervisorId => {
const statusResp = await Api.instance.get(
`/druid/indexer/v1/supervisor/${Api.encodePath(supervisorId)}/status`,
);
return statusResp.data;
},
});
const stream = deepGet(statusResp.data || {}, 'payload.stream');
const latestOffsets = deepGet(statusResp.data || {}, 'payload.latestOffsets');
async function onSave() {
if (!stream) return;
if (!Object.keys(offsetsToResetTo).length) return;
try {
await Api.instance.post(
`/druid/indexer/v1/supervisor/${Api.encodePath(supervisorId)}/resetOffsets`,
{
type: supervisorType,
partitions: {
type: 'end',
stream,
partitionOffsetMap: offsetsToResetTo,
},
},
);
} catch (e) {
AppToaster.show({
message: `Failed to set offsets: ${getDruidErrorMessage(e)}`,
intent: Intent.DANGER,
});
return;
}
AppToaster.show({
message: `${supervisorId} offsets have been set`,
intent: Intent.SUCCESS,
});
onClose();
}
return (
<Dialog
className="supervisor-reset-offsets-dialog"
isOpen
onClose={onClose}
title={`Set supervisor offsets: ${supervisorId}`}
>
<div className={Classes.DIALOG_FOOTER}>
<div className={Classes.DIALOG_BODY}>
<p>
Set <Code>{supervisorId}</Code> to specific offsets
</p>
{latestOffsets &&
Object.entries(latestOffsets).map(([key, latestOffset]) => (
<FormGroup key={key}>
<ControlGroup>
<Button text={`${key} (currently: ${latestOffset})`} disabled />
<FancyNumericInput
value={offsetsToResetTo[key]}
onValueChange={valueAsNumber => {
setOffsetsToResetTo({ ...offsetsToResetTo, [key]: valueAsNumber });
}}
min={0}
fill
placeholder={"Don't change"}
/>
</ControlGroup>
</FormGroup>
))}
</div>
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
<Button text="Close" onClick={onClose} />
<Button text="Save" intent={Intent.PRIMARY} onClick={() => void onSave()} />
</div>
</div>
</Dialog>
);
});

View File

@ -40,6 +40,7 @@ import {
SpecDialog,
SupervisorTableActionDialog,
} from '../../dialogs';
import { SupervisorResetOffsetsDialog } from '../../dialogs/supervisor-reset-offsets-dialog/supervisor-reset-offsets-dialog';
import type { QueryWithContext } from '../../druid-models';
import type { Capabilities } from '../../helpers';
import { SMALL_TABLE_PAGE_SIZE, SMALL_TABLE_PAGE_SIZE_OPTIONS } from '../../react-table';
@ -108,6 +109,7 @@ export interface SupervisorsViewState {
resumeSupervisorId?: string;
suspendSupervisorId?: string;
resetOffsetsSupervisorInfo?: { id: string; type: string };
resetSupervisorId?: string;
terminateSupervisorId?: string;
@ -339,6 +341,11 @@ GROUP BY 1, 2`;
? this.setState({ resumeSupervisorId: id })
: this.setState({ suspendSupervisorId: id }),
},
{
icon: IconNames.STEP_BACKWARD,
title: 'Set offsets',
onAction: () => this.setState({ resetOffsetsSupervisorInfo: { id, type } }),
},
{
icon: IconNames.STEP_BACKWARD,
title: 'Hard reset',
@ -417,6 +424,21 @@ GROUP BY 1, 2`;
);
}
renderResetOffsetsSupervisorAction() {
const { resetOffsetsSupervisorInfo } = this.state;
if (!resetOffsetsSupervisorInfo) return;
return (
<SupervisorResetOffsetsDialog
supervisorId={resetOffsetsSupervisorInfo.id}
supervisorType={resetOffsetsSupervisorInfo.type}
onClose={() => {
this.setState({ resetOffsetsSupervisorInfo: undefined });
}}
/>
);
}
renderResetSupervisorAction() {
const { resetSupervisorId } = this.state;
if (!resetSupervisorId) return;
@ -426,7 +448,7 @@ GROUP BY 1, 2`;
action={async () => {
const resp = await Api.instance.post(
`/druid/indexer/v1/supervisor/${Api.encodePath(resetSupervisorId)}/reset`,
{},
'',
);
return resp.data;
}}
@ -784,6 +806,7 @@ GROUP BY 1, 2`;
{this.renderSupervisorTable()}
{this.renderResumeSupervisorAction()}
{this.renderSuspendSupervisorAction()}
{this.renderResetOffsetsSupervisorAction()}
{this.renderResetSupervisorAction()}
{this.renderTerminateSupervisorAction()}
{supervisorSpecDialogOpen && (