aboutsummaryrefslogtreecommitdiffstats
path: root/src/static
diff options
context:
space:
mode:
Diffstat (limited to 'src/static')
-rw-r--r--src/static/css/base.css259
-rw-r--r--src/static/css/detail_view.css39
-rw-r--r--src/static/css/graph_common.css172
-rw-r--r--src/static/js/dashboard.js147
4 files changed, 363 insertions, 254 deletions
diff --git a/src/static/css/base.css b/src/static/css/base.css
index c51728c..9fec97e 100644
--- a/src/static/css/base.css
+++ b/src/static/css/base.css
@@ -1,3 +1,30 @@
+/* Sizing */
+#wrapper {
+ height: 100vh;
+}
+
+/* Used for turning divs into square */
+.square-20 {
+ height: 20px;
+ width: 20px;
+}
+
+/* Make links stay the same color with no underline */
+.discrete-a {
+ text-decoration: none;
+ color: inherit;
+}
+
+.discrete-a:hover {
+ text-decoration: none;
+ color: inherit;
+}
+
+/* Allow for sidebar to be small, but also resize on small screens */
+.sidebar {
+ min-width: 200px;
+}
+
/* Rotating arrows when dropdown happens */
i.fas.rotate {
transition: transform 0.3s ease-in-out;
@@ -6,3 +33,235 @@ i.fas.rotate {
a[aria-expanded="true"] > i.rotate {
transform: rotate(180deg);
}
+/* End rotating arrows */
+
+/* Start breadcrumbs for workflow */
+#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;
+}
+
+.topcrumb.active > span {
+ background: #007bff;
+ color: white;
+}
+
+.topcrumb.disabled > span {
+ color: #6c757d;
+ background: #f8f9fa;
+}
+
+/* Booking Node Styles */
+.selected_node {
+ border-color: #40c640;
+ 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;
+}
+
+/* Cursor effects */
+.not-allowed {
+ cursor: not-allowed;
+}
+
+/* Used with position-absolute class to make a full height object */
+.topToBottom {
+ bottom: 0;
+ top: 0;
+}
+
+.z-2 {
+ z-index: 2;
+}
+
+.mh-30vh {
+ max-height: 30vh;
+}
+
+.overflow-ellipsis {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+/* Graphing for networks */
+div.mxRubberband {
+ position: absolute;
+ overflow: hidden;
+ border-style: solid;
+ border-width: 1px;
+ border-color: #0000FF;
+ background: #0077FF;
+}
+.mxCellEditor {
+ background: url(data:image/gif;base64,R0lGODlhMAAwAIAAAP///wAAACH5BAEAAAAALAAAAAAwADAAAAIxhI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC8fyTNf2jef6zvf+DwwKh8Si8egpAAA7);
+ _background: url('/static/img/mxgraph/transparent.gif');
+ border-color: transparent;
+ border-style: solid;
+ display: inline-block;
+ position: absolute;
+ overflow: visible;
+ word-wrap: normal;
+ border-width: 0;
+ min-width: 1px;
+ resize: none;
+ padding: 0px;
+ margin: 0px;
+}
+.mxPlainTextEditor * {
+ padding: 0px;
+ margin: 0px;
+}
+div.mxWindow {
+ background: url('../img/mxgraph/window.gif');
+ border:1px solid #c3c3c3;
+ position: absolute;
+ overflow: hidden;
+ z-index: 3;
+}
+table.mxWindow {
+ border-collapse: collapse;
+ table-layout: fixed;
+ font-family: Arial;
+ font-size: 8pt;
+}
+td.mxWindowTitle {
+ background: url('/static/img/mxgraph/window-title.gif') repeat-x;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ text-align: center;
+ font-weight: bold;
+ overflow: hidden;
+ height: 13px;
+ padding: 2px;
+ padding-top: 4px;
+ padding-bottom: 6px;
+ color: black;
+}
+td.mxWindowPane {
+ vertical-align: top;
+ padding: 0px;
+}
+div.mxWindowPane {
+ overflow: hidden;
+ position: relative;
+}
+td.mxWindowPane td {
+ font-family: Arial;
+ font-size: 8pt;
+}
+td.mxWindowPane input, td.mxWindowPane select, td.mxWindowPane textarea, td.mxWindowPane radio {
+ font-family: Arial;
+ font-size: 8pt;
+ padding: 1px;
+}
+td.mxWindowPane button {
+ color: #fff;
+ background-color: #337ab7;
+ border-color: #2e6da4;
+ display: inline-block;
+ margin: 2%;
+ font-size: 14px;
+ font-weight: 400;
+ line-height: 1.42857143;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: middle;
+ -ms-touch-action: manipulation;
+ touch-action: manipulation;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ background-image: none;
+ border: 1px solid transparent;
+ border-radius: 4px;
+}
+img.mxToolbarItem {
+ margin-right: 6px;
+ margin-bottom: 6px;
+ border-width: 1px;
+}
+select.mxToolbarCombo {
+ vertical-align: top;
+ border-style: inset;
+ border-width: 2px;
+}
+div.mxToolbarComboContainer {
+ padding: 2px;
+}
+img.mxToolbarMode {
+ margin: 2px;
+ margin-right: 4px;
+ margin-bottom: 4px;
+ border-width: 0px;
+}
+img.mxToolbarModeSelected {
+ margin: 0px;
+ margin-right: 2px;
+ margin-bottom: 2px;
+ border-width: 2px;
+ border-style: inset;
+}
+div.mxTooltip {
+ -webkit-box-shadow: 3px 3px 12px #C0C0C0;
+ -moz-box-shadow: 3px 3px 12px #C0C0C0;
+ box-shadow: 3px 3px 12px #C0C0C0;
+ background: #FFFFCC;
+ border-style: solid;
+ border-width: 1px;
+ border-color: black;
+ font-family: Arial;
+ font-size: 8pt;
+ position: absolute;
+ cursor: default;
+ padding: 4px;
+ color: black;
+}
+div.mxPopupMenu {
+ -webkit-box-shadow: 3px 3px 12px #C0C0C0;
+ -moz-box-shadow: 3px 3px 12px #C0C0C0;
+ box-shadow: 3px 3px 12px #C0C0C0;
+ background: url('/static/img/mxgraph/window.gif');
+ position: absolute;
+ border-style: solid;
+ border-width: 1px;
+ border-color: black;
+}
+table.mxPopupMenu {
+ border-collapse: collapse;
+ margin-top: 1px;
+ margin-bottom: 1px;
+}
+tr.mxPopupMenuItem {
+ color: black;
+ cursor: pointer;
+}
+tr.mxPopupMenuItemHover {
+ background-color: #000066;
+ color: #FFFFFF;
+ cursor: pointer;
+}
+td.mxPopupMenuItem {
+ padding: 2px 30px 2px 10px;
+ white-space: nowrap;
+ font-family: Arial;
+ font-size: 8pt;
+}
+td.mxPopupMenuIcon {
+ background-color: #D0D0D0;
+ padding: 2px 4px 2px 4px;
+}
+.mxDisabled {
+ opacity: 0.2 !important;
+ cursor:default !important;
+}
diff --git a/src/static/css/detail_view.css b/src/static/css/detail_view.css
deleted file mode 100644
index c3d0a4d..0000000
--- a/src/static/css/detail_view.css
+++ /dev/null
@@ -1,39 +0,0 @@
-.card_container {
- display: grid;
- grid-template-columns: 1fr 1fr 1fr 1fr;
- grid-gap: 25px 25px;
- justify-items: stretch;
-}
-
-.card_container ul > li {
- padding: 7px !important;
- font-size: 16px;
-}
-
-.detail_button_container .btn {
- width: 49%;
-}
-
-.detail_button_container .btn-danger {
- float: right;
-}
-
-#modal_warning {
- transition: max-height 0.5s ease-out;
- overflow: hidden;
-}
-
-.detail_card {
- border-radius: 5px;
- border-top: 1px solid #ccc;
- border-left: 1px solid #ccc;
- border-right: 1px solid #ccc;
- border-bottom: 1px solid #ccc;
- margin: 5px;
- padding-left: 25px;
- padding-right: 25px;
- padding-bottom: 15px;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
-}
diff --git a/src/static/css/graph_common.css b/src/static/css/graph_common.css
deleted file mode 100644
index cff1516..0000000
--- a/src/static/css/graph_common.css
+++ /dev/null
@@ -1,172 +0,0 @@
-div.mxRubberband {
- position: absolute;
- overflow: hidden;
- border-style: solid;
- border-width: 1px;
- border-color: #0000FF;
- background: #0077FF;
-}
-.mxCellEditor {
- background: url(data:image/gif;base64,R0lGODlhMAAwAIAAAP///wAAACH5BAEAAAAALAAAAAAwADAAAAIxhI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC8fyTNf2jef6zvf+DwwKh8Si8egpAAA7);
- _background: url('/static/img/mxgraph/transparent.gif');
- border-color: transparent;
- border-style: solid;
- display: inline-block;
- position: absolute;
- overflow: visible;
- word-wrap: normal;
- border-width: 0;
- min-width: 1px;
- resize: none;
- padding: 0px;
- margin: 0px;
-}
-.mxPlainTextEditor * {
- padding: 0px;
- margin: 0px;
-}
-div.mxWindow {
- background: url('../img/mxgraph/window.gif');
- border:1px solid #c3c3c3;
- position: absolute;
- overflow: hidden;
- z-index: 3;
-}
-table.mxWindow {
- border-collapse: collapse;
- table-layout: fixed;
- font-family: Arial;
- font-size: 8pt;
-}
-td.mxWindowTitle {
- background: url('/static/img/mxgraph/window-title.gif') repeat-x;
- text-overflow: ellipsis;
- white-space: nowrap;
- text-align: center;
- font-weight: bold;
- overflow: hidden;
- height: 13px;
- padding: 2px;
- padding-top: 4px;
- padding-bottom: 6px;
- color: black;
-}
-td.mxWindowPane {
- vertical-align: top;
- padding: 0px;
-}
-div.mxWindowPane {
- overflow: hidden;
- position: relative;
-}
-td.mxWindowPane td {
- font-family: Arial;
- font-size: 8pt;
-}
-td.mxWindowPane input, td.mxWindowPane select, td.mxWindowPane textarea, td.mxWindowPane radio {
- font-family: Arial;
- font-size: 8pt;
- padding: 1px;
-}
-td.mxWindowPane button {
- color: #fff;
- background-color: #337ab7;
- border-color: #2e6da4;
- display: inline-block;
- margin: 2%;
- font-size: 14px;
- font-weight: 400;
- line-height: 1.42857143;
- text-align: center;
- white-space: nowrap;
- vertical-align: middle;
- -ms-touch-action: manipulation;
- touch-action: manipulation;
- cursor: pointer;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- background-image: none;
- border: 1px solid transparent;
- border-radius: 4px;
-}
-img.mxToolbarItem {
- margin-right: 6px;
- margin-bottom: 6px;
- border-width: 1px;
-}
-select.mxToolbarCombo {
- vertical-align: top;
- border-style: inset;
- border-width: 2px;
-}
-div.mxToolbarComboContainer {
- padding: 2px;
-}
-img.mxToolbarMode {
- margin: 2px;
- margin-right: 4px;
- margin-bottom: 4px;
- border-width: 0px;
-}
-img.mxToolbarModeSelected {
- margin: 0px;
- margin-right: 2px;
- margin-bottom: 2px;
- border-width: 2px;
- border-style: inset;
-}
-div.mxTooltip {
- -webkit-box-shadow: 3px 3px 12px #C0C0C0;
- -moz-box-shadow: 3px 3px 12px #C0C0C0;
- box-shadow: 3px 3px 12px #C0C0C0;
- background: #FFFFCC;
- border-style: solid;
- border-width: 1px;
- border-color: black;
- font-family: Arial;
- font-size: 8pt;
- position: absolute;
- cursor: default;
- padding: 4px;
- color: black;
-}
-div.mxPopupMenu {
- -webkit-box-shadow: 3px 3px 12px #C0C0C0;
- -moz-box-shadow: 3px 3px 12px #C0C0C0;
- box-shadow: 3px 3px 12px #C0C0C0;
- background: url('/static/img/mxgraph/window.gif');
- position: absolute;
- border-style: solid;
- border-width: 1px;
- border-color: black;
-}
-table.mxPopupMenu {
- border-collapse: collapse;
- margin-top: 1px;
- margin-bottom: 1px;
-}
-tr.mxPopupMenuItem {
- color: black;
- cursor: pointer;
-}
-tr.mxPopupMenuItemHover {
- background-color: #000066;
- color: #FFFFFF;
- cursor: pointer;
-}
-td.mxPopupMenuItem {
- padding: 2px 30px 2px 10px;
- white-space: nowrap;
- font-family: Arial;
- font-size: 8pt;
-}
-td.mxPopupMenuIcon {
- background-color: #D0D0D0;
- padding: 2px 4px 2px 4px;
-}
-.mxDisabled {
- opacity: 0.2 !important;
- cursor:default !important;
-}
diff --git a/src/static/js/dashboard.js b/src/static/js/dashboard.js
index 84c3703..a03dc98 100644
--- a/src/static/js/dashboard.js
+++ b/src/static/js/dashboard.js
@@ -1,3 +1,46 @@
+///////////////////
+// Global Variables
+///////////////////
+
+form_submission_callbacks = []; //all runnables will be executed before form submission
+
+
+///////////////////
+// Global Functions
+///////////////////
+
+function updatePage(data){
+ updateBreadcrumbs(data['meta']);
+ $("formContainer").html(data['content']);
+}
+
+function submitStepForm(next_step = "current"){
+ run_form_callbacks();
+ const step_form_data = $("#step_form").serialize();
+ const form_data = $.param({
+ "step": next_step,
+ "step_form": step_form_data,
+ "csrfmiddlewaretoken": $("[name=csrfmiddlewaretoken]").val()
+ });
+ console.log(form_data);
+ $.post(
+ '/workflow/manager/',
+ form_data,
+ (data) => updatePage(data),
+ 'json'
+ ).fail(() => alert("failure"));
+}
+
+function run_form_callbacks(){
+ for(f of form_submission_callbacks)
+ f();
+ form_submission_callbacks = [];
+}
+
+///////////////////
+//Class Definitions
+///////////////////
+
class MultipleSelectFilterWidget {
constructor(neighbors, items, initial) {
@@ -98,7 +141,7 @@ class MultipleSelectFilterWidget {
select(node) {
const elem = document.getElementById(node['id']);
node['selected'] = true;
- elem.classList.remove('disabled_node', 'cleared_node');
+ elem.classList.remove('bg-white', 'not-allowed', 'bg-light');
elem.classList.add('selected_node');
}
@@ -106,16 +149,16 @@ class MultipleSelectFilterWidget {
const elem = document.getElementById(node['id']);
node['selected'] = false;
node['selectable'] = true;
- elem.classList.add('cleared_node')
- elem.classList.remove('disabled_node', 'selected_node');
+ elem.classList.add('bg-white')
+ elem.classList.remove('not-allowed', 'bg-light', 'selected_node');
}
disable_node(node) {
const elem = document.getElementById(node['id']);
node['selected'] = false;
node['selectable'] = false;
- elem.classList.remove('cleared_node', 'selected_node');
- elem.classList.add('disabled_node');
+ elem.classList.remove('bg-white', 'selected_node');
+ elem.classList.add('not-allowed', 'bg-light');
}
processClick(id){
@@ -173,7 +216,7 @@ class MultipleSelectFilterWidget {
const button = document.createElement("BUTTON");
button.type = "button";
button.appendChild(document.createTextNode("Remove"));
- button.classList.add("btn", "btn-danger");
+ button.classList.add("btn", "btn-danger", "d-inline-block");
const that = this;
button.onclick = function(){ that.remove_dropdown(div.id, node.id); }
return button;
@@ -183,6 +226,7 @@ class MultipleSelectFilterWidget {
const input = document.createElement("INPUT");
input.type = node.form.type;
input.name = node.id + node.form.name
+ input.classList.add("form-control", "w-auto", "d-inline-block");
input.pattern = "(?=^.{1,253}$)(^([A-Za-z0-9-_]{1,62}\.)*[A-Za-z0-9-_]{1,63})";
input.title = "Only alphanumeric characters (a-z, A-Z, 0-9), underscore(_), and hyphen (-) are allowed"
input.placeholder = node.form.placeholder;
@@ -198,7 +242,7 @@ class MultipleSelectFilterWidget {
add_item_prepopulate(node, prepopulate){
const div = document.createElement("DIV");
div.id = "dropdown_" + this.dropdown_count;
- div.classList.add("dropdown_item");
+ div.classList.add("list-group-item");
this.dropdown_count++;
const label = document.createElement("H5")
label.appendChild(document.createTextNode(node['name']))
@@ -756,21 +800,28 @@ class NetworkStep {
}
makeSidebarNetwork(net_name, color, net_id){
- const newNet = document.createElement("li");
const colorBlob = document.createElement("div");
- colorBlob.className = "colorblob";
- const textContainer = document.createElement("p");
- textContainer.className = "network_innertext";
- newNet.id = net_id;
+ colorBlob.className = "square-20 rounded-circle";
+ colorBlob.style['background'] = color;
+
+ const textContainer = document.createElement("span");
+ textContainer.className = "ml-2";
+ textContainer.appendChild(document.createTextNode(net_name));
+
+ const timesIcon = document.createElement("i");
+ timesIcon.classList.add("fas", "fa-times");
+
const deletebutton = document.createElement("button");
- deletebutton.className = "btn btn-danger";
- deletebutton.style = "float: right; height: 20px; line-height: 8px; vertical-align: middle; width: 20px; padding-left: 5px;";
- deletebutton.appendChild(document.createTextNode("X"));
+ deletebutton.className = "btn btn-danger ml-auto square-20 p-0 d-flex justify-content-center";
+ deletebutton.appendChild(timesIcon);
deletebutton.addEventListener("click", function() { this.createDeleteDialog(net_id); }.bind(this), false);
- textContainer.appendChild(document.createTextNode(net_name));
- colorBlob.style['background'] = color;
+
+ const newNet = document.createElement("li");
+ newNet.classList.add("list-group-item", "d-flex", "bg-light");
+ newNet.id = net_id;
newNet.appendChild(colorBlob);
newNet.appendChild(textContainer);
+
if( net_name != "public" ) {
newNet.appendChild(deletebutton);
}
@@ -818,16 +869,9 @@ class NetworkStep {
this.graph.refresh(host);
}
- submitForm() {
- const form = document.getElementById("xml_form");
+ prepareForm() {
const input_elem = document.getElementById("hidden_xml_input");
input_elem.value = this.encodeGraph(this.graph);
- const req = new XMLHttpRequest();
- req.open("POST", "/wf/workflow/", false);
- req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
- req.onerror = function() { alert("problem with form submission"); }
- const formData = $("#xml_form").serialize();
- req.send(formData);
}
}
@@ -1048,18 +1092,19 @@ 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_button.appendChild(document.createTextNode(result_text));
- result_button.onclick = function() { searchable_select_multiple_widget.select_item(obj.id); };
+ 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);
tooltip.appendChild(tooltiptext);
- tooltip.setAttribute('class', 'entry_tooltip');
- result_button.appendChild(tooltip);
- result_entry.appendChild(result_button);
+ tooltip.classList.add("d-none");
+ result_entry.appendChild(tooltip);
drop.appendChild(result_entry);
}
@@ -1112,23 +1157,39 @@ class SearchableSelectMultipleWidget {
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="list_entry">'
- + '<p class="added_entry_text">'
- + element_entry_text
- + '</p>'
- + '<button onclick="searchable_select_multiple_widget.remove_item('
- + item_id
- + ')" class="btn-remove btn">remove</button>';
- list_html += '</div>';
+ list_html.append(itemRow);
}
- added_list.innerHTML = list_html;
+ added_list.innerHTML = list_html.innerHTML;
}
}