Skip to content

Commit

Permalink
MG-164 - Add input validation to chart modals (absmach#193)
Browse files Browse the repository at this point in the history
* Add input validation

Signed-off-by: felix.gateru <[email protected]>

* Solve conflicts

Signed-off-by: felix.gateru <[email protected]>

* Make uuid pattern accessible to all modals

Signed-off-by: felix.gateru <[email protected]>

* Add max date time

Signed-off-by: felix.gateru <[email protected]>

* Add aggregation to modals

Signed-off-by: felix.gateru <[email protected]>

* Change update interval pattern

Signed-off-by: felix.gateru <[email protected]>

* Make interval pattern global

Signed-off-by: felix.gateru <[email protected]>

* Add aggregation to charts

Signed-off-by: felix.gateru <[email protected]>

* Remove vestigial code

Signed-off-by: felix.gateru <[email protected]>

---------

Signed-off-by: felix.gateru <[email protected]>
  • Loading branch information
felixgateru authored Mar 8, 2024
1 parent adfeca4 commit 21463e5
Show file tree
Hide file tree
Showing 27 changed files with 1,060 additions and 180 deletions.
18 changes: 12 additions & 6 deletions ui/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ var (
domainRelations = []string{"administrator", "editor", "viewer", "member"}
groupRelations = []string{"administrator", "editor", "viewer"}
statusOptions = []string{"all", "enabled", "disabled"}
uuidPattern = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
intervalPattern = "^([0-9][0-9]*[smhd])$"
)

// Service specifies service API.
Expand Down Expand Up @@ -2560,19 +2562,23 @@ func (us *uiService) ViewDashboard(s Session, dashboardID string) ([]byte, error
}

data := struct {
NavbarActive string
CollapseActive string
Charts []Item
Dashboard Dashboard
Breadcrumbs []breadcrumb
Session Session
NavbarActive string
CollapseActive string
Charts []Item
Dashboard Dashboard
Breadcrumbs []breadcrumb
Session Session
UUIDPattern string
IntervalPattern string
}{
dashboardsActive,
dashboardsActive,
charts,
dashboard,
crumbs,
s,
uuidPattern,
intervalPattern,
}

if err := us.tpls.ExecuteTemplate(&btpl, "dashboard", data); err != nil {
Expand Down
25 changes: 25 additions & 0 deletions ui/web/static/js/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -336,3 +336,28 @@ function updateMetadata(layout, savedMetadata) {
}
return upMetadata;
}

// Set dynamic parameters for all the modals
document.addEventListener("DOMContentLoaded", function () {
// Get the current formatted date and time
function formatDateTime(date) {
let formatted = new Date(date.getTime() - date.getTimezoneOffset() * 60000)
.toISOString()
.slice(0, 16);
return formatted;
}

let now = new Date();
let formattedNow = formatDateTime(now);
let startTimes = document.querySelectorAll("#start-time");
let stopTimes = document.querySelectorAll("#stop-time");

// Set the max attribute for the start and stop times
startTimes.forEach(function (startTime) {
startTime.setAttribute("max", formattedNow);
});

stopTimes.forEach(function (stopTime) {
stopTime.setAttribute("max", formattedNow);
});
});
34 changes: 29 additions & 5 deletions ui/web/templates/charts/alarmcountmodal.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,27 @@ <h5 class="modal-title" id="alarmCountModalLabel">Alarm Count Card</h5>
<label for="channel-id" class="form-label">Channel ID</label>
<input
type="text"
pattern="{{ .UUIDPattern }}"
class="form-control mb-3"
name="channel"
id="channel-id"
placeholder="Enter the channel ID"
required
/>
<div class="invalid-feedback">Please enter a valid uuid</div>
</div>
<div class="mb-3">
<label for="thing-id" class="form-label">Thing ID</label>
<input
type="text"
pattern="{{ .UUIDPattern }}"
class="form-control mb-3"
name="thing"
id="thing-id"
placeholder="Enter the thing ID"
required
/>
<div class="invalid-feedback">Please enter a valid uuid</div>
</div>
<div class="mb-3">
<label for="value-name" class="form-label">Value name</label>
Expand All @@ -61,22 +65,26 @@ <h5 class="modal-title" id="alarmCountModalLabel">Alarm Count Card</h5>
<label for="update-interval" class="form-label">Update interval</label>
<input
type="text"
pattern="{{ .IntervalPattern }}"
class="form-control mb-3"
name="updateInterval"
id="update-interval"
placeholder="Enter the update interval in seconds"
placeholder="Enter the update interval, eg. 5s, 10m, 1h, 1d"
required
/>
<div class="invalid-feedback">Please enter a valid interval</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button
type="button"
class="btn body-button"
id="create-alarmCount-button"
class="btn btn-secondary"
id="close-alarmCount-button"
data-bs-dismiss="modal"
>
Close
</button>
<button type="button" class="btn body-button" id="create-alarmCount-button">
Create Chart
</button>
</div>
Expand All @@ -87,7 +95,12 @@ <h5 class="modal-title" id="alarmCountModalLabel">Alarm Count Card</h5>
<script>
// alarm count form
document.getElementById("create-alarmCount-button").addEventListener("click", function () {
let form = document.getElementById("create-alarmCount-form");
const form = document.getElementById("create-alarmCount-form");
if (!form.checkValidity()) {
form.classList.add("was-validated");
return;
}

// Create an object to store the form data
let chartData = {};
let formData = new FormData(form);
Expand All @@ -100,6 +113,17 @@ <h5 class="modal-title" id="alarmCountModalLabel">Alarm Count Card</h5>
chartData["Type"] = "alarmCount";
addWidget(chartData, widgetID);
metadataBuffer[widgetID] = chartData;

form.reset();
form.classList.remove("was-validated");

bootstrap.Modal.getInstance(document.getElementById("alarmCountModal")).hide();
});

document.getElementById("close-alarmCount-button").addEventListener("click", function () {
const form = document.getElementById("create-alarmCount-form");
form.reset();
form.classList.remove("was-validated");
});
</script>
{{ end }}
33 changes: 28 additions & 5 deletions ui/web/templates/charts/alarmstablemodal.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,27 @@ <h5 class="modal-title" id="alarmsTableModalLabel">Alarms Table</h5>
<label for="channel-id" class="form-label">Channel ID</label>
<input
type="text"
pattern="{{ .UUIDPattern }}"
class="form-control mb-3"
name="channel"
id="channel-id"
placeholder="Enter the channel ID"
required
/>
<div class="invalid-feedback">Please enter a valid uuid</div>
</div>
<div class="mb-3">
<label for="thing-id" class="form-label">Thing IDs</label>
<input
type="text"
pattern="{{ .UUIDPattern }}"
class="form-control mb-3"
name="thing"
id="thing-id"
placeholder="Enter the thing IDs"
required
/>
<div class="invalid-feedback">Please enter a valid uuid</div>
</div>
<div class="mb-3">
<label for="value-name" class="form-label">Value name</label>
Expand All @@ -61,22 +65,26 @@ <h5 class="modal-title" id="alarmsTableModalLabel">Alarms Table</h5>
<label for="update-interval" class="form-label">Update interval</label>
<input
type="text"
pattern="{{ .IntervalPattern }}"
class="form-control mb-3"
name="updateInterval"
id="update-interval"
placeholder="Enter the update interval in seconds"
placeholder="Enter the update interval, eg. 5s, 10m, 1h, 1d"
required
/>
<div class="invalid-feedback">Please enter a valid interval</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button
type="button"
class="btn body-button"
id="create-alarmsTable-button"
class="btn btn-secondary"
id="close-alarmsTable-button"
data-bs-dismiss="modal"
>
Close
</button>
<button type="button" class="btn body-button" id="create-alarmsTable-button">
Create Chart
</button>
</div>
Expand All @@ -87,7 +95,12 @@ <h5 class="modal-title" id="alarmsTableModalLabel">Alarms Table</h5>
<script>
// alarm table form
document.getElementById("create-alarmsTable-button").addEventListener("click", function () {
let form = document.getElementById("create-alarmsTable-form");
const form = document.getElementById("create-alarmsTable-form");
if (!form.checkValidity()) {
form.classList.add("was-validated");
return;
}

// Create an object to store the form data
let chartData = {};
let formData = new FormData(form);
Expand All @@ -100,6 +113,16 @@ <h5 class="modal-title" id="alarmsTableModalLabel">Alarms Table</h5>
chartData["Type"] = "alarmsTable";
addWidget(chartData, widgetID);
metadataBuffer[widgetID] = chartData;

form.reset();
form.classList.remove("was-validated");
bootstrap.Modal.getInstance(document.getElementById("alarmsTableModal")).hide();
});

document.getElementById("close-alarmsTable-button").addEventListener("click", function () {
const form = document.getElementById("create-alarmCount-form");
form.reset();
form.classList.remove("was-validated");
});
</script>
{{ end }}
66 changes: 57 additions & 9 deletions ui/web/templates/charts/arealinechartmodal.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,23 +68,27 @@ <h5 class="modal-title" id="areaLineChartModalLabel">Area Line Charts</h5>
<label for="channel-id" class="form-label">Channel ID</label>
<input
type="text"
pattern="{{ .UUIDPattern }}"
class="form-control mb-3"
name="channel"
id="channel-id"
placeholder="Enter channel ID"
placeholder="Enter the channel ID"
required
/>
<div class="invalid-feedback">Please enter a valid uuid</div>
</div>
<div class="mb-3">
<label for="thing-id" class="form-label">Thing IDs</label>
<input
type="text"
pattern="{{ .UUIDPattern }}"
class="form-control mb-3"
name="thing"
id="thing-id"
placeholder="Enter the thing IDs"
required
/>
<div class="invalid-feedback">Please enter a valid uuid</div>
</div>
<div class="mb-3">
<label for="value-name" class="form-label">Value names</label>
Expand Down Expand Up @@ -116,6 +120,7 @@ <h5 class="modal-title" id="areaLineChartModalLabel">Area Line Charts</h5>
id="start-time"
required
/>
<div class="invalid-time"></div>
</div>
<div class="mb-3">
<label for="stop-time" class="form-label">Stop time</label>
Expand All @@ -124,18 +129,32 @@ <h5 class="modal-title" id="areaLineChartModalLabel">Area Line Charts</h5>
class="form-control mb-3"
name="stopTime"
id="stop-time"
required
/>
</div>
<div class="mb-3">
<label for="time-interval" class="form-label">Time interval</label>
<label for="update-interval" class="form-label">Update interval</label>
<input
type="text"
pattern="{{ .IntervalPattern }}"
class="form-control mb-3"
name="timeInterval"
id="time-interval"
placeholder="Enter the time interval in seconds"
name="updateInterval"
id="update-interval"
placeholder="Enter the update interval, eg. 5s, 10m, 1h, 1d"
required
/>
<div class="invalid-feedback">Please enter a valid interval</div>
</div>
<div class="mb-3">
<label for="aggregation-type" class="form-label">Aggregation</label>
<select class="form-select mb-3" name="aggregationType" id="aggregation-type">
<option value="" disabled>Select an aggregation type</option>
<option value="MAX">Maximum</option>
<option value="MIN">Minimum</option>
<option value="SUM">Sum</option>
<option value="COUNT">Count</option>
<option value="AVG">Average</option>
</select>
</div>
</div>
<!-- Appearance Tab -->
Expand Down Expand Up @@ -180,13 +199,15 @@ <h5 class="modal-title" id="areaLineChartModalLabel">Area Line Charts</h5>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button
type="button"
class="btn body-button"
id="create-areaLineChart-button"
class="btn btn-secondary"
id="close-areaLineChart-button"
data-bs-dismiss="modal"
>
Close
</button>
<button type="button" class="btn body-button" id="create-areaLineChart-button">
Create Chart
</button>
</div>
Expand All @@ -196,19 +217,46 @@ <h5 class="modal-title" id="areaLineChartModalLabel">Area Line Charts</h5>
<script>
// area line chart form
document.getElementById("create-areaLineChart-button").addEventListener("click", function () {
let form = document.getElementById("create-areaLineChart-form");
const form = document.getElementById("create-areaLineChart-form");
if (!form.checkValidity()) {
form.classList.add("was-validated");
return;
}

// Create an object to store the form data
let chartData = {};
let formData = new FormData(form);
for (var pair of formData.entries()) {
chartData[pair[0]] = pair[1];
}

if (chartData.stopTime <= chartData.startTime) {
const invalidTimeFeedback = form.querySelector(".invalid-time");
invalidTimeFeedback.innerHTML = "Stop time should be greater than start time";
invalidTimeFeedback.style.color = "red";
const invalidTimeInput = form.querySelector("#stop-time");
invalidTimeInput.classList.remove("was-validated");
invalidTimeInput.classList.add("is-invalid");
return;
}

var widgetID = "areaLineChart-" + Date.now();

chartData["Type"] = "areaLineChart";
addWidget(chartData, widgetID);
metadataBuffer[widgetID] = chartData;

form.reset();
form.classList.remove("was-validated");
bootstrap.Modal.getInstance(document.getElementById("areaLineChartModal")).hide();
});

document.getElementById("close-areaLineChart-button").addEventListener("click", function () {
const form = document.getElementById("create-areaLineChart-form");
form.querySelector(".invalid-time").innerHTML = "";
form.querySelector("#stop-time").classList.remove("is-invalid");
form.reset();
form.classList.remove("was-validated");
});
</script>
{{ end }}
Loading

0 comments on commit 21463e5

Please sign in to comment.