From 69846c0b093ed748889640c418821f4ff435caa1 Mon Sep 17 00:00:00 2001 From: Christian Boettcher <c.boettcher@fz-juelich.de> Date: Thu, 10 Jun 2021 12:00:50 +0200 Subject: [PATCH] now able to list and show datasets, beginning of auth implementation --- frontend/js/apicalls.js | 117 +++++++++++------- frontend/js/auth.js | 15 +++ frontend/js/choose_storage.js | 4 +- .../templates/impressum_content.html.jinja | 10 +- frontend/templates/login_content.html.jinja | 45 ++++++- frontend/templates/storage_content.html.jinja | 41 ++++-- 6 files changed, 175 insertions(+), 57 deletions(-) diff --git a/frontend/js/apicalls.js b/frontend/js/apicalls.js index 86af4d2..bd9c42b 100644 --- a/frontend/js/apicalls.js +++ b/frontend/js/apicalls.js @@ -1,54 +1,45 @@ -// This file will contain the api calls, as well as transform the data into html-text (via a template) - -var apiUrl = "http://zam024.fritz.box/api/"; - -// get variable map from url -function getUrlVars() -{ - var vars = [], hash; - var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); - for(var i = 0; i < hashes.length; i++) - { - hash = hashes[i].split('='); - vars.push(hash[0]); - vars[hash[0]] = hash[1]; - } - return vars; -} +// This file contains the api calls, as well as transform the data into html-text -// return the storage type -function getType() { - var type = getUrlVars()["type"]; - console.log("Type: " + type); - return type; -} +var apiUrl = "http://zam024.fritz.box/api/"; // TODO switch out with real url, ideally during deployment +var allowedTypesList = []; // return the dataset id function getId() { - var id = getUrlVars()["id"]; + var id = getUrlVars()["oid"]; console.log("ID: " + id); return id; } -// set the text of the typetext element -function setTypeText() { - $('#typetext').text(getType()); -} - -// get option-html string from typename and url suffix +// get option-html string from typename suffix function getTypeHTMLString(name) { return '<li><a class="dropdown-item" href="?type=' + name + '">' + name + '</a></li>'; } +// get tableentry-html for a dataset +function getDatasetHTMLString(dataset) { + return '<tr><th scope="row">'+ dataset[0] + '</th><td><a href="?type=' + getType() + "&oid=" + dataset[1] + '">' + dataset[1] + '</a></td></tr>' +} + +/* +get html for table entry with a proeprty +The value field is editable, but the edit is blocked by default +authenticated users should be able to edit and submit +*/ +function getPropertyHTMLString(property, value) { + return '<tr><th scope="row">' + property + '</th><td><input class="form-control" type="text" value="' + value + '" readonly></td></tr>'; +} + // XMLHttpRequest EVENTLISTENER: if a dropdown-menu (a <ul> element) with the dropdownOptions id is present, update it with the available types function setTypeData() { console.log("GET " + this.responseUrl + ": " + this.responseText); var types = JSON.parse(this.responseText); + allowedTypesList = []; // types is now a list of {name : url} elements, where url starts with a slash, and is relative to the root var keyName = ""; types.forEach(element => { keyName = Object.keys(element)[0]; console.log("Detected location type: " + keyName); + allowedTypesList.push(keyName); $('#dropdownOptions').append(getTypeHTMLString(keyName)); }); } @@ -57,17 +48,42 @@ function setTypeData() { function setDatasetList() { console.log("GET " + this.responseUrl + ": " + this.responseText); var datasets = JSON.parse(this.responseText); - + datasets.forEach(element => { + console.log("Found Dataset: " + element) + $('#datasetTableBody').append(getDatasetHTMLString(element)); + }); } -// XMLHttpRequest EVENTLISTENER: show single datset -function setDatasetList() { +// XMLHttpRequest EVENTLISTENER: show dataset in table +function setDatasetView() { console.log("GET " + this.responseUrl + ": " + this.responseText); - var datasets = JSON.parse(this.responseText); - + var dataset = JSON.parse(this.responseText); + if (this.status >= 300) { + alert(getId() + " does not exists for this storage type!"); + window.location.href = "?type=" + getType(); + return; + } + // dataset has a name and url attribute, as well as a map as metadata attribute + // first, hide the list table and make the element viewer visible + $('#datasetListTable').hide(); + $('#storageTypeChooser').hide(); + $('#datasetViewTable').show(); + + // now append name and url to the view + $('#datasetViewTableBody').append(getPropertyHTMLString('Name', dataset.name)); + $('#datasetViewTableBody').append(getPropertyHTMLString('OID', getId())); + $('#datasetViewTableBody').append(getPropertyHTMLString('URL', dataset.url)); + + // insert a linebreak that announces other metadata + $('#datasetViewTableBody').append('<tr><th class="info" scope="row" colspan="2">Other Metadata</th></tr>'); + + // iterate over metadata map and add additional properties + for (const [key, val] of Object.entries(dataset.metadata)) { + $('#datasetViewTableBody').append(getPropertyHTMLString(key, val)); + } } -// get available types from api, put them in the relevant dropdown +// get available types from api, put them in the relevant dropdown (via listener) function getTypes() { var xmlhttp = new XMLHttpRequest(); xmlhttp.addEventListener("loadend", setTypeData); @@ -75,7 +91,7 @@ function getTypes() { xmlhttp.send(); } -// get listing of datasets of the given type, put them in the list element +// get listing of datasets of the given type, put them in the list element (via listener) function listDatasets(datatype) { var fullUrl = apiUrl + datatype; console.log("Full url for listing request is " + fullUrl) @@ -85,7 +101,7 @@ function listDatasets(datatype) { xmlhttp.send(); } -// get details about given dataset, put them in the view element§ +// get details about given dataset, put them in the view element (via listener) function showDataset(datatype, dataset_id) { var fullUrl = apiUrl + datatype + "/" + dataset_id; console.log("Full url for showing request is " + fullUrl) @@ -100,9 +116,22 @@ function showDataset(datatype, dataset_id) { //either enable the dataset listing or enable the single dataset view -function showListingOrSingleDataset() { - // compare getType with allowed types - // if none or illegal type: show first allowed one - // then check if dataset id is present, if yes, show that dataset - // if no id, or non-existent id, list all sets of type -} \ No newline at end of file +async function showListingOrSingleDataset() { + while (allowedTypesList.length == 0) { + await new Promise(resolve => setTimeout(resolve, 10)); + } + if (!getType() ||!allowedTypesList.includes(getType())) { + // no type or invalid type: reload page with first allowed type TODO add some alert? + window.location.href = "?type=" + allowedTypesList[0]; + } + if (!getId()) { // no id given, so list all elements + listDatasets(getType()); + } else { // an id is given, show the dataset, error message if invalid + showDataset(getType(), getId()); + } +} + + +// TODO function(s) to POST new Dataset (get bearer token from auth.js) +// TODO function(s) to PUT existing Dataset (get bearer token from auth.js) +// TODO function(s) to DELETE existing Dataset (get bearer token from auth.js) \ No newline at end of file diff --git a/frontend/js/auth.js b/frontend/js/auth.js index 48f89d3..80ba233 100644 --- a/frontend/js/auth.js +++ b/frontend/js/auth.js @@ -1 +1,16 @@ // This file will contain functions to manage authentication (including the token storage and access) + +// TODO function to rewrite Login as logout +// TODO function to add "ME" option to navbar (maybe add both and hide as needed) + +// TODO function(s) to post to receive and store bearer token + +/* +makes a post call for the token and stores it in localstorage +*/ +function login(isername, password) { + +} + +// TODO funciton to call /me +// TODO function to get bearer token (for external use) \ No newline at end of file diff --git a/frontend/js/choose_storage.js b/frontend/js/choose_storage.js index 8b71c9a..0778430 100644 --- a/frontend/js/choose_storage.js +++ b/frontend/js/choose_storage.js @@ -22,6 +22,4 @@ function getType() { // set the text of the typetext element function setTypeText() { $('#typetext').text(getType()) -} - -setTypeText() \ No newline at end of file +} \ No newline at end of file diff --git a/frontend/templates/impressum_content.html.jinja b/frontend/templates/impressum_content.html.jinja index a0a1793..6af8ed3 100644 --- a/frontend/templates/impressum_content.html.jinja +++ b/frontend/templates/impressum_content.html.jinja @@ -2,7 +2,15 @@ {% block title %}Impressum{% endblock %} {% block content %} -<p>INSERT IMPRESSUM HERE!!</p> +<div class="container"> + <div class="row"> + <div class="col-sm-8"> + <p>INSERT IMPRESSUM HERE!!</p> + + <hr class="hidden-sm hidden-md hidden-lg"> + </div> + </div> +</div> {% endblock %} {% block scripts %} diff --git a/frontend/templates/login_content.html.jinja b/frontend/templates/login_content.html.jinja index 1d044e9..466f063 100644 --- a/frontend/templates/login_content.html.jinja +++ b/frontend/templates/login_content.html.jinja @@ -1,9 +1,52 @@ {% extends "base.html.jinja"%} {% block title %}Login{% endblock %} +{% block extraheader %} +<link rel="stylesheet" href="css/loginform.css"> +{% endblock %} {% block content %} -<p>INSERT Login Stuff HERE!!</p> + +<div class="container"> + <div class="row"> + <div class="col-sm-8"> + <div id="loginForm"> + <!-- Tabs Titles --> + + <!-- Icon --> + <!-- + <div class="fadeIn first"> + <img src="http://danielzawadzki.com/codepen/01/icon.svg" id="icon" alt="User Icon" /> + </div> + --> + + <!-- Login Form --> + <form> + <input type="text" id="login" class="fadeIn second" name="login" placeholder="username" required='required'> + <input type="password" id="password" class="fadeIn third" name="login" placeholder="password" required='required'> + <button type="submit" class="fadeIn fourth" value="Log In">Log In</button> + </form> + + <!-- Remind Passowrd --> + <!-- + <div id="formFooter"> + <a class="underlineHover" href="#">Forgot Password?</a> + </div> + --> + </div> + + <hr class="hidden-sm hidden-md hidden-lg"> + </div> + </div> +</div> {% endblock %} {% block scripts %} +<script> +$("form").on('submit',function(e){ + e.preventDefault(); + //call actual submission here + // TODO + alert("Tried to Log in, but the function is not yet implemented!"); +}); +</script> {% endblock %} \ No newline at end of file diff --git a/frontend/templates/storage_content.html.jinja b/frontend/templates/storage_content.html.jinja index e5aebec..3914af2 100644 --- a/frontend/templates/storage_content.html.jinja +++ b/frontend/templates/storage_content.html.jinja @@ -5,18 +5,36 @@ <div class="container"> <div class="row"> <div class="col-sm-8"> - <div class="dropdown"> - <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuType" data-bs-toggle="dropdown" aria-expanded="false"> + <div class="dropdown" id="storageTypeChooser"> + <button class="btn btn-primary dropdown-toggle" type="button" id="dropdownType" data-toggle="dropdown" aria-expanded="false"> Select Storage Type </button> <label id="typetext">TYPENAME</label> - <ul class="dropdown-menu" aria-labelledby="dropdownMenuType"> - <li><a class="dropdown-item" href="?type=dataset">Dataset</a></li> - <li><a class="dropdown-item" href="?type=storagetarget">Storage Target</a></li> + <ul class="dropdown-menu" aria-labelledby="dropdownType" id="dropdownOptions"> </ul> </div> - <h2>Basic information about this service</h2> - <h5>Documentation of the data format</h5> - <div class="fakeimg">Maybe the Logo again</div> + + <table class="table table-hover" id="datasetListTable"> + <thead> + <tr> + <th scope="col">Name</th> + <th scope="col">OID</th> + </tr> + </thead> + <tbody id="datasetTableBody"> + </tbody> + </table> + + <table class="table table-hover" id="datasetViewTable"> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col">Value</th> + </tr> + </thead> + <tbody id="datasetViewTableBody"> + </tbody> + </table> + <hr class="hidden-sm hidden-md hidden-lg"> </div> </div> @@ -25,4 +43,11 @@ {% block scripts %} <script src="js/choose_storage.js"></script> + <script> + setTypeText(); + getTypes(); + $('#datasetViewTable').hide(); + $('#submitButton').hide(); + showListingOrSingleDataset(); + </script> {% endblock %} \ No newline at end of file -- GitLab