diff options
author | Parker Berberian <pberberian@iol.unh.edu> | 2020-01-30 13:33:35 -0500 |
---|---|---|
committer | Parker Berberian <pberberian@iol.unh.edu> | 2020-01-30 16:12:18 -0500 |
commit | 078273eb7db5a481a4131d44a943f3c9e34b6b88 (patch) | |
tree | 9e6e569e18712d77b8a65c6ebf4dda50ade1b55a /src/templates/base/dashboard | |
parent | 899e1a4baa95d0bc6f0eef34de66f0e257174878 (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.html | 30 | ||||
-rw-r--r-- | src/templates/base/dashboard/host_profile_detail.html | 70 | ||||
-rw-r--r-- | src/templates/base/dashboard/idf.yaml | 46 | ||||
-rw-r--r-- | src/templates/base/dashboard/lab_detail.html | 165 | ||||
-rw-r--r-- | src/templates/base/dashboard/lab_list.html | 29 | ||||
-rw-r--r-- | src/templates/base/dashboard/landing.html | 77 | ||||
-rw-r--r-- | src/templates/base/dashboard/login.html | 8 | ||||
-rw-r--r-- | src/templates/base/dashboard/multiple_select_filter_widget.html | 54 | ||||
-rw-r--r-- | src/templates/base/dashboard/pdf.yaml | 92 | ||||
-rw-r--r-- | src/templates/base/dashboard/resource.html | 57 | ||||
-rw-r--r-- | src/templates/base/dashboard/resource_all.html | 70 | ||||
-rw-r--r-- | src/templates/base/dashboard/resource_detail.html | 151 | ||||
-rw-r--r-- | src/templates/base/dashboard/searchable_select_multiple.html | 73 | ||||
-rw-r--r-- | src/templates/base/dashboard/server_table.html | 30 | ||||
-rw-r--r-- | src/templates/base/dashboard/table.html | 39 |
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 %} ∞ {% 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 %} |