aboutsummaryrefslogtreecommitdiffstats
path: root/src/templates/dashboard
diff options
context:
space:
mode:
Diffstat (limited to 'src/templates/dashboard')
-rw-r--r--src/templates/dashboard/genericselect.html104
-rw-r--r--src/templates/dashboard/grid.html10
-rw-r--r--src/templates/dashboard/host_profile_detail.html71
-rw-r--r--src/templates/dashboard/idf.yaml46
-rw-r--r--src/templates/dashboard/lab_detail.html154
-rw-r--r--src/templates/dashboard/lab_list.html28
-rw-r--r--src/templates/dashboard/landing.html172
-rw-r--r--src/templates/dashboard/login.html8
-rw-r--r--src/templates/dashboard/multiple_select_filter_widget.html149
-rw-r--r--src/templates/dashboard/pdf.yaml92
-rw-r--r--src/templates/dashboard/resource.html57
-rw-r--r--src/templates/dashboard/resource_all.html70
-rw-r--r--src/templates/dashboard/resource_detail.html151
-rw-r--r--src/templates/dashboard/searchable_select_multiple.html209
-rw-r--r--src/templates/dashboard/server_table.html30
-rw-r--r--src/templates/dashboard/table.html45
16 files changed, 1396 insertions, 0 deletions
diff --git a/src/templates/dashboard/genericselect.html b/src/templates/dashboard/genericselect.html
new file mode 100644
index 0000000..441d8dc
--- /dev/null
+++ b/src/templates/dashboard/genericselect.html
@@ -0,0 +1,104 @@
+{% extends "workflow/viewport-element.html" %}
+{% load staticfiles %}
+
+{% load bootstrap4 %}
+
+{% block content %}
+
+<style>
+ #page-wrapper {
+ display: flex;
+ flex-direction: column;
+ }
+
+ #{{select_type}}_form_div div {
+ }
+
+ #{{select_type}}_form_div > * {
+ margin-left: 10px;
+ margin-right: 10px;
+ margin-bottom: 20px;
+ }
+
+ #{{select_type}}_form_div div * {
+ }
+
+ #{{select_type}}_form_div {
+ flex: 1;
+ margin: 30px;
+ display: flex;
+ flex-direction: column;
+ }
+
+ #select_section {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ }
+
+ #{{select_type}}_select_form {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .autocomplete {
+ flex: 1;
+ }
+
+ #create_section {
+ }
+
+ #select_header_section {
+ }
+
+ h3 {
+ margin-top: 0;
+ margin-bottom: 0;
+ vertical-align: middle;
+ }
+
+ .divider {
+ border-top: 1px solid #ccc;
+ }
+
+
+</style>
+
+<div id="{{select_type}}_form_div">
+ <h3 id="create_section">Create a Resource
+ <button class="btn btn-primary {% if disabled %} disabled {% endif %}"
+ {% if not disabled %}onclick="parent.add_wf({{addable_type_num}})"
+ {% endif %}>Here
+ </button>
+ </h3>
+ <div class="divider"></div>
+ <h3 id="select_header_section">Or select from the list below:</h3>
+ <div id="select_section">
+ <form id="{{select_type}}_select_form" method="post" action="" class="form" id="{{select_type}}selectorform">
+ {% csrf_token %}
+ {{ form|default:"<p>no form loaded</p>" }}
+ {% buttons %}
+
+ {% endbuttons %}
+ </form>
+ </div>
+</div>
+
+<script>
+ {% if disabled %}
+ disable();
+ {% endif %}
+</script>
+
+{% endblock content %}
+{% block onleave %}
+var form = $("#{{select_type}}_select_form");
+var formData = form.serialize();
+var req = new XMLHttpRequest();
+req.open("POST", "/wf/workflow/", false);
+req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+req.onerror = function() { alert("problem with form submission"); }
+req.send(formData);
+{% endblock %}
+
diff --git a/src/templates/dashboard/grid.html b/src/templates/dashboard/grid.html
new file mode 100644
index 0000000..ca47f44
--- /dev/null
+++ b/src/templates/dashboard/grid.html
@@ -0,0 +1,10 @@
+{% extends "base.html" %}
+{% load staticfiles %}
+{% if script %} <script>{{ script }}</script> {% endif %}
+{% block content %}
+ {% for item in grid_items %}
+ <div class="grid-item" style="border:2px; border-style:solid; border-color:black; margin:3px">
+ {{ item }}
+ </div>
+ {% endfor %}
+{% endblock content %}
diff --git a/src/templates/dashboard/host_profile_detail.html b/src/templates/dashboard/host_profile_detail.html
new file mode 100644
index 0000000..abc7648
--- /dev/null
+++ b/src/templates/dashboard/host_profile_detail.html
@@ -0,0 +1,71 @@
+{% extends "base.html" %}
+{% load staticfiles %}
+
+{% block extrahead %}
+ {{block.super}}
+ <script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js?lang=yaml"></script>
+<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>
+
+{% endblock %}
+
+{% block content %}
+<script type="text/javascript">
+ $('.grid').masonry(
+ {
+ itemSelector: '.grid-item',
+ columnWidth: '.grid-sizer',
+ percentPosition: true
+ }
+ );
+</script>
+
+<style media="screen">
+
+ @media screen and (min-width: 0px) and (max-width: 767px)
+ {
+
+ .grid-item
+ {
+ width: 100%;
+ }
+}
+ @media screen and (min-width: 768px) and (max-width: 1200px) {
+ .grid-item {
+ width: 50%;
+ }
+
+ }
+
+ @media screen and (min-width: 1201px) and (max-width: 2000px) {
+ .grid-item {
+ width: 33%;
+ }
+ }
+ @media screen and (min-width: 2001px) {
+ .grid-item {
+ width: 25%;
+ }
+
+ }
+ .grid-item-content {
+ height: 100px;
+ background: #D26;
+ border: 2px solid hsla(0, 0%, 0%, 0.5);
+ border-radius: 5px;
+}
+
+.grid-item-content--height2 { height: 200px; }
+</style>
+
+<div class="container-fluid">
+ <!-- add extra container element for Masonry -->
+ <div class="grid">
+ {% for host in hosts %}
+ <div class="grid-item col-xs-4">
+ <p>stub for current PR</p>
+ </div>
+ {% endfor %}
+ </div>
+</div>
+
+{% endblock content %}
diff --git a/src/templates/dashboard/idf.yaml b/src/templates/dashboard/idf.yaml
new file mode 100644
index 0000000..9e0cc26
--- /dev/null
+++ b/src/templates/dashboard/idf.yaml
@@ -0,0 +1,46 @@
+---
+idf:
+ version: {{version|default:"0.1"}}
+ net_config:
+ oob:
+ ip-range: {{net_config.oob.ip_range}}
+ vlan: {{net_config.oob.vlan}}
+ admin:
+ interface: {{net_config.admin.interface}}
+ vlan: {{net_config.admin.vlan}}
+ network: {{net_config.admin.network}}
+ mask: {{net_config.admin.mask}}
+ mgmt:
+ interface: {{net_config.mgmt.interface}}
+ vlan: {{net_config.mgmt.vlan}}
+ network: {{net_config.mgmt.network}}
+ mask: {{net_config.mgmt.mask}}
+ private:
+ interface: {{net_config.private.interface}}
+ vlan: {{net_config.private.vlan}}
+ network: {{net_config.private.network}}
+ mask: {{net_config.private.mask}}
+ public:
+ interface: {{net_config.public.interface}}
+ vlan: {{net_config.public.vlan}}
+ network: {{net_config.public.network}}
+ mask: {{net_config.public.mask}}
+ ip-range: {{net_config.public.ip_range}}
+ mask: {{net_config.public.mask}}
+ gateway: {{net_config.public.gateway}}
+ dns: {% for serv in net_config.public.dns %}
+ - {{serv}}{% endfor %}
+ fuel:
+ jumphost:
+ bridges:
+ admin: {{fuel.jumphost.bridges.admin}}
+ mgmt: {{fuel.jumphost.bridges.mgmt}}
+ private: {{fuel.jumphost.bridges.private}}
+ public: {{fuel.jumphost.bridges.public}}
+ network: {% for node in fuel.network.nodes %}
+ node:
+ - interfaces: {% for iface in node.interfaces %}
+ - {{ iface }}{% endfor %}
+ - busaddr: {% for addr in node.bus_addrs %}
+ - {{addr}}{% endfor %}
+ {% endfor %}
diff --git a/src/templates/dashboard/lab_detail.html b/src/templates/dashboard/lab_detail.html
new file mode 100644
index 0000000..336b32e
--- /dev/null
+++ b/src/templates/dashboard/lab_detail.html
@@ -0,0 +1,154 @@
+{% extends "base.html" %}
+{% load staticfiles %}
+
+{% block extrahead %}
+ {{block.super}}
+ <script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js?lang=yaml"></script>
+{% endblock %}
+
+{% block content %}
+<div class="row">
+ <div class="col-lg-4">
+ <div class="card my-2">
+ <div class="card-header d-flex">
+ <h4>Lab Profile</h4>
+ <button class="btn btn-outline-secondary ml-auto" data-toggle="collapse" data-target="#panel_overview">Expand</button>
+ </div>
+ <div id="panel_overview" class="card-body collapse show">
+ <table class="table">
+ <tr>
+ <td>Lab Name: </td><td>{{lab.name}}</td>
+ </tr>
+ <tr>
+ <td>Lab Location: </td><td>{{lab.location}}</td>
+ </tr>
+ <tr>
+ <td>Lab Email: </td>
+ <td>{{lab.contact_email}}</td>
+ </tr>
+ {% if lab.contact_phone %}
+ <tr>
+ <td>Lab Phone: </td>
+ <td>{{lab.contact_phone}}</td>
+ </tr>
+ {% endif %}
+ <tr>
+ <td>Lab Status: </td>
+ {% if lab.status < 100 %}
+ <td><div style="border-radius: 50%; background:#40B976; height: 20px; width: 20px; display: inline-block;"></div>
+ Up</td>
+ {% elif lab.status < 200 %}
+ <td>
+ <div style="border-radius: 50%; background:#eeee00; height: 20px; width: 20px; display: inline-block;"></div>
+ Temporarily Offline</td>
+ {% else %}
+ <td>
+ <div style="border-radius: 50%; background:#e50000; height: 20px; width: 20px; display: inline-block;"></div>
+ Offline Indefinitely</td>
+ {% endif %}
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="card my-2">
+ <div class="card-header d-flex">
+ <h4 class="d-inline-block">Host Profiles</h4>
+ <button data-toggle="collapse" data-target="#profile_panel" class="btn btn-outline-secondary ml-auto" style="line-height: 1;" >Expand</button>
+ </div>
+ <div id="profile_panel" class="card-body collapse show">
+ <table class="table">
+ {% for profile in hostprofiles %}
+ <tr>
+ <td>{{profile.name}}</td>
+ <td>{{profile.description}}</td>
+ <td><a href="/resource/profiles/{{ profile.id }}" class="btn btn-info">Profile</a></td>
+ </tr>
+ {% endfor %}
+ </table>
+ </div>
+ </div>
+
+
+ <div class="card my-2">
+ <div class="card-header d-flex">
+ <h4 style="display: inline;">Networking Capabilities</h4>
+ <button data-toggle="collapse" data-target="#network_panel" class="btn btn-outline-secondary ml-auto" style="line-height: 1;" >Expand</button>
+ </div>
+
+ <div class="card-body collapse show" id="network_panel">
+ <table class="table">
+ <tr>
+ <td>Block Size: (number of VLANs allowed per deployment)</td><td>{{lab.vlan_manager.block_size}}</td>
+ </tr>
+ <tr>
+ <td>Overlapping Vlans Allowed (user can pick which VLANs they wish to use): </td>
+ <td>{{lab.vlan_manager.allow_overlapping}}</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="card my-2">
+ <div class="card-header d-flex">
+ <h4>Images</h4>
+ <button data-toggle="collapse" data-target="#image_panel" class="btn btn-outline-secondary ml-auto">Expand</button>
+ </div>
+ <div class="card-body collapse show" id="image_panel">
+ <table class="table">
+ <tr>
+ <th>Name</th>
+ <th>Owner</th>
+ <th>For Host Type</th>
+ <th>Description</th>
+ </tr>
+ {% for image in images %}
+ <tr>
+ <td>{{image.name}}</td>
+ <td>{{image.owner}}</td>
+ <td>{{image.host_type}}</td>
+ <td>{{image.description}}</td>
+ </tr>
+ {% endfor %}
+ </table>
+ </div>
+ </div>
+
+ </div>
+ <div class="col-lg-8">
+ <div class="card my-2">
+ <div class="card-header d-flex">
+ <h4>Lab Hosts</h4>
+ <button data-toggle="collapse" data-target="#lab_hosts_panel" class="btn btn-outline-secondary ml-auto">Expand</button>
+ </div>
+
+ <div class="card-body collapse show" id="lab_hosts_panel">
+ <table class="table">
+ <tr>
+ <th>Name</th>
+ <th>Profile</th>
+ <th>Booked</th>
+ <th>Working</th>
+ <th>Vendor</th>
+ </tr>
+ {% for host in lab.host_set.all %}
+ <tr>
+ <td>{{host.labid}}</td>
+ <td>{{host.profile}}</td>
+ <td>{{host.booked}}</td>
+ {% if host.working %}
+ <td style="background-color: #40B976;">{{host.working}}</td>
+ {% else %}
+ <td>{{host.working}}</td>
+ {% endif %}
+ <td>{{host.vendor}}</td>
+ </tr>
+ {% endfor %}
+ </table>
+ </div>
+ </div>
+ </div>
+
+</div>
+
+
+{% endblock content %}
+
diff --git a/src/templates/dashboard/lab_list.html b/src/templates/dashboard/lab_list.html
new file mode 100644
index 0000000..9cde80c
--- /dev/null
+++ b/src/templates/dashboard/lab_list.html
@@ -0,0 +1,28 @@
+{% extends "base.html" %}
+{% block content %}
+<h2>Labs</h2>
+<div class="card_container">
+ {% for lab in labs %}
+ <div class="card">
+ <div class="card-header">
+ <h3 class="mt-2">{{lab.name}}</h3>
+ </div>
+ <div class="p-4">
+ <ul class="list-group">
+ <li class="list-group-item">name: {{lab.name}}</li>
+ <li class="list-group-item">description: {{lab.description}}</li>
+ <li class="list-group-item">location: {{lab.location}}</li>
+ {% if lab.status == 0 %}
+ <li class="list-group-item">status: Up</li>
+ {% elif lab.status == 100 %}
+ <li class="list-group-item">status: Down for Maintenance</li>
+ {% elif lab.status == 200 %}
+ <li class="list-group-item">status: Down</li>
+ {% endif %}
+ </ul>
+ <a class="btn btn-primary mt-4 w-100" href="/lab/{{lab.name}}/">Details</a>
+ </div>
+ </div>
+ {% endfor %}
+</div>
+{% endblock %} \ No newline at end of file
diff --git a/src/templates/dashboard/landing.html b/src/templates/dashboard/landing.html
new file mode 100644
index 0000000..e6a235f
--- /dev/null
+++ b/src/templates/dashboard/landing.html
@@ -0,0 +1,172 @@
+{% extends "base.html" %}
+{% load staticfiles %}
+
+{% block content %}
+<div class="" style="text-align: center;">
+ {% if not request.user.is_anonymous %}
+ {% if not request.user.userprofile.ssh_public_key %}
+ <div class="alert alert-danger" role="alert">
+ Warning: you need to upload an ssh key under <a href="/accounts/settings">account settings</a> if you wish to
+ log into the servers you book
+ </div>
+ {% endif %}
+ {% else %}
+ {% endif %}
+</div>
+{% csrf_token %}
+
+<style>
+ .wf_create {
+ display: inline-block;
+ text-align: center;
+ }
+
+ .wf_create_div {
+ text-align: center;
+ }
+
+ .hidden_form {
+ display: none;
+ }
+
+ .panel {
+ border: none;
+ }
+
+ .panels {
+ display: grid;
+ grid-template-columns: 33% 34% 33%;
+ }
+
+ .landing_container {
+ display: grid;
+ grid-template-columns: 1fr 30px 1fr;
+ }
+
+ .grid_panel {
+ padding: 30px;
+ }
+
+ .btn-primary {
+ margin: 10px;
+ }
+
+ h2 {
+ border-bottom: 1px solid #cccccc;
+ }
+
+ h1 {}
+</style>
+<div class="container-fluid">
+ <div class="row">
+ <!-- About us -->
+ <div class="col-12 col-lg-6 mb-4">
+ <h2>About Us:</h2>
+ <p>The Lab as a Service (LaaS) project aims to help in the development and testing of LFN projects such as
+ OPNFV
+ by hosting hardware and providing access to the community. Currently, the only participating lab is the
+ University of New Hampshire Interoperability Lab (UNH-IOL).</p>
+ <p>To get started, you can request access to a server at the right. PTL's have the ability to design and
+ book a
+ whole block of servers with customized layer2 networks (e.g. a Pharos Pod). Read more here: <a
+ href="https://wiki.opnfv.org/display/INF/Lab+as+a+Service+2.0">LaaS Wiki</a></p>
+ </div>
+ <!-- Get started -->
+ <div class="col-12 col-lg-6 mb-4">
+ <h2>Get Started:</h2>
+ {% if request.user.is_anonymous %}
+ <h4 style="text-align:center;">To get started, please log in with your <a href="/accounts/login">Linux
+ Foundation Jira account</a></h4>
+ {% else %}
+ <p>To get started, book a server below:</p>
+ <a class="wf_create btn btn-primary"
+ style="display: flex; flex-direction: column; justify-content: center; margin: 20px; height: 100pt; vertical-align: middle; text-align: center; color: #FFF;"
+ href="/booking/quick/">
+ <p style="font-size: xx-large">Book a Server</p>
+ </a>
+ <p>PTLs can use our advanced options to book multi-node pods. If you are a PTL, you may use the options
+ below:
+ </p>
+ <div class='container'>
+ <div class="row">
+ <div class="col-12 col-xl-4">
+ <button class="wf_create btn btn-primary w-100" onclick="cwf(0)">Book a Pod</button>
+ </div>
+ <div class="col-12 col-xl-4">
+ <button class="wf_create btn btn-primary w-100" onclick="cwf(1)">Design a Pod</button>
+ </div>
+ <div class="col-12 col-xl-4">
+ <button class="wf_create btn btn-primary w-100" onclick="cwf(2)">Configure a Pod</button>
+ </div>
+ </div>
+ {% endif %}
+ </div>
+ </div>
+ <!-- Returning users -->
+ {% if not request.user.is_anonymous %}
+ <div class="col-12 col-lg-6 offset-lg-6 mb-4 mt-lg-4">
+ <h2 class="ht-4">Returning Users:</h2>
+ <p>If you're a returning user, some of the following options may be of interest:</p>
+ <div class="container">
+ <div class="row">
+ <div class="col-12 col-xl-4">
+ <button class="wf_create btn btn-primary w-100" onclick="cwf(3)">Snapshot a Host</button>
+ </div>
+ <div class="col-12 col-xl-4">
+ <a class="wf_create btn btn-primary w-100" href="{% url 'account:my-bookings' %}">My
+ Bookings</a>
+ </div>
+ {% if manager == True %}
+ <div class="col-12 col-xl-4">
+ <button class="wf_continue btn btn-primary w-100" onclick="continue_wf()">Resume
+ Workflow</button>
+ </div>
+ {% endif %}
+ </div>
+ </div>
+ </div>
+ {% endif %}
+ </div>
+</div>
+
+<script type="text/javascript">
+ function cwf(type) {
+ $.ajax({
+ type: "POST",
+ url: "/",
+ data: {
+ "create": type
+ },
+ beforeSend: function (request) {
+ request.setRequestHeader("X-CSRFToken",
+ $('input[name="csrfmiddlewaretoken"]').val()
+ );
+ }
+
+ }).done(function (data) {
+ window.location.replace("/wf/");
+ }).fail(function (jqxHR, textstatus) {
+ alert("Something went wrong...");
+ });
+ }
+
+ function continue_wf() {
+ window.location.replace("/wf/");
+ }
+</script>
+
+<div class="hidden_form" id="form_div">
+ <form method="post" action="" class="form" id="wf_selection_form">
+ {% csrf_token %}
+
+ <input type="hidden" id="landing_action">
+
+ <button type="submit" class="btn btn btn-success">
+ Confirm Edit
+ </button>
+ </form>
+</div>
+
+{% block vport_comm %}
+{% endblock %}
+{% endblock content %} \ No newline at end of file
diff --git a/src/templates/dashboard/login.html b/src/templates/dashboard/login.html
new file mode 100644
index 0000000..d3aa4ad
--- /dev/null
+++ b/src/templates/dashboard/login.html
@@ -0,0 +1,8 @@
+{% extends "base.html" %}
+
+{% block content %}
+<h3>You Must Login To Do That</h3>
+
+<a href="/accounts/login">Login Here</a>
+
+{% endblock %}
diff --git a/src/templates/dashboard/multiple_select_filter_widget.html b/src/templates/dashboard/multiple_select_filter_widget.html
new file mode 100644
index 0000000..4302543
--- /dev/null
+++ b/src/templates/dashboard/multiple_select_filter_widget.html
@@ -0,0 +1,149 @@
+<script src="/static/js/dashboard.js">
+</script>
+
+<style>
+.object_class_wrapper {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+ border: 0px;
+}
+
+.class_grid_wrapper {
+ border: 0px;
+ text-align: center;
+ border-right: 1px;
+ border-style: solid;
+ border-color: grey;
+}
+
+.class_grid_wrapper:last-child {
+ border-right: none;
+}
+
+.grid_wrapper {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+}
+
+.grid-item {
+ cursor: pointer;
+ border: 1px solid #cccccc;
+ border-radius: 5px;
+ margin: 20px;
+ height: 200px;
+ padding: 7px;
+ transition: border-color ease-in-out .1s,box-shadow ease-in-out .1s;
+ box-shadow: 0 1px 1px rgba(0,0,0,.075);
+
+ display: flex;
+ flex-direction: column;
+}
+
+.grid-item > .btn:active, .grid-item > .btn:focus {
+ outline: none; !important;
+ box-shadow: none;
+}
+
+.grid-item-description {
+ flex: 1;
+}
+
+.selected_node {
+ border-color: #40c640;
+ box-shadow: 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(109, 243, 76, 0.6);
+ transition: border-color ease-in-out .1s,box-shadow ease-in-out .1s;
+}
+
+.grid-item:hover:not(.selected_node):not(.disabled_node) {
+ box-shadow: 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(100, 100, 100, 0.3);
+ transition: border-color ease-in-out .1s,box-shadow ease-in-out .1s;
+}
+
+.disabled_node {
+ cursor: not-allowed;
+ background-color: #EFEFEF;
+}
+
+.disabled_node:hover {}
+
+.cleared_node {
+ background-color: #FFFFFF;
+}
+
+.grid-item-header {
+ font-weight: bold;
+ font-size: 20px;
+ margin-top: 10px;
+}
+
+.dropdown_item {
+ border: 1px;
+ border-style: solid;
+ border-color: lightgray;
+ border-radius: 5px;
+ margin: 20px;
+ padding: 2px;
+ grid-column: 1;
+ display: grid;
+ grid-template-columns: 1fr 3fr 1fr;
+ justify-items: center;
+}
+
+.dropdown_item > button {
+ margin: 2px;
+ justify-self: end;
+}
+
+.dropdown_item > h5 {
+ margin: auto;
+}
+
+.dropdown_item > input {
+ padding: 7px;
+ margin: 2px;
+ width: 90%;
+}
+
+#dropdown_wrapper {
+ display: grid;
+ grid-template-columns: 4fr 5fr;
+}
+</style>
+
+<input name="filter_field" id="filter_field" type="hidden"/>
+<div id="grid_wrapper" class="grid_wrapper">
+{% for object_class, object_list in display_objects %}
+ <div class="class_grid_wrapper">
+ <div style="display:inline-block;margin:auto">
+ <h4>{{object_class}}</h4>
+ </div>
+ <div id="{{object_class}}" class="object_class_wrapper">
+ {% for obj in object_list %}
+ <div id="{{ obj.id|default:'not_provided' }}" class="grid-item" onclick="multi_filter_widget.processClick(
+ '{{obj.id}}');">
+ <p class="grid-item-header">{{obj.name}}</p>
+ <p class="grid-item-description">{{obj.description}}</p>
+ <button type="button" class="btn btn-success grid-item-select-btn">
+ {% if obj.multiple %}Add{% else %}Select{% endif %}
+ </button>
+ </div>
+ {% endfor %}
+ </div>
+ </div>
+{% endfor %}
+</div>
+
+<div id="dropdown_wrapper">
+</div>
+<script>
+function multipleSelectFilterWidgetEntry() {
+ const graph_neighbors = {{ neighbors|safe }};
+ const filter_items = {{ filter_items|safe }};
+ const initial_value = {{ initial_value|default_if_none:"{}"|safe }};
+
+ //global variable
+ multi_filter_widget = new MultipleSelectFilterWidget(graph_neighbors, filter_items, initial_value);
+}
+
+multipleSelectFilterWidgetEntry();
+</script>
diff --git a/src/templates/dashboard/pdf.yaml b/src/templates/dashboard/pdf.yaml
new file mode 100644
index 0000000..c893919
--- /dev/null
+++ b/src/templates/dashboard/pdf.yaml
@@ -0,0 +1,92 @@
+---
+version: {{version|default:"1.0"}}
+details:
+ contact: {{details.contact}}
+ lab: {{details.lab}}
+ link: {{details.link}}
+ location: {{details.location}}
+ pod_owner: {{details.owner}}
+ type: {{details.type}}
+jumphost:
+ disks:
+ {% for disk in jumphost.disks %}
+ - disk_capacity: {{disk.capacity}}
+ disk_interface: {{disk.interface}}
+ disk_rotation: {{disk.rotation}}
+ disk_type: {{disk.type}}
+ name: {{disk.name}}
+ {% endfor %}
+ interfaces:
+ {% for interface in jumphost.interfaces %}
+ - features: {{interface.features}}
+ mac_address: {{interface.mac_address}}
+ name: {{interface.name}}
+ speed: {{interface.speed}}
+ {% endfor %}
+ name: {{jumphost.name}}
+ node:
+ arch: {{jumphost.node.arch}}
+ cores: {{jumphost.node.cores}}
+ cpu_cflags: {{jumphost.node.cpu_cflags}}
+ cpus: {{jumphost.node.cpus}}
+ memory: {{jumphost.node.memory}}
+ model: {{jumphost.node.model}}
+ type: {{jumphost.node.type}}
+ vendor: {{jumphost.node.vendor}}
+ os: {{jumphost.os}}
+ remote_management:
+ address: {{jumphost.remote.address}}
+ mac_address: {{jumphost.remote.mac_address}}
+ pass: {{jumphost.remote.pass}}
+ type: {{jumphost.remote.type}}
+ user: {{jumphost.remote.user}}
+ versions:
+ {% for version in jumphost.remote.versions %}
+ - {{version}}
+ {% endfor %}
+ remote_params:
+ pass: {{jumphost.remote.pass}}
+ type: {{jumphost.remote.type}}
+ user: {{jumphost.remote.user}}
+ versions:
+ {% for version in jumphost.remote.versions %}
+ - {{version}}
+ {% endfor %}
+nodes:
+{% for node in nodes %}
+- disks:
+ {% for disk in node.disks %}
+ - disk_capacity: {{disk.capacity}}
+ disk_interface: {{disk.interface}}
+ disk_rotation: {{disk.rotation}}
+ disk_type: {{disk.type}}
+ name: {{disk.name}}
+ {% endfor %}
+ interfaces:
+ {% for interface in node.interfaces %}
+ - features: {{interface.features}}
+ mac_address: {{interface.mac_address}}
+ name: {{interface.name}}
+ speed: {{interface.speed}}
+ {% endfor %}
+ name: {{node.name}}
+ node:
+ arch: {{node.node.arch}}
+ cores: {{node.node.cores}}
+ cpu_cflags: {{node.node.cpu_cflags}}
+ cpus: {{node.node.cpus}}
+ memory: {{node.node.memory}}
+ model: {{node.node.model}}
+ type: {{node.node.type}}
+ vendor: {{node.node.vendor}}
+ remote_management:
+ address: {{node.remote.address}}
+ mac_address: {{node.remote.mac_address}}
+ pass: {{node.remote.pass}}
+ type: {{node.remote.type}}
+ user: {{node.remote.user}}
+ versions:
+ {% for version in node.remote.versions %}
+ - {{version}}
+ {% endfor %}
+{% endfor %}
diff --git a/src/templates/dashboard/resource.html b/src/templates/dashboard/resource.html
new file mode 100644
index 0000000..f36ee7b
--- /dev/null
+++ b/src/templates/dashboard/resource.html
@@ -0,0 +1,57 @@
+{% extends "base.html" %}
+{% load staticfiles %}
+
+{% block extrahead %}
+ {{ block.super }}
+ <!-- Morris Charts CSS -->
+ <link href="{% static "bower_components/morrisjs/morris.css" %}" rel="stylesheet">
+
+ <!-- DataTables CSS -->
+ <link href="{% static "bower_components/datatables.net-bs4/css/dataTables.bootstrap4.min.css" %}"
+ rel="stylesheet">
+
+ <!-- DataTables Responsive CSS -->
+ <link href="{% static "bower_components/datatables.net-responsive-bs4/css/responsive.bootstrap4.min.css" %}"
+ rel="stylesheet">
+{% endblock extrahead %}
+
+
+{% block content %}
+ {% include "dashboard/resource_detail.html" %}
+{% endblock content %}
+
+
+{% block extrajs %}
+ <!-- DataTables JavaScript -->
+ <link href="{% static "bower_components/datatables/media/css/dataTables.bootstrap.css" %}"
+ rel="stylesheet">
+
+ <script src={% static "bower_components/datatables.net/js/jquery.dataTables.min.js" %}></script>
+ <script src={% static "bower_components/datatables.net-bs4/js/dataTables.bootstrap4.min.js" %}></script>
+
+
+
+ <!-- Flot Charts JavaScript -->
+ <script src="{% static "bower_components/flot/excanvas.min.js" %}"></script>
+ <script src="{% static "bower_components/flot/jquery.flot.js" %}"></script>
+ <script src="{% static "bower_components/flot/jquery.flot.pie.js" %}"></script>
+ <script src="{% static "bower_components/flot/jquery.flot.resize.js" %}"></script>
+ <script src="{% static "bower_components/flot/jquery.flot.time.js" %}"></script>
+ <script src="{% static "bower_components/flot.tooltip/js/jquery.flot.tooltip.min.js" %}"></script>
+
+ <script src="{% static "js/flot-pie-chart.js" %}"></script>
+
+ <script type="text/javascript">
+ $(document).ready(function () {
+ $('#{{ resource.id }}_server_table').DataTable({});
+ $('#{{ resource.id }}_bookings_table').DataTable({});
+ $('#{{ resource.id }}_vpn_user_table').DataTable({});
+
+ var chart_id = "{{ resource.id }}_booking_utilization";
+ var utilization_url = "{% url 'dashboard:booking_utilization' resource_id=resource.id weeks=4 %}";
+ loadChartData(chart_id, utilization_url);
+
+ loadChartData(chart_id, utilization_url);
+ });
+ </script>
+{% endblock extrajs %} \ No newline at end of file
diff --git a/src/templates/dashboard/resource_all.html b/src/templates/dashboard/resource_all.html
new file mode 100644
index 0000000..fb8cc7e
--- /dev/null
+++ b/src/templates/dashboard/resource_all.html
@@ -0,0 +1,70 @@
+{% extends "base.html" %}
+{% load staticfiles %}
+
+{% block extrahead %}
+ {{ block.super }}
+ <!-- Morris Charts CSS -->
+ <link href="{% static "bower_components/morrisjs/morris.css" %}" rel="stylesheet">
+
+ <!-- DataTables CSS -->
+ <link href="{% static "bower_components/datatables.net-bs4/css/dataTables.bootstrap4.min.css" %}"
+ rel="stylesheet">
+
+ <!-- DataTables Responsive CSS -->
+ <link href="{% static "bower_components/datatables.net-responsive-bs4/css/responsive.bootstrap4.min.css" %}"
+ rel="stylesheet">
+{% endblock extrahead %}
+
+
+{% block content %}
+ {% for resource, utilization, bookings in pods %}
+ <div class="row">
+ <div class="col-lg-12">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ {{ resource.name }}
+ </div>
+ <div class="panel-body">
+ {% include "dashboard/resource_detail.html" %}
+ </div>
+ </div>
+ </div>
+ </div>
+ {% endfor %}
+{% endblock content %}
+
+
+{% block extrajs %}
+ <!-- DataTables JavaScript -->
+ <link href="{% static "bower_components/datatables/media/css/dataTables.bootstrap.css" %}"
+ rel="stylesheet">
+
+ <script src={% static "bower_components/datatables.net/js/jquery.dataTables.min.js" %}></script>
+ <script src={% static "bower_components/datatables.net-bs4/js/dataTables.bootstrap4.min.js" %}></script>
+
+
+
+ <!-- Flot Charts JavaScript -->
+ <script src="{% static "bower_components/flot/excanvas.min.js" %}"></script>
+ <script src="{% static "bower_components/flot/jquery.flot.js" %}"></script>
+ <script src="{% static "bower_components/flot/jquery.flot.pie.js" %}"></script>
+ <script src="{% static "bower_components/flot/jquery.flot.resize.js" %}"></script>
+ <script src="{% static "bower_components/flot/jquery.flot.time.js" %}"></script>
+ <script src="{% static "bower_components/flot.tooltip/js/jquery.flot.tooltip.min.js" %}"></script>
+ <script src="{% static "js/flot-pie-chart.js" %}"></script><
+
+ <script type="text/javascript">
+ $(document).ready(function () {
+ {% for resource, utilization, bookings in pods %}
+
+ $('#{{ resource.id }}_server_table').DataTable({});
+ $('#{{ resource.id }}_bookings_table').DataTable({});
+ $('#{{ resource.id }}_vpn_user_table').DataTable({});
+
+ var chart_id = "{{ resource.id }}_booking_utilization";
+ var utilization_url = "{% url 'dashboard:booking_utilization' resource_id=resource.id weeks=4 %}";
+ loadChartData(chart_id, utilization_url);
+ {% endfor %}
+ });
+ </script>
+{% endblock extrajs %} \ No newline at end of file
diff --git a/src/templates/dashboard/resource_detail.html b/src/templates/dashboard/resource_detail.html
new file mode 100644
index 0000000..0a443d9
--- /dev/null
+++ b/src/templates/dashboard/resource_detail.html
@@ -0,0 +1,151 @@
+<div class="row">
+ <div class="col-lg-9">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ Status
+ </div>
+ <div class="panel-body">
+ <div class="list-group pre-scrollable">
+ {% for status in resource.resourcestatus_set.all %}
+ <a href="#" class="list-group-item">
+ <i class="fa fa-info fa-fw"></i> {{ status.title }}
+ <span class="pull-right text-muted small">
+ <em>{{ status.timestamp }}</em>
+ </span>
+ </a>
+ {% endfor %}
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col-lg-9">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ Servers
+ </div>
+ <div class="panel-body">
+ <div class="dataTables_wrapper">
+ <table class="table table-striped table-bordered table-hover"
+ id="{{ resource.id }}_server_table" cellspacing="0"
+ width="100%">
+ {% include "dashboard/server_table.html" %}
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+<div class="row">
+ <div class="col-lg-3">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ Booking Utilization
+ <div class="pull-right">
+ <div class="form-group">
+ <select onchange="loadChartData('{{ resource.id }}_booking_utilization', this.value);">
+ <option value="{% url 'dashboard:booking_utilization' resource_id=resource.id weeks=-4 %}">
+ Last Month
+ </option>
+ <option value="{% url 'dashboard:booking_utilization' resource_id=resource.id weeks=-1 %}">
+ Last Week
+ </option>
+ <option value="{% url 'dashboard:booking_utilization' resource_id=resource.id weeks=1 %}">
+ Next Week
+ </option>
+ <option selected="selected"
+ value="{% url 'dashboard:booking_utilization' resource_id=resource.id weeks=4 %}">
+ Next Month
+ </option>
+ </select>
+ </div>
+ </div>
+ </div>
+ <div class="panel-body">
+ <div class="flot-chart">
+ <div class="flot-chart-content"
+ id="{{ resource.id }}_booking_utilization"></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col-lg-9">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ Bookings
+ </div>
+ <div class="panel-body">
+ <div class="dataTables_wrapper">
+ <table class="table table-striped table-bordered table-hover"
+ id="{{ resource.id }}_bookings_table" cellspacing="0"
+ width="100%">
+ {% include "booking/booking_table.html" %}
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+<div class="row">
+ <div class="col-lg-3">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ Contact
+ </div>
+ <div class="panel-body">
+ <p>
+ <b>Lab Owner: </b>
+ {{ resource.owner.username }}
+ </p>
+ <p>
+ <b>Email: </b>
+ {{ resource.owner.email }}
+ </p>
+ <p>
+ <a href="{% url 'booking:create' resource_id=resource.id %}" class="btn btn-primary">
+ Booking
+ </a>
+ <a href="{{ resource.url }}" class="btn btn-primary">
+ OPNFV Wiki
+ </a>
+ </p>
+ </div>
+ </div>
+ </div>
+ <div class="col-lg-6">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ VPN Users
+ </div>
+ <div class="panel-body">
+ <div class="dataTables_wrapper">
+ <table class="table table-striped table-bordered table-hover"
+ id="{{ resource.id }}_vpn_user_table" cellspacing="0"
+ width="100%">
+ <thead>
+ <tr>
+ <th>User</th>
+ <th>Email</th>
+ <th>Company</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for user in resource.vpn_users.all %}
+ <tr>
+ <td>
+ {{ user.username }}
+ </td>
+ <td>
+ {{ user.email }}
+ </td>
+ <td>
+ {{ user.userprofile.company }}
+ </td>
+ </tr>
+ {% endfor %}
+ </table>
+ </tbody>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/src/templates/dashboard/searchable_select_multiple.html b/src/templates/dashboard/searchable_select_multiple.html
new file mode 100644
index 0000000..8bcf890
--- /dev/null
+++ b/src/templates/dashboard/searchable_select_multiple.html
@@ -0,0 +1,209 @@
+<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
+<script src="/static/js/dashboard.js"></script>
+
+<div id="search_select_outer" class="autocomplete">
+ <div id="warning_pane" style="background: #FFFFFF; color: #CC0000;">
+ {% if incompatible == "true" %}
+ <h3>Warning: Incompatible Configuration</h3>
+ <p>Please make a different selection, as the current config conflicts with the selected pod</p>
+ {% endif %}
+ </div>
+ <div id="added_counter">
+ <p id="added_number">0</p>
+ <p id="addable_limit">/ {% if selectable_limit > -1 %} {{ selectable_limit }} {% else %} &infin; {% endif %}added</p>
+ </div>
+
+ <div id="added_list">
+
+ </div>
+
+ <input id="user_field" name="ignore_this" class="form-control" autocomplete="off" type="text" placeholder="{{placeholder}}" value="" oninput="searchable_select_multiple_widget.search(this.value)"
+ {% if disabled %} disabled {% endif %}
+ >
+ </input>
+
+ <input type="hidden" id="selector" name="{{ name }}" class="form-control" style="display: none;"
+ {% if disabled %} disabled {% endif %}
+ >
+ </input>
+
+ <div id="scroll_restrictor">
+ <ul id="drop_results"></ul>
+ </div>
+ <style>
+ #scroll_restrictor {
+ flex: 1;
+ position: relative;
+ overflow-y: auto;
+ padding-bottom: 10px;
+ }
+
+ #added_list {
+ margin-bottom: 5px;
+ }
+
+ .autocomplete {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ }
+ #user_field {
+ font-size: 14pt;
+ padding: 5px;
+ height: 40px;
+ border: 1px solid #ccc;
+ border-radius: 5px;
+
+ }
+
+ #drop_results{
+ list-style-type: none;
+ padding: 0;
+ margin: 0;
+ min-height: 0;
+ border: solid 1px #ddd;
+ border-top: none;
+ border-bottom: none;
+ visibility: inherit;
+ flex: 1;
+
+ position: absolute;
+ width: 100%;
+
+ }
+
+ #drop_results li a{
+ font-size: 14pt;
+ background-color: #f6f6f6;
+ padding: 7px;
+ text-decoration: none;
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ #drop_results li a {
+ border-bottom: 1px solid #ddd;
+ }
+
+ .list_entry {
+ border: 1px solid #ccc;
+ border-radius: 5px;
+ margin-top: 5px;
+ vertical-align: middle;
+ line-height: 40px;
+ height: 40px;
+ padding-left: 12px;
+ width: 100%;
+ display: flex;
+ }
+
+ #drop_results li a:hover{
+ background-color: #ffffff;
+ }
+
+ .added_entry_text {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: inline;
+ width: 100%;
+ }
+
+ .btn-remove {
+ float: right;
+ height: 30px;
+ margin: 4px;
+ padding: 1px;
+ max-width: 20%;
+ width: 15%;
+ min-width: 70px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ .entry_tooltip {
+ display: none;
+ }
+
+ #drop_results li a:hover .entry_tooltip {
+ position: absolute;
+ background: #444;
+ color: #ddd;
+ text-align: center;
+ font-size: 12pt;
+ border-radius: 3px;
+
+ }
+
+ #drop_results {
+ max-width: 100%;
+ display: inline-block;
+ list-style-type: none;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+
+ #drop_results li {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ #added_counter {
+ text-align: center;
+ }
+
+ #added_number, #addable_limit {
+ display: inline;
+ }
+ </style>
+</div>
+
+<script type="text/javascript">
+ function searchableSelectMultipleWidgetEntry() {
+ let format_vars = {
+ "show_from_noentry": {{show_from_noentry|yesno:"true,false"}},
+ "show_x_results": {{show_x_results|default:-1}},
+ "results_scrollable": {{results_scrollable|yesno:"true,false"}},
+ "selectable_limit": {{selectable_limit|default:-1}},
+ "placeholder": "{{placeholder|default:"begin typing"}}"
+ };
+
+ let field_dataset = {{items|safe}};
+
+ let field_initial = {{ initial|safe }};
+
+ //global
+ searchable_select_multiple_widget = new SearchableSelectMultipleWidget(format_vars, field_dataset, field_initial);
+ }
+
+ searchableSelectMultipleWidgetEntry();
+
+ /*
+ var show_from_noentry = context(show_from_noentry|yesno:"true,false") // whether to show any results before user starts typing
+ var show_x_results = context(show_x_results|default:-1) // how many results to show at a time, -1 shows all results
+ var results_scrollable = {{results_scrollable|yesno:"true,false") // whether list should be scrollable
+ var selectable_limit = {{selectable_limit|default:-1) // how many selections can be made, -1 allows infinitely many
+ var placeholder = "context(placeholder|default:"begin typing")" // placeholder that goes in text box
+
+ needed info
+ var items = context(items|safe) // items to add to trie. Type is a dictionary of dictionaries with structure:
+ {
+ id# : {
+ "id": any, identifiable on backend
+ "small_name": string, displayed first (before separator), searchable (use for e.g. username)
+ "expanded_name": string, displayed second (after separator), searchable (use for e.g. email address)
+ "string": string, not displayed, still searchable
+ }
+ }
+
+ used later:
+ context(selectable_limit): changes what number displays for field
+ context(name): form identifiable name, relevant for backend
+ // when submitted, form will contain field data in post with name as the key
+ context(placeholder): "greyed out" contents put into search field initially to guide user as to what they're searching for
+ context(initial): in search_field_init(), marked safe, an array of id's each referring to an id from items
+ */
+</script>
diff --git a/src/templates/dashboard/server_table.html b/src/templates/dashboard/server_table.html
new file mode 100644
index 0000000..f01bd60
--- /dev/null
+++ b/src/templates/dashboard/server_table.html
@@ -0,0 +1,30 @@
+<thead>
+<tr>
+ <th>Server</th>
+ <th>Model</th>
+ <th>CPU</th>
+ <th>RAM</th>
+ <th>Storage</th>
+</tr>
+</thead>
+<tbody>
+{% for server in resource.server_set.all %}
+ <tr>
+ <td>
+ {{ server.name }}
+ </td>
+ <td>
+ {{ server.model }}
+ </td>
+ <td>
+ {{ server.cpu }}
+ </td>
+ <td>
+ {{ server.ram }}
+ </td>
+ <td>
+ {{ server.storage }}
+ </td>
+ </tr>
+{% endfor %}
+</tbody> \ No newline at end of file
diff --git a/src/templates/dashboard/table.html b/src/templates/dashboard/table.html
new file mode 100644
index 0000000..0a37ded
--- /dev/null
+++ b/src/templates/dashboard/table.html
@@ -0,0 +1,45 @@
+{% extends "base.html" %}
+{% load staticfiles %}
+
+{% block extrahead %}
+ {{ block.super }}
+ <!-- DataTables CSS -->
+ <link href="{% static "bower_components/datatables.net-bs4/css/dataTables.bootstrap4.min.css" %}"
+ rel="stylesheet">
+
+ <!-- DataTables Responsive CSS -->
+ <link href="{% static "bower_components/datatables.net-responsive-bs4/css/responsive.bootstrap4.min.css" %}"
+ rel="stylesheet">
+{% endblock extrahead %}
+
+{% block content %}
+ <div class="row">
+ <div class="col-lg-12">
+ <div class="dataTables_wrapper">
+ <table class="table table-striped table-bordered table-hover" id="table" cellspacing="0"
+ width="100%">
+
+ {% block table %}
+ {% endblock table %}
+
+ </table>
+ </div>
+ <!-- /.table-responsive -->
+ <!-- /.panel-body -->
+ <!-- /.panel -->
+ </div>
+ <!-- /.col-lg-12 -->
+ </div>
+{% endblock content %}
+
+{% block extrajs %}
+ <!-- DataTables JavaScript -->
+
+ <script src={% static "bower_components/datatables.net/js/jquery.dataTables.min.js" %}></script>
+ <script src={% static "bower_components/datatables.net-bs4/js/dataTables.bootstrap4.min.js" %}></script>
+
+ <script src={% static "js/dataTables-sort.js" %}></script>
+
+ {% block tablejs %}
+ {% endblock tablejs %}
+{% endblock extrajs %}