diff options
49 files changed, 958 insertions, 817 deletions
diff --git a/requirements.txt b/requirements.txt index 9ea10a4..55e5fc9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ celery==3.1.23 cryptography==2.3.1 Django==2.1 -django-bootstrap3==10.0.1 +django-bootstrap4==0.0.8 django-crispy-forms==1.7.2 django-filter==2.0.0 django-registration==2.1.2 diff --git a/src/booking/stats.py b/src/booking/stats.py index b706577..62ba648 100644 --- a/src/booking/stats.py +++ b/src/booking/stats.py @@ -25,7 +25,7 @@ class StatisticsManager(object): some point in the given date span is the number of days to plot. The last x value will always be the current time """ - x_set = set() + data = [] x = [] y = [] users = [] @@ -33,26 +33,26 @@ class StatisticsManager(object): delta = datetime.timedelta(days=span) end = now - delta bookings = Booking.objects.filter(start__lte=now, end__gte=end) - for booking in bookings: - x_set.add(booking.start) - if booking.end < now: - x_set.add(booking.end) + for booking in bookings: # collect data from each booking + user_list = [u.pk for u in booking.collaborators.all()] + user_list.append(booking.owner.pk) + data.append((booking.start, 1, user_list)) + data.append((booking.end, -1, user_list)) - x_set.add(now) - x_set.add(end) + # sort based on time + data.sort(key=lambda i: i[0]) - x_list = list(x_set) - x_list.sort(reverse=True) - for time in x_list: - x.append(str(time)) - active = Booking.objects.filter(start__lte=time, end__gt=time) - booking_count = len(active) - users_set = set() - for booking in active: - users_set.add(booking.owner) - for user in booking.collaborators.all(): - users_set.add(user) - y.append(booking_count) - users.append(len(users_set)) + # collect data + count = 0 + active_users = {} + for datum in data: + x.append(str(datum[0])) # time + count += datum[1] # booking count + y.append(count) + for pk in datum[2]: # maintain count of each user's active bookings + active_users[pk] = active_users.setdefault(pk, 0) + datum[1] + if active_users[pk] == 0: + del active_users[pk] + users.append(len([x for x in active_users.values() if x > 0])) return {"booking": [x, y], "user": [x, users]} diff --git a/src/pharos_dashboard/settings.py b/src/pharos_dashboard/settings.py index 793eec7..86de78c 100644 --- a/src/pharos_dashboard/settings.py +++ b/src/pharos_dashboard/settings.py @@ -35,7 +35,7 @@ INSTALLED_APPS = [ 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.humanize', - 'bootstrap3', + 'bootstrap4', 'crispy_forms', 'rest_framework', 'rest_framework.authtoken', diff --git a/src/static/bower.json b/src/static/bower.json index 9ae744a..dda786d 100644 --- a/src/static/bower.json +++ b/src/static/bower.json @@ -16,12 +16,14 @@ "tests" ], "dependencies": { - "eonasdan-bootstrap-datetimepicker": "^4.17.37", "fullcalendar": "^2.9.0", "jquery-migrate": "^3.0.0", - "startbootstrap-sb-admin-2-blackrockdigital": "^3.3.7" - }, - "resolutions": { - "font-awesome": "~4.6.3" + "bootstrap": "4.3.1", + "popper.js": "1.14.3", + "Font-Awesome": "5.9.0", + "datatables.net": "1.10.19", + "datatables.net-bs4": "1.10.19", + "datatables.net-responsive": "2.1.1", + "datatables.net-responsive-bs4": "2.2.3" } } diff --git a/src/static/css/base.css b/src/static/css/base.css new file mode 100644 index 0000000..c51728c --- /dev/null +++ b/src/static/css/base.css @@ -0,0 +1,8 @@ +/* Rotating arrows when dropdown happens */ +i.fas.rotate { + transition: transform 0.3s ease-in-out; +} + +a[aria-expanded="true"] > i.rotate { + transform: rotate(180deg); +} diff --git a/src/templates/account/booking_list.html b/src/templates/account/booking_list.html index ed59b81..98ab5c8 100644 --- a/src/templates/account/booking_list.html +++ b/src/templates/account/booking_list.html @@ -3,9 +3,11 @@ <h2>Bookings I Own</h2> <div class="card_container"> {% for booking in bookings %} - <div class="detail_card"> - <div> + <div class="card"> + <div class="card-header"> <h3>Booking {{booking.id}}</h3> + </div> + <div class="card-body"> <ul class="list-group"> <li class="list-group-item">id: {{booking.id}}</li> <li class="list-group-item">lab: {{booking.lab}}</li> @@ -15,8 +17,8 @@ <li class="list-group-item">purpose: {{booking.purpose}}</li> </ul> </div> - <div class="detail_button_container"> - <a class="btn btn-primary" href="/booking/detail/{{booking.id}}/">Details</a> + <div class="card-footer d-flex"> + <a class="btn btn-primary ml-auto mr-2" href="/booking/detail/{{booking.id}}/">Details</a> <button class="btn btn-danger" onclick='cancel_booking({{booking.id}});' @@ -29,32 +31,37 @@ </div> <h2>Bookings I Collaborate On</h2> <div class="card_container"> - {% for booking in collab_bookings %} - <div class="detail_card"> - <div> - <h3>Booking {{booking.id}}</h3> - <ul class="list-group"> - <li class="list-group-item">id: {{booking.id}}</li> - <li class="list-group-item">lab: {{booking.lab}}</li> - <li class="list-group-item">resource: {{booking.resource.template.name}}</li> - <li class="list-group-item">start: {{booking.start}}</li> - <li class="list-group-item">end: {{booking.end}}</li> - <li class="list-group-item">purpose: {{booking.purpose}}</li> - </ul> + {% for booking in collab_bookings %} + <div class="card"> + <div class="card-header"> + <h3>Booking {{booking.id}}</h3> + </div> + <div class="card-body"> + <ul class="list-group"> + <li class="list-group-item">id: {{booking.id}}</li> + <li class="list-group-item">lab: {{booking.lab}}</li> + <li class="list-group-item">resource: {{booking.resource.template.name}}</li> + <li class="list-group-item">start: {{booking.start}}</li> + <li class="list-group-item">end: {{booking.end}}</li> + <li class="list-group-item">purpose: {{booking.purpose}}</li> + </ul> + </div> + <div class="card-footer d-flex"> + <a class="btn btn-primary ml-auto" href="/booking/detail/{{booking.id}}/">Details</a> + </div> </div> - <a class="btn btn-primary" href="/booking/detail/{{booking.id}}/">Details</a> - </div> - {% endfor %} + {% endfor %} </div> - <h2>Expired Bookings <i class="fa fa-fw fa-caret-down" onclick='toggle_display("expired_bookings");'></i> </h2> <div id="expired_bookings" class="card_container" style="display:none;"> {% for booking in expired_bookings %} - <div class="detail_card"> - <div> + <div class="card"> + <div class="card-header"> <h3>Booking {{booking.id}}</h3> + </div> + <div class="card-body"> <ul class="list-group"> <li class="list-group-item">id: {{booking.id}}</li> <li class="list-group-item">lab: {{booking.lab}}</li> @@ -65,7 +72,9 @@ <li class="list-group-item">owner: {{booking.owner.userprofile.email_addr}}</li> </ul> </div> - <a class="btn btn-primary" href="/booking/detail/{{booking.id}}/">Details</a> + <div class="card-footer d-flex"> + <a class="btn btn-primary ml-auto" href="/booking/detail/{{booking.id}}/">Details</a> + </div> </div> {% endfor %} </div> diff --git a/src/templates/account/configuration_list.html b/src/templates/account/configuration_list.html index b920ba6..6f7844a 100644 --- a/src/templates/account/configuration_list.html +++ b/src/templates/account/configuration_list.html @@ -2,9 +2,11 @@ {% block content %} <div class="card_container"> {% for config in configurations %} - <div class="detail_card"> - <div> + <div class="card"> + <div class="card-header"> <h3>Configuration {{config.id}}</h3> + </div> + <div class="card-body"> <ul class="list-group"> <li class="list-group-item">id: {{config.id}}</li> <li class="list-group-item">name: {{config.name}}</li> @@ -12,10 +14,9 @@ <li class="list-group-item">resource: {{config.bundle}}</li> </ul> </div> - <div class="detail_button_container"> + <div class="card-footer"> <button - class="btn btn-danger" - style="width:49%;float:right;" + class="btn btn-danger w-100" onclick='delete_config({{config.id}});' data-toggle="modal" data-target="#configModal" diff --git a/src/templates/account/image_list.html b/src/templates/account/image_list.html index cd83dcf..068e096 100644 --- a/src/templates/account/image_list.html +++ b/src/templates/account/image_list.html @@ -3,9 +3,11 @@ <h2>Images I Own</h2> <div class="card_container"> {% for image in images %} - <div class="detail_card"> - <div> + <div class="card"> + <div class="card-header"> <h3>Image {{image.id}}</h3> + </div> + <div class="card-body"> <ul class="list-group"> <li class="list-group-item">id: {{image.id}}</li> <li class="list-group-item">lab: {{image.from_lab.name}}</li> @@ -14,10 +16,9 @@ <li class="list-group-item">host profile: {{image.host_type.name}}</li> </ul> </div> - <div class="detail_button_container"> + <div class="card-footer"> <button - class="btn btn-danger" - style="width:49%;float:right;" + class="btn btn-danger w-100" onclick='delete_image({{image.id}});' data-toggle="modal" data-target="#imageModal" @@ -29,9 +30,11 @@ <h2>Public Images</h2> <div class="card_container"> {% for image in public_images %} - <div class="detail_card"> - <div> + <div class="card"> + <div class="card-header"> <h3>Image {{image.id}}</h3> + </div> + <div class="card-body"> <ul class="list-group"> <li class="list-group-item">id: {{image.id}}</li> <li class="list-group-item">lab: {{image.from_lab.name}}</li> diff --git a/src/templates/account/resource_list.html b/src/templates/account/resource_list.html index 1391e8e..f92f78e 100644 --- a/src/templates/account/resource_list.html +++ b/src/templates/account/resource_list.html @@ -2,18 +2,20 @@ {% block content %} <div class="card_container"> {% for resource in resources %} - <div class="detail_card"> - <div> + <div class="card"> + <div class="card-header"> <h3>Resource {{resource.id}}</h3> + </div> + <div class="card-body p-4"> <ul class="list-group"> <li class="list-group-item">id: {{resource.id}}</li> <li class="list-group-item">name: {{resource.name}}</li> <li class="list-group-item">description: {{resource.description}}</li> </ul> </div> - <div class="detail_button_container"> + <div class="card-footer"> <button - class="btn btn-danger" + class="btn btn-danger w-100" onclick='delete_resource({{resource.id}});' data-toggle="modal" data-target="#resModal" diff --git a/src/templates/account/userprofile_update_form.html b/src/templates/account/userprofile_update_form.html index f1d2852..6ab8242 100644 --- a/src/templates/account/userprofile_update_form.html +++ b/src/templates/account/userprofile_update_form.html @@ -1,17 +1,12 @@ -{% extends "layout.html" %} -{% load bootstrap3 %} +{% extends "base.html" %} +{% load bootstrap4 %} -{% block basecontent %} - <div class="container"> +{% block content %} + <div class="container-fluid"> <div class="row"> - <div class="col-md-4 col-md-offset-4"> + <div class="col-12 col-xl-6"> {% bootstrap_messages %} <div class="login-panel panel panel-default"> - <div class="panel-heading"> - <h3 class="panel-title"> - {{ title }} - </h3> - </div> <div class="panel-body"> <form enctype="multipart/form-data" method="post"> {% csrf_token %} @@ -35,4 +30,4 @@ </div> </div> </div> -{% endblock basecontent %} +{% endblock content %} diff --git a/src/templates/base.html b/src/templates/base.html index 1c83a0e..62a9ed5 100644 --- a/src/templates/base.html +++ b/src/templates/base.html @@ -1,52 +1,51 @@ {% extends "layout.html" %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% load staticfiles %} {% block extrahead %} - <!-- Custom CSS --> - <link href="{% static "bower_components/startbootstrap-sb-admin-2-blackrockdigital/dist/css/sb-admin-2.css" %}" - rel="stylesheet"> - <link href="{% static "css/theme.css" %}" rel="stylesheet"> - <link href="{% static "css/detail_view.css" %}" rel="stylesheet"> - +<!-- Custom CSS --> +<link href="{% static "css/detail_view.css" %}" rel="stylesheet"> +<link href="{% static "css/base.css" %}" rel="stylesheet"> <script type="text/javascript"> - function cwf(type) - { + function cwf(type) { $.ajax({ type: "POST", url: "/", - data: {"create":type}, - beforeSend: function(request) { + data: { + "create": type + }, + beforeSend: function (request) { request.setRequestHeader("X-CSRFToken", - $('input[name="csrfmiddlewaretoken"]').val() + $('input[name="csrfmiddlewaretoken"]').val() ); } }).done(function (data) { window.location.replace("/wf/"); - }).fail(function(jqxHR, textstatus) { - alert("Something went wrong...");}); + }).fail(function (jqxHR, textstatus) { + alert("Something went wrong..."); + }); } - function continue_wf() - { + + function continue_wf() { window.location.replace("/wf/"); } - function toggle_create_drop() - { + function toggle_create_drop() { drop_div = document.getElementById("create_drop"); - if (drop_div.style.display === "none") - { + if (drop_div.style.display === "none") { drop_div.style.display = "inherit"; - } - else - { + } else { drop_div.style.display = "none"; } } </script> <style> + .navbar { + min-width: 200px; + } + .create_drop { display: none; width: 100%; @@ -66,137 +65,172 @@ border-top: 1px solid #E7E7E7; border-bottom: 1px solid #E7E7E7; } + + #wrapper { + height: 100vh; + } </style> {% endblock %} {% block basecontent %} - <div id="wrapper"> - <!-- Navigation --> - <nav class="navbar navbar-default navbar-static-top" role="navigation" - style="margin-bottom: 0"> - <div class="navbar-header"> - <button type="button" class="navbar-toggle" data-toggle="collapse" - data-target=".navbar-collapse"> - <span class="sr-only">Toggle navigation</span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - </button> - <a href="https://www.opnfv.org/" class="navbar-left"><img - src="{% static "img/opnfv-logo.png" %}"></a> - <a class="navbar-brand" href={% url 'dashboard:index' %}>Pharos Dashboard</a> +<div id="wrapper" class="d-flex flex-column"> + <!-- Navigation --> + <nav class="navbar navbar-light bg-light navbar-fixed-top border-bottom py-0" role="navigation" style="margin-bottom: 0"> + <div class="container-fluid"> + <div class="col order-2 order-lg-1 text-center text-lg-left"> + <a href="https://www.opnfv.org/" class="navbar-brand"> + <img src="{% static "img/opnfv-logo.png" %}"> + </a> + <a class="navbar-brand" href={% url 'dashboard:index' %}> + Pharos Dashboard + </a> </div> <!-- /.navbar-header --> + <div class="col-2 order-1 order-lg-3 d-lg-none"> + <button class="btn border" type="button" data-toggle="collapse" data-target="#sidebar" + aria-expanded="false" aria-controls="sidebar"> + <i class="fas fa-bars"></i> + </button> + </div> + <div class="col-2 order-3"> + <ul class="nav ml-auto"> + <li class="dropdown ml-auto"> + <a class="nav-link p-0 text-dark p-2" data-toggle="dropdown" href="#"> + {% if request.user.username %} + {{request.user.username}} + {% else %} + <i class="fas fa-user"></i> + {% endif %} + <i class="fas fa-caret-down rotate"></i> + </a> + <div class="dropdown-menu dropdown-menu-right"> + {% if user.is_authenticated %} + <a href="{% url 'account:settings' %}" class="text-dark dropdown-item"> + <i class="fas fa-cog"></i> + Settings + </a> + <a href="{% url 'account:logout' %}?next={{ request.path }}" class="text-dark dropdown-item"> + <i class="fas fa-sign-out-alt"></i> + Logout + </a> + {% else %} + <a href="{% url 'account:login' %}" class="text-dark dropdown-item"> + <i class="fas fa-sign-in-alt"></i> + Login with Jira + </a> + {% endif %} + </div> <!-- End dropdown-menu --> + </li> <!-- End dropdown --> + </ul> + </div> <!-- End top right account menu --> + </div> + </nav> + <!-- /.navbar-top-links --> - <ul class="nav navbar-top-links navbar-right"> - <li class="dropdown"> - <a class="dropdown-toggle" data-toggle="dropdown" href="#"> - <i class="fa fa-user fa-fw"></i> <i class="fa fa-caret-down"></i> - </a> - <ul class="dropdown-menu dropdown-user"> - {% if user.is_authenticated %} - <li><a href="{% url 'account:settings' %}"><i - class="fa fa-gear fa-fw"></i> - Settings</a> - </li> - <li class="divider"></li> - <li><a href="{% url 'account:logout' %}?next={{ request.path }}"><i - class="fa fa-sign-out fa-fw"></i> - Logout</a> - </li> - {% else %} - <li><a href="{% url 'account:login' %}"><i - class="fa fa-sign-in fa-fw"></i> - Login with Jira</a> - <li> - {% endif %} - </ul> - <!-- /.dropdown-user --> - </li> - <!-- /.dropdown --> - </ul> - <!-- /.navbar-top-links --> - - <div class="navbar-default sidebar" role="navigation"> - <div class="sidebar-nav navbar-collapse"> - <ul class="nav" id="side-menu"> - <li> - <a href="/"><i class="fa fa-fw"></i>Home</a> - </li> - <li style="width: 100%;"> - <a href="javascript:toggle_create_drop();"><i class="fa fa-fw"></i>Create<i - class="fa fa-fw fa-caret-down"></i> + <!-- Page Content --> + <div class="container-fluid d-lg-flex flex-lg-grow-1 px-0"> + <div class="row h-100 w-100 mx-0"> + <div class="col-12 col-lg-auto px-0 border-right border-left bg-light" role="navigation"> + <nav class="navbar navbar-expand-lg border-bottom p-0 w-100"> + <div class="collapse navbar-collapse" id="sidebar"> + <div class="list-group list-group-flush w-100 bg-light"> + <a href="/" class="list-group-item list-group-item-action bg-light"> + Home + </a> + {% csrf_token %} + <a class="list-group-item list-group-item-action bg-light" data-toggle="collapse" + href="#createList" role="button"> + Create <i class="fas fa-angle-down rotate"></i> + </a> + <div class="collapse" id="createList"> + <a href="/booking/quick/" class="list-group-item list-group-item-action list-group-item-secondary"> + Express Booking + </a> + <a href="#" onclick="cwf(0)" class="list-group-item list-group-item-action list-group-item-secondary"> + Book a Pod + </a> + <a href="#" onclick="cwf(1)" class="list-group-item list-group-item-action list-group-item-secondary"> + Design a Pod + </a> + <a href="#" onclick="cwf(2)" class="list-group-item list-group-item-action list-group-item-secondary"> + Configure a Pod + </a> + <a href="#" onclick="cwf(3)" class="list-group-item list-group-item-action list-group-item-secondary"> + Create a Snapshot </a> - {% csrf_token %} - <div id="create_drop" class="create_drop" style="display:none"> - <button class="btn drop_btn" onclick="location.href='/booking/quick/'">Express Booking</a> - <button class="btn drop_btn" onclick="cwf(0)">Book a Pod</button> - <button class="btn drop_btn" onclick="cwf(1)">Design a Pod</button> - <button class="btn drop_btn" onclick="cwf(2)">Configure a Pod</button> - <button class="btn drop_btn" onclick="cwf(3)">Create a Snapshot</button> - <button class="btn drop_btn" onclick="cwf(4)">Configure OPNFV</button> - </div> - </li> - <li> - <a href="{% url 'resource:hosts' %}"><i - class="fa fa-fw"></i>Hosts + <a href="#" onclick="cwf(4)" class="list-group-item list-group-item-action list-group-item-secondary"> + Configure OPNFV </a> - </li> - {% if user.is_authenticated %} - <li> - <a href="{% url 'account:users' %}"><i - class="fa fa-fw"></i>User List + </div> + <a href="{% url 'resource:hosts' %}" class="list-group-item list-group-item-action bg-light"> + Hosts </a> - </li> - {% endif %} - <li> - <a href="{% url 'booking:list' %}"><i - class="fa fa-fw"></i>Booking List + {% if user.is_authenticated %} + <a href="{% url 'account:users' %}" class="list-group-item list-group-item-action bg-light"> + User List + </a> + {% endif %} + <a href="{% url 'booking:list' %}" class="list-group-item list-group-item-action bg-light"> + Booking List </a> - </li> - <li> - <a href="{% url 'booking:stats' %}"><i - class="fa fa-fw"></i>Booking Statistics</a> - </li> - <li> - <a href="{% url 'account:my-account' %}"><i - class="fa fa-fw"></i>Account + <a href="{% url 'booking:stats' %}" class="list-group-item list-group-item-action bg-light"> + Booking Statistics </a> - </li> - <li> - <a href="{% url 'dashboard:all_labs' %}"><i - class="fa fa-fw"></i>Lab Info + <!-- <a href="{% url 'account:my-account' %}" class="list-group-item list-group-item-action bg-light"> + Account + </a> --> + <a class="list-group-item list-group-item-action bg-light" data-toggle="collapse" + href="#accountList" role="button"> + Account <i class="fas fa-angle-down rotate"></i> </a> - </li> - <li> - <a href="{% url 'notifier:messages' %}"><i - class="fa fa-fw"></i>Inbox + <div class="collapse" id="accountList"> + <a href="{% url 'account:my-resources' %}" class="list-group-item list-group-item-action list-group-item-secondary"> + My Resources + </a> + <a href="{% url 'account:my-bookings' %}" class="list-group-item list-group-item-action list-group-item-secondary"> + My Bookings + </a> + <a href="{% url 'account:my-configurations' %}" class="list-group-item list-group-item-action list-group-item-secondary"> + My Configurations + </a> + <a href="{% url 'account:my-images' %}" class="list-group-item list-group-item-action list-group-item-secondary"> + My Snapshots + </a> + </div> + <a href="{% url 'dashboard:all_labs' %}" class="list-group-item list-group-item-action bg-light"> + Lab Info </a> - </li> - </ul> - </div> - <!-- /.sidebar-collapse --> + <a href="{% url 'notifier:messages' %}" class="list-group-item list-group-item-action bg-light"> + Inbox + </a> + </div> + </div> + </nav> + <!--/.well --> </div> - <!-- /.navbar-static-side --> - </nav> + <!--/span--> - <!-- Page Content --> - <div id="page-wrapper"> - {% if title %} - <div class="row"> - <div class="col-lg-12"> - <h1 class="page-header">{{ title }}</h1> + <div class="col flex-grow-1 d-flex flex-column"> + {% if title %} + <div class="row flex-shrink-1"> + <div class="col-lg-12"> + <h1 class="page-header">{{ title }}</h1> + </div> + <!-- /.col-lg-12 --> </div> - <!-- /.col-lg-12 --> + {% endif %} + <div id="bsm">{% bootstrap_messages %}</div> + <!-- Content block placed here --> + {% block content %} + {% endblock content %} </div> - {% endif %} - <div id="bsm">{% bootstrap_messages %}</div> + <!--/span--> - {% block content %} - {% endblock content %} </div> - <!-- /#page-wrapper --> + <!--/row--> </div> - <!-- /#wrapper --> + <!-- /#page-wrapper --> +</div> +<!-- /#wrapper --> {% endblock basecontent %} diff --git a/src/templates/booking/booking_calendar.html b/src/templates/booking/booking_calendar.html index 1b29dc2..ddcb45d 100644 --- a/src/templates/booking/booking_calendar.html +++ b/src/templates/booking/booking_calendar.html @@ -1,7 +1,7 @@ {% extends "base.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block extrahead %} {{ block.super }} diff --git a/src/templates/booking/booking_delete.html b/src/templates/booking/booking_delete.html index 76a5634..b89eb15 100644 --- a/src/templates/booking/booking_delete.html +++ b/src/templates/booking/booking_delete.html @@ -1,5 +1,5 @@ {% load jira_filters %} -{% load bootstrap3 %} +{% load bootstrap4 %} <p> Really delete Booking from {{ booking.start}} to {{ booking.end }}? diff --git a/src/templates/booking/booking_detail.html b/src/templates/booking/booking_detail.html index ac00e22..918f5af 100644 --- a/src/templates/booking/booking_detail.html +++ b/src/templates/booking/booking_detail.html @@ -1,6 +1,6 @@ {% extends "base.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block extrahead %} {{block.super}} @@ -19,13 +19,13 @@ <div class="container-fluid"> <div class="row"> - <div class="col-lg-4"> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> + <div class="col-12 col-lg-5"> + <div class="card mb-4"> + <div class="card-header d-flex"> <h4 style="display: inline;">Overview</h4> - <a data-toggle="collapse" data-target="#panel_overview" class="btn pull-right" style="line-height: 1;">Expand</a> + <button data-toggle="collapse" data-target="#panel_overview" class="btn btn-outline-secondary ml-auto">Expand</button> </div> - <div class="panel-body collapse in" id="panel_overview"> + <div class="card-body collapse show" id="panel_overview"> <table class="table"> <tr> <td>Purpose</td> @@ -60,12 +60,12 @@ </div> <div class="row"> <div class="col-lg-12"> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> + <div class="card"> + <div class="card-header d-flex"> <h4 style="display: inline;">Pod</h4> - <a data-toggle="collapse" data-target="#pod_panel" class="btn pull-right" style="line-height: 1;" >Expand</a> + <button data-toggle="collapse" data-target="#pod_panel" class="btn btn-outline-secondary ml-auto">Expand</button> </div> - <div class="panel-body pod_panel collapse in" id="pod_panel"> + <div class="card-body collapse show" id="pod_panel"> <table class="table"> {% for host in booking.resource.hosts.all %} <tr> @@ -177,14 +177,14 @@ </div> </div> </div> - <div class="col-lg-8"> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> + <div class="col"> + <div class="card mb-4"> + <div class="card-header d-flex"> <h4 style="display: inline;">Deployment Progress</h4> <p style="display: inline; margin-left: 10px;"> These are the different tasks that have to be completed before your deployment is ready</p> - <a data-toggle="collapse" data-target="#panel_tasks" class="btn pull-right" style="line-height: 1;" >Expand</a> + <button data-toggle="collapse" data-target="#panel_tasks" class="btn btn-outline-secondary ml-auto">Expand</button> </div> - <div class="panel-body collapse in" id="panel_tasks"> + <div class="card-body collapse show" id="panel_tasks"> <table class="table"> <style> .progress { @@ -269,15 +269,15 @@ </div> </div> <div class="row"> - <div class="col-lg-8"> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> + <div class="col"> + <div class="card"> + <div class="card-header d-flex"> <h4 style="display: inline;">PDF</h4> - <a data-toggle="collapse" data-target="#pdf_panel" class="btn pull-right" style="line-height: 1;" >Expand</a> + <button data-toggle="collapse" data-target="#pdf_panel" class="btn btn-outline-secondary ml-auto">Expand</button> </div> - <div class="panel-body collapse in" id="pdf_panel" style="padding: 0px;"> + <div class="card-body collapse show" id="pdf_panel" style="padding: 0px;"> <pre class="prettyprint lang-yaml" style="margin: 0px; padding: 15px; border: none;"> -{{pdf}} + {{pdf}} </pre> </div> </div> diff --git a/src/templates/booking/booking_list.html b/src/templates/booking/booking_list.html index a245450..591ecc9 100644 --- a/src/templates/booking/booking_list.html +++ b/src/templates/booking/booking_list.html @@ -1,44 +1,38 @@ {% extends "base.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block extrahead %} {{ block.super }} <!-- DataTables CSS --> - <link href="{% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.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-responsive/css/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="panel-body"> - <div class="dataTables_wrapper"> - <table class="table table-striped table-bordered table-hover" id="table" - cellspacing="0" - width="100%"> - {% include "booking/booking_table.html" %} - </table> - </div> - <!-- /.table-responsive --> - <!-- /.panel-body --> - <!-- /.panel --> + <div class="col"> + <div class="panel-body"> + <div class="dataTables_wrapper"> + <table class="table table-striped table-bordered table-hover" id="table" + cellspacing="0" + width="100%"> + {% include "booking/booking_table.html" %} + </table> + </div> + </div> </div> - <!-- /.col-lg-12 --> </div> {% endblock content %} {% block extrajs %} <!-- DataTables JavaScript --> - <link href="{% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.css" %}" - rel="stylesheet"> - - - <script src={% static "bower_components/datatables/media/js/jquery.dataTables.min.js" %}></script> - <script src={% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.min.js" %}></script> + <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 type="text/javascript"> $(document).ready(function () { diff --git a/src/templates/booking/quick_deploy.html b/src/templates/booking/quick_deploy.html index 8cf8481..ea80af4 100644 --- a/src/templates/booking/quick_deploy.html +++ b/src/templates/booking/quick_deploy.html @@ -1,6 +1,6 @@ {% extends "base.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} <style> .grid_container { diff --git a/src/templates/booking/stats.html b/src/templates/booking/stats.html index 42eebdd..8bc68cd 100644 --- a/src/templates/booking/stats.html +++ b/src/templates/booking/stats.html @@ -41,17 +41,28 @@ function getData(){ {% endblock %} {% block content %} - <p>Number of days to plot: </p> - <div class="form-group"> - <input id="number_days" type="number" class="form-control" min="1" step="1" style="display:inline;width:200px"/> - <button class="btn btn-primary" onclick="getData();" style="display:inline;">Submit</button> - </div> - <div id="all_graph_container"> - <div id="booking_graph_wrapper"> - <div id="booking_graph_container"/> + <div class="container-fluid"> + <div class="row"> + <div class="col"> + <p>Number of days to plot: </p> + <div class="form-group"> + <input id="number_days" type="number" class="form-control" min="1" step="1" style="display:inline;width:200px"/> + <button class="btn btn-primary" onclick="getData();" style="display:inline;">Submit</button> + </div> + </div> </div> - <div id="user_graph_wrapper" > - <div id="user_graph_container"/> + <div class="row"> + <div class="col-12 col-md-10"> + <!-- These graphs do NOT get redrawn when the browser size is changed --> + <div id="all_graph_container border" class="mw-100"> + <div id="booking_graph_wrapper"> + <div id="booking_graph_container"/> + </div> + <div id="user_graph_wrapper"> + <div id="user_graph_container"/> + </div> + </div> + </div> </div> </div> <script> diff --git a/src/templates/booking/steps/booking_confirm.html b/src/templates/booking/steps/booking_confirm.html index 9c7e951..40c30a9 100644 --- a/src/templates/booking/steps/booking_confirm.html +++ b/src/templates/booking/steps/booking_confirm.html @@ -1,7 +1,7 @@ {% extends "workflow/viewport-element.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} diff --git a/src/templates/booking/steps/booking_meta.html b/src/templates/booking/steps/booking_meta.html index cdd7834..710d4ee 100644 --- a/src/templates/booking/steps/booking_meta.html +++ b/src/templates/booking/steps/booking_meta.html @@ -1,7 +1,7 @@ {% extends "workflow/viewport-element.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} @@ -10,6 +10,17 @@ padding: 5%; } + .bkcontrib_panel { + display: flex; + flex-direction: column; + } + + .bkcontrib_panel > .form-group { + flex: 1; + display: flex; + flex-direction: column; + } + .panel{ padding: 5%; /*border: solid 1px black;*/ @@ -52,7 +63,7 @@ </div> <div class="panel panel_center"> </div> - <div class="panel"> + <div class="panel bkcontrib_panel"> <p>You may add collaborators on your booking to share resources with coworkers.</p> {% bootstrap_field form.users label="Collaborators" %} </div> diff --git a/src/templates/booking/steps/resource_select.html b/src/templates/booking/steps/resource_select.html index 7ccceb3..382316f 100644 --- a/src/templates/booking/steps/resource_select.html +++ b/src/templates/booking/steps/resource_select.html @@ -1,7 +1,7 @@ {% extends "workflow/viewport-element.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} diff --git a/src/templates/booking/steps/swconfig_select.html b/src/templates/booking/steps/swconfig_select.html index 15c79d8..60a0df7 100644 --- a/src/templates/booking/steps/swconfig_select.html +++ b/src/templates/booking/steps/swconfig_select.html @@ -1,7 +1,7 @@ {% extends "workflow/viewport-element.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} diff --git a/src/templates/config_bundle/steps/assign_host_roles.html b/src/templates/config_bundle/steps/assign_host_roles.html index 3ba7665..b87a17f 100644 --- a/src/templates/config_bundle/steps/assign_host_roles.html +++ b/src/templates/config_bundle/steps/assign_host_roles.html @@ -1,6 +1,6 @@ {% extends "config_bundle/steps/table_formset.html" %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block table %} <thead> diff --git a/src/templates/config_bundle/steps/assign_network_roles.html b/src/templates/config_bundle/steps/assign_network_roles.html index 0e887d6..aa1df44 100644 --- a/src/templates/config_bundle/steps/assign_network_roles.html +++ b/src/templates/config_bundle/steps/assign_network_roles.html @@ -1,6 +1,6 @@ {% extends "config_bundle/steps/table_formset.html" %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block table %} <thead> diff --git a/src/templates/config_bundle/steps/config_software.html b/src/templates/config_bundle/steps/config_software.html index b181c7e..68417bc 100644 --- a/src/templates/config_bundle/steps/config_software.html +++ b/src/templates/config_bundle/steps/config_software.html @@ -1,7 +1,7 @@ {% extends "workflow/viewport-element.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} diff --git a/src/templates/config_bundle/steps/define_software.html b/src/templates/config_bundle/steps/define_software.html index ba1ff34..87e5997 100644 --- a/src/templates/config_bundle/steps/define_software.html +++ b/src/templates/config_bundle/steps/define_software.html @@ -1,6 +1,6 @@ {% extends "config_bundle/steps/table_formset.html" %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block table %} <thead> diff --git a/src/templates/config_bundle/steps/pick_installer.html b/src/templates/config_bundle/steps/pick_installer.html index 3b170d9..31a06de 100644 --- a/src/templates/config_bundle/steps/pick_installer.html +++ b/src/templates/config_bundle/steps/pick_installer.html @@ -1,7 +1,7 @@ {% extends "workflow/viewport-element.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} diff --git a/src/templates/config_bundle/steps/table_formset.html b/src/templates/config_bundle/steps/table_formset.html index ad2c5a3..18edc72 100644 --- a/src/templates/config_bundle/steps/table_formset.html +++ b/src/templates/config_bundle/steps/table_formset.html @@ -1,15 +1,16 @@ {% extends "workflow/viewport-element.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block extrahead %} <!-- DataTables CSS --> - <link href="{% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.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-responsive/css/dataTables.responsive.css" %}" rel="stylesheet"> + <link href="{% static "bower_components/datatables.net-responsive-bs4/css/responsive.bootstrap4.min.css" %}" + rel="stylesheet"> {% endblock extrahead %} {% block content %} @@ -42,8 +43,8 @@ {{ block.super }} <!-- DataTables JavaScript --> - <script src={% static "bower_components/datatables/media/js/jquery.dataTables.min.js" %}></script> - <script src={% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.min.js" %}></script> + <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> diff --git a/src/templates/dashboard/genericselect.html b/src/templates/dashboard/genericselect.html index a03f759..441d8dc 100644 --- a/src/templates/dashboard/genericselect.html +++ b/src/templates/dashboard/genericselect.html @@ -1,7 +1,7 @@ {% extends "workflow/viewport-element.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} @@ -14,9 +14,10 @@ #{{select_type}}_form_div div { } - #{{select_type}}_form_div > *:not(.divider) { + #{{select_type}}_form_div > * { margin-left: 10px; margin-right: 10px; + margin-bottom: 20px; } #{{select_type}}_form_div div * { @@ -25,17 +26,14 @@ #{{select_type}}_form_div { flex: 1; margin: 30px; - display: grid; - grid-template-rows: auto 1px auto 1fr; - grid-template-columns: repeat(24, 1fr); - grid-row-gap: 15px; + display: flex; + flex-direction: column; } #select_section { + flex: 1; display: flex; flex-direction: column; - grid-column-start: 3; - grid-column-end: 21; } #{{select_type}}_select_form { @@ -49,12 +47,9 @@ } #create_section { - grid-column-start: 1; - grid-column-end: 24; } #select_header_section { - grid-column: 1 / 24; } h3 { @@ -65,8 +60,6 @@ .divider { border-top: 1px solid #ccc; - grid-column-start: 1; - grid-column-end: 24; } diff --git a/src/templates/dashboard/lab_detail.html b/src/templates/dashboard/lab_detail.html index 7938e86..336b32e 100644 --- a/src/templates/dashboard/lab_detail.html +++ b/src/templates/dashboard/lab_detail.html @@ -9,12 +9,12 @@ {% block content %} <div class="row"> <div class="col-lg-4"> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> - <h4 style="display: inline;">Lab Profile</h4> - <a data-toggle="collapse" data-target="#panel_overview" class="btn pull-right" style="line-height: 1;" >Expand</a> + <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 class="panel-body" id="panel_overview"> + <div id="panel_overview" class="card-body collapse show"> <table class="table"> <tr> <td>Lab Name: </td><td>{{lab.name}}</td> @@ -50,19 +50,18 @@ </table> </div> </div> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> - <h4 style="display: inline;">Host Profiles</h4> - - <a data-toggle="collapse" data-target="#profile_panel" class="btn pull-right" style="line-height: 1;" >Expand</a> + <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 class="panel-body pod_panel" id="profile_panel"> + <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-primary">Profile</a></td> + <td><a href="/resource/profiles/{{ profile.id }}" class="btn btn-info">Profile</a></td> </tr> {% endfor %} </table> @@ -70,31 +69,30 @@ </div> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> + <div class="card my-2"> + <div class="card-header d-flex"> <h4 style="display: inline;">Networking Capabilities</h4> - <a data-toggle="collapse" data-target="#network_panel" class="btn pull-right" style="line-height: 1;" >Expand</a> + <button data-toggle="collapse" data-target="#network_panel" class="btn btn-outline-secondary ml-auto" style="line-height: 1;" >Expand</button> </div> - <div class="panel-body" 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 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="panel panel-default"> - <div class="panel-heading clearfix"> - <h4 style="display: inline;">Images</h4> - <a data-toggle="collapse" data-target="#image_panel" class="btn pull-right" style="line-height: 1;" >Expand</a> + <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="panel-body" id="image_panel"> + <div class="card-body collapse show" id="image_panel"> <table class="table"> <tr> <th>Name</th> @@ -116,14 +114,13 @@ </div> <div class="col-lg-8"> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> - <h4 style="display: inline;">Lab Hosts</h4> - <p style="display: inline; margin-left: 10px;"></p> - <a data-toggle="collapse" data-target="#lab_hosts_panel" class="btn pull-right" style="line-height: 1;" >Expand</a> + <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="panel-body" id="lab_hosts_panel"> + <div class="card-body collapse show" id="lab_hosts_panel"> <table class="table"> <tr> <th>Name</th> diff --git a/src/templates/dashboard/lab_list.html b/src/templates/dashboard/lab_list.html index c459dd9..9cde80c 100644 --- a/src/templates/dashboard/lab_list.html +++ b/src/templates/dashboard/lab_list.html @@ -1,26 +1,28 @@ {% extends "base.html" %} {% block content %} - <h2>Labs</h2> - <div class="card_container"> +<h2>Labs</h2> +<div class="card_container"> {% for lab in labs %} - <div class="detail_card"> - <div> - <h3>{{lab.name}}</h3> - <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> - </div> - <a class="btn btn-primary" href="/lab/{{lab.name}}/">Details</a> + <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> - {% endfor %} </div> -{% endblock %} + {% endfor %} +</div> +{% endblock %}
\ No newline at end of file diff --git a/src/templates/dashboard/landing.html b/src/templates/dashboard/landing.html index fb75d5f..e6a235f 100644 --- a/src/templates/dashboard/landing.html +++ b/src/templates/dashboard/landing.html @@ -2,27 +2,30 @@ {% load staticfiles %} {% block content %} - <div class="" style="text-align: center;"> - {% if not request.user.is_anonymous %} - {% if not request.user.userprofile.ssh_public_key %} - <h4 style="display: inline; text-align: center; border: 3px solid red; padding: 10px; border-radius: 10000px; height: 40px;"> - 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 - </h4> - {% endif %} - {% else %} - {% endif %} +<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{ + .wf_create { display: inline-block; text-align: center; } - .wf_create_div{ + + .wf_create_div { text-align: center; } - .hidden_form{ + + .hidden_form { display: none; } @@ -39,81 +42,117 @@ 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="landing_container"> - <div class="info_panel grid_panel"> - <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> + 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 %} - <h2 style="margin-top: 50px;">Returning Users:</h2> - <p>If you're a returning user, some of the following options may be of interest:</p> - <button class="wf_create btn btn-primary" onclick="cwf(3)">Snapshot a Host</button> - <a class="wf_create btn btn-primary" href="{% url 'account:my-bookings' %}">My Bookings</a> - {% if manager == True %} - <button class="wf_continue btn btn-primary" onclick="continue_wf()">Continue Unfinished Workflow</button> - {% endif %} - {% endif %} - </div> - <div class=""> - </div> - <div class="actions_panel grid_panel"> - <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='wf_create_div'> - - <button class="wf_create btn btn-primary" onclick="cwf(0)">Book a Pod</button> - <button class="wf_create btn btn-primary" onclick="cwf(1)">Design a Pod</button> - <button class="wf_create btn btn-primary" onclick="cwf(2)">Configure a Pod</button> - {% endif %} + <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) - { + function cwf(type) { $.ajax({ type: "POST", url: "/", - data: {"create":type}, - beforeSend: function(request) { + data: { + "create": type + }, + beforeSend: function (request) { request.setRequestHeader("X-CSRFToken", - $('input[name="csrfmiddlewaretoken"]').val() + $('input[name="csrfmiddlewaretoken"]').val() ); } }).done(function (data) { window.location.replace("/wf/"); - }).fail(function(jqxHR, textstatus) { - alert("Something went wrong...");}); + }).fail(function (jqxHR, textstatus) { + alert("Something went wrong..."); + }); } - function continue_wf() - { + + function continue_wf() { window.location.replace("/wf/"); } - </script> <div class="hidden_form" id="form_div"> @@ -130,4 +169,4 @@ {% block vport_comm %} {% endblock %} -{% endblock content %} +{% endblock content %}
\ No newline at end of file diff --git a/src/templates/dashboard/resource.html b/src/templates/dashboard/resource.html index 28e7998..f36ee7b 100644 --- a/src/templates/dashboard/resource.html +++ b/src/templates/dashboard/resource.html @@ -7,11 +7,11 @@ <link href="{% static "bower_components/morrisjs/morris.css" %}" rel="stylesheet"> <!-- DataTables CSS --> - <link href="{% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.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-responsive/css/dataTables.responsive.css" %}" + <link href="{% static "bower_components/datatables.net-responsive-bs4/css/responsive.bootstrap4.min.css" %}" rel="stylesheet"> {% endblock extrahead %} @@ -23,11 +23,11 @@ {% block extrajs %} <!-- DataTables JavaScript --> - <link href="{% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.css" %}" + <link href="{% static "bower_components/datatables/media/css/dataTables.bootstrap.css" %}" rel="stylesheet"> - <script src={% static "bower_components/datatables/media/js/jquery.dataTables.min.js" %}></script> - <script src={% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.min.js" %}></script> + <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> diff --git a/src/templates/dashboard/resource_all.html b/src/templates/dashboard/resource_all.html index 0b0d0d4..fb8cc7e 100644 --- a/src/templates/dashboard/resource_all.html +++ b/src/templates/dashboard/resource_all.html @@ -7,11 +7,11 @@ <link href="{% static "bower_components/morrisjs/morris.css" %}" rel="stylesheet"> <!-- DataTables CSS --> - <link href="{% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.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-responsive/css/dataTables.responsive.css" %}" + <link href="{% static "bower_components/datatables.net-responsive-bs4/css/responsive.bootstrap4.min.css" %}" rel="stylesheet"> {% endblock extrahead %} @@ -36,11 +36,11 @@ {% block extrajs %} <!-- DataTables JavaScript --> - <link href="{% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.css" %}" + <link href="{% static "bower_components/datatables/media/css/dataTables.bootstrap.css" %}" rel="stylesheet"> - <script src={% static "bower_components/datatables/media/js/jquery.dataTables.min.js" %}></script> - <script src={% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.min.js" %}></script> + <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> diff --git a/src/templates/dashboard/searchable_select_multiple.html b/src/templates/dashboard/searchable_select_multiple.html index 4290147..91ed09c 100644 --- a/src/templates/dashboard/searchable_select_multiple.html +++ b/src/templates/dashboard/searchable_select_multiple.html @@ -1,21 +1,21 @@ <script src="https://code.jquery.com/jquery-2.2.4.min.js"></script> -<div class="autocomplete"> +<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_list"> - - </div> <div id="added_counter"> <p id="added_number">0</p> <p id="addable_limit">/ {% if selectable_limit > -1 %} {{ selectable_limit }} {% else %} ∞ {% 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="search(this.value)" {% if disabled %} disabled {% endif %} > @@ -34,7 +34,13 @@ flex: 1; position: relative; overflow-y: auto; + padding-bottom: 10px; } + + #added_list { + margin-bottom: 5px; + } + .autocomplete { display: flex; flex: 1; @@ -43,6 +49,9 @@ #user_field { font-size: 14pt; padding: 5px; + height: 40px; + border: 1px solid #ccc; + border-radius: 5px; } @@ -54,12 +63,11 @@ border: solid 1px #ddd; border-top: none; border-bottom: none; - visibility: hidden; + visibility: inherit; flex: 1; position: absolute; width: 100%; - box-shadow: rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px; } @@ -401,13 +409,15 @@ drop.appendChild(result_entry); } + var scroll_restrictor = document.getElementById("scroll_restrictor"); + if( !drop.firstChild ) { - drop.style.visibility = 'hidden'; + scroll_restrictor.style.visibility = 'hidden'; } else { - drop.style.visibility = 'inherit'; + scroll_restrictor.style.visibility = 'inherit'; } } @@ -423,7 +433,10 @@ } } update_selected_list(); + // clear search bar contents + document.getElementById("user_field").value = ""; document.getElementById("user_field").focus(); + search(""); } function remove_item(item_ref) @@ -473,5 +486,4 @@ added_list.innerHTML = list_html; } - </script> diff --git a/src/templates/dashboard/table.html b/src/templates/dashboard/table.html index b3f4b5f..0a37ded 100644 --- a/src/templates/dashboard/table.html +++ b/src/templates/dashboard/table.html @@ -4,11 +4,12 @@ {% block extrahead %} {{ block.super }} <!-- DataTables CSS --> - <link href="{% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.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-responsive/css/dataTables.responsive.css" %}" rel="stylesheet"> + <link href="{% static "bower_components/datatables.net-responsive-bs4/css/responsive.bootstrap4.min.css" %}" + rel="stylesheet"> {% endblock extrahead %} {% block content %} @@ -34,8 +35,8 @@ {% block extrajs %} <!-- DataTables JavaScript --> - <script src={% static "bower_components/datatables/media/js/jquery.dataTables.min.js" %}></script> - <script src={% static "bower_components/datatables-plugins/integration/bootstrap/3/dataTables.bootstrap.min.js" %}></script> + <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> diff --git a/src/templates/layout.html b/src/templates/layout.html index 378cc63..d37d4f5 100644 --- a/src/templates/layout.html +++ b/src/templates/layout.html @@ -20,7 +20,7 @@ <link href="{% static "bower_components/metisMenu/dist/metisMenu.min.css" %}" rel="stylesheet"> <!-- Custom Fonts --> - <link href="{% static "bower_components/font-awesome/css/font-awesome.min.css" %}" + <link href="{% static "bower_components/Font-Awesome/css/all.min.css" %}" rel="stylesheet" type="text/css"> <!-- Favicon --> @@ -50,17 +50,12 @@ {#<!-- jQuery -->#} {#<script src="{% static "bower_components/jquery/dist/jquery.min.js" %}"></script>#} {#<script src="{% static "bower_components/jquery-migrate/jquery-migrate.min.js" %}"></script>#} - +<!-- Popper.js --> +<script src="{% static "bower_components/popper.js/dist/umd/popper.min.js" %}"></script> {#<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>#} <!-- Bootstrap Core JavaScript --> <script src="{% static "bower_components/bootstrap/dist/js/bootstrap.min.js" %}"></script> -<!-- Metis Menu Plugin JavaScript --> -<script src="{% static "bower_components/metisMenu/dist/metisMenu.min.js" %}"></script> - -<!-- Custom Theme JavaScript --> -<script src="{% static "bower_components/startbootstrap-sb-admin-2-blackrockdigital/dist/js/sb-admin-2.js" %}"></script> - {% block extrajs %} {% endblock extrajs %} </body> diff --git a/src/templates/notifier/inbox.html b/src/templates/notifier/inbox.html index 4184d1d..72207ed 100644 --- a/src/templates/notifier/inbox.html +++ b/src/templates/notifier/inbox.html @@ -6,97 +6,124 @@ {% block content %} <style media="screen"> - - .inbox-panel { - display: grid; - grid-template-columns: 30% 5% 65%; - } - - .section-panel { - padding: 10px; - } - - .iframe-panel { - padding: 0px; - margin-top: 0px; - } - - .card-container { - border: 1px solid #cccccc; - border-bottom: 0px; - } - .card { - height: 50px; - position: relative; - border-bottom: 1px solid #cccccc; - padding: 10px; - width: 100%; - background-color: #ffffff; - z-index: 5; - } - .selected-card { - background-color: #f3f3f3; - } - - .card:hover { - box-shadow: 0px 0 5px 2px #cccccc; - z-index: 6; - } - - #inbox-iframe { - height: calc(100vh - 57px); - } - - .half_width { - width: 50%; - } - .card-wrapper { - } - - #page-wrapper{ - padding: 0px; - } - - .read_notification{ - background-color: #efefef; - } + .inbox-panel { + display: grid; + grid-template-columns: 30% 5% 65%; + } + + .section-panel { + padding: 10px; + } + + .iframe-panel { + padding: 0px; + margin-top: 0px; + } + + .card-container { + border: 1px solid #cccccc; + border-bottom: 0px; + } + + .card { + height: 50px; + position: relative; + border-bottom: 1px solid #cccccc; + padding: 10px; + width: 100%; + background-color: #ffffff; + z-index: 5; + } + + .selected-card { + background-color: #f3f3f3; + } + + .card:hover { + box-shadow: 0px 0 5px 2px #cccccc; + z-index: 6; + } + + .half_width { + width: 50%; + } + + #page-wrapper { + padding: 0px; + } + + .read_notification { + background-color: #efefef; + } + + .scrollable { + overflow-y: auto; + } </style> - -<div class="inbox-panel"> - <div class="section-panel"> - <h4>New:</h4> - <div class="card-container"> - {% for notification in unread_notifications %} - <div class="inbox-entry card" onclick="showmessage({{notification.id}}); setactive(this);"> - {{ notification }} +<div class="container-fluid d-flex flex-grow-1 flex-column"> + <div class="row mt-3 mb-2"> + <div class="col-2 px-0"> + <div class="btn-group w-100" id="filterGroup"> + <button class="btn btn-secondary active" data-read="-1">All</button> + <button class="btn btn-secondary" data-read="0">Unread</button> + <button class="btn btn-secondary" data-read="1">Read</button> + </div> </div> - {% endfor %} </div> - <h4>Read:</h4> - <div class="card-container"> - {% for notification in read_notifications %} - <div class="inbox-entry card read_notification" onclick="showmessage({{notification.id}}); setactive(this);"> - {{ notification }} + <div class="row flex-grow-1" id="fixHeight"> + <!-- Notification list && Controls --> + <div class="mb-2 mb-lg-0 col-lg-2 px-0 mh-100"> + <div class="list-group rounded-0 rounded-left scrollable mh-100 notifications" id="unreadNotifications" data-read="0"> + {% for notification in unread_notifications %} + <a + href="#" + onclick="showmessage({{notification.id}}); setactive(this);" + class="list-group-item list-group-item-action notification"> + {{ notification }} + </a> + {% endfor %} + </div> + <div class="list-group rounded-0 rounded-left scrollable mh-100 notifications" id="readNotifications" data-read="1"> + {% for notification in read_notifications %} + <a + href="#" + onclick="showmessage({{notification.id}}); setactive(this);" + class="list-group-item list-group-item-action list-group-item-secondary notification"> + {{ notification }} + </a> + {% endfor %} + </div> + </div> + <!-- Content --> + <div class="col ml-lg-2 border mh-100 p-4"> + <iframe class="w-100 h-100" id="inbox-iframe" frameBorder="0" scrolling="yes">Please select a notification</iframe> </div> - {% endfor %} </div> - </div> - <div> - </div> - <div class="iframe-panel inbox-expanded-view"> - <div class="inbox-iframe-div"> - <iframe id="inbox-iframe" frameBorder="0" width="100%" height="100vh" scrolling="yes">Please select a notification</iframe> - </div> - </div> </div> <script type="text/javascript"> - - function showmessage(msg_id) - { - iframe = document.getElementById("inbox-iframe"); - iframe.src = "notification/" + msg_id; - } - + function showmessage(msg_id) { + iframe = document.getElementById("inbox-iframe"); + iframe.src = "notification/" + msg_id; + } + + function setactive(obj) { + $(".notification").removeClass("active"); + $(obj).addClass("active"); + } + + $(document).ready(function(){ + // For all / unread / read + $("#filterGroup button").click(function(){ + let read = $(this).attr("data-read"); + $(this).siblings().removeClass("active"); + $(".notifications").addClass("d-none"); + $(this).addClass("active"); + if (read === "-1") { + return $(".notifications").removeClass("d-none"); + } + $(`.notifications[data-read="${read}"]`).removeClass("d-none"); + }); + }); </script> -{% endblock %} +{% endblock %}
\ No newline at end of file diff --git a/src/templates/resource/hostprofile_detail.html b/src/templates/resource/hostprofile_detail.html index 0776b9e..dc20600 100644 --- a/src/templates/resource/hostprofile_detail.html +++ b/src/templates/resource/hostprofile_detail.html @@ -4,45 +4,35 @@ {% block content %} <div class="row"> <div class="col-lg-6"> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> + <div class="card mb-4"> + <div class="card-header d-flex"> <h4 style="display: inline;">Available at</h4> - <a data-toggle="collapse" data-target="#panel_overview" class="btn pull-right" style="line-height: 1;" >Expand</a> + <button data-toggle="collapse" data-target="#avilableAt" class="btn ml-auto btn-outline-secondary">Expand</button> </div> - <div class="panel-body" id="panel_overview"> - <table class="table"> - <tr> - <td> - <ul> - {% for lab in hostprofile.labs.all %} - <li>{{lab.name}}</li> - {% endfor %} - </ul> - </td> - </tr> - </table> + <div class="card-body collapse show" id="avilableAt"> + <ul class="list-group"> + {% for lab in hostprofile.labs.all %} + <li class="list-group-item">{{lab.name}}</li> + {% endfor %} + </ul> </div> </div> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> + <div class="card mb-4"> + <div class="card-header d-flex"> <h4 style="display: inline;">RAM</h4> - <a data-toggle="collapse" data-target="#panel_overview" class="btn pull-right" style="line-height: 1;" >Expand</a> + <button data-toggle="collapse" data-target="#ramPanel" class="btn ml-auto btn-outline-secondary">Expand</button> </div> - <div class="panel-body" id="panel_overview"> - <table class="table"> - <tr> - <td>{{hostprofile.ramprofile.first.amount}}G, - {{hostprofile.ramprofile.first.channels}} channels</td> - </tr> - </table> + <div class="card-body collapse show" id="ramPanel"> + {{hostprofile.ramprofile.first.amount}}G, + {{hostprofile.ramprofile.first.channels}} channels </div> </div> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> + <div class="card mb-4"> + <div class="card-header d-flex"> <h4 style="display: inline;">CPU</h4> - <a data-toggle="collapse" data-target="#panel_overview" class="btn pull-right" style="line-height: 1;" >Expand</a> + <button data-toggle="collapse" data-target="#cpuPanel" class="btn ml-auto btn-outline-secondary">Expand</button> </div> - <div class="panel-body" id="panel_overview"> + <div class="card-body collapse show" id="cpuPanel"> <table class="table"> <tr> <td>Arch:</td> @@ -59,42 +49,12 @@ </table> </div> </div> - </div> - <div class="col-lg-6"> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> - <h4 style="display: inline;">Interfaces</h4> - <a data-toggle="collapse" data-target="#panel_overview" class="btn pull-right" style="line-height: 1;" >Expand</a> - </div> - <div class="panel-body" id="panel_overview"> - <table class="table"> - {% for intprof in hostprofile.interfaceprofile.all %} - <tr> - <td> - <table class="table borderless"> - <tr> - <td>Name:</td> - <td>{{intprof.name}}</td> - </tr> - <tr> - <td>Speed:</td> - <td>{{intprof.speed}}</td> - </tr> - </table> - </td> - </tr> - {% endfor %} - </table> - </div> - </div> - </div> - <div class="col-lg-6"> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> + <div class="card mb-4"> + <div class="card-header d-flex"> <h4 style="display: inline;">Disk</h4> - <a data-toggle="collapse" data-target="#panel_overview" class="btn pull-right" style="line-height: 1;" >Expand</a> + <button data-toggle="collapse" data-target="#diskPanel" class="btn ml-auto btn-outline-secondary">Expand</button> </div> - <div class="panel-body" id="panel_overview"> + <div class="card-body collapse show" id="diskPanel"> <table class="table"> <tr> <td>Size:</td> @@ -112,5 +72,31 @@ </div> </div> </div> + <div class="col-lg-6"> + <div class="card"> + <div class="card-header d-flex"> + <h4 style="display: inline;">Interfaces</h4> + <button data-toggle="collapse" data-target="#interfacePanel" class="btn ml-auto btn-outline-secondary">Expand</button> + </div> + <div class="card-body collapse show" id="interfacePanel"> + <table class="table"> + <thead> + <tr> + <th>Name</th> + <th>Speed</th> + </tr> + </thead> + <tbody> + {% for intprof in hostprofile.interfaceprofile.all %} + <tr> + <td>{{intprof.name}}</td> + <td>{{intprof.speed}}</td> + </tr> + {% endfor %} + </tbody> + </table> + </div> + </div> + </div> </div> {% endblock content %} diff --git a/src/templates/resource/steps/define_hardware.html b/src/templates/resource/steps/define_hardware.html index 9192842..77df5a2 100644 --- a/src/templates/resource/steps/define_hardware.html +++ b/src/templates/resource/steps/define_hardware.html @@ -1,7 +1,7 @@ {% extends "workflow/viewport-element.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} <p>Note that not all labs host every kind of machine. diff --git a/src/templates/resource/steps/host_info.html b/src/templates/resource/steps/host_info.html index 0275727..bbbafdc 100644 --- a/src/templates/resource/steps/host_info.html +++ b/src/templates/resource/steps/host_info.html @@ -1,7 +1,7 @@ {% extends "workflow/viewport-element.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} diff --git a/src/templates/resource/steps/meta_info.html b/src/templates/resource/steps/meta_info.html index da98267..cebd343 100644 --- a/src/templates/resource/steps/meta_info.html +++ b/src/templates/resource/steps/meta_info.html @@ -1,7 +1,7 @@ {% extends "workflow/viewport-element.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} diff --git a/src/templates/resource/steps/pod_definition.html b/src/templates/resource/steps/pod_definition.html index 2cb6257..f8aaa74 100644 --- a/src/templates/resource/steps/pod_definition.html +++ b/src/templates/resource/steps/pod_definition.html @@ -206,7 +206,7 @@ function deleteCell(cellId) { } function newNetworkWindow() { - var innerHtml = 'Name: <input type="text" name="net_name" id="net_name_input" style="margin:5px;"><br>'; + var innerHtml = 'Name: <input type="text" name="net_name" maxlength="100" id="net_name_input" style="margin:5px;"><br>'; innerHtml += '<button style="width: 46%;" onclick="parseNetworkWindow()">Okay</button>'; innerHtml += '<button style="width: 46%;" onclick="currentWindow.destroy();">Cancel</button><br>'; innerHtml += '<div id="current_window_errors"/>'; diff --git a/src/templates/snapshot_workflow/steps/meta.html b/src/templates/snapshot_workflow/steps/meta.html index cc49691..bea475d 100644 --- a/src/templates/snapshot_workflow/steps/meta.html +++ b/src/templates/snapshot_workflow/steps/meta.html @@ -1,7 +1,7 @@ {% extends "workflow/viewport-element.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} <style> diff --git a/src/templates/snapshot_workflow/steps/select_host.html b/src/templates/snapshot_workflow/steps/select_host.html index 27a9238..f438bac 100644 --- a/src/templates/snapshot_workflow/steps/select_host.html +++ b/src/templates/snapshot_workflow/steps/select_host.html @@ -1,7 +1,7 @@ {% extends "workflow/viewport-element.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} diff --git a/src/templates/workflow/confirm.html b/src/templates/workflow/confirm.html index a234a71..c1f3440 100644 --- a/src/templates/workflow/confirm.html +++ b/src/templates/workflow/confirm.html @@ -1,7 +1,7 @@ {% extends "workflow/viewport-element.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} diff --git a/src/templates/workflow/resource_select.html b/src/templates/workflow/resource_select.html index c319ff5..cd04137 100644 --- a/src/templates/workflow/resource_select.html +++ b/src/templates/workflow/resource_select.html @@ -1,7 +1,7 @@ {% extends "workflow/viewport-element.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} diff --git a/src/templates/workflow/viewport-base.html b/src/templates/workflow/viewport-base.html index beea7d2..aa01d7e 100644 --- a/src/templates/workflow/viewport-base.html +++ b/src/templates/workflow/viewport-base.html @@ -1,12 +1,12 @@ {% extends "base.html" %} {% load staticfiles %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% block content %} <style> - .go_btn{ + .go_btn { position: absolute; width: 100px; @@ -14,43 +14,36 @@ height: calc(100% - 170px); } - .go_btn_disabled{ - background-color: #ffffff; + + .go_btn_disabled { + background-color: #ffffff; } - .go_forward{ + + .go_forward { right: 0px; border-left: none; } - .go_back{ + .go_back { left: 251px; border-right: none; } - .btn_wrapper{ + .btn_wrapper { text-align: center; margin-bottom: 5px; } {% if DEBUG %} - - .add_btn_wrapper{ - right: 130px; - top: 10px; - position: absolute; - } + .add_btn_wrapper { + right: 130px; + top: 10px; + position: absolute; + } {% endif %} - - - .options{ - position: absolute; - top: 60px; - right: 20px; - } - #breadcrumbs { margin-bottom: 0; } @@ -59,23 +52,25 @@ margin: 0; } - .step{ + .step { display: inline; padding: 7px; margin: 1px; font-size: 14pt; cursor: default; } + .step:active { -webkit-box-shadow: inherit; box-shadow: inherit; } + .step_active:active { -webkit-box-shadow: inherit; box-shadow: inherit; } - .step_active{ + .step_active { display: inline; padding: 7px; margin: 1px; @@ -85,26 +80,22 @@ border-bottom: 4px solid #41ba78 !important; } - .step_hidden - { + .step_hidden { background: #EFEFEF; color: #999999; } - .step_invalid::after - { + .step_invalid::after { content: " \2612"; color: #CC3300; } - .step_valid::after - { + .step_valid::after { content: " \2611"; color: #41ba78; } - .step_untouched::after - { + .step_untouched::after { content: " \2610"; } @@ -126,55 +117,153 @@ background-color: inherit; } - #breadcrumbs.breadcrumb > li { + #breadcrumbs.breadcrumb>li { border: 1px solid #cccccc; border-left: none; } - #breadcrumbs.breadcrumb > li:first-child { + + #breadcrumbs.breadcrumb>li:first-child { border-left: 1px solid #cccccc; } - #breadcrumbs.breadcrumb > li + li:before { + + #breadcrumbs.breadcrumb>li+li:before { content: ""; width: 0; margin: 0; padding: 0; } -</style> -<button id="gof" onclick="go('next')" class="btn go_btn go_forward">Go Forward</button> -<button id="gob" onclick="go('prev')" class="btn go_btn go_back">Go Back</button> + #topPagination .topcrumb { + flex: 1 1 0; + display: flex; + align-content: center; + justify-content: center; + border: 1px solid #dee2e6; + border-left: none; + } + + .topcrumb > span { + color: #343a40; + cursor: default; + } -<div class="options"> - <button id="cancel_btn" class="btn btn-primary" onclick="cancel_wf()">Cancel</button> + .topcrumb.active > span { + background: #007bff; + color: white; + } + + .topcrumb.disabled > span { + color: #6c757d; + background: #f8f9fa; + } +</style> +<!-- Pagination --> +<div class="row mt-3"> + <div class="col"> + <nav> + <ul class="pagination d-flex flex-row" id="topPagination"> + <li class="page-item flex-shrink-1 page-control"> + <a class="page-link" href="#" id="gob" onclick="go('prev')"> + <i class="fas fa-backward"></i> Back + </a> + </li> + <li class="page-item flex-grow-1 active"> + <a class="page-link disabled" href="#"> + Select <i class="far fa-check-square"></i> + </a> + </li> + <li class="page-item flex-grow-1"> + <a class="page-link disabled" href="#"> + Configure <i class="far fa-square"></i> + </a> + </li> + <li class="page-item flex-grow-1"> + <a class="page-link disabled" href="#"> + Information <i class="far fa-square"></i> + </a> + </li> + <li class="page-item flex-grow-1"> + <a class="page-link disabled" href="#"> + OPNFV <i class="far fa-square"></i> + </a> + </li> + <li class="page-item flex-grow-1"> + <a class="page-link disabled" href="#"> + Confirm <i class="far fa-square"></i> + </a> + </li> + <li class="page-item flex-shrink-1 page-control"> + <a class="page-link text-right" href="#" id="gof" onclick="go('next')"> + Next <i class="fas fa-forward"></i> + </a> + </li> + </ul> + </nav> + </div> +</div> +<!-- Top header --> +<div class="row px-4"> + <div class="col"> + <div id="iframe_header" class="row view-header"> + <div class="col-lg-12 step_header"> + <h1 class="step_title d-inline-block" id="view_title"></h1> + <span class="description text-muted" id="view_desc"></span> + <p class="step_message" id="view_message"></p> + </div> + <script> + function update_description(title, desc) { + document.getElementById("view_title").innerText = title; + document.getElementById("view_desc").innerText = desc; + } + + function update_message(message, stepstatus) { + document.getElementById("view_message").innerText = message; + document.getElementById("view_message").className = "step_message"; + document.getElementById("view_message").classList.add("message_" + stepstatus); + } + </script> + <!-- /.col-lg-12 --> + </div> + </div> + <div class="col-auto align-self-center d-flex"> + <button id="cancel_btn" class="btn btn-danger ml-auto" onclick="cancel_wf()">Cancel</button> + </div> +</div> +<!-- Content here --> +<div class="row d-flex flex-column flex-grow-1"> + <div class="container-fluid d-flex flex-column h-100"> + <div class="row d-flex flex-grow-1 p-4"> + <!-- iframe workflow --> + <div class="col-12 d-flex border flex-grow-1"> + <!-- This was where the iframe went --> + <iframe src="/wf/workflow" class="w-100 h-100" scrolling="yes" id="viewport-iframe" + frameBorder="0"></iframe> + </div> + </div> + </div> </div> <div class="btn_wrapper"> -<ol id="breadcrumbs" class="btn-group breadcrumb"> -</ol> </div> {% csrf_token %} <script type="text/javascript"> - - update_context(); var step = 0; var page_count = 0; var context_data = false; - function go(to) - { + function go(to) { step_on_leave(); request_leave(to); } - function request_leave(to) - { + function request_leave(to) { $.ajax({ type: "GET", url: "/wf/manager/", - beforeSend: function(request) { + beforeSend: function (request) { request.setRequestHeader("X-CSRFToken", - $('input[name="csrfmiddlewaretoken"]').val()); + $('input[name="csrfmiddlewaretoken"]').val()); }, success: function (data) { confirm_permission(to, data); @@ -183,49 +272,44 @@ }); } - function confirm_permission(to, data) - { - if( errors_exist(data) ) - { - var continueanyway = confirm("The current step has errors that will prevent it from saving. Continue anyway?"); - if( !continueanyway ) - { + function confirm_permission(to, data) { + if (errors_exist(data)) { + if (to != "prev") { return; } } - var problem = function() { + var problem = function () { alert("There was a problem"); } //makes an asynch request req = new XMLHttpRequest(); url = "/wf/workflow/?step=" + to; req.open("GET", url, true); - req.onload = function(e) { - if(req.readyState === 4){ - if(req.status < 300){ + req.onload = function (e) { + if (req.readyState === 4) { + if (req.status < 300) { document.getElementById("viewport-iframe").srcdoc = this.responseText; - } else { problem(); } - } else { problem(); } + } else { + problem(); + } + } else { + problem(); + } } req.onerror = problem; req.send(); } - function step_on_leave() - { + function step_on_leave() { document.getElementById("viewport-iframe").contentWindow.step_on_leave(); } - function errors_exist(data) - { + function errors_exist(data) { var stat = data['steps'][data['active']]['valid']; - if( stat >= 100 && stat < 200 ) - { + if (stat >= 100 && stat < 200) { return true; - } - else - { + } else { return false; } } @@ -234,9 +318,9 @@ $.ajax({ type: "GET", url: "/wf/manager/", - beforeSend: function(request) { + beforeSend: function (request) { request.setRequestHeader("X-CSRFToken", - $('input[name="csrfmiddlewaretoken"]').val()); + $('input[name="csrfmiddlewaretoken"]').val()); }, success: function (data) { update_page(data); @@ -244,120 +328,100 @@ }); } - function update_page(data) - { + function update_page(data) { context_data = data; update_breadcrumbs(data); - if(data["workflow_count"] == 1) - { - document.getElementById("cancel_btn").innerText = "Exit Workflow"; - } - else - { - document.getElementById("cancel_btn").innerText = "Return to Parent"; + if (data["workflow_count"] == 1) { + document.getElementById("cancel_btn").innerText = "Exit Workflow"; + } else { + document.getElementById("cancel_btn").innerText = "Return to Parent"; } } function update_breadcrumbs(meta_json) { step = meta_json['active']; page_count = meta_json['steps'].length; - if( step == 0 ) - { - var btn = document.getElementById("gob"); - btn.classList.add("go_btn_disabled"); - btn.disabled = true; - } - else - { - var btn = document.getElementById("gob"); - btn.classList.remove("go_btn_disabled"); - btn.disabled = false; + if (step == 0) { + var btn = document.getElementById("gob"); + btn.classList.add("invisible"); + btn.disabled = true; + } else { + var btn = document.getElementById("gob"); + btn.classList.remove("invisible"); + btn.disabled = false; } - if( step == page_count - 1 ) - { - var btn = document.getElementById("gof"); - btn.classList.add("go_btn_disabled"); - btn.disabled = true; - } - else - { - var btn = document.getElementById("gof"); - btn.classList.remove("go_btn_disabled"); - btn.disabled = false; + if (step == page_count - 1) { + var btn = document.getElementById("gof"); + btn.classList.add("invisible"); + btn.disabled = true; + } else { + var btn = document.getElementById("gof"); + btn.classList.remove("invisible"); + btn.disabled = false; } //remove all children of breadcrumbs so we can redraw - var container = document.getElementById("breadcrumbs"); - while(container.firstChild){ - container.removeChild(container.firstChild); - } - + $("#topPagination").children().not(".page-control").remove(); draw_steps(meta_json); } - function draw_steps(meta_json){ - for( var i = 0; i < meta_json["steps"].length; i++ ) - { + function draw_steps(meta_json) { + for (var i = 0; i < meta_json["steps"].length; i++) { meta_json["steps"][i]["index"] = i; var step_btn = create_step(meta_json["steps"][i], i == meta_json["active"]); - document.getElementById("breadcrumbs").appendChild(step_btn); + $("#topPagination li:last-child").before(step_btn); } } - function create_step(step_json, active){ + function create_step(step_json, active) { var step_dom = document.createElement("li"); - if(active){ - step_dom.className = "step_active"; - - } else{ - step_dom.className = "step"; + // First create the dom object depending on active or not + if (active) { + step_dom.className = "topcrumb active"; + } else { + step_dom.className = "topcrumb"; } - step_dom.appendChild(document.createTextNode(step_json['title'])); + $(step_dom).html(`<span class="d-flex align-items-center justify-content-center text-capitalize w-100">${step_json['title']}</span>`) var code = step_json['valid']; stat = ""; msg = ""; - if( code < 100 ) - { - step_dom.classList.add("step_untouched"); - + if (code < 100) { + $(step_dom).children().first().append("<i class='ml-2 far fa-square'></i>") stat = ""; msg = ""; - } - else if( code < 200 ) - { - step_dom.classList.add("step_invalid"); + } else if (code < 200) { + $(step_dom).children().first().append("<i class='ml-2 fas fa-minus-square'></i>") stat = "invalid"; msg = step_json['message']; - } - else if( code < 300 ) - { - step_dom.classList.add("step_valid"); + } else if (code < 300) { + $(step_dom).children().first().append("<i class='ml-2 far fa-check-square'></i>") stat = "valid"; msg = step_json['message']; } - if( step_json['enabled'] == false ) - { - step_dom.classList.add("step_hidden"); + if (step_json['enabled'] == false) { + step_dom.classList.add("disabled"); } - if(active) - { + if (active) { update_message(msg, stat); } - step_dom.classList.add("btn"); var step_number = step_json['index']; return step_dom; } - function cancel_wf(){ + function cancel_wf() { var form = $("#workflow_pop_form"); var formData = form.serialize(); var req = new XMLHttpRequest(); req.open("POST", "/wf/workflow/finish/", false); req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); - req.onerror = function() { alert("problem occurred while trying to cancel current workflow"); } - req.onreadystatechange = function() { if(req.readyState === 4){ - refresh_iframe(); - }}; + req.onerror = function () { + alert("problem occurred while trying to cancel current workflow"); + } + req.onreadystatechange = function () { + if (req.readyState === 4) { + refresh_iframe(); + } + }; req.send(formData); } @@ -365,43 +429,45 @@ req = new XMLHttpRequest(); url = "/wf/workflow/"; req.open("GET", url, true); - req.onload = function(e) { + req.onload = function (e) { var doc = document.getElementById("viewport-iframe").contentWindow.document; - doc.open(); doc.write(this.responseText); doc.close(); + doc.open(); + doc.write(this.responseText); + doc.close(); } req.send(); } - function write_iframe(contents) - { - document.getElementById("viewport-iframe").contentWindow.document.innerHTML= contents; + function write_iframe(contents) { + document.getElementById("viewport-iframe").contentWindow.document.innerHTML = contents; } - function redirect_root() - { + function redirect_root() { window.location.replace('/wf/'); } - function add_wf(type){ + function add_wf(type) { add_wf_internal(type, false); } - function add_edit_wf(type, target){ + function add_edit_wf(type, target) { add_wf_internal(type, target); } - function add_wf_internal(type, itemid){ - data = {"add": type}; - if(itemid){ + function add_wf_internal(type, itemid) { + data = { + "add": type + }; + if (itemid) { data['target'] = itemid; } $.ajax({ type: "POST", url: "/wf/manager/", data: data, - beforeSend: function(request) { + beforeSend: function (request) { request.setRequestHeader("X-CSRFToken", - $('input[name="csrfmiddlewaretoken"]').val() + $('input[name="csrfmiddlewaretoken"]').val() ); }, success: refresh_wf_iframe() @@ -409,66 +475,12 @@ } function refresh_wf_iframe() { - window.location=window.location; + window.location = window.location; } </script> -<div id="iframe_header" class="row view-header"> - <div class="col-lg-12 step_header"> - <h1 class="step_title" id="view_title"></h1> - <p class="description" id="view_desc"></p> - <p class="step_message" id="view_message"></p> - </div> - <style> - #view_desc{ - margin-bottom: 15px; - margin-top: 5px; - margin-left: 30px; - display: inline; - } - #view_title{ - margin-top: 5px; - margin-bottom: 0px; - display: inline; - } - #view_message{ - margin-top: 10px; - margin-bottom: 5px; - float: right; - } - .message_invalid{ - color: #ff4400; - } - .message_valid{ - color: #44cc00; - } - .step_header{ - border-bottom: 1px solid #eee; - border-top: 1px solid #eee; - left: 101px; - width: calc(100% - 202px); - } - </style> - <script> - function update_description(title, desc){ - document.getElementById("view_title").innerText = title; - document.getElementById("view_desc").innerText = desc; - } - function update_message(message, stepstatus){ - document.getElementById("view_message").innerText = message; - document.getElementById("view_message").className = "step_message"; - document.getElementById("view_message").classList.add("message_" + stepstatus); - } - - </script> - <!-- /.col-lg-12 --> -</div> <div style="display: none;" id="workflow_pop_form_div"> -<form id="workflow_pop_form" action="/wf/workflow/finish/" method="post"> - {% csrf_token %} -</form> -</div> - -<div class="iframe_div"> - <iframe src="/wf/workflow" class="iframe_elem" scrolling="yes" id="viewport-iframe"></iframe> + <form id="workflow_pop_form" action="/wf/workflow/finish/" method="post"> + {% csrf_token %} + </form> </div> -{% endblock content %} +{% endblock content %}
\ No newline at end of file diff --git a/src/templates/workflow/viewport-element.html b/src/templates/workflow/viewport-element.html index f25e644..7a7165a 100644 --- a/src/templates/workflow/viewport-element.html +++ b/src/templates/workflow/viewport-element.html @@ -1,5 +1,5 @@ {% extends "layout.html" %} -{% load bootstrap3 %} +{% load bootstrap4 %} {% load staticfiles %} {% block basecontent %} diff --git a/src/workflow/workflow_manager.py b/src/workflow/workflow_manager.py index 26f926e..80b8a67 100644 --- a/src/workflow/workflow_manager.py +++ b/src/workflow/workflow_manager.py @@ -97,7 +97,13 @@ class SessionManager(): def post_render(self, request): return self.active_workflow().steps[self.active_workflow().active_index].post_render(request) + def get_active_step(self): + return self.active_workflow().steps[self.active_workflow().active_index] + def go_next(self, **kwargs): + # need to verify current step is valid to allow this + if self.get_active_step().valid < 200: + return next_step = self.active_workflow().active_index + 1 if next_step >= len(self.active_workflow().steps): raise Exception("Out of bounds request for step") |