Merge pull request #93: Update section completion and show rule violations
Display rule violations and update section completion flag
This commit is contained in:
		
						commit
						8f290fe2ed
					
				
					 5 changed files with 127 additions and 44 deletions
				
			
		| 
						 | 
				
			
			@ -1,13 +0,0 @@
 | 
			
		|||
.signup
 | 
			
		||||
{
 | 
			
		||||
    height: 200px;
 | 
			
		||||
    width: 400px;
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    left: 50%;
 | 
			
		||||
    margin-left: -150px;
 | 
			
		||||
    width:60%;
 | 
			
		||||
}
 | 
			
		||||
.border
 | 
			
		||||
{
 | 
			
		||||
    border-color:black;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								front/static/css/style.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								front/static/css/style.css
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
.fa-check-square {
 | 
			
		||||
    float: right;
 | 
			
		||||
    color: green;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.fa-exclamation-triangle {
 | 
			
		||||
    float: right;
 | 
			
		||||
    color: orange;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5,6 +5,7 @@
 | 
			
		|||
    <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
			
		||||
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
 | 
			
		||||
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
 | 
			
		||||
    <link rel="stylesheet" href="css/style.css">
 | 
			
		||||
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
 | 
			
		||||
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
 | 
			
		||||
    <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.2.20171210/classList.min.js"></script>
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +54,6 @@
 | 
			
		|||
                                <tr>
 | 
			
		||||
                                    <th>Title</th>
 | 
			
		||||
                                    <th>Date Created</th>
 | 
			
		||||
                                    <th class="d-none d-lg-table-cell">State</th>
 | 
			
		||||
                                    <th class="d-none d-md-table-cell">Date Submitted</th>
 | 
			
		||||
                                    <th>Action</th>
 | 
			
		||||
                                </tr>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,12 +9,6 @@ function getEndpointDomain() {
 | 
			
		|||
    return "https://" + window.location.hostname + ":8444/";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function saveSectionCallback(parsedData, saveButton) {
 | 
			
		||||
    alert(JSON.stringify(parsedData));
 | 
			
		||||
    saveButton.innerHTML = "Save";
 | 
			
		||||
    saveButton.disabled = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function makeAjaxRequest(method, url, callback, optional, payload) {
 | 
			
		||||
    const token = localStorage.getItem("token");
 | 
			
		||||
    const xhr = new XMLHttpRequest();
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +51,45 @@ function makeAjaxRequest(method, url, callback, optional, payload) {
 | 
			
		|||
    xhr.send(payload);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function updateSection(parsedData, saveButton) {
 | 
			
		||||
    const sectionIdStr = "#section-" + parsedData.id + "-";
 | 
			
		||||
    const sectionState = document.querySelector(sectionIdStr + "state");
 | 
			
		||||
    const collapseDiv = document.querySelector(sectionIdStr + "collapse");
 | 
			
		||||
 | 
			
		||||
    // A completed section gets a header icon
 | 
			
		||||
    if (parsedData.completed) {
 | 
			
		||||
        const sectionAlert = collapseDiv.querySelector(".section-alert");
 | 
			
		||||
        console.log(sectionAlert);
 | 
			
		||||
        if (sectionAlert) {
 | 
			
		||||
            collapseDiv.firstChild.removeChild(sectionAlert);
 | 
			
		||||
        }
 | 
			
		||||
        if (parsedData.rule_violations.length === 0) {
 | 
			
		||||
            // Complete with no rule violations
 | 
			
		||||
            sectionState.classList = "fas fa-check-square";
 | 
			
		||||
            collapseDiv.className = "collapse";
 | 
			
		||||
        } else {
 | 
			
		||||
            // Complete but with rule violations
 | 
			
		||||
            sectionState.classList = "fas fa-exclamation-triangle";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const cardFooter = createCardFooter(parsedData.rule_violations);
 | 
			
		||||
    if (collapseDiv.lastElementChild.classList.contains("card-footer")) {
 | 
			
		||||
        collapseDiv.removeChild(collapseDiv.lastElementChild);
 | 
			
		||||
        if (cardFooter) {
 | 
			
		||||
            collapseDiv.appendChild(cardFooter);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        if (cardFooter) {
 | 
			
		||||
            collapseDiv.appendChild(cardFooter);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    saveButton.innerHTML = "Save";
 | 
			
		||||
    saveButton.disabled = false;
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Wraps a Bootstrap form group around a field
 | 
			
		||||
function createFormGroup(sectionIdStr, field) {
 | 
			
		||||
    const inputId = sectionIdStr + field.field_name;
 | 
			
		||||
| 
						 | 
				
			
			@ -164,15 +197,27 @@ function createFormGroup(sectionIdStr, field) {
 | 
			
		|||
    return formGroup;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createCollapsibleCard(sectionIdStr, sectionTitle) {
 | 
			
		||||
function createCollapsibleCard(sectionIdStr, sectionTitle, sectionCompleted, ruleViolations) {
 | 
			
		||||
    // Create card and header
 | 
			
		||||
    const card = document.createElement("div");
 | 
			
		||||
    card.classList.add("card");
 | 
			
		||||
    const cardHeader = document.createElement("div");
 | 
			
		||||
    cardHeader.classList.add("card-header");
 | 
			
		||||
    const sectionState = document.createElement("i");
 | 
			
		||||
    sectionState.id = sectionIdStr + "state";
 | 
			
		||||
 | 
			
		||||
    // A completed section gets a header icon
 | 
			
		||||
    if (sectionCompleted) {
 | 
			
		||||
        if (ruleViolations.length === 0) {
 | 
			
		||||
            sectionState.classList.add("fas", "fa-check-square");
 | 
			
		||||
        } else {
 | 
			
		||||
            sectionState.classList.add("fas", "fa-exclamation-triangle");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Create h2, button. Append button to h2, h2 to header, and header to card
 | 
			
		||||
    const h2 = document.createElement("h2");
 | 
			
		||||
    h2.classList.add("mb-0");
 | 
			
		||||
    const button = document.createElement("button");
 | 
			
		||||
    button.classList.add("btn", "btn-link");
 | 
			
		||||
    button.type = "button";
 | 
			
		||||
| 
						 | 
				
			
			@ -180,43 +225,75 @@ function createCollapsibleCard(sectionIdStr, sectionTitle) {
 | 
			
		|||
    button.setAttribute("data-target", "#" + sectionIdStr + "collapse");
 | 
			
		||||
    button.innerHTML = sectionTitle;
 | 
			
		||||
    h2.appendChild(button);
 | 
			
		||||
    h2.appendChild(sectionState);
 | 
			
		||||
    cardHeader.appendChild(h2);
 | 
			
		||||
    card.appendChild(cardHeader);
 | 
			
		||||
 | 
			
		||||
    return card;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createCollapsibleCardBody(form, type, sectionIdStr, sectionDescription, sectionCompleted) {
 | 
			
		||||
function createCollapsibleCardBody(form, type, sectionIdStr, sectionDescription, sectionCompleted, ruleViolations) {
 | 
			
		||||
    // Create wrapper div
 | 
			
		||||
    const div = document.createElement("div");
 | 
			
		||||
    div.id = sectionIdStr + "collapse";
 | 
			
		||||
    const sectionAlert = document.createElement("div");
 | 
			
		||||
    const collapseDiv = document.createElement("div");
 | 
			
		||||
    collapseDiv.id = sectionIdStr + "collapse";
 | 
			
		||||
    const cardBody = document.createElement("div");
 | 
			
		||||
    cardBody.classList.add("card-body");
 | 
			
		||||
    const sectionAlert = document.createElement("div");
 | 
			
		||||
 | 
			
		||||
    if (sectionCompleted) {
 | 
			
		||||
        div.classList.add("collapse");
 | 
			
		||||
        sectionAlert.classList.add("alert", "alert-success");
 | 
			
		||||
        sectionAlert.innerHTML = "This section is complete";
 | 
			
		||||
        if (ruleViolations.length === 0) {
 | 
			
		||||
            collapseDiv.classList.add("collapse");
 | 
			
		||||
        } else {
 | 
			
		||||
            collapseDiv.classList.add("collapse", "show");
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        div.classList.add("collapse", "show");
 | 
			
		||||
        sectionAlert.classList.add("alert", "alert-danger");
 | 
			
		||||
        sectionAlert.classList.add("alert", "alert-danger", "section-alert");
 | 
			
		||||
        sectionAlert.innerHTML = "This section is not complete";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (type === reportType.EDIT) {
 | 
			
		||||
        div.setAttribute("data-parent", "#editReportAccordion");
 | 
			
		||||
        collapseDiv.setAttribute("data-parent", "#editReportAccordion");
 | 
			
		||||
    } else {
 | 
			
		||||
        div.setAttribute("data-parent", "#newReportAccordion");
 | 
			
		||||
        collapseDiv.setAttribute("data-parent", "#newReportAccordion");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Create card body. Append form to body, body to wrapper div
 | 
			
		||||
    cardBody.appendChild(sectionAlert);
 | 
			
		||||
    cardBody.insertAdjacentHTML("beforeend", sectionDescription);
 | 
			
		||||
    cardBody.appendChild(form);
 | 
			
		||||
    div.appendChild(cardBody);
 | 
			
		||||
    collapseDiv.appendChild(cardBody);
 | 
			
		||||
 | 
			
		||||
    return div;
 | 
			
		||||
    return collapseDiv;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createCardFooter(ruleViolations) {
 | 
			
		||||
    if (ruleViolations.length === 0) {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const cardFooter = document.createElement("div");
 | 
			
		||||
    cardFooter.classList.add("card-footer");
 | 
			
		||||
    const violationMessage = document.createElement("div");
 | 
			
		||||
    violationMessage.classList.add("alert", "alert-danger");
 | 
			
		||||
    const heading = document.createElement("div");
 | 
			
		||||
    heading.innerHTML = "Rule Violations";
 | 
			
		||||
    heading.classList.add("alert-heading");
 | 
			
		||||
    violationMessage.appendChild(heading);
 | 
			
		||||
    violationMessage.appendChild(document.createElement("hr"));
 | 
			
		||||
 | 
			
		||||
    for (let i = 0; i < ruleViolations.length; i++) {
 | 
			
		||||
        let violation = document.createElement("p");
 | 
			
		||||
        let violationLabel = document.createElement("strong");
 | 
			
		||||
        violationLabel.innerHTML = ruleViolations[i].label;
 | 
			
		||||
        violation.appendChild(violationLabel);
 | 
			
		||||
        violation.appendChild(document.createElement("br"));
 | 
			
		||||
        let ruleBreakText = document.createTextNode(ruleViolations[i].rule_break_text);
 | 
			
		||||
        violation.appendChild(ruleBreakText);
 | 
			
		||||
        violationMessage.appendChild(violation);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    cardFooter.appendChild(violationMessage);
 | 
			
		||||
    return cardFooter;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function createReportForm(parsedData, type) {
 | 
			
		||||
| 
						 | 
				
			
			@ -252,16 +329,14 @@ function createReportForm(parsedData, type) {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // Add report title and date
 | 
			
		||||
    const reportTitle = parsedData.title;
 | 
			
		||||
    modalLabel.innerHTML = reportTitle;
 | 
			
		||||
    modalLabel.innerHTML = parsedData.title;
 | 
			
		||||
 | 
			
		||||
    // Traverse the report's sections array
 | 
			
		||||
    const sections = parsedData.sections;
 | 
			
		||||
    for (let i = 0; i < sections.length; i++) {
 | 
			
		||||
        let sectionIdStr = "section-" + sections[i].id + "-";
 | 
			
		||||
        let collapsibleCard = createCollapsibleCard(sectionIdStr, sections[i].title)
 | 
			
		||||
 | 
			
		||||
        // Create a new form with the section key index as id
 | 
			
		||||
        // Create a new form
 | 
			
		||||
        let sectionIdStr = "section-" + sections[i].id + "-";
 | 
			
		||||
        let form = document.createElement("form");
 | 
			
		||||
        form.classList.add("form", "section-form");
 | 
			
		||||
        form.id = sectionIdStr + "form";
 | 
			
		||||
| 
						 | 
				
			
			@ -272,9 +347,11 @@ function createReportForm(parsedData, type) {
 | 
			
		|||
        let fields = sections[i].fields;
 | 
			
		||||
        for (let j = 0; j < fields.length; j++) {
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
            console.log("Field label: " + fields[j].label);
 | 
			
		||||
            console.log("Field type: " + fields[j].field_type);
 | 
			
		||||
            console.log("Field value: " + fields[j].value);
 | 
			
		||||
            */
 | 
			
		||||
 | 
			
		||||
            // Create a form group for each field and add it to the form
 | 
			
		||||
            form.appendChild(createFormGroup(sectionIdStr, fields[j]));
 | 
			
		||||
| 
						 | 
				
			
			@ -288,7 +365,14 @@ function createReportForm(parsedData, type) {
 | 
			
		|||
        form.appendChild(saveButton);
 | 
			
		||||
 | 
			
		||||
        // Create collapsible card body, append form to it, append card to accordion
 | 
			
		||||
        let cardBody = createCollapsibleCardBody(form, type, sectionIdStr, sections[i].html_description, sections[i].completed);
 | 
			
		||||
        let cardBody = createCollapsibleCardBody(form, type, sectionIdStr,
 | 
			
		||||
            sections[i].html_description, sections[i].completed, sections[i].rule_violations);
 | 
			
		||||
        let cardFooter = createCardFooter(sections[i].rule_violations);
 | 
			
		||||
        if (cardFooter) {
 | 
			
		||||
            cardBody.appendChild(cardFooter);
 | 
			
		||||
        }
 | 
			
		||||
        let collapsibleCard = createCollapsibleCard(sectionIdStr, sections[i].title,
 | 
			
		||||
            sections[i].completed, sections[i].rule_violations)
 | 
			
		||||
        collapsibleCard.appendChild(cardBody);
 | 
			
		||||
        accordion.appendChild(collapsibleCard);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -323,9 +407,11 @@ function displayListOfReports(parsedData) {
 | 
			
		|||
            bodyRow.insertCell(0).innerHTML = title;
 | 
			
		||||
            bodyRow.insertCell(1).innerHTML = dateCreated;
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
            let stateCell = bodyRow.insertCell(2);
 | 
			
		||||
            stateCell.innerHTML = state;
 | 
			
		||||
            stateCell.classList.add("d-none", "d-lg-table-cell"); // Column visible only on large displays
 | 
			
		||||
            */
 | 
			
		||||
 | 
			
		||||
            // Create edit/view button
 | 
			
		||||
            let actionButton = document.createElement("button");
 | 
			
		||||
| 
						 | 
				
			
			@ -349,10 +435,10 @@ function displayListOfReports(parsedData) {
 | 
			
		|||
                actionButton.setAttribute("data-target", "#viewReportModal");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let dateSubmittedCell = bodyRow.insertCell(3);
 | 
			
		||||
            let dateSubmittedCell = bodyRow.insertCell(2);
 | 
			
		||||
            dateSubmittedCell.innerHTML = dateSubmitted;
 | 
			
		||||
            dateSubmittedCell.classList.add("d-none", "d-md-table-cell"); // Column visible on medium and larger displays
 | 
			
		||||
            bodyRow.insertCell(4).appendChild(actionButton);
 | 
			
		||||
            bodyRow.insertCell(3).appendChild(actionButton);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        table.style.visibility = "visible";
 | 
			
		||||
| 
						 | 
				
			
			@ -468,7 +554,6 @@ if (newReportForm) {
 | 
			
		|||
        console.log("Payload:\n" + payload);
 | 
			
		||||
        const type = reportType.NEW;
 | 
			
		||||
        makeAjaxRequest("POST", url, createReportForm, type, payload);
 | 
			
		||||
        this.reset();
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -494,7 +579,7 @@ document.addEventListener("submit", function(event) {
 | 
			
		|||
        saveButton.appendChild(document.createTextNode("  Saving..."));
 | 
			
		||||
        const formData = new FormData(event.target);
 | 
			
		||||
        const url = getEndpointDomain() + "api/v1/report/" + event.target.dataset.rid + "/section/" + event.target.dataset.sid;
 | 
			
		||||
        makeAjaxRequest("PUT", url, saveSectionCallback, saveButton, formData);
 | 
			
		||||
        makeAjaxRequest("PUT", url, updateSection, saveButton, formData);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@
 | 
			
		|||
    <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
			
		||||
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
 | 
			
		||||
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
 | 
			
		||||
    <link rel="stylesheet" href="css/style.css">
 | 
			
		||||
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
 | 
			
		||||
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
 | 
			
		||||
    <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.2.20171210/classList.min.js"></script>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue