Merge "Hacking on AJAX"
authorSawyer Bergeron <sbergeron@iol.unh.edu>
Mon, 8 Jul 2019 14:36:23 +0000 (14:36 +0000)
committerGerrit Code Review <gerrit@opnfv.org>
Mon, 8 Jul 2019 14:36:23 +0000 (14:36 +0000)
1  2 
src/static/js/dashboard.js
src/templates/dashboard/multiple_select_filter_widget.html
src/templates/dashboard/searchable_select_multiple.html

  
  form_submission_callbacks = [];  //all runnables will be executed before form submission
  
  ///////////////////
  // Global Functions
  ///////////////////
+ function update_page(response) {
+     if( response.redirect )
+     {
+         window.location.replace(response.redirect);
+         return;
+     }
+     draw_breadcrumbs(response.meta);
+     update_exit_button(response.meta);
+     update_side_buttons(response.meta);
+     $("#formContainer").html(response.content);
+ }
+ function update_side_buttons(meta) {
+     const step = meta.active;
+     const page_count = meta.steps.length;
+     const back_button = document.getElementById("gob");
+     if (step == 0) {
+         back_button.classList.add("disabled");
+         back_button.disabled = true;
+     } else {
+         back_button.classList.remove("disabled");
+         back_button.disabled = false;
+     }
+     const forward_btn = document.getElementById("gof");
+     if (step == page_count - 1) {
+         forward_btn.classList.add("disabled");
+         forward_btn.disabled = true;
+     } else {
+         forward_btn.classList.remove("disabled");
+         forward_btn.disabled = false;
+     }
+ }
+ function update_exit_button(meta) {
+     if (meta.workflow_count == 1) {
+         document.getElementById("cancel_btn").innerText = "Exit Workflow";
+     } else {
+         document.getElementById("cancel_btn").innerText = "Return to Parent";
+     }
+ }
+ function draw_breadcrumbs(meta) {
+     $("#topPagination").children().not(".page-control").remove();
+     for (const i in meta.steps) {
+         const step_btn = create_step(meta.steps[i], i == meta["active"]);
+         $("#topPagination li:last-child").before(step_btn);
+     }
+ }
+ function create_step(step_json, active) {
+     const step_dom = document.createElement("li");
+     // First create the dom object depending on active or not
+     step_dom.className = "topcrumb";
+     if (active) {
+         step_dom.classList.add("active");
+     }
+     $(step_dom).html(`<span class="d-flex align-items-center justify-content-center text-capitalize w-100">${step_json['title']}</span>`)
+     const code = step_json.valid;
+     let stat = "";
+     let msg = "";
+     if (code < 100) {
+         $(step_dom).children().first().append("<i class='ml-2 far fa-square'></i>")
+         stat = "";
+         msg = "";
+     } 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).children().first().append("<i class='ml-2 far fa-check-square'></i>")
+         stat = "valid";
+         msg = step_json.message;
+     }
  
- function updatePage(data){
-     updateBreadcrumbs(data['meta']);
-     $("formContainer").html(data['content']);
+     if (step_json.enabled == false) {
+         step_dom.classList.add("disabled");
+     }
+     if (active) {
+         update_message(msg, stat);
+     }
+     return step_dom;
+ }
+ 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);
  }
  
  function submitStepForm(next_step = "current"){
          "step_form": step_form_data,
          "csrfmiddlewaretoken": $("[name=csrfmiddlewaretoken]").val()
      });
-     console.log(form_data);
      $.post(
          '/workflow/manager/',
          form_data,
-         (data) => updatePage(data),
+         (data) => update_page(data),
          'json'
      ).fail(() => alert("failure"));
  }
@@@ -37,6 -129,58 +129,58 @@@ function run_form_callbacks()
      form_submission_callbacks = [];
  }
  
+ function create_workflow(type) {
+     $.ajax({
+         type: "POST",
+         url: "/workflow/create/",
+         data: {
+             "workflow_type": type
+         },
+         headers: {
+             "X-CSRFToken": $('input[name="csrfmiddlewaretoken"]').val()
+         }
+     }).done(function (data, textStatus, jqXHR) {
+         window.location = "/workflow/";
+     }).fail(function (jqxHR, textstatus) {
+         alert("Something went wrong...");
+     });
+ }
+ function add_workflow(type) {
+     data = $.ajax({
+         type: "POST",
+         url: "/workflow/add/",
+         data: {
+             "workflow_type": type
+         },
+         headers: {
+             "X-CSRFToken": $('input[name="csrfmiddlewaretoken"]').val()
+         }
+     }).done(function (data, textStatus, jqXHR) {
+         update_page(data);
+     }).fail(function (jqxHR, textstatus) {
+         alert("Something went wrong...");
+     });
+ }
+ function pop_workflow() {
+     data = $.ajax({
+         type: "POST",
+         url: "/workflow/pop/",
+         headers: {
+             "X-CSRFToken": $('input[name="csrfmiddlewaretoken"]').val()
+         }
+     }).done(function (data, textStatus, jqXHR) {
+         update_page(data);
+     }).fail(function (jqxHR, textstatus) {
+         alert("Something went wrong...");
+     });
+ }
+ function continue_workflow() {
+     window.location.replace("/workflow/");
+ }
  ///////////////////
  //Class Definitions
  ///////////////////
@@@ -1092,13 -1236,12 +1236,13 @@@ class SearchableSelectMultipleWidget 
  
          for( const id in ids )
          {
 -            const result_entry = document.createElement("li");
 -            const result_button = document.createElement("a");
              const obj = this.items[id];
              const result_text = this.generate_element_text(obj);
 -            result_entry.classList.add("list-group-item", "list-group-item-action");
 +            const result_entry = document.createElement("a");
 +            result_entry.href = "#";
              result_entry.innerText = result_text;
 +            result_entry.title = result_text;
 +            result_entry.classList.add("list-group-item", "list-group-item-action", "overflow-ellipsis", "flex-shrink-0");
              result_entry.onclick = function() { searchable_select_multiple_widget.select_item(obj.id); };
              const tooltip = document.createElement("span");
              const tooltiptext = document.createTextNode(result_text);
              added_list.removeChild(added_list.firstChild);
          }
  
 -        let list_html = "";
 +        const list_html = document.createElement("div");
 +        list_html.classList.add("list-group");
  
          for( const item_id of this.added_items )
          {
 -            const item = this.items[item_id];
 +            const times = document.createElement("li");
 +            times.classList.add("fas", "fa-times");
 +
 +            const deleteButton = document.createElement("a");
 +            deleteButton.href = "#";
 +            deleteButton.innerHTML = "<i class='fas fa-times'></i>"
 +            // Setting .onclick/.addEventListener does not work,
 +            // which is why I took the setAttribute approach
 +            // If anyone knows why, please let me know :]
 +            deleteButton.setAttribute("onclick", `searchable_select_multiple_widget.remove_item(${item_id});`);
 +            deleteButton.classList.add("btn");
 +            const deleteColumn = document.createElement("div");
 +            deleteColumn.classList.add("col-auto");
 +            deleteColumn.append(deleteButton);
  
 +            const item = this.items[item_id];
              const element_entry_text = this.generate_element_text(item);
 +            const textColumn = document.createElement("div");
 +            textColumn.classList.add("col", "overflow-ellipsis");
 +            textColumn.innerText = element_entry_text;
 +            textColumn.title = element_entry_text;
 +
 +            const itemRow = document.createElement("div");
 +            itemRow.classList.add("list-group-item", "d-flex", "p-0", "align-items-center");
 +            itemRow.append(textColumn, deleteColumn);
  
 -            list_html += '<div class="border rounded mt-2 w-100 d-flex align-items-center pl-2">'
 -                + element_entry_text
 -                + '<button onclick="searchable_select_multiple_widget.remove_item('
 -                + item_id
 -                + ')" class="btn btn-danger ml-auto">Remove</button>';
 -            list_html += '</div>';
 +            list_html.append(itemRow);
          }
 -        added_list.innerHTML = list_html;
 +        added_list.innerHTML = list_html.innerHTML;
      }
  }
@@@ -1,18 -1,15 +1,15 @@@
- <script src="/static/js/dashboard.js">
- </script>
  <input name="filter_field" id="filter_field" type="hidden"/>
 -<div id="grid_wrapper" class="container-fluid p-4">
 -    <div class="row">
 -        {% for object_class, object_list in display_objects %}
 -            <div class="col-12 col-lg d-flex flex-column pt-2 my-2">
 +<div class="row">
 +    {% for object_class, object_list in display_objects %}
 +        <div class="col-12 col-lg-6 d-flex flex-column pt-2 mx-0 px-1">
 +            <div class="col mx-0 border rounded py-2 flex-grow-1 d-flex flex-column">
                  <div class="w-100">
                      <h4 class="text-capitalize">{{object_class}}</h4>
                  </div>
 -                <div id="{{object_class}}" class="row h-100">
 +                <div id="{{object_class}}" class="row flex-grow-1">
                  {% for obj in object_list %}
 -                    <div class="col-12 col-md-6 col-xl-4 my-2">
 -                        <div id="{{ obj.id|default:'not_provided' }}" class="card h-100" onclick="multi_filter_widget.processClick('{{obj.id}}');">
 +                    <div class="col-12 col-md-6 col-xl-4 my-2 d-flex flex-grow-1">
 +                        <div id="{{ obj.id|default:'not_provided' }}" class="card flex-grow-1">
                              <div class="card-header">
                                  <p class="h5 font-weight-bold mt-2">{{obj.name}}</p>
                              </div>
                                  <p class="grid-item-description">{{obj.description}}</p>
                              </div>
                              <div class="card-footer">
 -                                <button type="button" class="btn btn-success grid-item-select-btn w-100">{% if obj.multiple %}Add{% else %}Select{% endif %}</button>
 +                                <button type="button" class="btn btn-success grid-item-select-btn w-100 stretched-link"
 +                                        onclick="multi_filter_widget.processClick('{{obj.id}}');">
 +                                    {% if obj.multiple %}
 +                                        Add
 +                                    {% else %}
 +                                        Select
 +                                    {% endif %}
 +                                </button>
                              </div>
                          </div>
                      </div>
                  {% endfor %}
                  </div>
              </div>
 -        {% endfor %}
 -    </div>
 +        </div>
 +    {% endfor %}
  </div>
  
  <div id="dropdown_wrapper" class="px-3 list-group-flush w-25 mt-2">
@@@ -1,5 -1,3 +1,3 @@@
- <script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
- <script src="/static/js/dashboard.js"></script>
  <div id="search_select_outer" class="d-flex flex-column">
      {% if incompatible == "true" %}
          <div class="alert alert-danger" role="alert">
@@@ -27,7 -25,7 +25,7 @@@
      </input>
  
      <div id="scroll_restrictor" class="d-flex pb-4 position-relative">
 -        <ul id="drop_results" class="list-group w-100 overflow-auto position-absolute"></ul>
 +        <div id="drop_results" class="list-group w-100 z-2 overflow-auto position-absolute mh-30vh"></div>
      </div>
  </div>