+.PHONY: build dev-up dev-start dev-stop up start stop data shell-nginx shell-web shell-db log-nginx log-web log-ps log-rmq log-worker
+
build:
docker-compose -f docker-compose.yml -f docker-compose.override-dev.yml build
box-shadow: 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(109, 243, 76, 0.6);
transition: border-color ease-in-out .1s,box-shadow ease-in-out .1s;
}
-#grid_wrapper > .row > div:first-child {
- border-right: 1px solid gray;
-}
/* Cursor effects */
.not-allowed {
top: 0;
}
-/* Dropdown for collaborators */
-#drop_results {
- max-height: 10rem;
+.z-2 {
z-index: 2;
}
-#drop_results > li {
- word-wrap: anywhere;
+.mh-30vh {
+ max-height: 30vh;
+}
+
+.overflow-ellipsis {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
}
/* Graphing for networks */
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;
}
}
<form id="quick_booking_form" action="/booking/quick/" method="POST" class="form">
{% csrf_token %}
<div class="container-fluid">
- <div class="row">
- <div class="col-12 px-1 my-2">
- <div class="col py-2 rounded border">
- <p>Please select a host type you wish to book. Only available types are shown.</p>
- {% bootstrap_field form.filter_field show_label=False %}
- </div>
+ <div class="row mx-0 px-0">
+ <div class="col-12 mx-0 px-0 mt-2">
+ <p class="my-0">Please select a host type you wish to book. Only available types are shown.</p>
+ {% bootstrap_field form.filter_field show_label=False %}
</div>
+ </div>
+ <div class="row">
<div class="col-12 col-lg-3 px-1 my-2">
<div class="col border rounded py-2 h-100">
{% bootstrap_field form.purpose %}
var sup_installer_dict = {{installer_filter | safe}};
var sup_scenario_dict = {{scenario_filter | safe}};
- function imageHider() {
+ function imageFilter() {
var drop = document.getElementById("id_image");
-
- hide_dropdown("id_image");
-
var lab_pk = get_selected_value("lab");
var host_pk = get_selected_value("host");
var image_object = sup_image_dict[childNode.value];
if (image_object) //weed out empty option
{
- if (image_object.host_profile == host_pk && image_object.lab == lab_pk) {
- childNode.style.display = "inherit";
- childNode.disabled = false;
- }
+ childNode.disabled = !(image_object.host_profile == host_pk && image_object.lab == lab_pk);
}
}
}
- imageHider();
+ imageFilter();
$('#id_installer').children().hide();
$('#id_scenario').children().hide();
Array.from(document.getElementsByClassName("grid-item-select-btn")).forEach(function (element) {
- element.addEventListener('click', imageHider);
+ element.addEventListener('click', imageFilter);
});
function installerHider() {
<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">
</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>
<p>Note that not all labs host every kind of machine.
As you make your selections, labs and hosts that are not compatible
with your current configuration will become unavailable.</p>
-<h4>NOTE: Only PTL's are able to create multi-node PODs. See <a href="https://google.com">here</a>
+<h4>NOTE: Only PTL's are able to create multi-node PODs. See
+ <a href="https://wiki.opnfv.org/display/INF/Lab-as-a-Service+at+the+UNH-IOL">here</a>
for more details</h4>
-<form id="step_form" method="post">
+<form id="step_form" method="post" class="px-3">
{% csrf_token %}
{{form.filter_field|default:"<p>No Form</p>"}}
</form>