diff --git a/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/schema/plugin.json b/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/schema/plugin.json index 416bf0047a..4483cf72b5 100644 --- a/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/schema/plugin.json +++ b/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/schema/plugin.json @@ -17,6 +17,9 @@ }, { "command": "jp-vdk:menu-delete" + }, + { + "command": "jp-vdk:menu-download" } ] } diff --git a/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/src/commandsAndMenu.tsx b/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/src/commandsAndMenu.tsx index 1275a94af7..c850ad3dfc 100644 --- a/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/src/commandsAndMenu.tsx +++ b/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/src/commandsAndMenu.tsx @@ -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", { @@ -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: , + buttons: [Dialog.okButton(), Dialog.cancelButton()], + }).then(result => { + if (!result.value) { + if(result.button.accept){ + downloadJobRequest(); + } + } + }).catch((e) => console.log(e)); + }, + }); } diff --git a/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/src/components/DownloadJob.tsx b/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/src/components/DownloadJob.tsx new file mode 100644 index 0000000000..eb8b577d8e --- /dev/null +++ b/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/src/components/DownloadJob.tsx @@ -0,0 +1,100 @@ +import React, { Component } from 'react'; + +export interface IDownloadJobDialogProps { + /** + * Current Path + */ + parentPath: string; +} + + +export default class DownloadJobDialog extends Component { + /** + * 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 ( + <> +
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + ); + } + /** + * 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) + }; +} diff --git a/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/src/serverRequests.ts b/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/src/serverRequests.ts index c970ebc295..b7d6a2edfd 100644 --- a/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/src/serverRequests.ts +++ b/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/src/serverRequests.ts @@ -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('download', { + body: JSON.stringify(dataToSend), + method: 'POST', + }) + .then(data => { + alert(data["message"]); + }) + .catch(reason => { + throw(reason) + }); +} diff --git a/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/vdk-jupyterlab-extension/handlers.py b/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/vdk-jupyterlab-extension/handlers.py index 6973a2d036..9622f708ff 100644 --- a/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/vdk-jupyterlab-extension/handlers.py +++ b/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/vdk-jupyterlab-extension/handlers.py @@ -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 = ".*$" @@ -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) diff --git a/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/vdk-jupyterlab-extension/vdk.py b/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/vdk-jupyterlab-extension/vdk.py index 2f09bc9cd7..fe8607bbcb 100644 --- a/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/vdk-jupyterlab-extension/vdk.py +++ b/projects/vdk-plugins/vdk-jupyter/vdk-jupyterlab-extension/vdk-jupyterlab-extension/vdk.py @@ -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: @@ -50,9 +51,20 @@ def delete_job(name: str, team: str, rest_api_url: str): :param rest_api_url: The base REST API URL. :return: message that the job is deleted """ - try: - cmd = JobDelete(rest_api_url) - cmd.delete_job(name, team) - return f"Deleted the job with name {name} from {team} team. " - except Exception as e: - raise e + cmd = JobDelete(rest_api_url) + cmd.delete_job(name, team) + return f"Deleted the job with name {name} from {team} team. " + + @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 + """ + cmd = JobDownloadSource(rest_api_url) + cmd.download(team, name, path) + return f"Downloaded the job with name {name} to {path}. "