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 download job command to jupyter #1492

Merged
merged 7 commits into from
Jan 16, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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 @@ -17,6 +17,9 @@
},
{
"command": "jp-vdk:menu-delete"
},
{
"command": "jp-vdk:menu-download"
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { CommandRegistry } from "@lumino/commands";
import { Dialog, showDialog } from "@jupyterlab/apputils";
import React from "react";
import RunJobDialog from "./components/RunJob";
import { deleteJobRequest, jobRunRequest } from "./serverRequests";
import { deleteJobRequest, downloadJobRequest, jobRunRequest } from "./serverRequests";
import CreateJobDialog from "./components/CreateJob";
import DeleteJobDialog from "./components/DeleteJob";
import DownloadJobDialog from "./components/DownloadJob";

export function updateVDKMenu(commands: CommandRegistry) {
commands.addCommand("jp-vdk:menu-run", {
Expand Down Expand Up @@ -75,4 +76,22 @@ export function updateVDKMenu(commands: CommandRegistry) {
}).catch((e) => console.log(e));
},
});

commands.addCommand("jp-vdk:menu-download", {
label: "Download",
caption: 'Execute VDK Download Command',
execute: async () => {
showDialog({
title: "Download Job",
body: <DownloadJobDialog parentPath={sessionStorage.getItem("current-path")!}></DownloadJobDialog>,
buttons: [Dialog.okButton(), Dialog.cancelButton()],
}).then(result => {
if (!result.value) {
if(result.button.accept){
downloadJobRequest();
}
}
}).catch((e) => console.log(e));
},
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import React, { Component } from 'react';

export interface IDownloadJobDialogProps {
/**
* Current Path
*/
parentPath: string;
}


export default class DownloadJobDialog extends Component<IDownloadJobDialogProps> {
/**
* Returns a React component for rendering a download menu.
*
* @param props - component properties
* @returns React component
*/
constructor(props: IDownloadJobDialogProps) {
super(props);
}
/**
* Renders a dialog for downloading a data job.
*
* @returns React element
*/
render(): React.ReactElement {
return (
<>
<div className='jp-vdk-input-wrapper'>
<label className='jp-vdk-label' htmlFor="jobName">Job Name:</label>
<input type="text" id="jobName" className='jp-vdk-input' placeholder="job-to-download" onChange={this.onNameChange} />
</div>
<div className='jp-vdk-input-wrapper'>
<label className='jp-vdk-label' htmlFor="jobTeam">Job Team:</label>
<input type="text" id="jobTeam" className='jp-vdk-input' placeholder="my-team" onChange={this.onTeamChange} />
</div>
<div className='jp-vdk-input-wrapper'>
<label className='jp-vdk-label' htmlFor="jobRestApiUrl">Rest Api URL:</label>
<input type="text" id="jobRestApiUrl" className='jp-vdk-input' placeholder="rest-api-url" onChange={this.onRestApiUrlChange} />
</div>
<div className='jp-vdk-input-wrapper'>
<label className='jp-vdk-label' htmlFor="jobPath">Path to parent directory where the job will be saved:</label>
<input type="text" id="jobPath" className='jp-vdk-input' placeholder={this.props.parentPath} onChange={this.onPathChange} />
</div>
</>
);
}
/**
* Callback invoked upon changing the job name input.
*
* @param event - event object
*/
private onNameChange = (event: any): void => {
const nameInput = event.currentTarget as HTMLInputElement;
let value = nameInput.value;
if (!value) {
value = "default-job";
}
sessionStorage.setItem("download-job-name", value);
};
/**
* Callback invoked upon changing the job team input.
*
* @param event - event object
*/
private onTeamChange = (event: any): void => {
const teamInput = event.currentTarget as HTMLInputElement;
let value = teamInput.value;
if (!value) {
value = "default-team";
}
sessionStorage.setItem("download-job-team", value);
};
/**
* Callback invoked upon changing the job rest-api-url input.
*
* @param event - event object
*/
private onRestApiUrlChange = (event: any): void => {
const urlInput = event.currentTarget as HTMLInputElement;
let value = urlInput.value;
if (!value) {
value = "default-url";
}
sessionStorage.setItem("download-job-rest-api-url", value);
};
/**
* Callback invoked upon changing the job path input.
*
* @param event - event object
*/
private onPathChange = (event: any): void => {
const element = event.currentTarget as HTMLInputElement;
let value = element.value;
if(!value){
value = this.props.parentPath;
}
sessionStorage.setItem("download-job-path", value)
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,27 @@ export function jobRunRequest() {
throw(reason)
});
}


/**
* Sent a POST request to the server to download a data job.
* The information about the data job is retrieved from sessionStorage and sent as JSON.
*/
export function downloadJobRequest() {
let dataToSend = {
jobName: sessionStorage.getItem("download-job-name"),
jobTeam: sessionStorage.getItem("download-job-team"),
restApiUrl: sessionStorage.getItem("download-job-rest-api-url"),
parentPath: sessionStorage.getItem("download-job-path"),
};
requestAPI<any>('download', {
body: JSON.stringify(dataToSend),
method: 'POST',
})
.then(data => {
alert(data["message"]);
})
.catch(reason => {
throw(reason)
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ def post(self):
self.finish(json.dumps({"message": f"{e}"}))


class DownloadJobHandler(APIHandler):
@tornado.web.authenticated
def post(self):
input_data = self.get_json_body()
try:
status = VdkUI.download_job(
input_data["jobName"],
input_data["jobTeam"],
input_data["restApiUrl"],
input_data["parentPath"],
)
self.finish(json.dumps({"message": f"{status}"}))
except Exception as e:
self.finish(json.dumps({"message": f"{e}"}))


def setup_handlers(web_app):
host_pattern = ".*$"

Expand All @@ -48,3 +64,9 @@ def setup_handlers(web_app):
)
delete_job_handlers = [(delete_job_route_pattern, DeleteJobHandler)]
web_app.add_handlers(host_pattern, delete_job_handlers)

download_job_route_pattern = url_path_join(
base_url, "vdk-jupyterlab-extension", "download"
)
download_job_handlers = [(download_job_route_pattern, DownloadJobHandler)]
web_app.add_handlers(host_pattern, download_job_handlers)
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import subprocess

from vdk.internal.control.command_groups.job.delete import JobDelete
from vdk.internal.control.command_groups.job.download_job import JobDownloadSource


class VdkUI:
Expand Down Expand Up @@ -56,3 +57,20 @@ def delete_job(name: str, team: str, rest_api_url: str):
return f"Deleted the job with name {name} from {team} team. "
except Exception as e:
raise e

@staticmethod
def download_job(name: str, team: str, rest_api_url: str, path: str):
"""
Execute `download job`.
:param name: the name of the data job that will be downloaded
:param team: the team of the data job that will be downloaded
:param rest_api_url: The base REST API URL
:param path: the path to the directory where the job will be downloaded
:return: message that the job is downloaded
"""
try:
cmd = JobDownloadSource(rest_api_url)
cmd.download(team, name, path)
return f"Downloaded the job with name {name} to {path}. "
except Exception as e:
raise e