Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vdk-jupyter: add Convert Job To Notebook UI button #2329

Merged
merged 21 commits into from
Jun 29, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
d2115eb
vdk-jupyter: add Transform Job UI component
yonitoo Jun 21, 2023
38f116d
Merge branch 'main' into topic/ysalambashev/jupyter-add-transform-job…
yonitoo Jun 26, 2023
0690a89
Merge branch 'main' into topic/ysalambashev/jupyter-add-transform-job…
yonitoo Jun 26, 2023
061ca60
vdk-jupyter: add API request for the transform job
yonitoo Jun 26, 2023
4011094
Merge branch 'main' into topic/ysalambashev/jupyter-add-transform-job…
yonitoo Jun 26, 2023
ed7bc06
Merge branch 'main' into topic/ysalambashev/jupyter-add-transform-job…
yonitoo Jun 27, 2023
dc3d802
vdk-jupyter: add jest tests
yonitoo Jun 27, 2023
97ac5bf
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 27, 2023
ce7a82e
build(deps): Bump io.swagger.core.v3:swagger-models from 2.2.12 to 2.…
dependabot[bot] Jun 27, 2023
401386c
vdk-core: add vdk sdk secrets api - part III (#2325)
Jun 27, 2023
b9e2b27
vdk-jupyter: address review comments
yonitoo Jun 27, 2023
b3f456f
Merge branch 'main' into topic/ysalambashev/jupyter-add-transform-job…
yonitoo Jun 27, 2023
62674a1
vdk-jupyter: remove job and team name
yonitoo Jun 27, 2023
49c0e6a
vdk-jupyter: add confirmation dialog upon transform job operation
yonitoo Jun 27, 2023
3c1c922
vdk-jupyter: extract repeated strings into constants
yonitoo Jun 28, 2023
252fdee
Merge branch 'main' into topic/ysalambashev/jupyter-add-transform-job…
yonitoo Jun 28, 2023
33d6e6e
vdk-jupyter: fix lint issues
yonitoo Jun 28, 2023
913ddef
change formatting in utils.ts
duyguHsnHsn Jun 28, 2023
18d718d
vdk-jupyter: rename to transform job to notebook
yonitoo Jun 28, 2023
a7a81c8
vdk-jupyter: rename to convert
yonitoo Jun 29, 2023
b4360c9
Merge branch 'main' into topic/ysalambashev/jupyter-add-transform-job…
yonitoo Jun 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
{
"command": "jp-vdk:menu-download"
},
{
"command": "jp-vdk:menu-transform-job-to-notebook"
},
{
"command": "jp-vdk:menu-create-deployment"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2023-2023 VMware, Inc.
* SPDX-License-Identifier: Apache-2.0
*/
import TransformJobToNotebookDialog from '../components/TransformJobToNotebook';
import { render, fireEvent } from '@testing-library/react';
import { jobData } from '../jobData';
import { VdkOption } from '../vdkOptions/vdk_options';
import { IJobPathProp } from '../components/props';

const defaultProps: IJobPathProp = {
jobPath: 'test-path'
};

// created with the expectation to compare a rendered value with expected value parsed from config.ini
// yet to be implemented
describe('#render()', () => {
it('should return contain job path input with placeholder equal to jobPath from props', () => {
const component = render(
new TransformJobToNotebookDialog(defaultProps).render()
);
const input = component.getByPlaceholderText(defaultProps.jobPath);
expect(input).toBe(
component.getAllByLabelText('Path to job directory:')[0]
);
});
});

describe('#onPathChange', () => {
it('should change the path in jobData', () => {
const component = render(
new TransformJobToNotebookDialog(defaultProps).render()
);
const input = component.getByPlaceholderText(defaultProps.jobPath);
fireEvent.change(input, { target: { value: 'other/path' } });
expect(jobData.get(VdkOption.PATH)).toEqual('other/path');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { jobData, setJobDataToDefault } from './jobData';
import { showCreateDeploymentDialog } from './components/DeployJob';
import { showCreateJobDialog } from './components/CreateJob';
import { showDownloadJobDialog } from './components/DownloadJob';
import { showTransformJobToNotebookDialog } from './components/TransformJobToNotebook';
import { showDeleteJobDialog } from './components/DeleteJob';
import { jobdDataRequest } from './serverRequests';
import { VdkOption } from './vdkOptions/vdk_options';
Expand All @@ -26,6 +27,9 @@ export function updateVDKMenu(commands: CommandRegistry, docManager: IDocumentMa
// Add Download job command
add_command(commands, 'jp-vdk:menu-download','Download','Execute VDK Download Command', showDownloadJobDialog);

// Add Transform Job To Notebook command
add_command(commands, 'jp-vdk:menu-transform-job-to-notebook', 'Transform Job To Notebook', 'Transform Data Job To Jupyter Notebook', showTransformJobToNotebookDialog);

// Add Create Deployment command
add_command(commands, 'jp-vdk:menu-create-deployment','Deploy','Create deployment of a VDK job', showCreateDeploymentDialog);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import VDKTextInput from './VdkTextInput';
import { Dialog, showDialog } from '@jupyterlab/apputils';
import { jobRequest } from '../serverRequests';
import { IJobFullProps } from './props';

import { CREATE_JOB_BUTTON_LABEL } from '../utils';

export default class CreateJobDialog extends Component<(IJobFullProps)> {
/**
Expand Down Expand Up @@ -110,7 +110,7 @@ export default class CreateJobDialog extends Component<(IJobFullProps)> {

export async function showCreateJobDialog() {
const result = await showDialog({
title: 'Create Job',
title: CREATE_JOB_BUTTON_LABEL,
body: (
<CreateJobDialog
jobPath={jobData.get(VdkOption.PATH)!}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Dialog, showDialog, showErrorMessage } from '@jupyterlab/apputils';
import { jobData } from '../jobData';
import { jobRequest } from '../serverRequests';
import { IJobNameAndTeamProps } from './props';

import { DELETE_JOB_BUTTON_LABEL } from '../utils';

export default class DeleteJobDialog extends Component<IJobNameAndTeamProps> {
/**
Expand Down Expand Up @@ -42,7 +42,7 @@ export default class DeleteJobDialog extends Component<IJobNameAndTeamProps> {

export async function showDeleteJobDialog() {
const result = await showDialog({
title: 'Delete Job',
title: DELETE_JOB_BUTTON_LABEL,
body: (
<DeleteJobDialog
jobName={jobData.get(VdkOption.NAME)!}
Expand All @@ -54,7 +54,7 @@ export async function showDeleteJobDialog() {
if (result.button.accept) {
try {
const finalResult = await showDialog({
title: 'Delete a data job',
title: DELETE_JOB_BUTTON_LABEL,
body:
'Do you really want to delete the job with name ' +
jobData.get(VdkOption.NAME) +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import VDKTextInput from './VdkTextInput';
import { Dialog, showDialog, showErrorMessage } from '@jupyterlab/apputils';
import { jobRequest, jobRunRequest } from '../serverRequests';
import { IJobFullProps } from './props';
import { CREATE_DEP_BUTTON_LABEL } from '../utils';


export default class DeployJobDialog extends Component<(IJobFullProps)> {
export default class DeployJobDialog extends Component<IJobFullProps> {
/**
* Returns a React component for rendering a Deploy menu.
*
Expand Down Expand Up @@ -65,7 +65,7 @@ export default class DeployJobDialog extends Component<(IJobFullProps)> {
*/
private onEnableClick() {
return (event: React.MouseEvent) => {
let checkbox = document.getElementById('enable');
const checkbox = document.getElementById('enable');
if (checkbox?.classList.contains('checked')) {
checkbox.classList.remove('checked');
jobData.set(VdkOption.DEPLOY_ENABLE, '');
Expand All @@ -79,7 +79,7 @@ export default class DeployJobDialog extends Component<(IJobFullProps)> {

export async function showCreateDeploymentDialog() {
const result = await showDialog({
title: 'Create Deployment',
title: CREATE_DEP_BUTTON_LABEL,
body: (
<DeployJobDialog
jobName={jobData.get(VdkOption.NAME)!}
Expand All @@ -93,18 +93,20 @@ export async function showCreateDeploymentDialog() {
if (resultButtonClicked) {
try {
const runConfirmationResult = await showDialog({
title: 'Create deployment',
title: CREATE_DEP_BUTTON_LABEL,
body: 'The job will be executed once before deployment.',
buttons: [
Dialog.cancelButton({ label: 'Cancel' }),
Dialog.okButton({ label: 'Continue' })
]
});
if (runConfirmationResult.button.accept) {
let { message, status } = await jobRunRequest();
const { message, status } = await jobRunRequest();
if (status) {
if (await checkIfVdkOptionDataIsDefined(VdkOption.DEPLOYMENT_REASON)){
await jobRequest("deploy");
if (
await checkIfVdkOptionDataIsDefined(VdkOption.DEPLOYMENT_REASON)
) {
await jobRequest('deploy');
}
} else {
showErrorMessage(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Dialog, showDialog } from '@jupyterlab/apputils';
import { jobRequest } from '../serverRequests';
import { IJobPathProp } from './props';
import { jobData } from '../jobData';

import { DOWNLOAD_JOB_BUTTON_LABEL } from '../utils';

export default class DownloadJobDialog extends Component<IJobPathProp> {
/**
Expand Down Expand Up @@ -47,7 +47,7 @@ export default class DownloadJobDialog extends Component<IJobPathProp> {

export async function showDownloadJobDialog() {
const result = await showDialog({
title: 'Download Job',
title: DOWNLOAD_JOB_BUTTON_LABEL,
body: (
<DownloadJobDialog
jobPath={jobData.get(VdkOption.PATH)!}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { getNotebookInfo, jobRunRequest } from '../serverRequests';
import { IJobPathProp } from './props';
import { VdkErrorMessage } from './VdkErrorMessage';
import { IDocumentManager } from '@jupyterlab/docmanager';
import { RUN_FAILED_BUTTON_LABEL, RUN_JOB_BUTTON_LABEL } from '../utils';

export default class RunJobDialog extends Component<IJobPathProp> {
/**
Expand Down Expand Up @@ -73,15 +74,15 @@ export default class RunJobDialog extends Component<IJobPathProp> {

export async function showRunJobDialog(docManager?: IDocumentManager) {
const result = await showDialog({
title: 'Run Job',
title: RUN_JOB_BUTTON_LABEL,
body: <RunJobDialog jobPath={jobData.get(VdkOption.PATH)!}></RunJobDialog>,
buttons: [Dialog.okButton(), Dialog.cancelButton()]
});
if (result.button.accept) {
let { message, status } = await jobRunRequest();
if (status) {
showDialog({
title: 'Run Job',
title: RUN_JOB_BUTTON_LABEL,
body: (
<div className="vdk-run-dialog-message-container">
<p className="vdk-run-dialog-message">
Expand All @@ -99,7 +100,7 @@ export async function showRunJobDialog(docManager?: IDocumentManager) {
!(await handleErrorsProducedByNotebookCell(errorMessage, docManager))
) {
showDialog({
title: 'Run Job',
title: RUN_JOB_BUTTON_LABEL,
body: (
<div className="vdk-run-error-message ">
<p>{errorMessage.exception_message}</p>
Expand Down Expand Up @@ -178,7 +179,7 @@ export const findFailingCellInNotebookCells = async (
const cells = element.children;
if (failingCellIndex > cells.length) {
showDialog({
title: 'Run Failed',
title: RUN_FAILED_BUTTON_LABEL,
body: (
<div>
<p>
Expand Down Expand Up @@ -234,7 +235,7 @@ export const handleErrorsProducedByNotebookCell = async (
};

const result = await showDialog({
title: 'Run Job',
title: RUN_JOB_BUTTON_LABEL,
body: (
<div className="vdk-run-error-message ">
<p>{message.exception_message}</p>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React, { Component } from 'react';
import { jobData } from '../jobData';
import { VdkOption } from '../vdkOptions/vdk_options';
import VDKTextInput from './VdkTextInput';
import { Dialog, showDialog } from '@jupyterlab/apputils';
import { jobTransformToNotebookRequest } from '../serverRequests';
import { IJobPathProp } from './props';
import { VdkErrorMessage } from './VdkErrorMessage';
import { TRANSFORM_JOB_TO_NOTEBOOK_BUTTON_LABEL } from '../utils';

export default class TransformJobToNotebookDialog extends Component<IJobPathProp> {
/**
* Returns a React component for rendering a transform menu.
*
* @param props - component properties
* @returns React component
*/
constructor(props: IJobPathProp) {
super(props);
}
/**
* Renders a dialog for transforming a data job.
*
* @returns React element
*/
render(): React.ReactElement {
return (
<>
<VDKTextInput
option={VdkOption.PATH}
value={this.props.jobPath}
label="Path to job directory:"
></VDKTextInput>
</>
);
}
}

export async function showTransformJobToNotebookDialog() {
const result = await showDialog({
title: TRANSFORM_JOB_TO_NOTEBOOK_BUTTON_LABEL,
body: (
<TransformJobToNotebookDialog
jobPath={jobData.get(VdkOption.PATH)!}
></TransformJobToNotebookDialog>
),
buttons: [Dialog.okButton(), Dialog.cancelButton()]
});
if (result.button.accept) {
const confirmation = await showDialog({
title: TRANSFORM_JOB_TO_NOTEBOOK_BUTTON_LABEL,
body: (
<p>
Are you sure you want to transform the Data Job with path:{' '}
<i>{jobData.get(VdkOption.PATH)}</i> to notebook?
</p>
),
buttons: [Dialog.okButton(), Dialog.cancelButton()]
});
if (confirmation.button.accept) {
let { message, status } = await jobTransformToNotebookRequest();
if (status) {
await showDialog({
title: TRANSFORM_JOB_TO_NOTEBOOK_BUTTON_LABEL,
body: (
<div className="vdk-transform-to-notebook-dialog-message-container">
<p className="vdk-transform-to-notebook-dialog-message">
The Data Job with path <i>{jobData.get(VdkOption.PATH)}</i> was
transformed to notebook successfully!
</p>
</div>
),
buttons: [Dialog.okButton()]
});
} else {
message = 'ERROR : ' + message;
const errorMessage = new VdkErrorMessage(message);
await showDialog({
title: TRANSFORM_JOB_TO_NOTEBOOK_BUTTON_LABEL,
body: (
<div className="vdk-transform-to-notebook-error-message ">
<p>{errorMessage.exception_message}</p>
<p>{errorMessage.what_happened}</p>
<p>{errorMessage.why_it_happened}</p>
<p>{errorMessage.consequences}</p>
<p>{errorMessage.countermeasures}</p>
</div>
),
buttons: [Dialog.okButton()]
});
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@


export type IJobPathProp = {
/**
* Current Job path or the path to job's parent directory
*/
jobPath: string;
}
/**
* Current Job path or the path to job's parent directory
*/
jobPath: string;
};

export type IJobNameAndTeamProps = {
/**
* Current Job name
*/
jobName: string;
/**
* Current Team name
*/
jobTeam: string;
}
/**
* Current Job name
*/
jobName: string;
/**
* Current Team name
*/
jobTeam: string;
};

export type IJobFullProps = IJobPathProp & IJobNameAndTeamProps;
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,29 @@ export async function jobRequest(endPoint: string): Promise<void> {
}
}

export async function jobTransformToNotebookRequest(): Promise<{
message: String;
status: boolean;
}> {
if (await checkIfVdkOptionDataIsDefined(VdkOption.PATH)) {
try {
const data = await requestAPI<serverVdkOperationResult>(
'transformJobToNotebook',
{
body: JSON.stringify(getJobDataJsonObject()),
method: 'POST'
}
);
return { message: data['message'], status: data['message'] == '0' };
} catch (error) {
showError(error);
return { message: '', status: false };
}
} else {
return { message: '', status: false };
}
}

/**
* Sent a POST request to the server to get information about the data job of current directory
*/
Expand Down
Loading