Skip to content

Commit

Permalink
VTAdmin(web): Support for MoveTables complete
Browse files Browse the repository at this point in the history
Signed-off-by: Noble Mittal <noblemittal@outlook.com>
  • Loading branch information
beingnoble03 committed Sep 21, 2024
1 parent 71db432 commit 1010780
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 4 deletions.
16 changes: 16 additions & 0 deletions web/vtadmin/src/api/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,22 @@ export const stopWorkflow = async ({ clusterID, keyspace, name }: WorkflowAction
return vtctldata.WorkflowUpdateResponse.create(result);
};

export interface MoveTablesCompleteParams {
clusterID: string;
request: vtctldata.IMoveTablesCompleteRequest;
}

export const completeMoveTables = async ({ clusterID, request }: MoveTablesCompleteParams) => {
const { result } = await vtfetch(`/api/movetables/${clusterID}/complete`, {
body: JSON.stringify(request),
method: 'post',
});
const err = vtctldata.MoveTablesCompleteResponse.verify(result);
if (err) throw Error(err);

return vtctldata.MoveTablesCompleteResponse.create(result);
};

export const fetchVTExplain = async <R extends pb.IVTExplainRequest>({ cluster, keyspace, sql }: R) => {
// As an easy enhancement for later, we can also validate the request parameters on the front-end
// instead of defaulting to '', to save a round trip.
Expand Down
1 change: 1 addition & 0 deletions web/vtadmin/src/components/routes/Workflows.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ export const Workflows = () => {
keyspace={row.keyspace as string}
clusterID={row.clusterID as string}
name={row.name as string}
workflowType={row.workflowType as string}
/>
</DataCell>
</ReadOnlyGate>
Expand Down
15 changes: 13 additions & 2 deletions web/vtadmin/src/components/routes/workflows/WorkflowAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ interface WorkflowActionProps {
mutation: UseMutationResult<any, any, any>;
title: string;
confirmText: string;
successText: string;
successText?: string;
errorText: string;
errorDescription?: string;
loadingText: string;
description?: string;
className?: string;
body?: JSX.Element;
successBody?: JSX.Element;
hideSuccessDialog?: boolean;
refetchWorkflows: Function;
closeDialog: () => void;
}
Expand All @@ -29,8 +32,11 @@ const WorkflowAction: React.FC<WorkflowActionProps> = ({
successBody,
loadingText,
errorText,
errorDescription,
refetchWorkflows,
hideSuccessDialog,
body,
className,
}) => {
const onCloseDialog = () => {
setTimeout(mutation.reset, 500);
Expand All @@ -43,6 +49,9 @@ const WorkflowAction: React.FC<WorkflowActionProps> = ({
{},
{
onSuccess: () => {
if (hideSuccessDialog) {
closeDialog();
}
refetchWorkflows();
},
}
Expand All @@ -61,10 +70,11 @@ const WorkflowAction: React.FC<WorkflowActionProps> = ({
hideCancel={hasRun}
title={hasRun ? undefined : title}
description={hasRun ? undefined : description}
className={className}
>
<div className="w-full">
{!hasRun && body}
{mutation.data && !mutation.error && (
{!hideSuccessDialog && mutation.data && !mutation.error && (
<div className="w-full flex flex-col justify-center items-center">
<span className="flex h-12 w-12 relative items-center justify-center">
<Icon className="fill-current text-green-500" icon={Icons.checkSuccess} />
Expand All @@ -79,6 +89,7 @@ const WorkflowAction: React.FC<WorkflowActionProps> = ({
<Icon className="fill-current text-red-500" icon={Icons.alertFail} />
</span>
<div className="text-lg mt-3 font-bold text-center">{errorText}</div>
{errorDescription && <div className="text-sm mt-1">{errorDescription}</div>}
</div>
)}
</div>
Expand Down
125 changes: 123 additions & 2 deletions web/vtadmin/src/components/routes/workflows/WorkflowActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,75 @@ import Dropdown from '../../dropdown/Dropdown';
import MenuItem from '../../dropdown/MenuItem';
import { Icons } from '../../Icon';
import WorkflowAction from './WorkflowAction';
import { useStartWorkflow, useStopWorkflow } from '../../../hooks/api';
import { useCompleteMoveTables, useStartWorkflow, useStopWorkflow } from '../../../hooks/api';
import Toggle from '../../toggle/Toggle';
import { success } from '../../Snackbar';

interface WorkflowActionsProps {
refetchWorkflows: Function;
keyspace: string;
clusterID: string;
name: string;
workflowType: string;
}

const WorkflowActions: React.FC<WorkflowActionsProps> = ({ refetchWorkflows, keyspace, clusterID, name }) => {
interface CompleteMoveTablesOptions {
keepData: boolean;
keepRoutingRoules: boolean;
renameTables: boolean;
}

const DefaultCompleteMoveTablesOptions: CompleteMoveTablesOptions = {
keepData: false,
keepRoutingRoules: false,
renameTables: false,
};

const WorkflowActions: React.FC<WorkflowActionsProps> = ({
refetchWorkflows,
keyspace,
clusterID,
name,
workflowType,
}) => {
const [currentDialog, setCurrentDialog] = useState<string>('');

const [completeMoveTablesOptions, SetCompleteMoveTablesOptions] = useState<CompleteMoveTablesOptions>(
DefaultCompleteMoveTablesOptions
);

const closeDialog = () => setCurrentDialog('');

const startWorkflowMutation = useStartWorkflow({ keyspace, clusterID, name });

const stopWorkflowMutation = useStopWorkflow({ keyspace, clusterID, name });

const completeMoveTablesMutation = useCompleteMoveTables(
{
clusterID,
request: {
workflow: name,
target_keyspace: keyspace,
keep_data: completeMoveTablesOptions.keepData,
keep_routing_rules: completeMoveTablesOptions.keepRoutingRoules,
rename_tables: completeMoveTablesOptions.renameTables,
},
},
{
onSuccess: (data) => {
success(data.summary, { autoClose: 1600 });
},
}
);

const isMoveTablesWorkflow = workflowType === 'MoveTables';

return (
<div className="w-min inline-block">
<Dropdown dropdownButton={Icons.info} position="bottom-right">
{isMoveTablesWorkflow && (
<MenuItem onClick={() => setCurrentDialog('Complete MoveTables')}>Complete MoveTables</MenuItem>
)}
<MenuItem onClick={() => setCurrentDialog('Start Workflow')}>Start Workflow</MenuItem>
<MenuItem onClick={() => setCurrentDialog('Stop Workflow')}>Stop Workflow</MenuItem>
</Dropdown>
Expand Down Expand Up @@ -72,6 +121,78 @@ const WorkflowActions: React.FC<WorkflowActionsProps> = ({ refetchWorkflows, key
</div>
}
/>
<WorkflowAction
className="sm:max-w-xl"
title="Complete MoveTables"
description={`Complete the ${name} workflow.`}
confirmText="Complete"
loadingText="Completing"
hideSuccessDialog={true}
mutation={completeMoveTablesMutation}
errorText={`Error occured while completing workflow ${name}`}
errorDescription={completeMoveTablesMutation.error ? completeMoveTablesMutation.error.message : ''}
closeDialog={closeDialog}
isOpen={currentDialog === 'Complete MoveTables'}
refetchWorkflows={refetchWorkflows}
body={
<div className="flex flex-col gap-2">
<div className="flex justify-between items-center w-full p-4 border border-vtblue rounded-md">
<div className="mr-2">
<h5 className="font-medium m-0 mb-2">Keep Data</h5>
<p className="m-0 text-sm">
Keep the original source table data that was copied by the MoveTables workflow.
</p>
</div>
<Toggle
enabled={completeMoveTablesOptions.keepData}
onChange={() =>
SetCompleteMoveTablesOptions((prevOptions) => ({
...prevOptions,
keepData: !prevOptions.keepData,
}))
}
/>
</div>
<div className="flex justify-between items-center w-full p-4 border border-vtblue rounded-md">
<div className="mr-2">
<h5 className="font-medium m-0 mb-2">Keep Routing Rules</h5>
<p className="m-0 text-sm">
Keep the routing rules in place that direct table traffic from the source keyspace
to the target keyspace of the MoveTables workflow.
</p>
</div>
<Toggle
enabled={completeMoveTablesOptions.keepRoutingRoules}
onChange={() =>
SetCompleteMoveTablesOptions((prevOptions) => ({
...prevOptions,
keepRoutingRoules: !prevOptions.keepRoutingRoules,
}))
}
/>
</div>
<div className="flex justify-between items-center w-full p-4 border border-vtblue rounded-md">
<div className="mr-2">
<h5 className="font-medium m-0 mb-2">Rename Tables</h5>
<p className="m-0 text-sm">
Keep the original source table data that was copied by the MoveTables workflow, but
rename each table to{' '}
<span className="font-mono bg-gray-300">{'_<tablename>_old'}</span>.
</p>
</div>
<Toggle
enabled={completeMoveTablesOptions.renameTables}
onChange={() =>
SetCompleteMoveTablesOptions((prevOptions) => ({
...prevOptions,
renameTables: !prevOptions.renameTables,
}))
}
/>
</div>
</div>
}
/>
</div>
);
};
Expand Down
13 changes: 13 additions & 0 deletions web/vtadmin/src/hooks/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import {
stopWorkflow,
FetchTransactionsParams,
fetchTransactions,
completeMoveTables,
} from '../api/http';
import { vtadmin as pb, vtctldata } from '../proto/vtadmin';
import { formatAlias } from '../util/tablets';
Expand Down Expand Up @@ -498,6 +499,18 @@ export const useStopWorkflow = (
}, options);
};

/**
* useCompleteMoveTables is a mutate hook that completes a MoveTables workflow.
*/
export const useCompleteMoveTables = (
params: Parameters<typeof completeMoveTables>[0],
options?: UseMutationOptions<Awaited<ReturnType<typeof completeMoveTables>>, Error>
) => {
return useMutation<Awaited<ReturnType<typeof completeMoveTables>>, Error>(() => {
return completeMoveTables(params);
}, options);
};

/**
* useReloadSchema is a mutate hook that reloads schemas in one or more
* keyspaces, shards, or tablets in the cluster, depending on the request parameters.
Expand Down

0 comments on commit 1010780

Please sign in to comment.