aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSawyer Bergeron <sbergeron@iol.unh.edu>2022-12-16 22:08:06 +0000
committerGerrit Code Review <gerrit@opnfv.org>2022-12-16 22:08:06 +0000
commit8ddc7e820e120f1dde4e901d3cb6f1dd3f281e65 (patch)
treeb8251f8703550bbdce86239364749025aafccbb8
parent1773e2b7fc4564e693dfbf29074374379ed86ebb (diff)
parent4edb8881357e043fd7ea15efeb2d592c9fb55efc (diff)
Merge "Laas Dashboard Front End Improvements"
-rw-r--r--src/api/tests/test_models_unittest.py2
-rw-r--r--src/booking/forms.py1
-rw-r--r--src/resource_inventory/resource_manager.py2
-rw-r--r--src/static/js/dashboard.js14
-rw-r--r--src/templates/base/resource/steps/pod_definition.html41
-rw-r--r--src/templates/base/workflow/confirm.html8
-rw-r--r--src/templates/base/workflow/viewport-base.html4
-rw-r--r--src/workflow/forms.py16
-rw-r--r--src/workflow/models.py14
-rw-r--r--src/workflow/resource_bundle_workflow.py35
-rw-r--r--src/workflow/workflow_manager.py2
11 files changed, 85 insertions, 54 deletions
diff --git a/src/api/tests/test_models_unittest.py b/src/api/tests/test_models_unittest.py
index 2a6fa0b..2dee29b 100644
--- a/src/api/tests/test_models_unittest.py
+++ b/src/api/tests/test_models_unittest.py
@@ -116,7 +116,7 @@ class ValidBookingCreatesValidJob(TestCase):
count = hostprofile.interfaceprofile.all().count()
for i in range(count):
network_struct.append([])
- while(nets):
+ while (nets):
index = len(nets) % count
network_struct[index].append(nets.pop())
diff --git a/src/booking/forms.py b/src/booking/forms.py
index ff829b2..9c9b053 100644
--- a/src/booking/forms.py
+++ b/src/booking/forms.py
@@ -19,6 +19,7 @@ from booking.lib import get_user_items, get_user_field_opts
class QuickBookingForm(forms.Form):
+ # Django Form class for Express Booking
purpose = forms.CharField(max_length=1000)
project = forms.CharField(max_length=400)
hostname = forms.CharField(required=False, max_length=400)
diff --git a/src/resource_inventory/resource_manager.py b/src/resource_inventory/resource_manager.py
index 52af824..16c106e 100644
--- a/src/resource_inventory/resource_manager.py
+++ b/src/resource_inventory/resource_manager.py
@@ -176,7 +176,7 @@ class ResourceManager:
vlan_manager = template.lab.vlan_manager
for net_name, vlan_id in vlans.items():
net = Network.objects.get(name=net_name, bundle=template)
- if(net.is_public):
+ if (net.is_public):
vlan_manager.release_public_vlan(vlan_id)
else:
vlan_manager.release_vlans(vlan_id)
diff --git a/src/static/js/dashboard.js b/src/static/js/dashboard.js
index e3978e3..a63c71b 100644
--- a/src/static/js/dashboard.js
+++ b/src/static/js/dashboard.js
@@ -41,7 +41,7 @@ function update_side_buttons(meta) {
const step = meta.active;
const page_count = meta.steps.length;
- const back_button = document.getElementById("gob");
+ const back_button = document.getElementById("workflow-nav-back");
if (step == 0) {
back_button.classList.add("disabled");
back_button.disabled = true;
@@ -50,7 +50,7 @@ function update_side_buttons(meta) {
back_button.disabled = false;
}
- const forward_btn = document.getElementById("gof");
+ const forward_btn = document.getElementById("workflow-nav-next");
if (step == page_count - 1) {
forward_btn.classList.add("disabled");
forward_btn.disabled = true;
@@ -120,9 +120,18 @@ function update_description(title, desc) {
}
function update_message(message, stepstatus) {
+ let color_code;
+ if (stepstatus == 'valid') {
+ color_code = 'text-success';
+ } else if (stepstatus == 'invalid') {
+ color_code = 'text-danger';
+ } else {
+ color_code = 'none';
+ }
document.getElementById("view_message").innerText = message;
document.getElementById("view_message").className = "step_message";
document.getElementById("view_message").classList.add("message_" + stepstatus);
+ document.getElementById("view_message").classList.add(color_code);
}
function submitStepForm(next_step = "current"){
@@ -795,6 +804,7 @@ class NetworkStep {
tagged.type = "radio";
tagged.name = "tagged";
tagged.value = "True";
+ tagged.checked = "True";
form.appendChild(tagged);
form.appendChild(document.createTextNode(" Tagged"));
form.appendChild(document.createElement("br"));
diff --git a/src/templates/base/resource/steps/pod_definition.html b/src/templates/base/resource/steps/pod_definition.html
index 83c4fcb..233d995 100644
--- a/src/templates/base/resource/steps/pod_definition.html
+++ b/src/templates/base/resource/steps/pod_definition.html
@@ -39,27 +39,32 @@
</form>
<script>
//gather context data
- let debug = false;
- {% if debug %}
- debug = true;
- {% endif %}
+ try {
+ let debug = false;
+ {% if debug %}
+ debug = true;
+ {% endif %}
- const False = false;
- const True = true;
+ const False = false;
+ const True = true;
- let resources = {{resources|safe}};
- let networks = {{networks|safe}};
+ let resources = {{resources|safe}};
+ let networks = {{networks|safe}};
+
+ network_step = new NetworkStep(
+ debug,
+ resources,
+ networks,
+ document.getElementById('graphContainer'),
+ document.getElementById('outlineContainer'),
+ document.getElementById('toolbarContainer'),
+ document.getElementById('sidebarContainer')
+ );
+ form_submission_callbacks.push(() => network_step.prepareForm());
+ } catch (e) {
+ console.log(e)
+ }
- network_step = new NetworkStep(
- debug,
- resources,
- networks,
- document.getElementById('graphContainer'),
- document.getElementById('outlineContainer'),
- document.getElementById('toolbarContainer'),
- document.getElementById('sidebarContainer')
- );
- form_submission_callbacks.push(() => network_step.prepareForm());
</script>
{% endblock content %}
{% block onleave %}
diff --git a/src/templates/base/workflow/confirm.html b/src/templates/base/workflow/confirm.html
index 2f99a41..bc8e4e3 100644
--- a/src/templates/base/workflow/confirm.html
+++ b/src/templates/base/workflow/confirm.html
@@ -43,16 +43,10 @@
{
select.value = "True";
submitStepForm();
+ pop_workflow();
}
function formcancel()
{
- select.value = "False";
- submitStepForm();
- }
-
- var confirmed = {{confirm_succeeded|default:"false"}};
- if( confirmed )
- {
pop_workflow();
}
</script>
diff --git a/src/templates/base/workflow/viewport-base.html b/src/templates/base/workflow/viewport-base.html
index d9648c2..88229ca 100644
--- a/src/templates/base/workflow/viewport-base.html
+++ b/src/templates/base/workflow/viewport-base.html
@@ -10,7 +10,7 @@
<div class="col">
<nav>
<ul class="pagination d-flex flex-row" id="topPagination">
- <li class="page-item flex-shrink-1 page-control">
+ <li class="page-item flex-shrink-1 page-control" id="workflow-nav-back">
<a class="page-link" href="#" id="gob" onclick="submit_and_go('prev')">
<i class="fas fa-backward"></i> Back
</a>
@@ -20,7 +20,7 @@
<i class="far"></i>
</a>
</li>
- <li class="page-item flex-shrink-1 page-control">
+ <li class="page-item flex-shrink-1 page-control" id="workflow-nav-next">
<a class="page-link text-right" href="#" id="gof" onclick="submit_and_go('next')">
Next <i class="fas fa-forward"></i>
</a>
diff --git a/src/workflow/forms.py b/src/workflow/forms.py
index 9b56f93..62abad6 100644
--- a/src/workflow/forms.py
+++ b/src/workflow/forms.py
@@ -222,7 +222,7 @@ class ResourceSelectorForm(SearchableSelectAbstractForm):
class BookingMetaForm(forms.Form):
-
+ # Django Form class for Book a Pod
length = forms.IntegerField(
widget=NumberInput(
attrs={
@@ -380,7 +380,7 @@ class PodDefinitionForm(forms.Form):
class ResourceMetaForm(forms.Form):
bundle_name = forms.CharField(label="POD Name")
- bundle_description = forms.CharField(label="POD Description", widget=forms.Textarea)
+ bundle_description = forms.CharField(label="POD Description", widget=forms.Textarea, max_length=1000)
class GenericHostMetaForm(forms.Form):
@@ -400,8 +400,12 @@ class NetworkConfigurationForm(forms.Form):
class HostSoftwareDefinitionForm(forms.Form):
-
- host_name = forms.CharField(max_length=200, disabled=False, required=True)
+ # Django Form class for Design a Pod
+ host_name = forms.CharField(
+ max_length=200,
+ disabled=False,
+ required=True
+ )
headnode = forms.BooleanField(required=False, widget=forms.HiddenInput)
def __init__(self, *args, **kwargs):
@@ -441,8 +445,8 @@ class ConfirmationForm(forms.Form):
confirm = forms.ChoiceField(
choices=(
- (True, "Confirm"),
- (False, "Cancel")
+ (False, "Cancel"),
+ (True, "Confirm")
)
)
diff --git a/src/workflow/models.py b/src/workflow/models.py
index 91a216c..e065202 100644
--- a/src/workflow/models.py
+++ b/src/workflow/models.py
@@ -326,11 +326,15 @@ class Confirmation_Step(WorkflowStep):
def get_context(self):
context = super(Confirmation_Step, self).get_context()
context['form'] = ConfirmationForm()
- context['confirmation_info'] = yaml.dump(
- self.repo_get(self.repo.CONFIRMATION),
- default_flow_style=False
- ).strip()
-
+ # Summary of submitted form data shown on the 'confirm' step of the workflow
+ confirm_details = "\nPod:\n Name: '{name}'\n Description: '{desc}'\nLab: '{lab}'".format(
+ name=self.repo_get(self.repo.CONFIRMATION)['resource']['name'],
+ desc=self.repo_get(self.repo.CONFIRMATION)['resource']['description'],
+ lab=self.repo_get(self.repo.CONFIRMATION)['template']['lab'])
+ confirm_details += "\nResources:"
+ for i, device in enumerate(self.repo_get(self.repo.RESOURCE_TEMPLATE_MODELS)['resources']):
+ confirm_details += "\n " + str(device) + ": " + str(self.repo_get(self.repo.CONFIRMATION)['template']['resources'][i]['profile'])
+ context['confirmation_info'] = confirm_details
if self.valid == WorkflowStepStatus.VALID:
context["confirm_succeeded"] = "true"
diff --git a/src/workflow/resource_bundle_workflow.py b/src/workflow/resource_bundle_workflow.py
index a461e9a..4e288b5 100644
--- a/src/workflow/resource_bundle_workflow.py
+++ b/src/workflow/resource_bundle_workflow.py
@@ -14,6 +14,7 @@ from django.core.exceptions import ValidationError
from typing import List
+import re
import json
from xml.dom import minidom
import traceback
@@ -172,7 +173,8 @@ class Define_Hardware(WorkflowStep):
except Exception as e:
print("Caught exception: " + str(e))
traceback.print_exc()
- self.set_invalid(str(e))
+ self.form = None
+ self.set_invalid("Please select a lab.")
class Define_Software(WorkflowStep):
@@ -208,12 +210,15 @@ class Define_Software(WorkflowStep):
hosts_initial = []
configs = self.repo_get(self.repo.RESOURCE_TEMPLATE_MODELS, {}).get("resources")
if configs:
- for config in configs:
+ for i in range(len(configs)):
+ default_name = 'laas-node'
+ if i > 0:
+ default_name = default_name + "-" + str(i + 1)
hosts_initial.append({
- 'host_id': config.id,
- 'host_name': config.name,
- 'headnode': config.is_head_node,
- 'image': config.image
+ 'host_id': configs[i].id,
+ 'host_name': default_name,
+ 'headnode': False,
+ 'image': configs[i].image
})
else:
for host in hostlist:
@@ -248,9 +253,6 @@ class Define_Software(WorkflowStep):
def post(self, post_data, user):
hosts = self.get_host_list()
-
- # TODO: fix headnode in form, currently doesn't return a selected one
- # models['headnode_index'] = post_data.get("headnode", 1)
formset = self.create_hostformset(hosts, data=post_data)
has_headnode = False
if formset.is_valid():
@@ -264,6 +266,17 @@ class Define_Software(WorkflowStep):
host.is_head_node = headnode
host.name = hostname
host.image = image
+ # RFC921: They must start with a letter, end with a letter or digit and have only letters or digits or hyphen as interior characters
+ if bool(re.match("^[A-Za-z0-9-]*$", hostname)) is False:
+ self.set_invalid("Device names must only contain alphanumeric characters and dashes.")
+ return
+ if not hostname[0].isalpha() or not hostname[-1].isalnum():
+ self.set_invalid("Device names must start with a letter and end with a letter or digit.")
+ return
+ for j in range(i):
+ if j != i and hostname == hosts[j].name:
+ self.set_invalid("Devices must have unique names. Please try again.")
+ return
host.save()
if not has_headnode and len(hosts) > 0:
@@ -272,7 +285,7 @@ class Define_Software(WorkflowStep):
self.set_valid("Completed")
else:
- self.set_invalid("Please complete all fields")
+ self.set_invalid("Please complete all fields.")
class Define_Nets(WorkflowStep):
@@ -598,4 +611,4 @@ class Resource_Meta_Info(WorkflowStep):
self.repo_put(self.repo.CONFIRMATION, confirm)
self.set_valid("Step Completed")
else:
- self.set_invalid("Please correct the fields highlighted in red to continue")
+ self.set_invalid("Please complete all fields.")
diff --git a/src/workflow/workflow_manager.py b/src/workflow/workflow_manager.py
index a48efe5..40be9d6 100644
--- a/src/workflow/workflow_manager.py
+++ b/src/workflow/workflow_manager.py
@@ -48,7 +48,7 @@ class SessionManager():
def add_workflow(self, workflow_type=None, **kwargs):
repo = Repository()
- if(len(self.workflows) >= 1):
+ if (len(self.workflows) >= 1):
defaults = self.workflows[-1].repository.get_child_defaults()
repo.set_defaults(defaults)
repo.el[repo.HAS_RESULT] = False