aboutsummaryrefslogtreecommitdiffstats
path: root/src/templates/base/dashboard
diff options
context:
space:
mode:
authorParker Berberian <pberberian@iol.unh.edu>2020-01-30 13:33:35 -0500
committerParker Berberian <pberberian@iol.unh.edu>2020-01-30 16:12:18 -0500
commit078273eb7db5a481a4131d44a943f3c9e34b6b88 (patch)
tree9e6e569e18712d77b8a65c6ebf4dda50ade1b55a /src/templates/base/dashboard
parent899e1a4baa95d0bc6f0eef34de66f0e257174878 (diff)
Adds Template Overrides
Changes the structure of the template directories to allow a new project to define their own set of override templates that inherit from a common base. I have slightly modified landing.html here as an example. In comming changes we will try to move all the "laas" specific content into the laas directory Change-Id: I46151be182de901f870debb247b305ea34ae77ba Signed-off-by: Parker Berberian <pberberian@iol.unh.edu>
Diffstat (limited to 'src/templates/base/dashboard')
-rw-r--r--src/templates/base/dashboard/genericselect.html30
-rw-r--r--src/templates/base/dashboard/host_profile_detail.html70
-rw-r--r--src/templates/base/dashboard/idf.yaml46
-rw-r--r--src/templates/base/dashboard/lab_detail.html165
-rw-r--r--src/templates/base/dashboard/lab_list.html29
-rw-r--r--src/templates/base/dashboard/landing.html77
-rw-r--r--src/templates/base/dashboard/login.html8
-rw-r--r--src/templates/base/dashboard/multiple_select_filter_widget.html54
-rw-r--r--src/templates/base/dashboard/pdf.yaml92
-rw-r--r--src/templates/base/dashboard/resource.html57
-rw-r--r--src/templates/base/dashboard/resource_all.html70
-rw-r--r--src/templates/base/dashboard/resource_detail.html151
-rw-r--r--src/templates/base/dashboard/searchable_select_multiple.html73
-rw-r--r--src/templates/base/dashboard/server_table.html30
-rw-r--r--src/templates/base/dashboard/table.html39
15 files changed, 991 insertions, 0 deletions
diff --git a/src/templates/base/dashboard/genericselect.html b/src/templates/base/dashboard/genericselect.html
new file mode 100644
index 0000000..863d33f
--- /dev/null
+++ b/src/templates/base/dashboard/genericselect.html
@@ -0,0 +1,30 @@
+{% extends "workflow/viewport-element.html" %}
+
+{% load bootstrap4 %}
+
+{% block content %}
+
+<div id="select_form_div" class="h-100 border d-flex flex-column p-4">
+ <h3 id="create_section">Create a Resource
+ <button class="btn btn-primary {% if disabled %} disabled {% endif %}"
+ {% if not disabled %}onclick="add_workflow({{addable_type_num}})"
+ {% endif %}>Here
+ </button>
+ </h3>
+ <div class="border-top"></div>
+ <h3 id="select_header_section">Or select from the list below:</h3>
+ <div id="select_section" class="d-flex flex-column">
+ <form id="step_form" method="post" action="" class="form d-flex flex-column">
+ {% csrf_token %}
+ {{ form|default:"<p>no form loaded</p>" }}
+ </form>
+ </div>
+</div>
+
+<script>
+ {% if disabled %}
+ disable();
+ {% endif %}
+</script>
+
+{% endblock content %}
diff --git a/src/templates/base/dashboard/host_profile_detail.html b/src/templates/base/dashboard/host_profile_detail.html
new file mode 100644
index 0000000..f65d4fe
--- /dev/null
+++ b/src/templates/base/dashboard/host_profile_detail.html
@@ -0,0 +1,70 @@
+{% 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/base/dashboard/idf.yaml b/src/templates/base/dashboard/idf.yaml
new file mode 100644
index 0000000..9e0cc26
--- /dev/null
+++ b/src/templates/base/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/base/dashboard/lab_detail.html b/src/templates/base/dashboard/lab_detail.html
new file mode 100644
index 0000000..a12c5da
--- /dev/null
+++ b/src/templates/base/dashboard/lab_detail.html
@@ -0,0 +1,165 @@
+{% 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 mb-3">
+ <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 class="collapse show" id="panel_overview">
+ <div class="overflow-auto">
+ <table class="table m-0">
+ <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 class="rounded-circle bg-success square-20 d-inline-block"></div>
+ Up
+ </td>
+ {% elif lab.status < 200 %}
+ <td>
+ <div class="rounded-circle bg-warning square-20 d-inline-block"></div>
+ Temporarily Offline
+ </td>
+ {% else %}
+ <td>
+ <div class="rounded-circle bg-danger square-20 d-inline-block"></div>
+ Offline Indefinitely
+ </td>
+ {% endif %}
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ <div class="card my-3">
+ <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">Expand</button>
+ </div>
+ <div class="collapse show" id="profile_panel">
+ <div class="overflow-auto">
+ <table class="table m-0">
+ {% 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>
+
+ <div class="card my-3">
+ <div class="card-header d-flex">
+ <h4 class="d-inline">Networking Capabilities</h4>
+ <button data-toggle="collapse" data-target="#network_panel" class="btn btn-outline-secondary ml-auto">Expand</button>
+ </div>
+
+ <div class="collapse show" id="network_panel">
+ <table class="table m-0">
+ <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|yesno:"Yes,No"}}</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="card my-3">
+ <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="collapse show" id="image_panel">
+ <div class="overflow-auto">
+ <table class="table m-0">
+ <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>
+ <div class="col-lg-8">
+ <div class="card mb-3">
+ <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="collapse show" id="lab_hosts_panel">
+ <table class="table m-0">
+ <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|yesno:"Yes,No"}}</td>
+ {% if host.working %}
+ <td class="bg-success text-white">Yes</td>
+ {% else %}
+ <td class="bg-danger text-white">No</td>
+ {% endif %}
+ <td>{{host.vendor}}</td>
+ </tr>
+ {% endfor %}
+ </table>
+ </div>
+ </div>
+ </div>
+
+</div>
+
+
+{% endblock content %}
+
diff --git a/src/templates/base/dashboard/lab_list.html b/src/templates/base/dashboard/lab_list.html
new file mode 100644
index 0000000..ba627bc
--- /dev/null
+++ b/src/templates/base/dashboard/lab_list.html
@@ -0,0 +1,29 @@
+{% extends "base.html" %}
+{% block content %}
+<div class="row">
+ {% for lab in labs %}
+ <div class="col-12 col-md-6 col-lg-4 col-xl-3 mb-3">
+ <div class="card h-100">
+ <div class="card-header">
+ <h3 class="mt-2">{{lab.name}}</h3>
+ </div>
+ <ul class="list-group list-group-flush h-100">
+ <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>
+ <div class="card-footer">
+ <a class="btn btn-primary w-100" href="/lab/{{lab.name}}/">Details</a>
+ </div>
+ </div>
+ </div>
+ {% endfor %}
+</div>
+{% endblock %} \ No newline at end of file
diff --git a/src/templates/base/dashboard/landing.html b/src/templates/base/dashboard/landing.html
new file mode 100644
index 0000000..9e45b09
--- /dev/null
+++ b/src/templates/base/dashboard/landing.html
@@ -0,0 +1,77 @@
+{% extends "base.html" %}
+{% load staticfiles %}
+
+{% block content %}
+<div class="text-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 %}
+
+<div class="row">
+ <!-- About us -->
+ <div class="col-12 col-lg-6 mb-4">
+ <h2 class="border-bottom">About Us</h2>
+ {% block about_us %}
+ <p>Here is some information about us!</p>
+ {% endblock about_us %}
+ </div>
+
+ <!-- Get started -->
+ <div class="col-12 col-lg-6 mb-4">
+ <h2 class="border-bottom">Get Started</h2>
+ {% if request.user.is_anonymous %}
+ <h4 class="text-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="btn btn-primary btn-lg d-flex flex-column justify-content-center align-content-center border text-white p-4"
+ href="/booking/quick/">
+ Book a Server
+ </a>
+ <p class="mt-4">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="btn-group-vertical w-100">
+ <button class="btn btn-primary" onclick="create_workflow(0)">Book a Pod</button>
+ <button class="btn btn-primary" onclick="create_workflow(1)">Design a Pod</button>
+ <button class="btn btn-primary" onclick="create_workflow(2)">Configure a Pod</button>
+ </div>
+ {% endif %}
+ </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 border-bottom">Returning Users</h2>
+ <p>If you're a returning user, some of the following options may be of interest:</p>
+ <div class="btn-group-vertical w-100">
+ <button class="btn btn-primary" onclick="create_workflow(3)">Snapshot a Host</button>
+ <a class="btn btn-primary" href="{% url 'account:my-bookings' %}">
+ My Bookings
+ </a>
+ {% if manager == True %}
+ <button class="btn btn-primary" onclick="continue_workflow()">
+ Resume Workflow
+ </button>
+ {% endif %}
+ </div>
+ </div>
+ {% endif %}
+</div>
+
+<div class="hidden_form d-none" id="form_div">
+ <form method="post" action="" class="form" id="wf_selection_form">
+ {% csrf_token %}
+ </form>
+</div>
+
+{% endblock content %}
diff --git a/src/templates/base/dashboard/login.html b/src/templates/base/dashboard/login.html
new file mode 100644
index 0000000..d3aa4ad
--- /dev/null
+++ b/src/templates/base/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/base/dashboard/multiple_select_filter_widget.html b/src/templates/base/dashboard/multiple_select_filter_widget.html
new file mode 100644
index 0000000..92aa1ba
--- /dev/null
+++ b/src/templates/base/dashboard/multiple_select_filter_widget.html
@@ -0,0 +1,54 @@
+<input name="filter_field" id="filter_field" type="hidden"/>
+<div class="row">
+ {% for object_class, object_list in display_objects %}
+ <div class="col-12 col-lg-6 d-flex flex-column pt-2 mx-0">
+ <div class="col mx-0 border rounded py-2 flex-grow-1 d-flex flex-column">
+ <div class="w-100">
+ <h4 class="text-capitalize">{{object_class}}</h4>
+ </div>
+ <div id="{{object_class}}" class="row flex-grow-1">
+ {% for obj in object_list %}
+ <div class="col-12 col-md-6 col-xl-4 my-2 d-flex flex-grow-1">
+ <div id="{{ obj.id|default:'not_provided' }}" class="card flex-grow-1">
+ <div class="card-header">
+ <p class="h5 font-weight-bold mt-2">{{obj.name}}</p>
+ </div>
+ <div class="card-body">
+ <p class="grid-item-description">{{obj.description}}</p>
+ </div>
+ <div class="card-footer">
+ <button type="button" class="btn btn-success grid-item-select-btn w-100 stretched-link"
+ onclick="multi_filter_widget.processClick('{{obj.id}}');">
+ {% if obj.multiple %}
+ Add
+ {% else %}
+ Select
+ {% endif %}
+ </button>
+ </div>
+ </div>
+ </div>
+ {% endfor %}
+ </div>
+ </div>
+ </div>
+ {% endfor %}
+</div>
+
+<div id="dropdown_row" class="row">
+ <div id="dropdown_wrapper" class="col-12 col-lg-6 d-flex flex-column pt-2 mx-0">
+ </div>
+</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 variables
+ multi_filter_widget = new MultipleSelectFilterWidget(graph_neighbors, filter_items, initial_value);
+ form_submission_callbacks.push(() => multi_filter_widget.finish());
+}
+
+multipleSelectFilterWidgetEntry();
+</script>
diff --git a/src/templates/base/dashboard/pdf.yaml b/src/templates/base/dashboard/pdf.yaml
new file mode 100644
index 0000000..c893919
--- /dev/null
+++ b/src/templates/base/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/base/dashboard/resource.html b/src/templates/base/dashboard/resource.html
new file mode 100644
index 0000000..f36ee7b
--- /dev/null
+++ b/src/templates/base/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/base/dashboard/resource_all.html b/src/templates/base/dashboard/resource_all.html
new file mode 100644
index 0000000..fb8cc7e
--- /dev/null
+++ b/src/templates/base/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/base/dashboard/resource_detail.html b/src/templates/base/dashboard/resource_detail.html
new file mode 100644
index 0000000..0a443d9
--- /dev/null
+++ b/src/templates/base/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/base/dashboard/searchable_select_multiple.html b/src/templates/base/dashboard/searchable_select_multiple.html
new file mode 100644
index 0000000..f7fd189
--- /dev/null
+++ b/src/templates/base/dashboard/searchable_select_multiple.html
@@ -0,0 +1,73 @@
+<div id="search_select_outer" class="d-flex flex-column">
+ {% if incompatible == "true" %}
+ <div class="alert alert-danger" role="alert">
+ <h3>Warning: Incompatible Configuration</h3>
+ <p>Please make a different selection, as the current config conflicts with the selected pod</p>
+ </div>
+ {% endif %}
+ <div id="added_counter" class="text-center">
+ <span id="added_number">0</span>
+ <span id="addable_limit">/ {% if selectable_limit > -1 %} {{ selectable_limit }} {% else %} &infin; {% endif %}added</span>
+ </div>
+
+ <div id="added_list" class="pb-2">
+
+ </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 type="hidden" id="selector" name="{{ name }}" class="form-control d-none"
+ {% if disabled %} disabled {% endif %}>
+
+ <div id="scroll_restrictor" class="d-flex pb-4 position-relative">
+ <div id="drop_results" class="list-group w-100 z-2 overflow-auto position-absolute mh-30vh"></div>
+ </div>
+</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/base/dashboard/server_table.html b/src/templates/base/dashboard/server_table.html
new file mode 100644
index 0000000..f01bd60
--- /dev/null
+++ b/src/templates/base/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/base/dashboard/table.html b/src/templates/base/dashboard/table.html
new file mode 100644
index 0000000..2b4628e
--- /dev/null
+++ b/src/templates/base/dashboard/table.html
@@ -0,0 +1,39 @@
+{% 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-responsive mw-100">
+ <table class="table table-striped table-bordered table-hover" id="table" cellspacing="0"
+ width="100%">
+ {% block table %}
+ {% endblock table %}
+ </table>
+ </div>
+ </div>
+ </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 %}