From d5091b8c6b0fd03d8e9ef82d2ce176eb8b967e85 Mon Sep 17 00:00:00 2001 From: Steffen Vogel <post@steffenvogel.de> Date: Wed, 7 Oct 2020 15:34:38 +0200 Subject: [PATCH] add link-creation wizard --- script.js | 105 +++++++++++++++++++++++++++++++++++++++++++-- src/usage/Links.md | 72 ++++++++++++++++++++----------- style.css | 23 ++++++++++ 3 files changed, 172 insertions(+), 28 deletions(-) diff --git a/script.js b/script.js index 6389939..1d12edd 100644 --- a/script.js +++ b/script.js @@ -1,13 +1,107 @@ -const apiBase = 'https://profiles.jupyter.rwth-aachen.de/api/v1'; +const serviceUrl = 'https://jupyter.rwth-aachen.de/services'; +const spawnBaseUrl = "https://jupyter.rwth-aachen.de/hub/spawn"; +const badgeURL = "https://jupyter.pages.rwth-aachen.de/documentation/images/badge-launch-rwth-jupyter.svg"; + +// taken from https://stackoverflow.com/questions/6234773/can-i-escape-html-special-chars-in-javascript +function escapeHtml(unsafe) { + return unsafe + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + +function getProfiles() { + window.fetch(serviceUrl + '/profile/all', { mode: 'no-cors' }) + .then((response) => response.json()) + .then((json) => { + this.console.log(json); + for (const i in json.jobs) { + let job = json.jobs[i]; + elm = this.document.getElementById('build-' + job.name); + + if (elm) { + elm.classList.add(job.status); + elm.innerText = job.status; + elm.insertAdjacentHTML('afterend', '<span class="build-log">(open <a href="' + job.web_url + '">build log</a> #' + job.id + ' from ' + new Date(job.created_at).toLocaleString() + ')</span>'); + } + } + }); + + return [ + { + slug: "pti", + display_name: "[PTI] Praktikum Technische Informatik" + }, + { + slug: "gdet3", + display_name: "[GDET3] Grundgebiete der Elektrotechnik 3" + } + ] +} + +function updateLink(event) { + var profileSlug = document.getElementById("link-wizard-profile"); + var filePath = document.getElementById("link-wizard-path"); + var outputDiv = document.getElementById("link-wizard-output"); + var directLink = document.getElementById("link-wizard-direct-link"); + var badgePre_md = document.getElementById("link-wizard-badge-md"); + var badgePreHtml = document.getElementById("link-wizard-badge-html"); + + // Strip leading slash + var path = filePath.value.replace(/^\//, ''); + var slug = profileSlug.value; + + if (profileSlug.length > 0) { + var link = updateDirectLink(slug, path); + + // Link + directLink.innerHTML = link; + + // Badges + var badge_md = '[](' + link +')'; + var badgeHtml = '<a href="' + link + '"><img src="' + badgeURL + '" /></a>'; + + badgePre_md.innerHTML = badge_md; + badgePreHtml.innerHTML = escapeHtml(badgeHtml); + + outputDiv.style.display = 'block'; + } +} + +function generateProfileDropdown(profilesSelect) { + // Fill profiles select + var profiles = getProfiles(); + + for(var i = 0; i < profiles.length; i++) { + var o = document.createElement("option"); + + o.value = profiles[i].slug; + o.textContent = profiles[i].display_name; + + profilesSelect.appendChild(o); + } +} + +function updateDirectLink(profileSlug, path) { + var url = spawnBaseUrl + '?profile=' + profileSlug; + + if (path && path.length > 0) + url = url + '&next=/user-redirect/lab/tree/' + encodeURIComponent(path); + + return url; +} function loadBuildStatus() { - window.fetch(apiBase + '/profiles') + window.fetch(serviceUrl + '/profile/all') .then((response) => response.json()) .then((json) => { this.console.log(json); for (const i in json.jobs) { let job = json.jobs[i]; elm = this.document.getElementById('build-' + job.name); + if (elm) { elm.classList.add(job.status); elm.innerText = job.status; @@ -54,7 +148,7 @@ function insertVersionCollapsibles() { coll.insertAdjacentElement('beforebegin', btn) btn.addEventListener('click', () => { - window.fetch(apiBase + '/versions/' + slug + '/' + repo) + window.fetch(apiBaseUrl + '/versions/' + slug + '/' + repo) .then((response) => response.json()) .then((pkgs) => { tbl = document.createElement('table'); @@ -114,4 +208,9 @@ window.addEventListener('load', function () { loadBuildStatus(); insertVersionCollapsibles(); } + + if (window.location.pathname.endsWith('/Links.html')) { + var profileSelect = document.getElementById("link-wizard-profile"); + generateProfileDropdown(profileSelect); + } }); diff --git a/src/usage/Links.md b/src/usage/Links.md index 2dabd68..04aa980 100644 --- a/src/usage/Links.md +++ b/src/usage/Links.md @@ -2,40 +2,67 @@ This page shows a few examples of permanent links for accessing certain profiles or Notebooks in the Jupyter cluster. -## Individual link (contains username) +## Link creation wizard + +You can use the following wizard to generate links and badges which open specific notebooks and profiles. + +<html> + <div class="link-wizard"> + <form> + <fieldset> + <label for="link-wizard-profile">Jupyter Profile</label><br> + <select onchange="updateLink(event)" id="link-wizard-profile"> + <option selected="selected" value="">Select profile</option> + </select> + </fieldset> + <fieldset> + <label for="link-wizard-path">Path to a notebook file (optional)</label><br> + <input oninput="updateLink(event)" onkeydown="event.stopPropagation()" type="text" id="link-wizard-path" placeholder="Index.ipynb"> + </fieldset> + </form> + <div id="link-wizard-output"> + <h3>Link</h3> + <pre id="link-wizard-direct-link"></pre> + <h3>Badge</h3> + <img src="https://jupyter.pages.rwth-aachen.de/documentation/images/badge-launch-rwth-jupyter.svg" alt="RWTHjupyter badge"> + <h5>Markdown Snippet</h5> + <pre id="link-wizard-badge-md"></pre> + <h5>HTML Snippet</h5> + <pre id="link-wizard-badge-html"></pre> + </div> + </div> +</html> + +## Spawn and open Notebook + +Opens a specific notebook using the default profile (Python) or your running Jupyter server. -Opens a specific notebook for a specific user using the default profile (Python). -This type link is personalized due to the included username and can therefore not be shared with other users. - -If there is no running server existing for the user, a new server is started. - -**Schema:** `https://jupyter.rwth-aachen.de/user/{{ user_name }}/lab/tree/{{ notebook_path }}` -**Example:** https://jupyter.rwth-aachen.de/user/vzi3jsam/lab/tree/gdet3/GDET3%20Faltung%20GUI.ipynb +**Schema:** `https://jupyter.rwth-aachen.de/user-redirect/lab/tree/{{ notebook_path }}` +**Example:** https://jupyter.rwth-aachen.de/user-redirect/lab/tree/gdet3/GDET3%20Faltung%20GUI.ipynb #### Arguments -- `user_name` your Jupyter username which is a pseudo-random 8 digit alpha numeric identfier displayed after login in the top right cormer. -- `notebook_path` and URL encoded path to the Notebook which should be opened. - -## Generic link (user-redirect) +- `notebook_path` and URL encoded path to the Notebook which should be opened. Please not that this path must be [URL encoded](https://www.w3schools.com/tags/ref_urlencode.ASP). -This is a generic version of the previous link which can be shared with other users. - -**Schema:** `https://jupyter.rwth-aachen.de/user-redirect/lab/tree/{{ notebook_path }}` -**Example:** https://jupyter.rwth-aachen.de/user-redirect/lab/tree/gdet3/GDET3%20Faltung%20GUI.ipynb - -## Spawn specific profile +## Spawn with a specific profile This link to spawn a specific profile. **Note:** If a server is already running with a different profile, no action will be taken. +**Schema:** `https://jupyter.rwth-aachen.de/hub/spawn?profile={{ profile_slug }}` +**Example:** https://jupyter.rwth-aachen.de/hub/spawn?profile=gdet3 + #### Arguments - `profile_slug` a short alpha numeric identifier for the profile. Please take a look at the [profile list](Profiles.md) for available profiles. -**Schema:** `https://jupyter.rwth-aachen.de/hub/spawn?profile={{ profile_slug }}` -**Example:** https://jupyter.rwth-aachen.de/hub/spawn?profile=gdet3 +## Spawn with a specific profile and open a notebook + +This version combines the first two types of links: + +**Schema:** `https://jupyter.rwth-aachen.de/hub/spawn?profile={{ profile_slug }}&next=/user-redirect/lab/tree/{{ notebook_path }}` +**Example:** https://jupyter.rwth-aachen.de/hub/spawn?profile=gdet3&next=/user-redirect/lab/tree/gdet3/GDET3%20Faltung%20GUI.ipynb ### Specify username and server name @@ -51,11 +78,6 @@ A normal user can start up to 10 named servers. E.g. for using several profiles - `server_name` is a alpha numeric identifier for the named server -## Spawn specific profile and open a notebook - -**Schema:** `https://jupyter.rwth-aachen.de/hub/spawn?profile={{ profile_slug }}&next=/user-redirect/lab/tree/{{ notebook_path }}` -**Example:** https://jupyter.rwth-aachen.de/hub/spawn?profile=gdet3&next=/user-redirect/lab/tree/gdet3/GDET3%20Faltung%20GUI.ipynb - ## Badge You can use the following Markdown or HTML snippets to embed a badge into your `README.md` files or Moodle activities for launching a Notebook: diff --git a/style.css b/style.css index 821f94b..c3dd432 100644 --- a/style.css +++ b/style.css @@ -72,3 +72,26 @@ span.manual { table.versions { margin: 5px; } + + +/* Link Wizard */ + +.link-wizard form { + border: 1px grey solid; +} + +.link-wizard h3 { + margin-top: 0.5em; +} + +.link-wizard fieldset { + border: 0; +} + +.link-wizard #link-wizard-path { + width: 100%; +} + +.link-wizard #link-wizard-output { + display: none; +} -- GitLab