Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ jupyter serverextension enable --py --system packagemanager

USER $NB_UID

EXPOSE 8888/tcp
EXPOSE 8888/tcp
25 changes: 22 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,45 @@
**[Link to Final Report](https://akashravi.github.io/SWAN-Package-Manager/)**


This Jupyter notebook extension will allow the users to specify python modules (and their respective versions) via a user interface and make them available automatically inside the corresponding project.
This Jupyter notebook extension will allow the users to install python modules (and their respective versions) via a user interface and make them available automatically inside the corresponding project.

Each project is internally mapped to a separate conda environment. This helps abstract the processing part, while providing an independent environment for each project.


## Features

- View packages installed for a specific project
- Update / Delete existing packages
- Search for new packages and install them
- Sync your project if any of your packages are missing or misconfigured

## Instructions

- This project assumes a [SWAN](https://gitlab.cern.ch/swan) setup. The APIs require certain actions as prerequisites, which are already fulfilled by SWAN.
## Setup Instructions

- This project assumes a SWAN setup. The APIs require certain actions as prerequisites, which are already fulfilled by SWAN.

- Please find the install instructions [here](extension/install.md)


## Usage Instructions

- From the Projects tab, you can create a folder by clicking on the **`+`** button. Internally, this will create a new conda environment for all the notebooks inside it.

- To configure the project, click the cog button. This would reveal a side panel listing down the installed packages, along with their corresponding versions.

- If in case the project metadata and the underlying environment are not in sync, the sidebar will also list the packages that need to be additionally installed. This is fundamental to share projects and collaborate with peers. By default, when a user clones a shared project, the required packages are not installed. This extension will let users install them.

- To install a new package, the user can search for them (an autocomplete feature is available). The selected packages are installed only when the user clicks the 'install' button. This allows the selection of other packages before issuing the 'install' command, which might take a while.

- Users can check for updates, for all or only the selected packages, by clicking the small cog button beside the list of installed packages. A pop-up modal will list the packages that need to be updated, along with their versions. Similarly, users can select one or more packages and uninstall them by clicking the bin icon.

- In order to create a notebook, click on the **`+`** button from inside a project or a regular folder. A list will then appear with the available kernels. Users will be able to launch notebooks only using the kernel corresponding to that project. Any external notebook (requiring a python kernel) placed under the project will also be using the same kernel.


## Documentation

- Please find the API Specification [here](docs/API_docs.md)
- The code is documented with necessary inline comments and docstrings


## Screenshot
Expand Down
2 changes: 1 addition & 1 deletion extension/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,4 @@ jupyter nbextension enable packagemanager --system --py
jupyter serverextension enable --py --system packagemanager
```

- For the purpose of API testing and development, please allow cross-site requests by adding c.NotebookApp.disable_check_xsrf = True (in ~/.jupyter/jupyter_notebook_config.py)
- For the purpose of API testing and development, please allow cross-site requests by adding `c.NotebookApp.disable_check_xsrf = True` (in ~/.jupyter/jupyter_notebook_config.py)
11 changes: 10 additions & 1 deletion extension/js/extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ function filter_kernel(project) {
if (env != name) {
$('#' + idList[i]).css("display", "none");
}
else {
var toRem = "[conda env:" + name + "]";
// Substring to remove from the entry
var kernelText = $('#' + idList[i]).find('a').text();
kernelText = kernelText.replace(toRem, '');
$('#' + idList[i]).find('a').text(kernelText);
var kernelTitle = $('#' + idList[i]).find('a').attr('title');
kernelTitle = kernelTitle.replace(toRem, '');
$('#' + idList[i]).find('a').attr('title', kernelTitle);
}
}
if (idList[i].startsWith('kernel-python')) {
// This hides the default python kernels that might appear
Expand All @@ -77,7 +87,6 @@ function filter_kernel(project) {
}
// This hides the conda root environment
$('#kernel-conda-root-py').css("display", "none");
//TODO: Change the display name for the visible kernel to make it user friendly.
});
}

Expand Down
110 changes: 62 additions & 48 deletions extension/js/methods.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,60 +24,65 @@ This function lists down all the updates and requires a user confirmation.
function update_packages(project) {
$('#updatebtn').unbind();
$('#updatebtn').click(function () {
var selectedPackages = common.get_selected_packages();
var html = $('<p> The following packages are about to be updated: </p> </br>');
$('#updatebtn').toggleClass('fa-wrench fa-spinner').addClass('fa-spin');
api.check_update(project, function (resp) {
$('#updatebtn').toggleClass('fa-wrench fa-spinner').removeClass('fa-spin');
var updates = resp.updates;
var packages = [];
if ($('#updatebtn').hasClass('fa-wrench')) {
var selectedPackages = common.get_selected_packages();
var html = $('<p> The following packages are about to be updated: </p> </br>');
$('#updatebtn').toggleClass('fa-wrench fa-spinner').addClass('fa-spin');
api.check_update(project, function (resp) {
$('#updatebtn').toggleClass('fa-wrench fa-spinner').removeClass('fa-spin');
var updates = resp.updates;
var packages = [];

if (selectedPackages.length > 0) {
html.append($('<ul/>'));
if (selectedPackages.length > 0) {
html.append($('<ul/>'));

for (var i = 0; i < selectedPackages.length; i++) {
var element = selectedPackages[i];
element = element.split('=');
var pkg = element[0];
var ver = element[1];
var nver = check_new_version(updates, pkg, ver);
if (nver != ver) {
packages.push(pkg);
html.append("<li>" + pkg + " &nbsp; " + ver + " -> " + nver + "</li>");
for (var i = 0; i < selectedPackages.length; i++) {
var element = selectedPackages[i];
element = element.split('=');
var pkg = element[0];
var ver = element[1];
var nver = check_new_version(updates, pkg, ver);
if (nver != ver) {
packages.push(pkg);
html.append("<li>" + pkg + " &nbsp; " + ver + " -> " + nver + "</li>");
}
}
}
}
else {
var list = $('.installed-values');
html.append($('<ul/>'));
for (var i = 0; i < list.length; i++) {
var element = list[i];
var pkg = $(element).find('.value-name')[0].innerText;
var ver = $(element).find('.value-version')[0].innerText;
var nver = check_new_version(updates, pkg, ver);
if (nver != ver) {
packages.push(pkg);
html.append("<li>" + pkg + " &nbsp; " + ver + " -> " + nver + "</li>");
else {
var list = $('.installed-values');
html.append($('<ul/>'));
for (var i = 0; i < list.length; i++) {
var element = list[i];
var pkg = $(element).find('.value-name')[0].innerText;
var ver = $(element).find('.value-version')[0].innerText;
var nver = check_new_version(updates, pkg, ver);
if (nver != ver) {
packages.push(pkg);
html.append("<li>" + pkg + " &nbsp; " + ver + " -> " + nver + "</li>");
}
}
}
}
if (packages.length === 0) {
html = $("<p> There are no updates available </p>");
common.display_msg("Update Packages", html);
}
else
common.confirm("Update Packages", html, "Confirm", function () {
api.update_packages(packages, project, function () {
scripts.package_view(project)
}, function () {
common.display_msg("Server Error", "The selected packages could not be updated. Please try again.");
if (packages.length === 0) {
html = $("<p> There are no updates available </p>");
common.display_msg("Update Packages", html);
}
else
common.confirm("Update Packages", html, "Confirm", function () {
$('#loadingtext').text("Updating Packages");
$('#loadingview').show();
api.update_packages(packages, project, function () {
$('#loadingview').hide();
scripts.package_view(project);
}, function () {
$('#loadingview').hide();
common.display_msg("Server Error", "The selected packages could not be updated. Please try again.");
});
});
},
function () {
common.display_msg("Server Error", "Error in checking for new updates. Please try again.");
});
},
function () {
common.display_msg("Server Error", "Error in checking for new updates. Please try again.");
});

}
});
}

Expand All @@ -100,9 +105,14 @@ function delete_packages(project) {
html.append("<li>" + element + "</li>");
}
common.confirm("Delete Packages", html, "Confirm", function () {
$('#loadingtext').text("Removing Packages");
$('#loadingview').show();
api.delete_packages(packages, project, function () {
scripts.package_view(project)
$('#loadingview').hide();
$('#deletebtn').css("display", "none");
scripts.package_view(project);
}, function () {
$('#loadingview').hide();
common.display_msg("Server Error", "The selected packages could not be removed. Please try again.");
});
});
Expand All @@ -126,9 +136,13 @@ function install_packages(project) {
html.append("<li>" + element + "</li>");
}
common.confirm("Install Packages", html, "Confirm", function () {
$('#loadingtext').text("Adding Packages");
$('#loadingview').show();
api.install_packages(toInstall, project, function () {
scripts.package_view(project)
$('#loadingview').hide();
scripts.package_view(project);
}, function () {
$('#loadingview').hide();
common.display_msg("Server Error", "The selected packages could not be installed. Please try again.");
});
});
Expand Down
1 change: 1 addition & 0 deletions extension/js/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ function package_view(dir) {
$('#loadingview').show();
$('#installed-packages').empty();
$('#to-install').empty();
$('#loadingtext').text("Loading Project Details");

api.get_info(dir, function (info) {
var data = info.packages;
Expand Down
2 changes: 1 addition & 1 deletion extension/js/templates/list_item.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="list_item">
<div class="row one">
<div class="col-sm-9 two">
<i class="list_icon fa"></i> &nbsp;
<i class="list_icon fa" aria-hidden="true" /> &nbsp;
<span class="value-name"></span>
</div>
<div class="col-sm-3 three">
Expand Down
10 changes: 9 additions & 1 deletion extension/js/templates/sidebar.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
}

#package-name {
width: 390px;
width: 380px;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you need to have this with fixed size?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having a 100% width seems to break the searchbar's dimensions. I'll check if there is any better alternative, compared to hardcoding the width.

}

#packageview {
Expand All @@ -35,6 +35,14 @@
font-size: larger;
}

#loadingview {
padding-left: 10px;
}

#loadingtext {
display: inline;
}

.installed-values, .to-install-values {
line-height: 30px;
cursor: pointer;
Expand Down
25 changes: 14 additions & 11 deletions extension/js/templates/sidebar.html
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
<div id="mySidenav" class="sidenav">
<div class="sidenavcontent">
<label for="package-name">Install Packages</label>
<div class="input-group mb-3">
<input type="text" class="form-control" id="package-name" list="searchlist" autocomplete="off"
placeholder="Search for available packages">
<span id="searchicon" class="fa fa-search form-control-feedback"></span>
<datalist id="searchlist">
</datalist>
</div>
<br>
<div id="loadingview">
<h2 id="loadingtext">Loading</h2>
&nbsp;&nbsp;
<i class="fa-spinner fa-spin fa" aria-hidden="true" />
<hr>
</div>
<div id="packageview">
<div class="main-content">
<label for="package-name">Install Packages</label>
<div class="input-group mb-3">
<input type="text" class="form-control" id="package-name" list="searchlist" autocomplete="off"
placeholder="Search for available packages">
<span id="searchicon" class="fa fa-search form-control-feedback"></span>
<datalist id="searchlist">
</datalist>
</div>
<br>
<div id="to-install-main">
<h2>Packages To Install</h2>
<br>
Expand All @@ -30,9 +33,9 @@ <h2>Packages To Install</h2>
<h2>Installed Packages</h2>
</div>
<div class="col-sm-2">
<i class="faicon fa fa-wrench" id="updatebtn"></i>
<i class="faicon fa fa-wrench" id="updatebtn" aria-hidden="true" />
&nbsp;
<i class="faicon fa fa-trash-o" id="deletebtn"></i>
<i class="faicon fa fa-trash-o" id="deletebtn" aria-hidden="true" />
</div>
</div>
<br>
Expand Down
7 changes: 5 additions & 2 deletions extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
"css-loader": "^3.2.0",
"html-loader": "^0.5.5",
"style-loader": "^1.0.0",
"webpack": "^4.39.2",
"webpack-cli": "^3.3.7"
"webpack": "^4.41.2",
"webpack-cli": "^3.3.9"
},
"scripts": {
"webpack": "webpack -p --config webpack.config.js",
"dev": "webpack --watch --config webpack.config.js"
},
"dependencies": {
"npm-check-updates": "^3.1.25"
}
}
Loading