From b87ed834f0610d8e8d8c116bbccf8018116cbd7e Mon Sep 17 00:00:00 2001
From: ianmuchyri <ianmuchiri8@gmail.com>
Date: Fri, 24 Nov 2023 14:55:45 +0300
Subject: [PATCH 01/11] add validation errors to js

Signed-off-by: ianmuchyri <ianmuchiri8@gmail.com>
---
 ui/web/static/js/clipboard.js | 91 +++++++++++++++++++++++++++++++++++
 ui/web/template/users.html    | 29 ++++++++---
 2 files changed, 114 insertions(+), 6 deletions(-)

diff --git a/ui/web/static/js/clipboard.js b/ui/web/static/js/clipboard.js
index 4d7b50006..dd8768806 100644
--- a/ui/web/static/js/clipboard.js
+++ b/ui/web/static/js/clipboard.js
@@ -21,3 +21,94 @@ function copyToClipboard(button) {
 		},
 	);
 }
+
+// Form validation functions
+
+function validateName(name, errorDiv, event) {
+	removeErrorMessage(errorDiv);
+	if (name.trim() === "") {
+		event.preventDefault();
+		displayErrorMessage("Name is Required", errorDiv);
+	}
+}
+
+const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
+function validateEmail(email, errorDiv, event) {
+	removeErrorMessage(errorDiv);
+	if (email.trim() === "") {
+		event.preventDefault();
+		displayErrorMessage("Email is Required", errorDiv);
+	} else if (!email.match(emailRegex)) {
+		event.preventDefault();
+		displayErrorMessage("Invalid email format", errorDiv);
+	}
+}
+
+const minLength = 8;
+function validatePassword(password, errorDiv, event) {
+	removeErrorMessage(errorDiv);
+	if (password.trim().length < minLength) {
+		event.preventDefault();
+		var errorMessage = `Password must be at least ${minLength} characters long`;
+		displayErrorMessage(errorMessage, errorDiv);
+	}
+}
+
+function validateMetadata(metadata, errorDiv, event) {
+	removeErrorMessage(errorDiv);
+	try {
+		if (metadata.trim() !== "") {
+			JSON.parse(metadata);
+		}
+	} catch (error) {
+		event.preventDefault();
+		displayErrorMessage("Metadata is not a valid JSON object", errorDiv);
+	}
+}
+
+function validateTags(tags, errorDiv, event) {
+	removeErrorMessage(errorDiv);
+	var tagsArray;
+	try {
+		if (tags.trim() !== "") {
+			tagsArray = JSON.parse(tags);
+		}
+	} catch (error) {
+		event.preventDefault();
+		displayErrorMessage("tags must be a string array", errorDiv);
+	}
+	if (
+		!Array.isArray(tagsArray) ||
+		!tagsArray.every(function (tag) {
+			return typeof tag === "string";
+		})
+	) {
+		event.preventDefault();
+		displayErrorMessage("tags must be strings", errorDiv);
+	}
+}
+
+function displayErrorMessage(errorMessage, divName) {
+	const errorDiv = document.getElementById(divName);
+	errorDiv.style.display = "block";
+	errorDiv.innerHTML = errorMessage;
+}
+
+function removeErrorMessage(divName) {
+	const errorDiv = document.getElementById(divName);
+	errorDiv.style.display = "none";
+}
+
+function attachValidationListener(config) {
+	const button = document.getElementById(config.buttonId);
+
+	button.addEventListener("click", function (event) {
+		for (const key in config.validations) {
+			if (config.validations.hasOwnProperty(key)) {
+				const validationFunc = config.validations[key];
+				const elementValue = document.getElementById(key).value;
+				validationFunc(elementValue, config.errorDivs[key], event);
+			}
+		}
+	});
+}
diff --git a/ui/web/template/users.html b/ui/web/template/users.html
index d03e2d25c..26db5a8cc 100644
--- a/ui/web/template/users.html
+++ b/ui/web/template/users.html
@@ -47,8 +47,8 @@ <h5 class="modal-title" id="addUserModalLabel">
 												<div class="modal-body">
 													<div id="alertMessage"></div>
 													<form
-														method="post"
-														onsubmit="return submitUserForm()"
+												
+														
 													>
 														<div class="mb-3">
 															<label for="name" class="form-label">Name</label>
@@ -58,8 +58,8 @@ <h5 class="modal-title" id="addUserModalLabel">
 																name="name"
 																id="name"
 																placeholder="User Name"
-																required
 															/>
+															<div id="nameError" class="text-danger"></div>
 														</div>
 														<div class="mb-3">
 															<label for="identity" class="form-label">
@@ -71,8 +71,8 @@ <h5 class="modal-title" id="addUserModalLabel">
 																name="identity"
 																id="identity"
 																placeholder="User Identity"
-																required
 															/>
+															<div id="identityError" class="text-danger"></div>
 														</div>
 														<div class="mb-3">
 															<label for="secret" class="form-label">
@@ -84,7 +84,6 @@ <h5 class="modal-title" id="addUserModalLabel">
 																name="secret"
 																id="secret"
 																placeholder="User Secret"
-																required
 															/>
 															<div id="secretError" class="text-danger"></div>
 														</div>
@@ -122,7 +121,7 @@ <h5 class="modal-title" id="addUserModalLabel">
 														<button
 															type="submit"
 															class="btn body-button"
-															onclick="return validateForm()"
+															id="create-user-button"
 														>
 															Submit
 														</button>
@@ -258,6 +257,24 @@ <h5 class="modal-title" id="addUsersModalLabel">
 			</div>
 			{{ template "footer" }}
 			<script>
+				attachValidationListener({
+					buttonId: "create-user-button",
+					errorDivs: {
+						name: "nameError",
+						identity: "identityError",
+						secret: "secretError",
+						metadata: "metadataError",
+						tags: "tagsError",
+					},
+					validations: {
+						name: validateName,
+						identity: validateEmail,
+						secret: validatePassword,
+						metadata: validateMetadata,
+						tags: validateTags,
+					}
+				})
+
 				function validateForm() {
 					var secret = document.getElementById("secret").value;
 					var tagsInput = document.getElementById("tags").value;

From a808c199299f9d4a1515f59a12c8d8cec924c309 Mon Sep 17 00:00:00 2001
From: ianmuchyri <ianmuchiri8@gmail.com>
Date: Mon, 27 Nov 2023 12:56:55 +0300
Subject: [PATCH 02/11] add users scripts to javascript  file

Signed-off-by: ianmuchyri <ianmuchiri8@gmail.com>
---
 ui/api/endpoint.go            |  15 +-
 ui/api/transport.go           |   2 +
 ui/web/static/js/clipboard.js | 114 -----------
 ui/web/static/js/main.js      | 344 ++++++++++++++++++++++++++++++++++
 ui/web/template/footer.html   |   1 -
 ui/web/template/header.html   |   1 +
 ui/web/template/user.html     | 196 +++----------------
 ui/web/template/users.html    | 154 ++-------------
 8 files changed, 392 insertions(+), 435 deletions(-)
 delete mode 100644 ui/web/static/js/clipboard.js
 create mode 100644 ui/web/static/js/main.js

diff --git a/ui/api/endpoint.go b/ui/api/endpoint.go
index 396c31235..52adf2d2c 100644
--- a/ui/api/endpoint.go
+++ b/ui/api/endpoint.go
@@ -273,8 +273,7 @@ func createUserEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": usersAPIEndpoint},
+			code: http.StatusCreated,
 		}, nil
 	}
 }
@@ -291,8 +290,7 @@ func createUsersEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": usersAPIEndpoint},
+			code: http.StatusCreated,
 		}, nil
 	}
 }
@@ -353,8 +351,7 @@ func updateUserEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": usersAPIEndpoint + "/" + req.id},
+			code: http.StatusOK,
 		}, nil
 	}
 }
@@ -375,8 +372,7 @@ func updateUserTagsEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": usersAPIEndpoint + "/" + req.id},
+			code: http.StatusOK,
 		}, nil
 	}
 }
@@ -400,8 +396,7 @@ func updateUserIdentityEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": usersAPIEndpoint + "/" + req.id},
+			code: http.StatusOK,
 		}, nil
 	}
 }
diff --git a/ui/api/transport.go b/ui/api/transport.go
index bda2d8cf5..a2fcb6f53 100644
--- a/ui/api/transport.go
+++ b/ui/api/transport.go
@@ -975,6 +975,8 @@ func decodeUserUpdate(_ context.Context, r *http.Request) (interface{}, error) {
 		Metadata: data.Metadata,
 	}
 
+	fmt.Println(req)
+
 	return req, nil
 }
 
diff --git a/ui/web/static/js/clipboard.js b/ui/web/static/js/clipboard.js
deleted file mode 100644
index dd8768806..000000000
--- a/ui/web/static/js/clipboard.js
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright (c) Abstract Machines
-// SPDX-License-Identifier: Apache-2.0
-
-//function to copy the ID to the clipboard
-function copyToClipboard(button) {
-	var clientIDElement = button.previousElementSibling.firstChild;
-	var clientId = clientIDElement.textContent;
-
-	navigator.clipboard.writeText(clientId).then(
-		function () {
-			//change the copy icon to indicate success
-			button.innerHTML = `<i class="fas fa-check success-icon">`;
-			setTimeout(function () {
-				//revert the copy icon after a short delay
-				button.innerHTML = `<i class ="far fa-copy">`;
-			}, 1000);
-		},
-		function (error) {
-			//handle error
-			console.error("failed to copy to clipboard: ", error);
-		},
-	);
-}
-
-// Form validation functions
-
-function validateName(name, errorDiv, event) {
-	removeErrorMessage(errorDiv);
-	if (name.trim() === "") {
-		event.preventDefault();
-		displayErrorMessage("Name is Required", errorDiv);
-	}
-}
-
-const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
-function validateEmail(email, errorDiv, event) {
-	removeErrorMessage(errorDiv);
-	if (email.trim() === "") {
-		event.preventDefault();
-		displayErrorMessage("Email is Required", errorDiv);
-	} else if (!email.match(emailRegex)) {
-		event.preventDefault();
-		displayErrorMessage("Invalid email format", errorDiv);
-	}
-}
-
-const minLength = 8;
-function validatePassword(password, errorDiv, event) {
-	removeErrorMessage(errorDiv);
-	if (password.trim().length < minLength) {
-		event.preventDefault();
-		var errorMessage = `Password must be at least ${minLength} characters long`;
-		displayErrorMessage(errorMessage, errorDiv);
-	}
-}
-
-function validateMetadata(metadata, errorDiv, event) {
-	removeErrorMessage(errorDiv);
-	try {
-		if (metadata.trim() !== "") {
-			JSON.parse(metadata);
-		}
-	} catch (error) {
-		event.preventDefault();
-		displayErrorMessage("Metadata is not a valid JSON object", errorDiv);
-	}
-}
-
-function validateTags(tags, errorDiv, event) {
-	removeErrorMessage(errorDiv);
-	var tagsArray;
-	try {
-		if (tags.trim() !== "") {
-			tagsArray = JSON.parse(tags);
-		}
-	} catch (error) {
-		event.preventDefault();
-		displayErrorMessage("tags must be a string array", errorDiv);
-	}
-	if (
-		!Array.isArray(tagsArray) ||
-		!tagsArray.every(function (tag) {
-			return typeof tag === "string";
-		})
-	) {
-		event.preventDefault();
-		displayErrorMessage("tags must be strings", errorDiv);
-	}
-}
-
-function displayErrorMessage(errorMessage, divName) {
-	const errorDiv = document.getElementById(divName);
-	errorDiv.style.display = "block";
-	errorDiv.innerHTML = errorMessage;
-}
-
-function removeErrorMessage(divName) {
-	const errorDiv = document.getElementById(divName);
-	errorDiv.style.display = "none";
-}
-
-function attachValidationListener(config) {
-	const button = document.getElementById(config.buttonId);
-
-	button.addEventListener("click", function (event) {
-		for (const key in config.validations) {
-			if (config.validations.hasOwnProperty(key)) {
-				const validationFunc = config.validations[key];
-				const elementValue = document.getElementById(key).value;
-				validationFunc(elementValue, config.errorDivs[key], event);
-			}
-		}
-	});
-}
diff --git a/ui/web/static/js/main.js b/ui/web/static/js/main.js
new file mode 100644
index 000000000..3f0d45b0e
--- /dev/null
+++ b/ui/web/static/js/main.js
@@ -0,0 +1,344 @@
+// Copyright (c) Abstract Machines
+// SPDX-License-Identifier: Apache-2.0
+
+//function to copy the ID to the clipboard
+function copyToClipboard(button) {
+	var clientIDElement = button.previousElementSibling.firstChild;
+	var clientId = clientIDElement.textContent;
+
+	navigator.clipboard.writeText(clientId).then(
+		function () {
+			//change the copy icon to indicate success
+			button.innerHTML = `<i class="fas fa-check success-icon">`;
+			setTimeout(function () {
+				//revert the copy icon after a short delay
+				button.innerHTML = `<i class ="far fa-copy">`;
+			}, 1000);
+		},
+		function (error) {
+			//handle error
+			console.error("failed to copy to clipboard: ", error);
+		},
+	);
+}
+
+// Form validation functions
+
+function validateName(name, errorDiv, event) {
+	removeErrorMessage(errorDiv);
+	if (name.trim() === "") {
+		event.preventDefault();
+		displayErrorMessage("Name is Required", errorDiv);
+		return false;
+	}
+	return true;
+}
+
+const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
+function validateEmail(email, errorDiv, event) {
+	removeErrorMessage(errorDiv);
+	if (email.trim() === "") {
+		event.preventDefault();
+		displayErrorMessage("Email is Required", errorDiv);
+		return false;
+	} else if (!email.match(emailRegex)) {
+		event.preventDefault();
+		displayErrorMessage("Invalid email format", errorDiv);
+		return false;
+	}
+	return true;
+}
+
+const minLength = 8;
+function validatePassword(password, errorDiv, event) {
+	removeErrorMessage(errorDiv);
+	if (password.trim().length < minLength) {
+		event.preventDefault();
+		var errorMessage = `Password must be at least ${minLength} characters long`;
+		displayErrorMessage(errorMessage, errorDiv);
+		return false;
+	}
+	return true;
+}
+
+function validateMetadata(metadata, errorDiv, event) {
+	removeErrorMessage(errorDiv);
+	try {
+		if (metadata.trim() !== "") {
+			JSON.parse(metadata);
+		}
+	} catch (error) {
+		event.preventDefault();
+		displayErrorMessage("Metadata is not a valid JSON object", errorDiv);
+		return false;
+	}
+	return true;
+}
+
+function validateTags(tags, errorDiv, event) {
+	removeErrorMessage(errorDiv);
+	var tagsArray;
+	try {
+		if (tags.trim() !== "") {
+			tagsArray = JSON.parse(tags);
+		}
+		if (
+			!Array.isArray(tagsArray) ||
+			!tagsArray.every(function (tag) {
+				return typeof tag === "string";
+			})
+		) {
+			event.preventDefault();
+			displayErrorMessage("tags must be strings in an array", errorDiv);
+			return false;
+		}
+	} catch (error) {
+		event.preventDefault();
+		displayErrorMessage("tags must be a string array", errorDiv);
+		return false;
+	}
+
+	return true;
+}
+
+function displayErrorMessage(errorMessage, divName) {
+	const errorDiv = document.getElementById(divName);
+	errorDiv.style.display = "block";
+	errorDiv.innerHTML = errorMessage;
+}
+
+function removeErrorMessage(divName) {
+	const errorDiv = document.getElementById(divName);
+	errorDiv.style.display = "none";
+}
+
+function attachValidationListener(config) {
+	const button = document.getElementById(config.buttonId);
+
+	button.addEventListener("click", function (event) {
+		for (const key in config.validations) {
+			if (config.validations.hasOwnProperty(key)) {
+				const validationFunc = config.validations[key];
+				const elementValue = document.getElementById(key).value;
+				validationFunc(elementValue, config.errorDivs[key], event);
+			}
+		}
+	});
+}
+
+// Form subsmission functions
+// config parameters are: formId, url, alertDiv, modal
+function submitCreateForm(config) {
+	const form = document.getElementById(config.formId);
+	form.addEventListener("submit", function (event) {
+		event.preventDefault();
+		const formData = new FormData(form);
+
+		fetch(config.url, {
+			method: "POST",
+			body: formData,
+		})
+			.then(function (response) {
+				switch (response.status) {
+					case 409:
+						showAlert("entity already exists!", config.alertDiv);
+						break;
+					case 400:
+						showAlert("invalid file contents!", config.alertDiv);
+						break;
+					case 415:
+						showAlert("invalid file type!", config.alertDiv);
+						break;
+					default:
+						form.reset();
+						config.modal.hide();
+						window.location.reload();
+				}
+			})
+			.catch((error) => {
+				console.error("error submitting form: ", error);
+			});
+	});
+}
+
+function showAlert(errorMessage, alertDiv) {
+	const alert = document.getElementById(alertDiv);
+	alert.innerHTML = `
+	<div class="alert alert-danger alert-dismissable fade show d-flex flex-row justify-content-between" role="alert">
+	  <div>${errorMessage}</div>
+	  <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>
+	</div> `;
+}
+
+// Functions to make a row editable.
+
+// make a cell editable.
+function makeEditable(cell) {
+	cell.setAttribute("contenteditable", "true");
+	cell.dataset.originalContent = cell.innerHTML;
+}
+
+// make cell uneditable.
+function makeUneditable(cell) {
+	const originalContent = cell.dataset.originalContent;
+	cell.innerHTML = originalContent;
+	cell.setAttribute("contenteditable", "false");
+}
+
+// function show the save/cancel buttons and hide the edit button.
+function showSaveCancelButtons(editBtn, saveCancelBtn) {
+	editBtn.style.display = "none";
+	saveCancelBtn.style.display = "inline-block";
+}
+
+// function to show the edit button anf hide the save/cancel buttons.
+function showEditButton(editBtn, saveCancelBtn) {
+	editBtn.style.display = "inline-block";
+	saveCancelBtn.style.display = "none";
+}
+
+// config parameters are: button, field
+function editRow(config) {
+	const button = document.getElementById(config.button);
+
+	button.addEventListener("click", function () {
+		makeEditable(config.cell);
+		showSaveCancelButtons(config.editBtn, config.saveCancelBtn);
+	});
+}
+
+function cancelEditRow(config) {
+	const button = document.getElementById(config.button);
+
+	button.addEventListener("click", function () {
+		makeUneditable(config.cell);
+		showEditButton(config.editBtn, config.saveCancelBtn);
+		removeErrorMessage(config.alertDiv);
+	});
+}
+
+function submitUpdateForm(config) {
+	fetch(config.url, {
+		method: "POST",
+		body: config.data,
+		headers: {
+			"Content-Type": "application/json",
+		},
+	}).then((response) => {
+		switch (response.status) {
+			case 409:
+				showAlert("entity already exists!", config.alertDiv);
+				break;
+			default:
+				window.location.reload();
+		}
+	});
+}
+
+function updateName(config) {
+	const button = document.getElementById(config.button);
+
+	button.addEventListener("click", function (event) {
+		const updatedValue = config.cell.textContent.trim();
+		if (validateName(updatedValue, config.alertDiv, event)) {
+			const url = `/${config.entity}/${config.id}`;
+			const data = JSON.stringify({ [config.field]: updatedValue });
+
+			submitUpdateForm({
+				url: url,
+				data: data,
+				alertDiv: config.alertDiv,
+			});
+		}
+	});
+}
+
+function updateIdentity(config) {
+	const button = document.getElementById(config.button);
+
+	button.addEventListener("click", function (event) {
+		const updatedValue = config.cell.textContent.trim();
+		if (validateEmail(updatedValue, config.alertDiv, event)) {
+			const url = `/${config.entity}/${config.id}/identity`;
+			const data = JSON.stringify({ [config.field]: updatedValue });
+
+			submitUpdateForm({
+				url: url,
+				data: data,
+				alertDiv: config.alertDiv,
+			});
+		}
+	});
+}
+
+function updateMetadata(config) {
+	const button = document.getElementById(config.button);
+
+	button.addEventListener("click", function (event) {
+		const updatedValue = config.cell.textContent.trim();
+		if (validateMetadata(updatedValue, config.alertDiv, event)) {
+			const url = `/${config.entity}/${config.id}`;
+			const data = JSON.stringify({ [config.field]: JSON.parse(updatedValue) });
+
+			submitUpdateForm({
+				url: url,
+				data: data,
+				alertDiv: config.alertDiv,
+			});
+		}
+	});
+}
+
+function updateTags(config) {
+	const button = document.getElementById(config.button);
+
+	button.addEventListener("click", function (event) {
+		const updatedValue = config.cell.textContent.trim();
+		if (validateTags(updatedValue, config.alertDiv, event)) {
+			const url = `/${config.entity}/${config.id}/tags`;
+			const data = JSON.stringify({ [config.field]: JSON.parse(updatedValue) });
+
+			submitUpdateForm({
+				url: url,
+				data: data,
+				alertDiv: config.alertDiv,
+			});
+		}
+	});
+}
+
+function attachEditRowListener(config) {
+	for (const key in config.rows) {
+		if (config.rows.hasOwnProperty(key)) {
+			const cell = document.querySelector(`td[data-field="${key}"]`);
+			const editBtn = cell.parentNode.querySelector(".edit-btn");
+			const saveCancelBtn = cell.parentNode.querySelector(
+				".save-cancel-buttons",
+			);
+			editRow({
+				button: `edit-${key}`,
+				cell: cell,
+				editBtn: editBtn,
+				saveCancelBtn: saveCancelBtn,
+			});
+			cancelEditRow({
+				button: `cancel-${key}`,
+				cell: cell,
+				editBtn: editBtn,
+				saveCancelBtn: saveCancelBtn,
+				alertDiv: config.errorDiv,
+			});
+			const saveRow = config.rows[key];
+			saveRow({
+				button: `save-${key}`,
+				field: key,
+				cell: cell,
+				editBtn: editBtn,
+				saveCancelBtn: saveCancelBtn,
+				id: config.id,
+				entity: config.entity,
+				alertDiv: config.errorDiv,
+			});
+		}
+	}
+}
diff --git a/ui/web/template/footer.html b/ui/web/template/footer.html
index 6ae7bd7fd..c64b769fa 100644
--- a/ui/web/template/footer.html
+++ b/ui/web/template/footer.html
@@ -5,7 +5,6 @@
 	<!-- Bootstrap core JavaScript
 ================================================== -->
 	<!-- Placed at the end of the document so the pages load faster -->
-	<script src="/js/clipboard.js"></script>
 	<script
 		src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"
 		integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r"
diff --git a/ui/web/template/header.html b/ui/web/template/header.html
index e504c37e0..07c3534bf 100644
--- a/ui/web/template/header.html
+++ b/ui/web/template/header.html
@@ -21,5 +21,6 @@
 			integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9"
 			crossorigin="anonymous"
 		/>
+		<script src="/js/main.js"></script>
 	</head>
 {{ end }}
diff --git a/ui/web/template/user.html b/ui/web/template/user.html
index fe9b420c3..aea0349bb 100644
--- a/ui/web/template/user.html
+++ b/ui/web/template/user.html
@@ -58,7 +58,7 @@
 												<td>
 													<button
 														class="edit-btn"
-														onclick="editRow('name')"
+														id="edit-name"
 														{{ if
 															$disableButton
 														}}
@@ -71,13 +71,10 @@
 														class="save-cancel-buttons"
 														style="display: none"
 													>
-														<button class="save-btn" onclick="saveRow('name')">
+														<button class="save-btn" id="save-name">
 															Save
 														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('name')"
-														>
+														<button class="cancel-btn" id="cancel-name">
 															Cancel
 														</button>
 													</div>
@@ -105,7 +102,7 @@
 												<td>
 													<button
 														class="edit-btn"
-														onclick="editRow('identity')"
+														id="edit-identity"
 														{{ if
 															$disableButton
 														}}
@@ -118,16 +115,10 @@
 														class="save-cancel-buttons"
 														style="display: none"
 													>
-														<button
-															class="save-btn"
-															onclick="saveRow('identity')"
-														>
+														<button class="save-btn" id="save-identity">
 															Save
 														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('identity')"
-														>
+														<button class="cancel-btn" id="cancel-identity">
 															Cancel
 														</button>
 													</div>
@@ -145,7 +136,7 @@
 												<td>
 													<button
 														class="edit-btn"
-														onclick="editRow('tags')"
+														id="edit-tags"
 														{{ if
 															$disableButton
 														}}
@@ -158,13 +149,10 @@
 														class="save-cancel-buttons"
 														style="display: none"
 													>
-														<button class="save-btn" onclick="saveRow('tags')">
+														<button class="save-btn" id="save-tags">
 															Save
 														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('tags')"
-														>
+														<button class="cancel-btn" id="cancel-tags">
 															Cancel
 														</button>
 													</div>
@@ -182,7 +170,7 @@
 												<td>
 													<button
 														class="edit-btn"
-														onclick="editRow('metadata')"
+														id="edit-metadata"
 														{{ if
 															$disableButton
 														}}
@@ -195,16 +183,10 @@
 														class="save-cancel-buttons"
 														style="display: none"
 													>
-														<button
-															class="save-btn"
-															onclick="saveRow('metadata')"
-														>
+														<button class="save-btn" id="save-metadata">
 															Save
 														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('metadata')"
-														>
+														<button class="cancel-btn" id="cancel-metadata">
 															Cancel
 														</button>
 													</div>
@@ -221,149 +203,19 @@
 			</div>
 			{{ template "footer" }}
     <script>
-      function makeEditable(cell) {
-        cell.setAttribute("contenteditable", "true");
-        cell.dataset.originalContent = cell.innerHTML;
-      }
-
-      function makeUneditable(cell) {
-        const originalContent = cell.dataset.originalContent;
-        cell.innerHTML = originalContent;
-        cell.setAttribute("contenteditable", "false");
-      }
-
-      function showButtons(editBtn, saveCancelBtn) {
-        editBtn.style.display = "none";
-        saveCancelBtn.style.display = "inline-block";
-      }
-
-      function hideButtons(editBtn, saveCancelBtn) {
-        editBtn.style.display = "inline-block";
-        saveCancelBtn.style.display = "none";
-      }
-
-      function editRow(field) {
-        const cell = document.querySelector(`td[data-field='${field}']`);
-        const editBtn = cell.parentNode.querySelector(".edit-btn");
-        const saveCancelBtn = cell.parentNode.querySelector(
-          ".save-cancel-buttons",
-        );
-
-        // Make the row editable
-        makeEditable(cell);
-
-        // Hide the edit button and show save and cancel buttons
-        showButtons(editBtn, saveCancelBtn);
-      }
-
-      function saveRow(field) {
-        const cell = document.querySelector(`td[data-field='${field}']`);
-        const editBtn = cell.parentNode.querySelector(".edit-btn");
-        const saveCancelBtn = cell.parentNode.querySelector(
-          ".save-cancel-buttons",
-        );
-        const errorMessage = document.getElementById("error-message");
-
-        // Get the updated value from the nameCell
-        const updatedValue = cell.textContent.trim();
-
-        // Email format validation regular expression
-        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
-
-        // Send the updated value to the server using a POST request
-        let url;
-        let data;
-        if (field === "name") {
-          url = "/users/{{.UserID}}";
-          data = { [field]: updatedValue };
-        } else if (field == "metadata") {
-          try {
-            const metadata = JSON.parse(updatedValue);
-            url = "/users/{{.UserID}}";
-            data = { [field]: metadata };
-          } catch (error) {
-            errorMessage.textContent = "Metadata must be a valid JSON object!";
-            return;
-          }
-        } else if (field === "identity") {
-          if (!emailRegex.test(updatedValue)) {
-            errorMessage.textContent = "Identity should be in email format!";
-            return;
-          }
-          url = "/users/{{.UserID}}/identity";
-          data = { [field]: updatedValue };
-        } else if (field === "tags") {
-          try {
-            const tags = JSON.parse(updatedValue);
-            if (
-              !Array.isArray(tags) ||
-              !tags.every(function (tag) {
-                return typeof tag === "string";
-              })
-            ) {
-              errorMessage.textContent = "Tags must be a string array";
-              return;
-            }
-            url = "/users/{{.UserID}}/tags";
-            data = { [field]: tags };
-          } catch (error) {
-            errorMessage.textContent = "Tags must be a valid string array";
-            return;
-          }
-        }
-
-        errorMessage.textContent = "";
-
-        if (url) {
-			errorMessage.textContent="";
-			fetch(url, {
-				method: "POST",
-				body: JSON.stringify(data),
-				headers: {
-				"Content-Type": "application/json",
+		attachEditRowListener(
+			{
+				entity: "users",
+				id: "{{ .UserID }}",
+				rows: {
+					name:updateName,
+					identity:updateIdentity,
+					tags:updateTags,
+					metadata:updateMetadata,
 				},
-			})
-            .then((response) => {
-              if (response.ok) {
-                // Make the row uneditable
-                cell.setAttribute("contenteditable", "false");
-
-                // Show edit button and hide save and cancel buttons
-                hideButtons(editBtn, saveCancelBtn);
-              } else {
-                throw new Error("Response not OK");
-              }
-            })
-            .catch((error) => {
-              // Restore original values in the row if there is an error
-              makeUneditable(cell);
-
-              // Show edit button and hide save and cancel buttons
-              hideButtons(editBtn, saveCancelBtn);
-
-              console.error("Error", error);
-              errorMessage.textContent = "Entity already exists";
-            });
-        } else {
-          console.error("Invalid field:", field);
-        }
-      }
-
-      function cancelEditRow(field) {
-        const cell = document.querySelector(`td[data-field='${field}']`);
-        const editBtn = cell.parentNode.querySelector(".edit-btn");
-        const saveCancelBtn = cell.parentNode.querySelector(
-          ".save-cancel-buttons",
-        );
-        const errorMessage = document.getElementById("error-message");
-
-        errorMessage.textContent = "";
-        // Restore original values in the row
-        makeUneditable(cell);
-
-        // Show the edit button and hide the save and cancel buttons
-        hideButtons(editBtn, saveCancelBtn);
-      }
+				errorDiv: "error-message",
+			}
+		);
     </script>
 		</body>
 	</html>
diff --git a/ui/web/template/users.html b/ui/web/template/users.html
index 26db5a8cc..ed7791c50 100644
--- a/ui/web/template/users.html
+++ b/ui/web/template/users.html
@@ -46,10 +46,7 @@ <h5 class="modal-title" id="addUserModalLabel">
 												</div>
 												<div class="modal-body">
 													<div id="alertMessage"></div>
-													<form
-												
-														
-													>
+													<form id="userform">
 														<div class="mb-3">
 															<label for="name" class="form-label">Name</label>
 															<input
@@ -150,9 +147,8 @@ <h5 class="modal-title" id="addUsersModalLabel">
 												<div class="modal-body">
 													<div id="alertBulkMessage"></div>
 													<form
-														method="post"
 														enctype="multipart/form-data"
-														onsubmit="return submitBulkUsersForm()"
+														id="bulkusersform"
 													>
 														<div class="form-group">
 															<label for="usersFile">
@@ -272,59 +268,8 @@ <h5 class="modal-title" id="addUsersModalLabel">
 						secret: validatePassword,
 						metadata: validateMetadata,
 						tags: validateTags,
-					}
-				})
-
-				function validateForm() {
-					var secret = document.getElementById("secret").value;
-					var tagsInput = document.getElementById("tags").value;
-					var metadataInput = document.getElementById("metadata").value;
-					var secretError = document.getElementById("secretError");
-					var tagsError = document.getElementById("tagsError");
-					var metadataError = document.getElementById("metadataError");
-					var submit = document.getElementById("submit");
-
-					var tags;
-					var metadata;
-
-					secretError.innerHTML = "";
-					tagsError.innerHTML = "";
-					metadataError.innerHTML = "";
-
-					var isValid = true;
-
-					if (secret.length < 8) {
-						secretError.innerHTML =
-							"secret must have a minimum of 8 characters";
-						isValid = false;
-					}
-					try {
-						tags = JSON.parse(tagsInput);
-					} catch (error) {
-						tagsError.innerHTML = "please enter valid tags as a string array!";
-						isValid = false;
-					}
-
-					if (
-						!Array.isArray(tags) ||
-						!tags.every(function (tag) {
-							return typeof tag === "string";
-						})
-					) {
-						tagsError.innerHTML = "tags must be a string array!";
-						isValid = false;
-					}
-
-					try {
-						metadata = JSON.parse(metadataInput);
-					} catch (error) {
-						metadataError.innerHTML =
-							"please enter valid metadata in JSON format!";
-						isValid = false;
-					}
-
-					return isValid;
-				}
+					},
+				});
 
 				const userModal = new bootstrap.Modal(
 					document.getElementById("addUserModal"),
@@ -341,86 +286,19 @@ <h5 class="modal-title" id="addUsersModalLabel">
 					}
 				}
 
-				function submitUserForm() {
-					event.preventDefault();
-					var form = event.target;
-					fetch("/users", {
-						method: "POST",
-						body: new FormData(form),
-					})
-						.then((response) => {
-							if (response.status === 409) {
-								errorMessage = "user already exists!";
-								showAlert(errorMessage, "single");
-								return false;
-							} else {
-								form.reset();
-								userModal.hide();
-								window.location.reload();
-								return true;
-							}
-						})
-						.catch((error) => {
-							console.error("error submitting user form: ", error);
-							return false;
-						});
-				}
-
-				function submitBulkUsersForm() {
-					event.preventDefault();
-					var form = event.target;
-					fetch("/users/bulk", {
-						method: "POST",
-						body: new FormData(form),
-					})
-						.then((response) => {
-							switch (response.status) {
-								case 409:
-									errorMessage = "users already exist!";
-									showAlert(errorMessage, "bulk");
-									return false;
-								case 400:
-									errorMessage = "invalid file contents!";
-									showAlert(errorMessage, "bulk");
-									return false;
-								case 415:
-									errorMessage = "file must be csv!";
-									showAlert(errorMessage, "bulk");
-									return false;
-								default:
-									form.reset();
-									usersModal.hide();
-									window.location.reload();
-									return true;
-							}
-						})
-						.catch((error) => {
-							console.error("Error submitting bulk users form: ", error);
-							return false;
-						});
-				}
+				submitCreateForm({
+					url: "/users",
+					formId: "userform",
+					alertDiv: "alertMessage",
+					modal: userModal,
+				});
 
-				function showAlert(errorMessage, modal) {
-					if (modal === "single") {
-						var alertMessage = document.getElementById("alertMessage");
-						alertMessage.innerHTML = `
-          <div id="alert-popup" class="alert alert-danger">
-            <span class="close-button" onclick="closeAlertPopup()">&times;</span>
-            <h5 class="alert-messsage" id="alert-message">${errorMessage}</h5>
-          </div> `;
-					} else if (modal === "bulk") {
-						var alertMessage = document.getElementById("alertBulkMessage");
-						alertMessage.innerHTML = `
-          <div id="alert-popup" class="alert alert-danger">
-            <span class="close-button" onclick="closeAlertPopup()">&times;</span>
-            <h5 class="alert-messsage" id="alert-message">${errorMessage}</h5>
-          </div> `;
-					}
-				}
-
-				function closeAlertPopup() {
-					document.getElementById("alert-popup").style.display = "none";
-				}
+				submitCreateForm({
+					url: "/users/bulk",
+					formId: "bulkusersform",
+					alertDiv: "alertBulkMessage",
+					modal: usersModal,
+				});
 			</script>
 		</body>
 	</html>

From 700865d2b9ff80f75f334e410722d42ee8c7fecd Mon Sep 17 00:00:00 2001
From: ianmuchyri <ianmuchiri8@gmail.com>
Date: Mon, 27 Nov 2023 14:36:14 +0300
Subject: [PATCH 03/11] update things, channels and groups

Signed-off-by: ianmuchyri <ianmuchiri8@gmail.com>
---
 ui/api/endpoint.go            |  18 +--
 ui/api/transport.go           |   2 -
 ui/web/static/js/main.js      | 122 +++++++++++++++++
 ui/web/template/channel.html  | 156 +++-------------------
 ui/web/template/channels.html | 243 +++++-----------------------------
 ui/web/template/group.html    | 157 +++-------------------
 ui/web/template/groups.html   | 233 +++++---------------------------
 ui/web/template/thing.html    | 206 ++++------------------------
 ui/web/template/things.html   | 178 +++++--------------------
 9 files changed, 293 insertions(+), 1022 deletions(-)

diff --git a/ui/api/endpoint.go b/ui/api/endpoint.go
index 52adf2d2c..327bff60e 100644
--- a/ui/api/endpoint.go
+++ b/ui/api/endpoint.go
@@ -707,8 +707,7 @@ func createThingEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": thingsAPIEndpoint},
+			code: http.StatusCreated,
 		}, nil
 	}
 }
@@ -725,8 +724,7 @@ func createThingsEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": thingsAPIEndpoint},
+			code: http.StatusCreated,
 		}, nil
 	}
 }
@@ -787,8 +785,7 @@ func updateThingEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": thingsAPIEndpoint + "/" + req.id},
+			code: http.StatusOK,
 		}, nil
 	}
 }
@@ -809,8 +806,7 @@ func updateThingTagsEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": thingsAPIEndpoint + "/" + req.id},
+			code: http.StatusOK,
 		}, nil
 	}
 }
@@ -827,8 +823,7 @@ func updateThingSecretEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": thingsAPIEndpoint + "/" + req.id},
+			code: http.StatusOK,
 		}, nil
 	}
 }
@@ -849,8 +844,7 @@ func updateThingOwnerEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": thingsAPIEndpoint + "/" + req.id},
+			code: http.StatusOK,
 		}, nil
 	}
 }
diff --git a/ui/api/transport.go b/ui/api/transport.go
index a2fcb6f53..bda2d8cf5 100644
--- a/ui/api/transport.go
+++ b/ui/api/transport.go
@@ -975,8 +975,6 @@ func decodeUserUpdate(_ context.Context, r *http.Request) (interface{}, error) {
 		Metadata: data.Metadata,
 	}
 
-	fmt.Println(req)
-
 	return req, nil
 }
 
diff --git a/ui/web/static/js/main.js b/ui/web/static/js/main.js
index 3f0d45b0e..068a5e63d 100644
--- a/ui/web/static/js/main.js
+++ b/ui/web/static/js/main.js
@@ -307,6 +307,56 @@ function updateTags(config) {
 	});
 }
 
+function updateSecret(config) {
+	const button = document.getElementById(config.button);
+
+	button.addEventListener("click", function (event) {
+		const updatedValue = config.cell.textContent.trim();
+		if (validatePassword(updatedValue, config.alertDiv, event)) {
+			const url = `/${config.entity}/${config.id}/secret`;
+			const data = JSON.stringify({ [config.field]: updatedValue });
+
+			submitUpdateForm({
+				url: url,
+				data: data,
+				alertDiv: config.alertDiv,
+			});
+		}
+	});
+}
+
+function updateOwner(config) {
+	const button = document.getElementById(config.button);
+
+	button.addEventListener("click", function () {
+		const updatedValue = config.cell.textContent.trim();
+		const url = `/${config.entity}/${config.id}/owner`;
+		const data = JSON.stringify({ [config.field]: updatedValue });
+
+		submitUpdateForm({
+			url: url,
+			data: data,
+			alertDiv: config.alertDiv,
+		});
+	});
+}
+
+function updateDescription(config) {
+	const button = document.getElementById(config.button);
+
+	button.addEventListener("click", function () {
+		const updatedValue = config.cell.textContent.trim();
+		const url = `/${config.entity}/${config.id}`;
+		const data = JSON.stringify({ [config.field]: updatedValue });
+
+		submitUpdateForm({
+			url: url,
+			data: data,
+			alertDiv: config.alertDiv,
+		});
+	});
+}
+
 function attachEditRowListener(config) {
 	for (const key in config.rows) {
 		if (config.rows.hasOwnProperty(key)) {
@@ -342,3 +392,75 @@ function attachEditRowListener(config) {
 		}
 	}
 }
+
+function fetchIndividualEntity(config) {
+	document.addEventListener("DOMContentLoaded", function () {
+		getEntities(config.item, "");
+		infiniteScroll(config.item);
+	});
+	
+	const input = document.getElementById(config.input);
+
+	input.addEventListener("input", function (event) {
+		const itemSelect = document.getElementById(config.itemSelect);
+		if (event.target.value === "") {
+			itemSelect.innerHTML = `<option disabled>select a ${config.type}</option>`;
+			getEntities(config.item, "");
+			infiniteScroll(config.item);
+		} else {
+			itemSelect.innerHTML = "";
+			getEntities(config.item, event.target.value);
+		}
+	});
+}
+
+function getEntities(item, name) {
+	fetchData(item, name, 1);
+}
+
+function infiniteScroll(item) {
+	var selectElement = document.getElementById("infiniteScroll");
+	var singleOptionHeight = selectElement.querySelector("option").offsetHeight;
+	var selectBoxHeight = selectElement.offsetHeight;
+	var numOptionsBeforeLoad = 2;
+	var lastScrollTop = 0;
+	var currentPageNo = 1;
+	var currentScroll = 0;
+
+	selectElement.addEventListener("scroll", function () {
+		var st = selectElement.scrollTop;
+		var totalHeight =
+			selectElement.querySelectorAll("option").length * singleOptionHeight;
+
+		if (st > lastScrollTop) {
+			currentScroll = st + selectBoxHeight;
+			if (
+				currentScroll + numOptionsBeforeLoad * singleOptionHeight >=
+				totalHeight
+			) {
+				currentPageNo++;
+				fetchData(item, "", currentPageNo);
+			}
+		}
+
+		lastScrollTop = st;
+	});
+}
+
+let limit = 5;
+function fetchData(item, name, page) {
+	fetch(`/entities?item=${item}&limit=${limit}&name=${name}&page=${page}`, {
+		method: "GET",
+	})
+		.then((response) => response.json())
+		.then((data) => {
+			const selectElement = document.getElementById("infiniteScroll");
+			data.data.forEach((entity) => {
+				const option = document.createElement("option");
+				option.value = entity.id;
+				option.text = entity.name;
+				selectElement.appendChild(option);
+			});
+		})
+		.catch((error) => console.error("Error:", error));
+}
diff --git a/ui/web/template/channel.html b/ui/web/template/channel.html
index e1c7f4db5..7d9af95a0 100644
--- a/ui/web/template/channel.html
+++ b/ui/web/template/channel.html
@@ -56,7 +56,7 @@
 												<td>
 													<button
 														class="edit-btn"
-														onclick="editRow('name')"
+														id="edit-name"
 														{{ if
 															$disableButton
 														}}
@@ -69,13 +69,10 @@
 														class="save-cancel-buttons"
 														style="display: none"
 													>
-														<button class="save-btn" onclick="saveRow('name')">
+														<button class="save-btn" id="save-name">
 															Save
 														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('name')"
-														>
+														<button class="cancel-btn" id="cancel-name">
 															Cancel
 														</button>
 													</div>
@@ -103,7 +100,7 @@
 												<td>
 													<button
 														class="edit-btn"
-														onclick="editRow('description')"
+														id="edit-description"
 														{{ if
 															$disableButton
 														}}
@@ -116,16 +113,10 @@
 														class="save-cancel-buttons"
 														style="display: none"
 													>
-														<button
-															class="save-btn"
-															onclick="saveRow('description')"
-														>
+														<button class="save-btn" id="save-description">
 															Save
 														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('description')"
-														>
+														<button class="cancel-btn" id="cancel-description">
 															Cancel
 														</button>
 													</div>
@@ -143,7 +134,7 @@
 												<td>
 													<button
 														class="edit-btn"
-														onclick="editRow('metadata')"
+														id="edit-metadata"
 														{{ if
 															$disableButton
 														}}
@@ -156,16 +147,10 @@
 														class="save-cancel-buttons"
 														style="display: none"
 													>
-														<button
-															class="save-btn"
-															onclick="saveRow('metadata')"
-														>
+														<button class="save-btn" id="save-metadata">
 															Save
 														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('metadata')"
-														>
+														<button class="cancel-btn" id="cancel-metadata">
 															Cancel
 														</button>
 													</div>
@@ -182,119 +167,18 @@
 			</div>
 			{{ template "footer" }}
     <script>
-      function makeEditable(cell) {
-        cell.setAttribute("contenteditable", "true");
-        cell.dataset.originalContent = cell.innerHTML;
-      }
-
-      function makeUneditable(cell) {
-        const originalContent = cell.dataset.originalContent;
-        cell.innerHTML = originalContent;
-        cell.setAttribute("contenteditable", "false");
-      }
-
-      function showButtons(editBtn, saveCancelBtn) {
-        editBtn.style.display = "none";
-        saveCancelBtn.style.display = "inline-block";
-      }
-      function hideButtons(editBtn, saveCancelBtn) {
-        editBtn.style.display = "inline-block";
-        saveCancelBtn.style.display = "none";
-      }
-
-      function editRow(field) {
-        const cell = document.querySelector(`td[data-field='${field}']`);
-        const editBtn = cell.parentNode.querySelector(".edit-btn");
-        const saveCancelBtn = cell.parentNode.querySelector(
-          ".save-cancel-buttons",
-        );
-
-        //make the row editable
-        makeEditable(cell);
-
-        //Hide edit button and show save and cancel buttons
-        showButtons(editBtn, saveCancelBtn);
-      }
-
-      function cancelEditRow(field) {
-        const cell = document.querySelector(`td[data-field='${field}']`);
-        const editBtn = cell.parentNode.querySelector(".edit-btn");
-        const saveCancelBtn = cell.parentNode.querySelector(
-          ".save-cancel-buttons",
-        );
-        const errorMessage = document.getElementById("error-message");
-
-        errorMessage.textContent = "";
-
-        //Restore original values in the row
-        makeUneditable(cell);
-
-        //show the edit button and hide the save and cancel buttons
-        hideButtons(editBtn, saveCancelBtn);
-      }
-
-      function saveRow(field) {
-        const cell = document.querySelector(`td[data-field='${field}']`);
-        const editBtn = cell.parentNode.querySelector(".edit-btn");
-        const saveCancelBtn = cell.parentNode.querySelector(
-          ".save-cancel-buttons",
-        );
-        const errorMessage = document.getElementById("error-message");
-
-        //Get the updated value from the nameCell
-        const updatedValue = cell.textContent.trim();
-
-        //send the updated value to the server using a post request
-        let url;
-        let data;
-        if (field === "name" || field === "description") {
-          url = "/channels/{{.Channel.ID}}";
-          data = { [field]: updatedValue };
-        } else if (field === "metadata") {
-          try {
-            const metadata = JSON.parse(updatedValue);
-            url = "/channels/{{.Channel.ID}}";
-            data = { [field]: metadata };
-          } catch (error) {
-            errorMessage.textContent = "Metadata must be a valid JSON object!";
-            return;
-          }
-        }
-
-        if (url) {
-			errorMessage.textContent="";
-			fetch(url, {
-				method: "POST",
-				body: JSON.stringify(data),
-				headers: {
-				"Content-Type": "application/json",
+      attachEditRowListener(
+			{
+				entity: "channels",
+				id: "{{ .Channel.ID }}",
+				rows: {
+					name:updateName,
+					description: updateDescription,
+					metadata:updateMetadata,
 				},
-			})
-            .then((response) => {
-              if (response.ok) {
-                //make the row uneditable
-                cell.setAttribute("contenteditable", "false");
-
-                //show edit button and hide save and cancel buttons
-                hideButtons(editBtn, saveCancelBtn);
-              } else {
-                throw new Error("Response not OK");
-              }
-            })
-            .catch((error) => {
-              //Restore original values in the row if there is an error
-              makeUneditable(cell);
-
-              //show edit button and hide save and cancel buttons
-              hideButtons(editBtn, saveCancelBtn);
-
-              console.error("Error", error);
-              errorMessage.textContent = "Entity already exists";
-            });
-        } else {
-          console.error("Invalid field:", field);
-        }
-      }
+				errorDiv: "error-message",
+			}
+		);
     </script>
 		</body>
 	</html>
diff --git a/ui/web/template/channels.html b/ui/web/template/channels.html
index 3e5f3d768..f0079449f 100644
--- a/ui/web/template/channels.html
+++ b/ui/web/template/channels.html
@@ -40,10 +40,7 @@ <h5 class="modal-title" id="addChannelModalLabel">
 												</div>
 												<div class="modal-body">
 													<div id="alertMessage"></div>
-													<form
-														method="post"
-														onsubmit="return submitChannelForm()"
-													>
+													<form method="post" id="channelform">
 														<div class="mb-3">
 															<label for="name" class="form-label">Name</label>
 															<input
@@ -52,8 +49,8 @@ <h5 class="modal-title" id="addChannelModalLabel">
 																name="name"
 																id="name"
 																placeholder="Channel Name"
-																required
 															/>
+															<div id="nameError" class="text-danger"></div>
 														</div>
 														<div class="mb-3">
 															<label for="infiniteScroll" class="form-label">
@@ -65,7 +62,6 @@ <h5 class="modal-title" id="addChannelModalLabel">
 																name="parentFilter"
 																id="parentFilter"
 																placeholder="Filter by parent name"
-																oninput="fetchIndividualEntity(this.value, 'infiniteScroll')"
 															/>
 															<select
 																class="form-select"
@@ -102,15 +98,12 @@ <h5 class="modal-title" id="addChannelModalLabel">
 															<div id="metadataHelp" class="form-text">
 																Enter channel metadata in JSON format.
 															</div>
-															<div
-																id="metadataError"
-																class="error-message"
-															></div>
+															<div id="metadataError" class="text-danger"></div>
 														</div>
 														<button
 															type="submit"
 															class="btn body-button"
-															onclick="return validateForm()"
+															id="create-channel-button"
 														>
 															Submit
 														</button>
@@ -150,7 +143,7 @@ <h5 class="modal-title" id="addChannelsModalLabel">
 													<form
 														method="post"
 														enctype="multipart/form-data"
-														onsubmit="return submitBulkChannelsForm()"
+														id="bulkchannelsform"
 													>
 														<div class="form-group">
 															<label for="channelsFile">
@@ -255,45 +248,18 @@ <h5 class="modal-title" id="addChannelsModalLabel">
 			</div>
 			{{ template "footer" }}
 			<script>
-				function filterItem(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					const options = itemSelect.getElementsByTagName("option");
-
-					for (let i = 0; i < options.length; i++) {
-						const option = options[i];
-						const itemId = option.value;
-						const itemName = option.innerHTML;
-						const shouldShow =
-							itemId.includes(filterValue) ||
-							itemName.toLowerCase().includes(filterValue.toLowerCase());
-						option.style.display = shouldShow ? "" : "none";
-					}
-				}
-				function validateForm() {
-					var name = document.getElementById("name").value;
-					var metadataInput = document.getElementById("metadata").value;
-					var nameError = document.getElementById("nameError");
-					var metadataError = document.getElementById("metadataError");
-					var metadata;
-
-					nameError.innerHTML = "";
-					metadataError.innerHTML = "";
+				attachValidationListener({
+					buttonId: "create-channel-button",
+					errorDivs: {
+						name: "nameError",
+						metadata: "metadataError",
+					},
+					validations: {
+						name: validateName,
+						metadata: validateMetadata,
+					},
+				});
 
-					var isValid = true;
-					if (name === "") {
-						nameError.innerHTML = "Field Required!";
-						isValid = false;
-					}
-					try {
-						metadata = JSON.parse(metadataInput);
-					} catch (error) {
-						metadataError.innerHTML =
-							"Please enter a valid metadaat in JSON  format!";
-						isValid = false;
-					}
-
-					return isValid;
-				}
 				const channelModal = new bootstrap.Modal(
 					document.getElementById("addChannelModal"),
 				);
@@ -304,173 +270,30 @@ <h5 class="modal-title" id="addChannelsModalLabel">
 				function openModal(modal) {
 					if (modal === "single") {
 						channelModal.show();
-						getChannels("");
-						getAdditionalChannels();
 					} else if (modal === "bulk") {
 						channelsModal.show();
 					}
 				}
 
-				function submitChannelForm() {
-					event.preventDefault();
-					var form = event.target;
-					fetch("/channels", {
-						method: "POST",
-						body: new FormData(form),
-					})
-						.then((response) => {
-							if (response.status === 409) {
-								errorMessage = "channel already exists!";
-								showAlert(errorMessage, "single");
-								return false;
-							} else {
-								form.reset();
-								channelModal.hide();
-								window.location.reload();
-								return true;
-							}
-						})
-						.catch((error) => {
-							console.error("error submitting channel form: ", error);
-							return false;
-						});
-				}
-
-				function submitBulkChannelsForm() {
-					event.preventDefault();
-					var form = event.target;
-					fetch("/channels/bulk", {
-						method: "POST",
-						body: new FormData(form),
-					})
-						.then((response) => {
-							switch (response.status) {
-								case 409:
-									errorMessage = "channels already exist!";
-									showAlert(errorMessage, "bulk");
-									return false;
-								case 400:
-									errorMessage = "invalid file contents!";
-									showAlert(errorMessage, "bulk");
-									return false;
-								case 415:
-									errorMessage = "file must be csv!";
-									showAlert(errorMessage, "bulk");
-									return false;
-								case 500:
-									errorMessage = "try again!";
-									showAlert(errorMessage, "bulk");
-									return false;
-								default:
-									form.reset();
-									channelsModal.hide();
-									window.location.reload();
-									return true;
-							}
-						})
-						.catch((error) => {
-							console.error("Error submitting bulk channels form: ", error);
-							return false;
-						});
-				}
+				submitCreateForm({
+					url: "/channels",
+					formId: "channelform",
+					alertDiv: "alertMessage",
+					modal: channelModal,
+				});
 
-				function showAlert(errorMessage, modal) {
-					if (modal === "single") {
-						var alertMessage = document.getElementById("alertMessage");
-						alertMessage.innerHTML = `
-					<div id="alert-popup" class="alert alert-danger">
-						<span class="close-button" onclick="closeAlertPopup()">&times;</span>
-						<h5 class="alert-messsage" id="alert-message">${errorMessage}</h5>
-					</div> `;
-					} else if (modal === "bulk") {
-						var alertMessage = document.getElementById("alertBulkMessage");
-						alertMessage.innerHTML = `
-					<div id="alert-popup" class="alert alert-danger">
-						<span class="close-button" onclick="closeAlertPopup()">&times;</span>
-						<h5 class="alert-messsage" id="alert-message">${errorMessage}</h5>
-					</div> `;
-					}
-				}
+				submitCreateForm({
+					url: "/channels/bulk",
+					formId: "bulkchannelsform",
+					alertDiv: "alertBulkMessage",
+					modal: channelsModal,
+				});
 
-				function closeAlertPopup() {
-					document.getElementById("alert-popup").style.display = "none";
-				}
-
-				function hideAlert() {
-					var alertElement = document.querySelector(".alert-danger");
-					alertElement.style.display = "none";
-				}
-
-				function fetchIndividualEntity(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					if (filterValue === "") {
-						itemSelect.innerHTML = "<option disabled>select a channel</option>";
-						getChannels("");
-						getAdditionalChannels();
-					} else {
-						itemSelect.innerHTML = "";
-						getChannels(filterValue);
-					}
-				}
-
-				let limit = 5;
-
-				function getChannels(name) {
-					fetchData(name, 1);
-				}
-
-				function getAdditionalChannels() {
-					var selectElement = document.getElementById("infiniteScroll");
-					var singleOptionHeight =
-						selectElement.querySelector("option").offsetHeight;
-					var selectBoxHeight = selectElement.offsetHeight;
-					var numOptionsBeforeLoad = 2;
-					var lastScrollTop = 0;
-					var currentPageNo = 1;
-					var currentScroll = 0;
-
-					selectElement.addEventListener("scroll", onselectScroll);
-
-					function onselectScroll(event) {
-						var st = selectElement.scrollTop;
-						var totalHeight =
-							selectElement.querySelectorAll("option").length *
-							singleOptionHeight;
-
-						if (st > lastScrollTop) {
-							currentScroll = st + selectBoxHeight;
-							if (
-								currentScroll + numOptionsBeforeLoad * singleOptionHeight >=
-								totalHeight
-							) {
-								currentPageNo++;
-								fetchData("", currentPageNo);
-							}
-						}
-
-						lastScrollTop = st;
-					}
-				}
-
-				function fetchData(name, page) {
-					fetch(
-						`/entities?item=channels&limit=${limit}&name=${name}&page=${page}`,
-						{
-							method: "GET",
-						},
-					)
-						.then((response) => response.json())
-						.then((data) => {
-							const selectElement = document.getElementById("infiniteScroll");
-							data.data.forEach((group) => {
-								const option = document.createElement("option");
-								option.value = group.id;
-								option.text = group.name;
-								selectElement.appendChild(option);
-							});
-						})
-						.catch((error) => console.error("Error:", error));
-				}
+				fetchIndividualEntity({
+					input: "parentFilter",
+					itemSelect: "infiniteScroll",
+					item: "channels",
+				});
 			</script>
 		</body>
 	</html>
diff --git a/ui/web/template/group.html b/ui/web/template/group.html
index 6edbe74a3..ecca37d44 100644
--- a/ui/web/template/group.html
+++ b/ui/web/template/group.html
@@ -49,7 +49,7 @@
 												<td>
 													<button
 														class="edit-btn"
-														onclick="editRow('name')"
+														id="edit-name"
 														{{ if
 															$disableButton
 														}}
@@ -62,13 +62,10 @@
 														class="save-cancel-buttons"
 														style="display: none"
 													>
-														<button class="save-btn" onclick="saveRow('name')">
+														<button class="save-btn" id="save-name">
 															Save
 														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('name')"
-														>
+														<button class="cancel-btn" id="cancel-name">
 															Cancel
 														</button>
 													</div>
@@ -91,7 +88,7 @@
 												<td>
 													<button
 														class="edit-btn"
-														onclick="editRow('description')"
+														id="edit-description"
 														{{ if
 															$disableButton
 														}}
@@ -104,16 +101,10 @@
 														class="save-cancel-buttons"
 														style="display: none"
 													>
-														<button
-															class="save-btn"
-															onclick="saveRow('description')"
-														>
+														<button class="save-btn" id="save-description">
 															Save
 														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('description')"
-														>
+														<button class="cancel-btn" id="cancel-description">
 															Cancel
 														</button>
 													</div>
@@ -131,7 +122,7 @@
 												<td>
 													<button
 														class="edit-btn"
-														onclick="editRow('metadata')"
+														id="edit-metadata"
 														{{ if
 															$disableButton
 														}}
@@ -144,16 +135,10 @@
 														class="save-cancel-buttons"
 														style="display: none"
 													>
-														<button
-															class="save-btn"
-															onclick="saveRow('metadata')"
-														>
+														<button class="save-btn" id="save-metadata">
 															Save
 														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('metadata')"
-														>
+														<button class="cancel-btn" id="cancel-metadata">
 															Cancel
 														</button>
 													</div>
@@ -170,120 +155,18 @@
 			</div>
 			{{ template "footer" }}
     <script>
-      function makeEditable(cell) {
-        cell.setAttribute("contenteditable", "true");
-        cell.dataset.originalContent = cell.innerHTML;
-      }
-
-      function makeUneditable(cell) {
-        const originalContent = cell.dataset.originalContent;
-        cell.innerHTML = originalContent;
-        cell.setAttribute("contenteditable", "false");
-      }
-
-      function showButtons(editBtn, saveCancelBtn) {
-        editBtn.style.display = "none";
-        saveCancelBtn.style.display = "inline-block";
-      }
-      function hideButtons(editBtn, saveCancelBtn) {
-        editBtn.style.display = "inline-block";
-        saveCancelBtn.style.display = "none";
-      }
-
-      function editRow(field) {
-        const cell = document.querySelector(`td[data-field='${field}']`);
-        const editBtn = cell.parentNode.querySelector(".edit-btn");
-        const saveCancelBtn = cell.parentNode.querySelector(
-          ".save-cancel-buttons",
-        );
-
-        //make the row editable
-        makeEditable(cell);
-
-        //Hide edit button and show save and cancel buttons
-        showButtons(editBtn, saveCancelBtn);
-      }
-
-      function cancelEditRow(field) {
-        const cell = document.querySelector(`td[data-field='${field}']`);
-        const editBtn = cell.parentNode.querySelector(".edit-btn");
-        const saveCancelBtn = cell.parentNode.querySelector(
-          ".save-cancel-buttons",
-        );
-        const errorMessage = document.getElementById("error-message");
-
-        errorMessage.textContent = "";
-
-        //Restore original values in the row
-        makeUneditable(cell);
-
-        //show the edit button and hide the save and cancel buttons
-        hideButtons(editBtn, saveCancelBtn);
-      }
-
-      function saveRow(field) {
-        const cell = document.querySelector(`td[data-field='${field}']`);
-        const editBtn = cell.parentNode.querySelector(".edit-btn");
-        const saveCancelBtn = cell.parentNode.querySelector(
-          ".save-cancel-buttons",
-        );
-        const errorMessage = document.getElementById("error-message");
-
-        //Get the updated value from the nameCell
-        const updatedValue = cell.textContent.trim();
-
-        //send the updated value to the server using a post request
-        let url;
-        let data;
-        if (field === "name" || field === "description") {
-          url = "/groups/{{.Group.ID}}";
-          data = { [field]: updatedValue };
-        } else if (field === "metadata") {
-          try {
-            const metadata = JSON.parse(updatedValue);
-            url = "/groups/{{.Group.ID}}";
-            data = { [field]: metadata };
-          } catch (error) {
-            errorMessage.textContent = "Metadata must be a valid JSON object!";
-            return;
-          }
-        }
-
-        if (url) {
-			errorMessage.textContent="";
-			fetch(url, {
-				method: "POST",
-				body: JSON.stringify(data),
-				headers: {
-				"Content-Type": "application/json",
+      attachEditRowListener(
+			{
+				entity: "groups",
+				id: "{{ .Group.ID }}",
+				rows: {
+					name:updateName,
+					description: updateDescription,
+					metadata:updateMetadata,
 				},
-			})
-            .then((response) => {
-              if (response.ok) {
-                //make the row uneditable
-                cell.setAttribute("contenteditable", "false");
-
-                //show edit button and hide save and cancel buttons
-                hideButtons(editBtn, saveCancelBtn);
-              } else {
-                throw new Error(response.statusText);
-                console.log(response.statusText);
-              }
-            })
-            .catch((error) => {
-              //Restore original values in the row if there is an error
-              makeUneditable(cell);
-
-              //show edit button and hide save and cancel buttons
-              hideButtons(editBtn, saveCancelBtn);
-
-              console.error("Error", error);
-              errorMessage.textContent = "Entity already exists";
-            });
-        } else {
-          console.error("Invalid field:", field);
-        }
-      }
+				errorDiv: "error-message",
+			}
+		);
     </script>
 		</body>
 	</html>
diff --git a/ui/web/template/groups.html b/ui/web/template/groups.html
index 6ce468fa7..da96eaf46 100644
--- a/ui/web/template/groups.html
+++ b/ui/web/template/groups.html
@@ -40,10 +40,7 @@ <h5 class="modal-title" id="addGroupModalLabel">
 												</div>
 												<div class="modal-body">
 													<div id="alertMessage"></div>
-													<form
-														method="post"
-														onsubmit="return submitGroupForm()"
-													>
+													<form method="post" id="groupform">
 														<div class="mb-3">
 															<label for="name" class="form-label">Name</label>
 															<input
@@ -52,8 +49,8 @@ <h5 class="modal-title" id="addGroupModalLabel">
 																name="name"
 																id="name"
 																placeholder="Group Name"
-																required
 															/>
+															<div id="nameError" class="text-danger"></div>
 														</div>
 														<div class="mb-3">
 															<label for="description" class="form-label">
@@ -77,7 +74,6 @@ <h5 class="modal-title" id="addGroupModalLabel">
 																name="parentFilter"
 																id="parentFilter"
 																placeholder="Filter by parent name"
-																oninput="fetchIndividualEntity(this.value, 'infiniteScroll')"
 															/>
 															<select
 																class="form-select"
@@ -102,15 +98,12 @@ <h5 class="modal-title" id="addGroupModalLabel">
 															<div id="metadataHelp" class="form-text">
 																Enter groups metadata in JSON format.
 															</div>
-															<div
-																id="metadataError"
-																class="error-message"
-															></div>
+															<div id="metadataError" class="text-danger"></div>
 														</div>
 														<button
 															type="submit"
 															class="btn body-button"
-															onclick="return validateForm()"
+															id="create-group-button"
 														>
 															Submit
 														</button>
@@ -146,9 +139,8 @@ <h5 class="modal-title" id="addGroupsModalLabel">
 												<div class="modal-body">
 													<div id="alertBulkMessage"></div>
 													<form
-														method="post"
 														enctype="multipart/form-data"
-														onsubmit="return submitBulkGroupForm()"
+														id="bulkgroupsform"
 													>
 														<div class="form-group">
 															<label for="groupsFile">
@@ -253,38 +245,17 @@ <h5 class="modal-title" id="addGroupsModalLabel">
 
 			{{ template "footer" }}
 			<script>
-				function validateForm() {
-					var metadataInput = document.getElementById("metadata").value;
-					var metadataError = document.getElementById("metadataError");
-					var metadata;
-
-					metadataError.innerHTML = "";
-
-					var isValid = true;
-					try {
-						metadata = JSON.parse(metadataInput);
-					} catch (error) {
-						metadataError.innerHTML =
-							"Please enter a valid metadata in JSON  format!";
-						isValid = false;
-					}
-
-					return isValid;
-				}
-				function filterItem(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					const options = itemSelect.getElementsByTagName("option");
-
-					for (let i = 0; i < options.length; i++) {
-						const option = options[i];
-						const itemId = option.value;
-						const itemName = option.innerHTML;
-						const shouldShow =
-							itemId.includes(filterValue) ||
-							itemName.toLowerCase().includes(filterValue.toLowerCase());
-						option.style.display = shouldShow ? "" : "none";
-					}
-				}
+				attachValidationListener({
+					buttonId: "create-group-button",
+					errorDivs: {
+						name: "nameError",
+						metadata: "metadataError",
+					},
+					validations: {
+						name: validateName,
+						metadata: validateMetadata,
+					},
+				});
 
 				const groupModal = new bootstrap.Modal(
 					document.getElementById("addGroupModal"),
@@ -296,168 +267,30 @@ <h5 class="modal-title" id="addGroupsModalLabel">
 				function openModal(modal) {
 					if (modal === "single") {
 						groupModal.show();
-						getGroups("");
-						getAdditionalGroups();
 					} else if (modal === "bulk") {
 						groupsModal.show();
 					}
 				}
 
-				function submitGroupForm() {
-					event.preventDefault();
-					var form = event.target;
-					fetch("/groups", {
-						method: "POST",
-						body: new FormData(form),
-					})
-						.then((response) => {
-							if (response.status === 409) {
-								errorMessage = "group already exists!";
-								showAlert(errorMessage, "single");
-								return false;
-							} else {
-								form.reset();
-								groupModal.hide();
-								window.location.reload();
-								return true;
-							}
-						})
-						.catch((error) => {
-							console.error("error submitting group form: ", error);
-							return false;
-						});
-				}
-
-				function submitBulkGroupForm() {
-					event.preventDefault();
-					var form = event.target;
-					fetch("/groups/bulk", {
-						method: "POST",
-						body: new FormData(form),
-					})
-						.then((response) => {
-							switch (response.status) {
-								case 409:
-									errorMessage = "groups already exist!";
-									showAlert(errorMessage, "bulk");
-									return false;
-								case 400:
-									errorMessage = "invalid file contents!";
-									showAlert(errorMessage, "bulk");
-									return false;
-								case 415:
-									errorMessage = "file must be csv!";
-									showAlert(errorMessage, "bulk");
-									return false;
-								case 500:
-									errorMessage = "try again!";
-									showAlert(errorMessage, "bulk");
-									return false;
-								default:
-									form.reset();
-									groupsModal.hide();
-									window.location.reload();
-									return true;
-							}
-						})
-						.catch((error) => {
-							console.error("Error submitting bulk groups form: ", error);
-							return false;
-						});
-				}
-
-				function showAlert(errorMessage, modal) {
-					if (modal === "single") {
-						var alertMessage = document.getElementById("alertMessage");
-						alertMessage.innerHTML = `
-        <div id="alert-popup" class="alert alert-danger">
-          <span class="close-button" onclick="closeAlertPopup()">&times;</span>
-          <h5 class="alert-messsage" id="alert-message">${errorMessage}</h5>
-        </div> `;
-					} else if (modal === "bulk") {
-						var alertMessage = document.getElementById("alertBulkMessage");
-						alertMessage.innerHTML = `
-        <div id="alert-popup" class="alert alert-danger">
-          <span class="close-button" onclick="closeAlertPopup()">&times;</span>
-          <h5 class="alert-messsage" id="alert-message">${errorMessage}</h5>
-        </div> `;
-					}
-				}
-
-				function closeAlertPopup() {
-					document.getElementById("alert-popup").style.display = "none";
-				}
+				submitCreateForm({
+					url: "/groups",
+					formId: "groupform",
+					alertDiv: "alertMessage",
+					modal: groupModal,
+				});
 
-				function fetchIndividualEntity(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					if (filterValue === "") {
-						itemSelect.innerHTML = "<option disabled>select a group</option>";
-						getGroups("");
-						getAdditionalGroups();
-					} else {
-						itemSelect.innerHTML = "";
-						getGroups(filterValue);
-					}
-				}
-
-				let limit = 5;
-
-				function getGroups(name) {
-					fetchData(name, 1);
-				}
+				submitCreateForm({
+					url: "/groups/bulk",
+					formId: "bulkgroupsform",
+					alertDiv: "alertBulkMessage",
+					modal: groupsModal,
+				});
 
-				function getAdditionalGroups() {
-					var selectElement = document.getElementById("infiniteScroll");
-					var singleOptionHeight =
-						selectElement.querySelector("option").offsetHeight;
-					var selectBoxHeight = selectElement.offsetHeight;
-					var numOptionsBeforeLoad = 2;
-					var lastScrollTop = 0;
-					var currentPageNo = 1;
-					var currentScroll = 0;
-
-					selectElement.addEventListener("scroll", onselectScroll);
-
-					function onselectScroll(event) {
-						var st = selectElement.scrollTop;
-						var totalHeight =
-							selectElement.querySelectorAll("option").length *
-							singleOptionHeight;
-
-						if (st > lastScrollTop) {
-							currentScroll = st + selectBoxHeight;
-							if (
-								currentScroll + numOptionsBeforeLoad * singleOptionHeight >=
-								totalHeight
-							) {
-								currentPageNo++;
-								fetchData("", currentPageNo);
-							}
-						}
-
-						lastScrollTop = st;
-					}
-				}
-
-				function fetchData(name, page) {
-					fetch(
-						`/entities?item=groups&limit=${limit}&name=${name}&page=${page}`,
-						{
-							method: "GET",
-						},
-					)
-						.then((response) => response.json())
-						.then((data) => {
-							const selectElement = document.getElementById("infiniteScroll");
-							data.data.forEach((group) => {
-								const option = document.createElement("option");
-								option.value = group.id;
-								option.text = group.name;
-								selectElement.appendChild(option);
-							});
-						})
-						.catch((error) => console.error("Error:", error));
-				}
+				fetchIndividualEntity({
+					input: "parentFilter",
+					itemSelect: "infiniteScroll",
+					item: "groups",
+				});
 			</script>
 		</body>
 	</html>
diff --git a/ui/web/template/thing.html b/ui/web/template/thing.html
index 1840bdf5f..c75ebb9c7 100644
--- a/ui/web/template/thing.html
+++ b/ui/web/template/thing.html
@@ -49,7 +49,7 @@
 												<td>
 													<button
 														class="edit-btn"
-														onclick="editRow('name')"
+														id="edit-name"
 														{{ if
 															$disableButton
 														}}
@@ -62,13 +62,10 @@
 														class="save-cancel-buttons"
 														style="display: none"
 													>
-														<button class="save-btn" onclick="saveRow('name')">
+														<button class="save-btn" id="save-name">
 															Save
 														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('name')"
-														>
+														<button class="cancel-btn" id="cancel-name">
 															Cancel
 														</button>
 													</div>
@@ -91,7 +88,7 @@
 												<td>
 													<button
 														class="edit-btn"
-														onclick="editRow('secret')"
+														id="edit-secret"
 														{{ if
 															$disableButton
 														}}
@@ -104,16 +101,10 @@
 														class="save-cancel-buttons"
 														style="display: none"
 													>
-														<button
-															class="save-btn"
-															onclick="saveRow('secret')"
-														>
+														<button class="save-btn" id="save-secret">
 															Save
 														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('secret')"
-														>
+														<button class="cancel-btn" id="cancel-secret">
 															Cancel
 														</button>
 													</div>
@@ -131,7 +122,7 @@
 												<td>
 													<button
 														class="edit-btn"
-														onclick="editRow('tags')"
+														id="edit-tags"
 														{{ if
 															$disableButton
 														}}
@@ -144,13 +135,10 @@
 														class="save-cancel-buttons"
 														style="display: none"
 													>
-														<button class="save-btn" onclick="saveRow('tags')">
+														<button class="save-btn" id="save-tags">
 															Save
 														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('tags')"
-														>
+														<button class="cancel-btn" id="cancel-tags">
 															Cancel
 														</button>
 													</div>
@@ -168,7 +156,7 @@
 												<td>
 													<button
 														class="edit-btn"
-														onclick="editRow('owner')"
+														id="edit-owner"
 														{{ if
 															$disableButton
 														}}
@@ -181,13 +169,10 @@
 														class="save-cancel-buttons"
 														style="display: none"
 													>
-														<button class="save-btn" onclick="saveRow('owner')">
+														<button class="save-btn" id="save-owner">
 															Save
 														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('owner')"
-														>
+														<button class="cancel-btn" id="cancel-owner">
 															Cancel
 														</button>
 													</div>
@@ -205,7 +190,7 @@
 												<td>
 													<button
 														class="edit-btn"
-														onclick="editRow('metadata')"
+														id="edit-metadata"
 														{{ if
 															$disableButton
 														}}
@@ -218,16 +203,10 @@
 														class="save-cancel-buttons"
 														style="display: none"
 													>
-														<button
-															class="save-btn"
-															onclick="saveRow('metadata')"
-														>
+														<button class="save-btn" id="save-metadata">
 															Save
 														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('metadata')"
-														>
+														<button class="cancel-btn" id="cancel-metadata">
 															Cancel
 														</button>
 													</div>
@@ -244,149 +223,20 @@
 			</div>
 			{{ template "footer" }}
     <script>
-      function makeEditable(cell) {
-        cell.setAttribute("contenteditable", "true");
-        cell.dataset.originalContent = cell.innerHTML;
-      }
-
-      function makeUneditable(cell) {
-        const originalContent = cell.dataset.originalContent;
-        cell.innerHTML = originalContent;
-        cell.setAttribute("contenteditable", "false");
-      }
-
-      function showButtons(editBtn, saveCancelBtn) {
-        editBtn.style.display = "none";
-        saveCancelBtn.style.display = "inline-block";
-      }
-
-      function hideButtons(editBtn, saveCancelBtn) {
-        editBtn.style.display = "inline-block";
-        saveCancelBtn.style.display = "none";
-      }
-
-      function editRow(field) {
-        const cell = document.querySelector(`td[data-field='${field}']`);
-        const editBtn = cell.parentNode.querySelector(".edit-btn");
-        const saveCancelBtn = cell.parentNode.querySelector(
-          ".save-cancel-buttons",
-        );
-
-        // Make the row editable
-        makeEditable(cell);
-
-        // Hide the edit button and show save and cancel buttons
-        showButtons(editBtn, saveCancelBtn);
-      }
-
-      function saveRow(field) {
-        const cell = document.querySelector(`td[data-field='${field}']`);
-        const editBtn = cell.parentNode.querySelector(".edit-btn");
-        const saveCancelBtn = cell.parentNode.querySelector(
-          ".save-cancel-buttons",
-        );
-        const errorMessage = document.getElementById("error-message");
-
-        // Get the updated value from the nameCell
-        const updatedValue = cell.textContent.trim();
-
-        // Send the updated value to the server using a POST request
-        let url;
-        let data;
-        if (field === "name") {
-          url = "/things/{{.Thing.ID}}";
-          data = { [field]: updatedValue };
-        } else if (field == "metadata") {
-          try {
-            const metadata = JSON.parse(updatedValue);
-            url = "/things/{{.Thing.ID}}";
-            data = { [field]: metadata };
-          } catch (error) {
-            errorMessage.textContent = "Metadata must be a valid JSON object!";
-            return;
-          }
-        } else if (field === "secret") {
-          if (updatedValue.length < 8) {
-            errorMessage.textContent =
-              "Secret must have a minimum of 8 characters!";
-            return;
-          }
-          url = "/things/{{.Thing.ID}}/secret";
-          data = { [field]: updatedValue };
-        } else if (field === "tags") {
-          try {
-            const tags = JSON.parse(updatedValue);
-            if (
-              !Array.isArray(tags) ||
-              !tags.every(function (tag) {
-                return typeof tag === "string";
-              })
-            ) {
-              errorMessage.textContent = "Tags must be a string array!";
-              return;
-            }
-            url = "/things/{{.Thing.ID}}/tags";
-            data = { [field]: JSON.parse(updatedValue) };
-          } catch (error) {
-            errorMessage.textContent = "Tags must be a valid string array";
-            return;
-          }
-        } else if (field === "owner") {
-          url = "/things/{{.Thing.ID}}/owner";
-          data = { [field]: updatedValue };
-        }
-
-        errorMessage.textContent = "";
-
-        if (url) {
-			errorMessage.textContent="";
-			fetch(url, {
-				method: "POST",
-				body: JSON.stringify(data),
-				headers: {
-				"Content-Type": "application/json",
+		attachEditRowListener(
+			{
+				entity: "things",
+				id: "{{ .Thing.ID }}",
+				rows: {
+					name:updateName,
+					secret: updateSecret,
+					tags:updateTags,
+					owner: updateOwner,
+					metadata:updateMetadata,
 				},
-			})
-            .then((response) => {
-              if (response.ok) {
-                // Make the row uneditable
-                cell.setAttribute("contenteditable", "false");
-
-                // Show edit button and hide save and cancel buttons
-                hideButtons(editBtn, saveCancelBtn);
-              }
-            })
-            .catch((error) => {
-              // Restore original values in the row if there is an error
-              makeUneditable(cell);
-
-              // Show edit button and hide save and cancel buttons
-              hideButtons(editBtn, saveCancelBtn);
-
-              console.error("Error", error);
-			  errorMessage.textContent=error;
-            });
-        } else {
-          console.error("Invalid field:", field);
-        }
-      }
-
-      function cancelEditRow(field) {
-        const cell = document.querySelector(`td[data-field='${field}']`);
-        const editBtn = cell.parentNode.querySelector(".edit-btn");
-        const saveCancelBtn = cell.parentNode.querySelector(
-          ".save-cancel-buttons",
-        );
-        const errorMessage = document.getElementById("error-message");
-
-        errorMessage.textContent = "";
-
-        // Restore original values in the row
-        makeUneditable(cell);
-
-        // Show the edit button and hide the save and cancel buttons
-        hideButtons(editBtn, saveCancelBtn);
-      }
+				errorDiv: "error-message",
+			}
+		);
     </script>
 		</body>
 	</html>
diff --git a/ui/web/template/things.html b/ui/web/template/things.html
index 7bc5d336e..76dbc8b85 100644
--- a/ui/web/template/things.html
+++ b/ui/web/template/things.html
@@ -40,10 +40,7 @@ <h5 class="modal-title" id="addThingModalLabel">
 												</div>
 												<div class="modal-body">
 													<div id="alertMessage"></div>
-													<form
-														method="post"
-														onsubmit="return submitThingForm()"
-													>
+													<form id="thingform">
 														<div class="mb-3">
 															<label for="name" class="form-label">Name</label>
 															<input
@@ -52,8 +49,8 @@ <h5 class="modal-title" id="addThingModalLabel">
 																name="name"
 																id="name"
 																placeholder="Device Name"
-																required
 															/>
+															<div id="nameError" class="text-danger"></div>
 														</div>
 														<div class="mb-3">
 															<label for="thingID" class="form-label">
@@ -105,7 +102,7 @@ <h5 class="modal-title" id="addThingModalLabel">
 															<div id="tagHelp" class="form-text">
 																Enter device tags as a string slice.
 															</div>
-															<div id="tagsError" class="error-message"></div>
+															<div id="tagsError" class="text-danger"></div>
 														</div>
 														<div class="mb-3">
 															<label for="metadata" class="form-label">
@@ -121,15 +118,12 @@ <h5 class="modal-title" id="addThingModalLabel">
 															<div id="metadataHelp" class="form-text">
 																Enter device metadata in JSON format.
 															</div>
-															<div
-																id="metadataError"
-																class="error-message"
-															></div>
+															<div id="metadataError" class="text-danger"></div>
 														</div>
 														<button
 															type="submit"
 															class="btn body-button"
-															onclick="return validateForm()"
+															id="create-thing-button"
 														>
 															Submit
 														</button>
@@ -169,7 +163,7 @@ <h5 class="modal-title" id="addThingsModalLabel">
 													<form
 														method="post"
 														enctype="multipart/form-data"
-														onsubmit="return submitBulkThingsForm()"
+														id="bulkThingsForm"
 													>
 														<div class="form-group">
 															<label for="thingsFile">
@@ -274,58 +268,19 @@ <h5 class="modal-title" id="addThingsModalLabel">
 			</div>
 			{{ template "footer" }}
 			<script>
-				function validateForm() {
-					var secret = document.getElementById("secret").value;
-					var tagsInput = document.getElementById("tags").value;
-					var metadataInput = document.getElementById("metadata").value;
-
-					var secretError = document.getElementById("secretError");
-					var tagsError = document.getElementById("tagsError");
-					var metadataError = document.getElementById("metadataError");
-
-					var tags;
-					var metadata;
-
-					secretError.innerHTML = "";
-					tagsError.innerHTML = "";
-					metadataError.innerHTML = "";
-
-					var isValid = true;
-
-					if (secret.trim() != "") {
-						if (secret.length < 8) {
-							secretError.innerHTML =
-								"Secret must have a minimum of 8 characters";
-							isValid = false;
-						}
-					}
-					try {
-						tags = JSON.parse(tagsInput);
-					} catch (error) {
-						tagsError.innerHTML = "Please enter valid tags as a string array!";
-						isValid = false;
-					}
-
-					if (
-						!Array.isArray(tags) ||
-						!tags.every(function (tag) {
-							return typeof tag === "string";
-						})
-					) {
-						tagsError.innerHTML = "Tags must be a string array!";
-						isValid = false;
-					}
-
-					try {
-						metadata = JSON.parse(metadataInput);
-					} catch (error) {
-						metadataError.innerHTML =
-							"Please enter valid metadata in JSON format!";
-						isValid = false;
-					}
-
-					return isValid;
-				}
+				attachValidationListener({
+					buttonId: "create-thing-button",
+					errorDivs: {
+						name: "nameError",
+						metadata: "metadataError",
+						tags: "tagsError",
+					},
+					validations: {
+						name: validateName,
+						metadata: validateMetadata,
+						tags: validateTags,
+					},
+				});
 
 				const thingModal = new bootstrap.Modal(
 					document.getElementById("addThingModal"),
@@ -342,90 +297,19 @@ <h5 class="modal-title" id="addThingsModalLabel">
 					}
 				}
 
-				function submitThingForm() {
-					event.preventDefault();
-					var form = event.target;
-					fetch("/things", {
-						method: "POST",
-						body: new FormData(form),
-					})
-						.then((response) => {
-							if (response.status === 409) {
-								errorMessage = "thing already exists!";
-								showAlert(errorMessage, "single");
-								return false;
-							} else {
-								form.reset();
-								thingModal.hide();
-								window.location.reload();
-								return true;
-							}
-						})
-						.catch((error) => {
-							console.error("error submitting thing form: ", error);
-							return false;
-						});
-				}
-
-				function submitBulkThingsForm() {
-					event.preventDefault();
-					var form = event.target;
-					fetch("/things/bulk", {
-						method: "POST",
-						body: new FormData(form),
-					})
-						.then((response) => {
-							switch (response.status) {
-								case 409:
-									errorMessage = "things already exist!";
-									showAlert(errorMessage, "bulk");
-									return false;
-								case 400:
-									errorMessage = "invalid file contents!";
-									showAlert(errorMessage, "bulk");
-									return false;
-								case 415:
-									errorMessage = "file must be csv!";
-									showAlert(errorMessage, "bulk");
-									return false;
-								case 500:
-									errorMessage = "try again!";
-									showAlert(errorMessage, "bulk");
-									return false;
-								default:
-									form.reset();
-									thingsModal.hide();
-									window.location.reload();
-									return true;
-							}
-						})
-						.catch((error) => {
-							console.error("Error submitting bulk things form: ", error);
-							return false;
-						});
-				}
+				submitCreateForm({
+					url: "/things",
+					formId: "thingform",
+					alertDiv: "alertMessage",
+					modal: thingModal,
+				});
 
-				function showAlert(errorMessage, modal) {
-					if (modal === "single") {
-						var alertMessage = document.getElementById("alertMessage");
-						alertMessage.innerHTML = `
-          <div id="alert-popup" class="alert alert-danger">
-            <span class="close-button" onclick="closeAlertPopup()">&times;</span>
-            <h5 class="alert-messsage" id="alert-message">${errorMessage}</h5>
-          </div> `;
-					} else if (modal === "bulk") {
-						var alertMessage = document.getElementById("alertBulkMessage");
-						alertMessage.innerHTML = `
-          <div id="alert-popup" class="alert alert-danger">
-            <span class="close-button" onclick="closeAlertPopup()">&times;</span>
-            <h5 class="alert-messsage" id="alert-message">${errorMessage}</h5>
-          </div> `;
-					}
-				}
-
-				function closeAlertPopup() {
-					document.getElementById("alert-popup").style.display = "none";
-				}
+				submitCreateForm({
+					url: "/things/bulk",
+					formId: "bulkThingsForm",
+					alertDiv: "alertBulkMessage",
+					modal: thingsModal,
+				});
 			</script>
 		</body>
 	</html>

From 83a5d3255ed99642f31966c93957b1296dce1d05 Mon Sep 17 00:00:00 2001
From: ianmuchyri <ianmuchiri8@gmail.com>
Date: Mon, 27 Nov 2023 15:58:54 +0300
Subject: [PATCH 04/11] update entity dependency templates

Signed-off-by: ianmuchyri <ianmuchiri8@gmail.com>
---
 ui/web/template/bootstraps.html    | 92 ++----------------------------
 ui/web/template/channelgroups.html | 80 +++-----------------------
 ui/web/template/channelthings.html | 80 +++-----------------------
 ui/web/template/channelusers.html  | 79 +++----------------------
 ui/web/template/groupchannels.html | 80 +++-----------------------
 ui/web/template/groupusers.html    | 79 +++----------------------
 ui/web/template/thingchannels.html | 80 +++-----------------------
 ui/web/template/thingusers.html    | 81 +++-----------------------
 ui/web/template/userchannels.html  | 79 +++----------------------
 ui/web/template/usergroups.html    | 80 +++-----------------------
 ui/web/template/userthings.html    | 83 +++------------------------
 11 files changed, 86 insertions(+), 807 deletions(-)

diff --git a/ui/web/template/bootstraps.html b/ui/web/template/bootstraps.html
index e8fe11a84..5e14dc3c6 100644
--- a/ui/web/template/bootstraps.html
+++ b/ui/web/template/bootstraps.html
@@ -62,7 +62,6 @@ <h5 class="modal-title" id="addBootstrapModalLabel">
 																name="thingFilter"
 																id="thingFilter"
 																placeholder="Filter by Thing name"
-																oninput="fetchIndividualEntity(this.value,'infiniteScroll')"
 															/>
 															<select
 																class="form-select"
@@ -276,20 +275,6 @@ <h5 class="modal-title" id="addBootstrapModalLabel">
 
 					return isValid;
 				}
-				function filterItem(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					const options = itemSelect.getElementsByTagName("option");
-
-					for (let i = 0; i < options.length; i++) {
-						const option = options[i];
-						const itemId = option.value;
-						const itemName = option.innerHTML;
-						const shouldShow =
-							itemId.includes(filterValue) ||
-							itemName.toLowerCase().includes(filterValue.toLowerCase());
-						option.style.display = shouldShow ? "" : "none";
-					}
-				}
 
 				const bootstrapsModal = new bootstrap.Modal(
 					document.getElementById("addBootstrapModal"),
@@ -297,80 +282,13 @@ <h5 class="modal-title" id="addBootstrapModalLabel">
 
 				function openModal() {
 					bootstrapsModal.show();
-					getThings("");
-					getAdditionalThings();
-				}
-
-				function fetchIndividualEntity(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					if (filterValue === "") {
-						itemSelect.innerHTML = "<option disabled>select a group</option>";
-						getThings("");
-						getAdditionalThings();
-					} else {
-						itemSelect.innerHTML = "";
-						getThings(filterValue);
-					}
-				}
-
-				let limit = 5;
-
-				function getThings(name) {
-					fetchData(name, 1);
 				}
 
-				function getAdditionalThings() {
-					var selectElement = document.getElementById("infiniteScroll");
-					var singleOptionHeight =
-						selectElement.querySelector("option").offsetHeight;
-					var selectBoxHeight = selectElement.offsetHeight;
-					var numOptionsBeforeLoad = 2;
-					var lastScrollTop = 0;
-					var currentPageNo = 1;
-					var currentScroll = 0;
-
-					selectElement.addEventListener("scroll", onselectScroll);
-
-					function onselectScroll(event) {
-						var st = selectElement.scrollTop;
-						var totalHeight =
-							selectElement.querySelectorAll("option").length *
-							singleOptionHeight;
-
-						if (st > lastScrollTop) {
-							currentScroll = st + selectBoxHeight;
-							if (
-								currentScroll + numOptionsBeforeLoad * singleOptionHeight >=
-								totalHeight
-							) {
-								currentPageNo++;
-								fetchData("", currentPageNo);
-							}
-						}
-
-						lastScrollTop = st;
-					}
-				}
-
-				function fetchData(name, page) {
-					fetch(
-						`/entities?item=things&limit=${limit}&name=${name}&page=${page}`,
-						{
-							method: "GET",
-						},
-					)
-						.then((response) => response.json())
-						.then((data) => {
-							const selectElement = document.getElementById("infiniteScroll");
-							data.data.forEach((group) => {
-								const option = document.createElement("option");
-								option.value = group.id;
-								option.text = group.name;
-								selectElement.appendChild(option);
-							});
-						})
-						.catch((error) => console.error("Error:", error));
-				}
+				fetchIndividualEntity({
+					input: "thingFilter",
+					itemSelect: "infiniteScroll",
+					item: "things",
+				});
 			</script>
 		</body>
 	</html>
diff --git a/ui/web/template/channelgroups.html b/ui/web/template/channelgroups.html
index 3946a72a0..eea84035b 100644
--- a/ui/web/template/channelgroups.html
+++ b/ui/web/template/channelgroups.html
@@ -75,20 +75,19 @@ <h4>Channel Groups</h4>
 													>
 														<div class="modal-body">
 															<div class="mb-3">
-																<label for="groups" class="form-label">
+																<label for="infiniteScroll" class="form-label">
 																	Group ID
 																</label>
 																<input
 																	type="text"
 																	name="groupFilter"
-																	id="groupFilterAssign"
+																	id="groupFilter"
 																	placeholder="Filter by Group ID"
-																	oninput="fetchIndividualEntity(this.value,'groups')"
 																/>
 																<select
 																	class="form-select"
 																	name="groupID"
-																	id="groups"
+																	id="infiniteScroll"
 																	size="5"
 																	required
 																>
@@ -191,76 +190,13 @@ <h4>Channel Groups</h4>
 				);
 				function openGroupModal() {
 					groupModal.show();
-					getGroup("");
-					getAdditionalGroups("");
 				}
-				function fetchIndividualEntity(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					if (filterValue === "") {
-						itemSelect.innerHTML = "<option disabled>select a group</option>";
-						getGroup("");
-						getAdditionalGroups();
-					} else {
-						itemSelect.innerHTML = "";
-						getGroup(filterValue);
-					}
-				}
-				let limit = 5;
-
-				function getGroup(name) {
-					fetchGroupData(name, 1);
-				}
-				function getAdditionalGroups() {
-					var selectElement = document.getElementById("groups");
-					var singleOptionHeight =
-						selectElement.querySelector("option").offsetHeight;
-					var selectBoxHeight = selectElement.offsetHeight;
-					var numOptionsBeforeLoad = 2;
-					var lastScrollTop = 0;
-					var currentPageNo = 1;
-					var currentScroll = 0;
-
-					selectElement.addEventListener("scroll", onselectScroll);
 
-					function onselectScroll(event) {
-						var st = selectElement.scrollTop;
-						var totalHeight =
-							selectElement.querySelectorAll("option").length *
-							singleOptionHeight;
-
-						if (st > lastScrollTop) {
-							currentScroll = st + selectBoxHeight;
-							if (
-								currentScroll + numOptionsBeforeLoad * singleOptionHeight >=
-								totalHeight
-							) {
-								currentPageNo++;
-								fetchGroupData("", currentPageNo);
-							}
-						}
-
-						lastScrollTop = st;
-					}
-				}
-				function fetchGroupData(name, page) {
-					fetch(
-						`/entities?item=groups&limit=${limit}&name=${name}&page=${page}`,
-						{
-							method: "GET",
-						},
-					)
-						.then((response) => response.json())
-						.then((data) => {
-							const selectElement = document.getElementById("groups");
-							data.data.forEach((group) => {
-								const option = document.createElement("option");
-								option.value = group.id;
-								option.text = group.name;
-								selectElement.appendChild(option);
-							});
-						})
-						.catch((error) => console.error("Error:", error));
-				}
+				fetchIndividualEntity({
+					input: "groupFilter",
+					itemSelect: "infiniteScroll",
+					item: "groups",
+				});
 			</script>
 		</body>
 	</html>
diff --git a/ui/web/template/channelthings.html b/ui/web/template/channelthings.html
index 8b86c57a5..1334325c4 100644
--- a/ui/web/template/channelthings.html
+++ b/ui/web/template/channelthings.html
@@ -75,20 +75,19 @@ <h4>Channel Things</h4>
 													>
 														<div class="modal-body">
 															<div class="mb-3">
-																<label for="things" class="form-label">
+																<label for="infiniteScroll" class="form-label">
 																	Thing ID
 																</label>
 																<input
 																	type="text"
 																	name="thingFilter"
-																	id="thingFilterAssign"
+																	id="thingFilter"
 																	placeholder="Filter by Thing ID"
-																	oninput="fetchIndividualEntity(this.value,'things')"
 																/>
 																<select
 																	class="form-select"
 																	name="thingID"
-																	id="things"
+																	id="infiniteScroll"
 																	size="5"
 																	required
 																>
@@ -191,76 +190,13 @@ <h4>Channel Things</h4>
 				);
 				function openThingModal() {
 					thingModal.show();
-					getThing("");
-					getAdditionalThings("");
 				}
-				function fetchIndividualEntity(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					if (filterValue === "") {
-						itemSelect.innerHTML = "<option disabled>select a thing</option>";
-						getThing("");
-						getAdditionalThings();
-					} else {
-						itemSelect.innerHTML = "";
-						getThing(filterValue);
-					}
-				}
-				let limit = 5;
-
-				function getThing(name) {
-					fetchThingData(name, 1);
-				}
-				function getAdditionalThings() {
-					var selectElement = document.getElementById("things");
-					var singleOptionHeight =
-						selectElement.querySelector("option").offsetHeight;
-					var selectBoxHeight = selectElement.offsetHeight;
-					var numOptionsBeforeLoad = 2;
-					var lastScrollTop = 0;
-					var currentPageNo = 1;
-					var currentScroll = 0;
-
-					selectElement.addEventListener("scroll", onselectScroll);
 
-					function onselectScroll(event) {
-						var st = selectElement.scrollTop;
-						var totalHeight =
-							selectElement.querySelectorAll("option").length *
-							singleOptionHeight;
-
-						if (st > lastScrollTop) {
-							currentScroll = st + selectBoxHeight;
-							if (
-								currentScroll + numOptionsBeforeLoad * singleOptionHeight >=
-								totalHeight
-							) {
-								currentPageNo++;
-								fetchThingData("", currentPageNo);
-							}
-						}
-
-						lastScrollTop = st;
-					}
-				}
-				function fetchThingData(name, page) {
-					fetch(
-						`/entities?item=things&limit=${limit}&name=${name}&page=${page}`,
-						{
-							method: "GET",
-						},
-					)
-						.then((response) => response.json())
-						.then((data) => {
-							const selectElement = document.getElementById("things");
-							data.data.forEach((thing) => {
-								const option = document.createElement("option");
-								option.value = thing.id;
-								option.text = thing.name;
-								selectElement.appendChild(option);
-							});
-						})
-						.catch((error) => console.error("Error:", error));
-				}
+				fetchIndividualEntity({
+					input: "thingFilter",
+					itemSelect: "infiniteScroll",
+					item: "things",
+				});
 			</script>
 		</body>
 	</html>
diff --git a/ui/web/template/channelusers.html b/ui/web/template/channelusers.html
index 43397599d..c66619721 100644
--- a/ui/web/template/channelusers.html
+++ b/ui/web/template/channelusers.html
@@ -72,20 +72,19 @@ <h1 class="modal-title fs-5" id="addUserModalLabel">
 													>
 														<div class="modal-body">
 															<div class="mb-3">
-																<label for="users" class="form-label">
+																<label for="infiniteScroll" class="form-label">
 																	User ID
 																</label>
 																<input
 																	type="text"
 																	name="userFilter"
-																	id="userFilterAssign"
+																	id="userFilter"
 																	placeholder="Filter by User ID"
-																	oninput="fetchIndividualEntity(this.value,'users')"
 																/>
 																<select
 																	class="form-select"
 																	name="userID"
-																	id="users"
+																	id="infiniteScroll"
 																	size="5"
 																	required
 																>
@@ -520,76 +519,14 @@ <h1 class="modal-title fs-5" id="addUserModalLabel">
 				);
 				function openUserModal() {
 					userModal.show();
-					getUser("");
-					getAdditionalUsers("");
 				}
-				function fetchIndividualEntity(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					if (filterValue === "") {
-						itemSelect.innerHTML = "<option disabled>select a user</option>";
-						getUser("");
-						getAdditionalUsers();
-					} else {
-						itemSelect.innerHTML = "";
-						getUser(filterValue);
-					}
-				}
-				let limit = 5;
-
-				function getUser(name) {
-					fetchUserData(name, 1);
-				}
-				function getAdditionalUsers() {
-					var selectElement = document.getElementById("users");
-					var singleOptionHeight =
-						selectElement.querySelector("option").offsetHeight;
-					var selectBoxHeight = selectElement.offsetHeight;
-					var numOptionsBeforeLoad = 2;
-					var lastScrollTop = 0;
-					var currentPageNo = 1;
-					var currentScroll = 0;
-
-					selectElement.addEventListener("scroll", onselectScroll);
 
-					function onselectScroll(event) {
-						var st = selectElement.scrollTop;
-						var totalHeight =
-							selectElement.querySelectorAll("option").length *
-							singleOptionHeight;
+				fetchIndividualEntity({
+					input: "userFilter",
+					itemSelect: "infiniteScroll",
+					item: "users",
+				});
 
-						if (st > lastScrollTop) {
-							currentScroll = st + selectBoxHeight;
-							if (
-								currentScroll + numOptionsBeforeLoad * singleOptionHeight >=
-								totalHeight
-							) {
-								currentPageNo++;
-								fetchUserData("", currentPageNo);
-							}
-						}
-
-						lastScrollTop = st;
-					}
-				}
-				function fetchUserData(name, page) {
-					fetch(
-						`/entities?item=users&limit=${limit}&name=${name}&page=${page}`,
-						{
-							method: "GET",
-						},
-					)
-						.then((response) => response.json())
-						.then((data) => {
-							const selectElement = document.getElementById("users");
-							data.data.forEach((user) => {
-								const option = document.createElement("option");
-								option.value = user.id;
-								option.text = user.name;
-								selectElement.appendChild(option);
-							});
-						})
-						.catch((error) => console.error("Error:", error));
-				}
                 function openTab(relation) {
 					event.preventDefault();
                     var channelID = '{{.ChannelID}}';
diff --git a/ui/web/template/groupchannels.html b/ui/web/template/groupchannels.html
index 2a7f37d04..6973610c8 100644
--- a/ui/web/template/groupchannels.html
+++ b/ui/web/template/groupchannels.html
@@ -68,20 +68,19 @@ <h4>Group Channels</h4>
 													>
 														<div class="modal-body">
 															<div class="mb-3">
-																<label for="channels" class="form-label">
+																<label for="infiniteScroll" class="form-label">
 																	Channel ID
 																</label>
 																<input
 																	type="text"
 																	name="channelFilter"
-																	id="channelFilterAssign"
+																	id="channelFilter"
 																	placeholder="Filter by Channel ID"
-																	oninput="fetchIndividualEntity(this.value,'channels')"
 																/>
 																<select
 																	class="form-select"
 																	name="channelID"
-																	id="channels"
+																	id="infiniteScroll"
 																	size="5"
 																	required
 																>
@@ -184,76 +183,13 @@ <h4>Group Channels</h4>
 				);
 				function openChannelModal() {
 					channelModal.show();
-					getChannel("");
-					getAdditionalChannels("");
 				}
-				function fetchIndividualGroup(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					if (filterValue === "") {
-						itemSelect.innerHTML = "<option disabled>select a channel</option>";
-						getChannel("");
-						getAdditionalChannels();
-					} else {
-						itemSelect.innerHTML = "";
-						getChannel(filterValue);
-					}
-				}
-				let limit = 5;
-
-				function getChannel(name) {
-					fetchChannelData(name, 1);
-				}
-				function getAdditionalChannels() {
-					var selectElement = document.getElementById("channels");
-					var singleOptionHeight =
-						selectElement.querySelector("option").offsetHeight;
-					var selectBoxHeight = selectElement.offsetHeight;
-					var numOptionsBeforeLoad = 2;
-					var lastScrollTop = 0;
-					var currentPageNo = 1;
-					var currentScroll = 0;
-
-					selectElement.addEventListener("scroll", onselectScroll);
 
-					function onselectScroll(event) {
-						var st = selectElement.scrollTop;
-						var totalHeight =
-							selectElement.querySelectorAll("option").length *
-							singleOptionHeight;
-
-						if (st > lastScrollTop) {
-							currentScroll = st + selectBoxHeight;
-							if (
-								currentScroll + numOptionsBeforeLoad * singleOptionHeight >=
-								totalHeight
-							) {
-								currentPageNo++;
-								fetchChannelData("", currentPageNo);
-							}
-						}
-
-						lastScrollTop = st;
-					}
-				}
-				function fetchChannelData(name, page) {
-					fetch(
-						`/entities?item=channels&limit=${limit}&name=${name}&page=${page}`,
-						{
-							method: "GET",
-						},
-					)
-						.then((response) => response.json())
-						.then((data) => {
-							const selectElement = document.getElementById("channels");
-							data.data.forEach((channel) => {
-								const option = document.createElement("option");
-								option.value = channel.id;
-								option.text = channel.name;
-								selectElement.appendChild(option);
-							});
-						})
-						.catch((error) => console.error("Error:", error));
-				}
+				fetchIndividualEntity({
+					input: "channelFilter",
+					itemSelect: "infiniteScroll",
+					item: "channels",
+				});
 			</script>
 		</body>
 	</html>
diff --git a/ui/web/template/groupusers.html b/ui/web/template/groupusers.html
index 11903623f..ea72a05d9 100644
--- a/ui/web/template/groupusers.html
+++ b/ui/web/template/groupusers.html
@@ -65,20 +65,19 @@ <h1 class="modal-title fs-5" id="addUserModalLabel">
 													>
 														<div class="modal-body">
 															<div class="mb-3">
-																<label for="users" class="form-label">
+																<label for="infiniteScroll" class="form-label">
 																	User ID
 																</label>
 																<input
 																	type="text"
 																	name="userFilter"
-																	id="userFilterAssign"
+																	id="userFilter"
 																	placeholder="Filter by User ID"
-																	oninput="fetchIndividualEntity(this.value,'users')"
 																/>
 																<select
 																	class="form-select"
 																	name="userID"
-																	id="users"
+																	id="infiniteScroll"
 																	size="5"
 																	required
 																>
@@ -514,76 +513,14 @@ <h1 class="modal-title fs-5" id="addUserModalLabel">
 				);
 				function openUserModal() {
 					userModal.show();
-					getUser("");
-					getAdditionalUsers("");
 				}
-				function fetchIndividualEntity(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					if (filterValue === "") {
-						itemSelect.innerHTML = "<option disabled>select a user</option>";
-						getUser("");
-						getAdditionalUsers();
-					} else {
-						itemSelect.innerHTML = "";
-						getUser(filterValue);
-					}
-				}
-				let limit = 5;
-
-				function getUser(name) {
-					fetchUserData(name, 1);
-				}
-				function getAdditionalUsers() {
-					var selectElement = document.getElementById("users");
-					var singleOptionHeight =
-						selectElement.querySelector("option").offsetHeight;
-					var selectBoxHeight = selectElement.offsetHeight;
-					var numOptionsBeforeLoad = 2;
-					var lastScrollTop = 0;
-					var currentPageNo = 1;
-					var currentScroll = 0;
-
-					selectElement.addEventListener("scroll", onselectScroll);
 
-					function onselectScroll(event) {
-						var st = selectElement.scrollTop;
-						var totalHeight =
-							selectElement.querySelectorAll("option").length *
-							singleOptionHeight;
+				fetchIndividualEntity({
+					input: "userFilter",
+					itemSelect: "infiniteScroll",
+					item: "users",
+				});
 
-						if (st > lastScrollTop) {
-							currentScroll = st + selectBoxHeight;
-							if (
-								currentScroll + numOptionsBeforeLoad * singleOptionHeight >=
-								totalHeight
-							) {
-								currentPageNo++;
-								fetchUserData("", currentPageNo);
-							}
-						}
-
-						lastScrollTop = st;
-					}
-				}
-				function fetchUserData(name, page) {
-					fetch(
-						`/entities?item=users&limit=${limit}&name=${name}&page=${page}`,
-						{
-							method: "GET",
-						},
-					)
-						.then((response) => response.json())
-						.then((data) => {
-							const selectElement = document.getElementById("users");
-							data.data.forEach((user) => {
-								const option = document.createElement("option");
-								option.value = user.id;
-								option.text = user.name;
-								selectElement.appendChild(option);
-							});
-						})
-						.catch((error) => console.error("Error:", error));
-				}
 				function openTab(relation) {
 					event.preventDefault();
                     var groupID = '{{.GroupID}}';
diff --git a/ui/web/template/thingchannels.html b/ui/web/template/thingchannels.html
index 44a751333..774b5b417 100644
--- a/ui/web/template/thingchannels.html
+++ b/ui/web/template/thingchannels.html
@@ -68,20 +68,19 @@ <h4>Thing Channels</h4>
 													>
 														<div class="modal-body">
 															<div class="mb-3">
-																<label for="channels" class="form-label">
+																<label for="infiniteScroll" class="form-label">
 																	Channel ID
 																</label>
 																<input
 																	type="text"
 																	name="channelFilter"
-																	id="channelFilterAssign"
+																	id="channelFilter"
 																	placeholder="Filter by Channel ID"
-																	oninput="fetchIndividualEntity(this.value,'channels')"
 																/>
 																<select
 																	class="form-select"
 																	name="channelID"
-																	id="channels"
+																	id="infiniteScroll"
 																	size="5"
 																	required
 																>
@@ -265,76 +264,13 @@ <h4>Thing Channels</h4>
 				);
 				function openChannelModal() {
 					channelModal.show();
-					getChannel("");
-					getAdditionalChannels("");
 				}
-				function fetchIndividualEntity(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					if (filterValue === "") {
-						itemSelect.innerHTML = "<option disabled>select a channel</option>";
-						getChannel("");
-						getAdditionalChannels();
-					} else {
-						itemSelect.innerHTML = "";
-						getChannel(filterValue);
-					}
-				}
-				let limit = 5;
-
-				function getChannel(name) {
-					fetchChannelData(name, 1);
-				}
-				function getAdditionalChannels() {
-					var selectElement = document.getElementById("channels");
-					var singleOptionHeight =
-						selectElement.querySelector("option").offsetHeight;
-					var selectBoxHeight = selectElement.offsetHeight;
-					var numOptionsBeforeLoad = 2;
-					var lastScrollTop = 0;
-					var currentPageNo = 1;
-					var currentScroll = 0;
-
-					selectElement.addEventListener("scroll", onselectScroll);
 
-					function onselectScroll(event) {
-						var st = selectElement.scrollTop;
-						var totalHeight =
-							selectElement.querySelectorAll("option").length *
-							singleOptionHeight;
-
-						if (st > lastScrollTop) {
-							currentScroll = st + selectBoxHeight;
-							if (
-								currentScroll + numOptionsBeforeLoad * singleOptionHeight >=
-								totalHeight
-							) {
-								currentPageNo++;
-								fetchChannelData("", currentPageNo);
-							}
-						}
-
-						lastScrollTop = st;
-					}
-				}
-				function fetchChannelData(name, page) {
-					fetch(
-						`/entities?item=channels&limit=${limit}&name=${name}&page=${page}`,
-						{
-							method: "GET",
-						},
-					)
-						.then((response) => response.json())
-						.then((data) => {
-							const selectElement = document.getElementById("channels");
-							data.data.forEach((channel) => {
-								const option = document.createElement("option");
-								option.value = channel.id;
-								option.text = channel.name;
-								selectElement.appendChild(option);
-							});
-						})
-						.catch((error) => console.error("Error:", error));
-				}
+				fetchIndividualEntity({
+					input: "channelFilter",
+					itemSelect: "infiniteScroll",
+					item: "channels",
+				});
 			</script>
 		</body>
 	</html>
diff --git a/ui/web/template/thingusers.html b/ui/web/template/thingusers.html
index a5d0c02d8..72038a9c0 100644
--- a/ui/web/template/thingusers.html
+++ b/ui/web/template/thingusers.html
@@ -65,20 +65,19 @@ <h1 class="modal-title fs-5" id="addUserModalLabel">
 													>
 														<div class="modal-body">
 															<div class="mb-3">
-																<label for="users" class="form-label">
+																<label for="infiniteScroll" class="form-label">
 																	User ID
 																</label>
 																<input
 																	type="text"
 																	name="userFilter"
-																	id="userFilterAssign"
+																	id="userFilter"
 																	placeholder="Filter by User ID"
-																	oninput="fetchIndividualEntity(this.value,'users')"
 																/>
 																<select
 																	class="form-select"
 																	name="userID"
-																	id="users"
+																	id="infiniteScroll"
 																	size="5"
 																	required
 																>
@@ -209,76 +208,12 @@ <h1 class="modal-title fs-5" id="addUserModalLabel">
 				);
 				function openUserModal() {
 					userModal.show();
-					getUser("");
-					getAdditionalUsers("");
-				}
-				function fetchIndividualEntity(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					if (filterValue === "") {
-						itemSelect.innerHTML = "<option disabled>select a user</option>";
-						getUser("");
-						getAdditionalUsers();
-					} else {
-						itemSelect.innerHTML = "";
-						getUser(filterValue);
-					}
-				}
-				let limit = 5;
-
-				function getUser(name) {
-					fetchUserData(name, 1);
-				}
-				function getAdditionalUsers() {
-					var selectElement = document.getElementById("users");
-					var singleOptionHeight =
-						selectElement.querySelector("option").offsetHeight;
-					var selectBoxHeight = selectElement.offsetHeight;
-					var numOptionsBeforeLoad = 2;
-					var lastScrollTop = 0;
-					var currentPageNo = 1;
-					var currentScroll = 0;
-
-					selectElement.addEventListener("scroll", onselectScroll);
-
-					function onselectScroll(event) {
-						var st = selectElement.scrollTop;
-						var totalHeight =
-							selectElement.querySelectorAll("option").length *
-							singleOptionHeight;
-
-						if (st > lastScrollTop) {
-							currentScroll = st + selectBoxHeight;
-							if (
-								currentScroll + numOptionsBeforeLoad * singleOptionHeight >=
-								totalHeight
-							) {
-								currentPageNo++;
-								fetchUserData("", currentPageNo);
-							}
-						}
-
-						lastScrollTop = st;
-					}
-				}
-				function fetchUserData(name, page) {
-					fetch(
-						`/entities?item=users&limit=${limit}&name=${name}&page=${page}`,
-						{
-							method: "GET",
-						},
-					)
-						.then((response) => response.json())
-						.then((data) => {
-							const selectElement = document.getElementById("users");
-							data.data.forEach((user) => {
-								const option = document.createElement("option");
-								option.value = user.id;
-								option.text = user.name;
-								selectElement.appendChild(option);
-							});
-						})
-						.catch((error) => console.error("Error:", error));
 				}
+				fetchIndividualEntity({
+					input: "userFilter",
+					itemSelect: "infiniteScroll",
+					item: "users",
+				});
 			</script>
 		</body>
 	</html>
diff --git a/ui/web/template/userchannels.html b/ui/web/template/userchannels.html
index 466bc77e5..0be2dd44c 100644
--- a/ui/web/template/userchannels.html
+++ b/ui/web/template/userchannels.html
@@ -75,20 +75,19 @@ <h4>User Channels</h4>
 													>
 														<div class="modal-body">
 															<div class="mb-3">
-																<label for="channels" class="form-label">
+																<label for="infiniteScroll" class="form-label">
 																	Channel ID
 																</label>
 																<input
 																	type="text"
 																	name="channelFilter"
-																	id="channelFilterAssign"
+																	id="channelFilter"
 																	placeholder="Filter by Channel ID"
-																	oninput="fetchIndividualEntity(this.value,'channels')"
 																/>
 																<select
 																	class="form-select"
 																	name="channelID"
-																	id="channels"
+																	id="infiniteScroll"
 																	size="5"
 																	required
 																>
@@ -523,76 +522,14 @@ <h4>User Channels</h4>
 				);
 				function openChannelModal() {
 					channelModal.show();
-					getChannel("");
-					getAdditionalChannels("");
 				}
-				function fetchIndividualGroup(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					if (filterValue === "") {
-						itemSelect.innerHTML = "<option disabled>select a channel</option>";
-						getChannel("");
-						getAdditionalChannels();
-					} else {
-						itemSelect.innerHTML = "";
-						getChannel(filterValue);
-					}
-				}
-				let limit = 5;
-
-				function getChannel(name) {
-					fetchChannelData(name, 1);
-				}
-				function getAdditionalChannels() {
-					var selectElement = document.getElementById("channels");
-					var singleOptionHeight =
-						selectElement.querySelector("option").offsetHeight;
-					var selectBoxHeight = selectElement.offsetHeight;
-					var numOptionsBeforeLoad = 2;
-					var lastScrollTop = 0;
-					var currentPageNo = 1;
-					var currentScroll = 0;
-
-					selectElement.addEventListener("scroll", onselectScroll);
 
-					function onselectScroll(event) {
-						var st = selectElement.scrollTop;
-						var totalHeight =
-							selectElement.querySelectorAll("option").length *
-							singleOptionHeight;
+				fetchIndividualEntity({
+					input: "channelFilter",
+					itemSelect: "infiniteScroll",
+					item: "channels",
+				});
 
-						if (st > lastScrollTop) {
-							currentScroll = st + selectBoxHeight;
-							if (
-								currentScroll + numOptionsBeforeLoad * singleOptionHeight >=
-								totalHeight
-							) {
-								currentPageNo++;
-								fetchChannelData("", currentPageNo);
-							}
-						}
-
-						lastScrollTop = st;
-					}
-				}
-				function fetchChannelData(name, page) {
-					fetch(
-						`/entities?item=channels&limit=${limit}&name=${name}&page=${page}`,
-						{
-							method: "GET",
-						},
-					)
-						.then((response) => response.json())
-						.then((data) => {
-							const selectElement = document.getElementById("channels");
-							data.data.forEach((channel) => {
-								const option = document.createElement("option");
-								option.value = channel.id;
-								option.text = channel.name;
-								selectElement.appendChild(option);
-							});
-						})
-						.catch((error) => console.error("Error:", error));
-				}
                 function openTab(relation) {
 					event.preventDefault();
                     var userID = '{{.UserID}}';
diff --git a/ui/web/template/usergroups.html b/ui/web/template/usergroups.html
index d294c3e47..16f9f3cd5 100644
--- a/ui/web/template/usergroups.html
+++ b/ui/web/template/usergroups.html
@@ -75,20 +75,19 @@ <h4>User Groups</h4>
 													>
 														<div class="modal-body">
 															<div class="mb-3">
-																<label for="groups" class="form-label">
+																<label for="infiniteScroll" class="form-label">
 																	Group ID
 																</label>
 																<input
 																	type="text"
 																	name="groupFilter"
-																	id="groupFilterAssign"
+																	id="groupFilter"
 																	placeholder="Filter by Group ID"
-																	oninput="fetchIndividualEntity(this.value,'groups')"
 																/>
 																<select
 																	class="form-select"
 																	name="groupID"
-																	id="groups"
+																	id="infiniteScroll"
 																	size="5"
 																	required
 																>
@@ -524,76 +523,13 @@ <h4>User Groups</h4>
 				);
 				function openGroupModal() {
 					groupModal.show();
-					getGroup("");
-					getAdditionalGroups("");
 				}
-				function fetchIndividualEntity(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					if (filterValue === "") {
-						itemSelect.innerHTML = "<option disabled>select a group</option>";
-						getGroup("");
-						getAdditionalGroups();
-					} else {
-						itemSelect.innerHTML = "";
-						getGroup(filterValue);
-					}
-				}
-				let limit = 5;
-
-				function getGroup(name) {
-					fetchGroupData(name, 1);
-				}
-				function getAdditionalGroups() {
-					var selectElement = document.getElementById("groups");
-					var singleOptionHeight =
-						selectElement.querySelector("option").offsetHeight;
-					var selectBoxHeight = selectElement.offsetHeight;
-					var numOptionsBeforeLoad = 2;
-					var lastScrollTop = 0;
-					var currentPageNo = 1;
-					var currentScroll = 0;
-
-					selectElement.addEventListener("scroll", onselectScroll);
 
-					function onselectScroll(event) {
-						var st = selectElement.scrollTop;
-						var totalHeight =
-							selectElement.querySelectorAll("option").length *
-							singleOptionHeight;
-
-						if (st > lastScrollTop) {
-							currentScroll = st + selectBoxHeight;
-							if (
-								currentScroll + numOptionsBeforeLoad * singleOptionHeight >=
-								totalHeight
-							) {
-								currentPageNo++;
-								fetchGroupData("", currentPageNo);
-							}
-						}
-
-						lastScrollTop = st;
-					}
-				}
-				function fetchGroupData(name, page) {
-					fetch(
-						`/entities?item=groups&limit=${limit}&name=${name}&page=${page}`,
-						{
-							method: "GET",
-						},
-					)
-						.then((response) => response.json())
-						.then((data) => {
-							const selectElement = document.getElementById("groups");
-							data.data.forEach((group) => {
-								const option = document.createElement("option");
-								option.value = group.id;
-								option.text = group.name;
-								selectElement.appendChild(option);
-							});
-						})
-						.catch((error) => console.error("Error:", error));
-				}
+				fetchIndividualEntity({
+					input: "groupFilter",
+					itemSelect: "infiniteScroll",
+					item: "groups",
+				});
 
 				function openTab(relation) {
 					event.preventDefault();
diff --git a/ui/web/template/userthings.html b/ui/web/template/userthings.html
index 984f85460..afcd4c842 100644
--- a/ui/web/template/userthings.html
+++ b/ui/web/template/userthings.html
@@ -21,7 +21,7 @@
 										User
 									</a>
 									<a
-										href="/users/{{ .UserID }}/things"
+										href="/users/{{ .UserID }}/groups"
 										type="button"
 										class="btn body-button"
 									>
@@ -75,20 +75,19 @@ <h4>User Things</h4>
 													>
 														<div class="modal-body">
 															<div class="mb-3">
-																<label for="things" class="form-label">
+																<label for="infiniteScroll" class="form-label">
 																	Thing ID
 																</label>
 																<input
 																	type="text"
 																	name="thingFilter"
-																	id="thingFilterAssign"
+																	id="thingFilter"
 																	placeholder="Filter by Thing ID"
-																	oninput="fetchIndividualEntity(this.value,'things')"
 																/>
 																<select
 																	class="form-select"
 																	name="thingID"
-																	id="things"
+																	id="infiniteScroll"
 																	size="5"
 																	required
 																>
@@ -219,76 +218,12 @@ <h4>User Things</h4>
 				);
 				function openThingModal() {
 					thingModal.show();
-					getThing("");
-					getAdditionalThings("");
-				}
-				function fetchIndividualEntity(filterValue, selectId) {
-					const itemSelect = document.getElementById(selectId);
-					if (filterValue === "") {
-						itemSelect.innerHTML = "<option disabled>select a thing</option>";
-						getThing("");
-						getAdditionalThings();
-					} else {
-						itemSelect.innerHTML = "";
-						getThing(filterValue);
-					}
-				}
-				let limit = 5;
-
-				function getThing(name) {
-					fetchThingData(name, 1);
-				}
-				function getAdditionalThings() {
-					var selectElement = document.getElementById("things");
-					var singleOptionHeight =
-						selectElement.querySelector("option").offsetHeight;
-					var selectBoxHeight = selectElement.offsetHeight;
-					var numOptionsBeforeLoad = 2;
-					var lastScrollTop = 0;
-					var currentPageNo = 1;
-					var currentScroll = 0;
-
-					selectElement.addEventListener("scroll", onselectScroll);
-
-					function onselectScroll(event) {
-						var st = selectElement.scrollTop;
-						var totalHeight =
-							selectElement.querySelectorAll("option").length *
-							singleOptionHeight;
-
-						if (st > lastScrollTop) {
-							currentScroll = st + selectBoxHeight;
-							if (
-								currentScroll + numOptionsBeforeLoad * singleOptionHeight >=
-								totalHeight
-							) {
-								currentPageNo++;
-								fetchThingData("", currentPageNo);
-							}
-						}
-
-						lastScrollTop = st;
-					}
-				}
-				function fetchThingData(name, page) {
-					fetch(
-						`/entities?item=things&limit=${limit}&name=${name}&page=${page}`,
-						{
-							method: "GET",
-						},
-					)
-						.then((response) => response.json())
-						.then((data) => {
-							const selectElement = document.getElementById("things");
-							data.data.forEach((thing) => {
-								const option = document.createElement("option");
-								option.value = thing.id;
-								option.text = thing.name;
-								selectElement.appendChild(option);
-							});
-						})
-						.catch((error) => console.error("Error:", error));
 				}
+				fetchIndividualEntity({
+					input: "thingFilter",
+					itemSelect: "things",
+					item: "things",
+				});
 			</script>
 		</body>
 	</html>

From f0f8badcd7683ab01da36ac7eaf25b94e371daad Mon Sep 17 00:00:00 2001
From: ianmuchyri <ianmuchiri8@gmail.com>
Date: Mon, 27 Nov 2023 20:00:43 +0300
Subject: [PATCH 05/11] update formatting to 2 spaces

Signed-off-by: ianmuchyri <ianmuchiri8@gmail.com>
---
 .prettierrc                         |  12 +-
 ui/web/template/bootstrap.html      | 378 ++++-------
 ui/web/template/bootstraps.html     | 513 +++++++-------
 ui/web/template/channel.html        | 295 ++++-----
 ui/web/template/channelgroups.html  | 364 +++++-----
 ui/web/template/channels.html       | 280 ++++----
 ui/web/template/channelthings.html  | 364 +++++-----
 ui/web/template/channelusers.html   | 994 +++++++++++++--------------
 ui/web/template/error.html          |  42 +-
 ui/web/template/footer.html         |  29 +-
 ui/web/template/group.html          | 267 ++++----
 ui/web/template/groupchannels.html  | 352 +++++-----
 ui/web/template/groups.html         | 300 ++++-----
 ui/web/template/groupusers.html     | 982 +++++++++++++--------------
 ui/web/template/header.html         |  40 +-
 ui/web/template/index.html          | 174 ++---
 ui/web/template/login.html          | 335 +++++-----
 ui/web/template/messagesread.html   | 247 ++++---
 ui/web/template/navbar.html         | 369 +++++------
 ui/web/template/resetpassword.html  | 168 +++--
 ui/web/template/tablefooter.html    | 114 ++--
 ui/web/template/tableheader.html    |  82 +--
 ui/web/template/terminal.html       | 108 +--
 ui/web/template/thing.html          | 381 +++++------
 ui/web/template/thingchannels.html  | 502 +++++++-------
 ui/web/template/things.html         | 304 ++++-----
 ui/web/template/thingusers.html     | 393 +++++------
 ui/web/template/updatepassword.html | 207 +++---
 ui/web/template/user.html           | 344 ++++------
 ui/web/template/userchannels.html   | 995 +++++++++++++---------------
 ui/web/template/usergroups.html     | 995 +++++++++++++---------------
 ui/web/template/users.html          | 282 ++++----
 ui/web/template/userthings.html     | 406 +++++-------
 33 files changed, 5357 insertions(+), 6261 deletions(-)

diff --git a/.prettierrc b/.prettierrc
index d5e92c768..6ceed361a 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,20 +1,16 @@
 {
-  "plugins": [
-    "prettier-plugin-go-template"
-  ],
+  "plugins": ["prettier-plugin-go-template"],
   "overrides": [
     {
-      "files": [
-        "*.html"
-      ],
+      "files": ["*.html"],
       "options": {
         "parser": "go-template"
       }
     }
   ],
   "goTemplateBracketSpacing": true,
-  "useTabs": true,
-  "printWidth": 80,
+  "useTabs": false,
+  "printWidth": 100,
   "semi": true,
   "tabWidth": 2,
   "jsxSingleQuote": false,
diff --git a/ui/web/template/bootstrap.html b/ui/web/template/bootstrap.html
index e89ec34c9..61a6cb1e5 100644
--- a/ui/web/template/bootstrap.html
+++ b/ui/web/template/bootstrap.html
@@ -2,241 +2,145 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "bootstrap" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<button
-										type="button"
-										class="btn body-button"
-										onclick="location.href='/bootstraps/{{ .Bootstrap.ThingID }}/terminal'"
-									>
-										Remote Terminal
-									</button>
-								</div>
-								<div class="table-responsive table-container">
-									<table id="itemsTable" class="table">
-										<thead>
-											<tr>
-												<th scope="row">Bootstrap</th>
-											</tr>
-										</thead>
-										<tbody>
-											<tr>
-												<th>Name</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="name"
-												>
-													{{ .Bootstrap.Name }}
-												</td>
-												<td>
-													<button class="edit-btn" onclick="editRow('name')">
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" onclick="saveRow('name')">
-															Save
-														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('name')"
-														>
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>Content</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="content"
-												>
-													{{ .Bootstrap.Content }}
-												</td>
-												<td>
-													<button class="edit-btn" onclick="editRow('content')">
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button
-															class="save-btn"
-															onclick="saveRow('content')"
-														>
-															Save
-														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('content')"
-														>
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>Channels</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="channels"
-												>
-													{{ toSlice .Bootstrap.Channels }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														onclick="editRow('channels')"
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button
-															class="save-btn"
-															onclick="saveRow('channels')"
-														>
-															Save
-														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('channels')"
-														>
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>Client Cert</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="clientCert"
-												>
-													{{ .Bootstrap.ClientCert }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														onclick="editRow('clientCert')"
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button
-															class="save-btn"
-															onclick="saveRow('clientCert')"
-														>
-															Save
-														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('clientCert')"
-														>
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>Client Key</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="clientKey"
-												>
-													{{ .Bootstrap.ClientKey }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														onclick="editRow('clientKey')"
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button
-															class="save-btn"
-															onclick="saveRow('clientKey')"
-														>
-															Save
-														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('clientKey')"
-														>
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>CA Cert</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="CACert"
-												>
-													{{ .Bootstrap.CACert }}
-												</td>
-												<td>
-													<button class="edit-btn" onclick="editRow('CACert')">
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button
-															class="save-btn"
-															onclick="saveRow('CACert')"
-														>
-															Save
-														</button>
-														<button
-															class="cancel-btn"
-															onclick="cancelEditRow('CACert')"
-														>
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-										</tbody>
-									</table>
-									<div id="error-message" class="text-danger"></div>
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <button
+                    type="button"
+                    class="btn body-button"
+                    onclick="location.href='/bootstraps/{{ .Bootstrap.ThingID }}/terminal'"
+                  >
+                    Remote Terminal
+                  </button>
+                </div>
+                <div class="table-responsive table-container">
+                  <table id="itemsTable" class="table">
+                    <thead>
+                      <tr>
+                        <th scope="row">Bootstrap</th>
+                      </tr>
+                    </thead>
+                    <tbody>
+                      <tr>
+                        <th>Name</th>
+                        <td class="editable" contenteditable="false" data-field="name">
+                          {{ .Bootstrap.Name }}
+                        </td>
+                        <td>
+                          <button class="edit-btn" onclick="editRow('name')">
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" onclick="saveRow('name')">Save</button>
+                            <button class="cancel-btn" onclick="cancelEditRow('name')">
+                              Cancel
+                            </button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>Content</th>
+                        <td class="editable" contenteditable="false" data-field="content">
+                          {{ .Bootstrap.Content }}
+                        </td>
+                        <td>
+                          <button class="edit-btn" onclick="editRow('content')">
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" onclick="saveRow('content')">Save</button>
+                            <button class="cancel-btn" onclick="cancelEditRow('content')">
+                              Cancel
+                            </button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>Channels</th>
+                        <td class="editable" contenteditable="false" data-field="channels">
+                          {{ toSlice .Bootstrap.Channels }}
+                        </td>
+                        <td>
+                          <button class="edit-btn" onclick="editRow('channels')">
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" onclick="saveRow('channels')">Save</button>
+                            <button class="cancel-btn" onclick="cancelEditRow('channels')">
+                              Cancel
+                            </button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>Client Cert</th>
+                        <td class="editable" contenteditable="false" data-field="clientCert">
+                          {{ .Bootstrap.ClientCert }}
+                        </td>
+                        <td>
+                          <button class="edit-btn" onclick="editRow('clientCert')">
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" onclick="saveRow('clientCert')">Save</button>
+                            <button class="cancel-btn" onclick="cancelEditRow('clientCert')">
+                              Cancel
+                            </button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>Client Key</th>
+                        <td class="editable" contenteditable="false" data-field="clientKey">
+                          {{ .Bootstrap.ClientKey }}
+                        </td>
+                        <td>
+                          <button class="edit-btn" onclick="editRow('clientKey')">
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" onclick="saveRow('clientKey')">Save</button>
+                            <button class="cancel-btn" onclick="cancelEditRow('clientKey')">
+                              Cancel
+                            </button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>CA Cert</th>
+                        <td class="editable" contenteditable="false" data-field="CACert">
+                          {{ .Bootstrap.CACert }}
+                        </td>
+                        <td>
+                          <button class="edit-btn" onclick="editRow('CACert')">
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" onclick="saveRow('CACert')">Save</button>
+                            <button class="cancel-btn" onclick="cancelEditRow('CACert')">
+                              Cancel
+                            </button>
+                          </div>
+                        </td>
+                      </tr>
+                    </tbody>
+                  </table>
+                  <div id="error-message" class="text-danger"></div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
     <script>
       function makeEditable(cell) {
         cell.setAttribute("contenteditable", "true");
@@ -376,6 +280,6 @@
         hideButtons(editBtn, saveCancelBtn);
       }
     </script>
-		</body>
-	</html>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/bootstraps.html b/ui/web/template/bootstraps.html
index 5e14dc3c6..1e0f7e70e 100644
--- a/ui/web/template/bootstraps.html
+++ b/ui/web/template/bootstraps.html
@@ -2,294 +2,253 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "bootstraps" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<button
-										type="button"
-										class="btn body-button"
-										onclick="openModal()"
-									>
-										Add
-									</button>
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <button type="button" class="btn body-button" onclick="openModal()">Add</button>
 
-									<!-- Modal -->
-									<div
-										class="modal fade"
-										id="addBootstrapModal"
-										tabindex="-1"
-										role="dialog"
-										aria-labelledby="addBootstrapModalLabel"
-										aria-hidden="true"
-									>
-										<div class="modal-dialog" role="document">
-											<div class="modal-content">
-												<div class="modal-header">
-													<h5 class="modal-title" id="addBootstrapModalLabel">
-														Add Bootstrap Config
-													</h5>
-												</div>
-												<div class="modal-body">
-													<form method="post" onsubmit="return validateForm()">
-														<div class="mb-3">
-															<label for="name" class="form-label">
-																Bootstrap Name
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="name"
-																id="name"
-																aria-describedby="tagHelp"
-																placeholder="Name"
-															/>
-														</div>
-														<div class="mb-3">
-															<label for="infiniteScroll" class="form-label">
-																Thing
-															</label>
-															<input
-																type="text"
-																class="itemsFilter"
-																name="thingFilter"
-																id="thingFilter"
-																placeholder="Filter by Thing name"
-															/>
-															<select
-																class="form-select"
-																name="thingID"
-																id="infiniteScroll"
-																required
-															>
-																<option disabled>select a group</option>
-															</select>
-														</div>
-														<div class="mb-3">
-															<label for="externalID" class="form-label">
-																External ID
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="externalID"
-																id="externalID"
-																placeholder="External ID"
-																required
-															/>
-														</div>
-														<div class="mb-3">
-															<label for="externalKey" class="form-label">
-																External Key
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="externalKey"
-																id="externalKey"
-																placeholder="External Key"
-																required
-															/>
-														</div>
-														<div class="mb-3">
-															<label for="channels" class="form-label">
-																Channels
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="channels"
-																id="channels"
-																value="[]"
-																required
-															/>
-															<div id="channelsHelp" class="form-text">
-																Enter channels as a string slice.
-															</div>
-															<div
-																id="channelsError"
-																class="error-message"
-															></div>
-														</div>
+                  <!-- Modal -->
+                  <div
+                    class="modal fade"
+                    id="addBootstrapModal"
+                    tabindex="-1"
+                    role="dialog"
+                    aria-labelledby="addBootstrapModalLabel"
+                    aria-hidden="true"
+                  >
+                    <div class="modal-dialog" role="document">
+                      <div class="modal-content">
+                        <div class="modal-header">
+                          <h5 class="modal-title" id="addBootstrapModalLabel">
+                            Add Bootstrap Config
+                          </h5>
+                        </div>
+                        <div class="modal-body">
+                          <form method="post" onsubmit="return validateForm()">
+                            <div class="mb-3">
+                              <label for="name" class="form-label">Bootstrap Name</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="name"
+                                id="name"
+                                aria-describedby="tagHelp"
+                                placeholder="Name"
+                              />
+                            </div>
+                            <div class="mb-3">
+                              <label for="infiniteScroll" class="form-label">Thing</label>
+                              <input
+                                type="text"
+                                class="itemsFilter"
+                                name="thingFilter"
+                                id="thingFilter"
+                                placeholder="Filter by Thing name"
+                              />
+                              <select
+                                class="form-select"
+                                name="thingID"
+                                id="infiniteScroll"
+                                required
+                              >
+                                <option disabled>select a group</option>
+                              </select>
+                            </div>
+                            <div class="mb-3">
+                              <label for="externalID" class="form-label">External ID</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="externalID"
+                                id="externalID"
+                                placeholder="External ID"
+                                required
+                              />
+                            </div>
+                            <div class="mb-3">
+                              <label for="externalKey" class="form-label">External Key</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="externalKey"
+                                id="externalKey"
+                                placeholder="External Key"
+                                required
+                              />
+                            </div>
+                            <div class="mb-3">
+                              <label for="channels" class="form-label">Channels</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="channels"
+                                id="channels"
+                                value="[]"
+                                required
+                              />
+                              <div id="channelsHelp" class="form-text">
+                                Enter channels as a string slice.
+                              </div>
+                              <div id="channelsError" class="error-message"></div>
+                            </div>
 
-														<div class="mb-3">
-															<label for="content" class="form-label">
-																Content
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="content"
-																id="content"
-																value="{}"
-															/>
-															<div id="contentHelp" class="form-text">
-																Enter content in JSON format.
-															</div>
-															<div
-																id="contentError"
-																class="error-message"
-															></div>
-														</div>
-														<div class="mb-3">
-															<label for="clientCert" class="form-label">
-																Client Cert
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="clientCert"
-																id="clientCert"
-																aria-describedby="tagHelp"
-																value="clientCert"
-															/>
-														</div>
-														<div class="mb-3">
-															<label for="clientKey" class="form-label">
-																Client Key
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="clientKey"
-																id="clientKey"
-																aria-describedby="tagHelp"
-																value="clientKey"
-															/>
-														</div>
-														<div class="mb-3">
-															<label for="CACert" class="form-label">
-																CA Cert
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="CACert"
-																id="CACert"
-																aria-describedby="tagHelp"
-																value="CACert"
-															/>
-														</div>
-														<button type="submit" class="btn body-button">
-															Submit
-														</button>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
-								</div>
-								<div class="table-responsive table-container">
-									{{ template "tableheader" . }}
-									<div class="itemsTable">
-										<table id="itemsTable" class="table">
-											<thead>
-												<tr>
-													<th scope="col">Name</th>
-													<th scope="col">Thing ID</th>
-													<th scope="col">External ID</th>
-												</tr>
-											</thead>
-											<tbody>
-												{{ range $i, $t := .Bootstraps }}
-													<tr>
-														<td>{{ $t.Name }}</td>
-														<td>
-															<div class="copy-con-container">
-																<a
-																	href="{{ printf "/bootstraps/%s" $t.ThingID }}"
-																>
-																	{{ $t.ThingID }}
-																</a>
-																<button
-																	class="copy-icon"
-																	onclick="copyToClipboard(this)"
-																>
-																	<i class="far fa-copy"></i>
-																</button>
-															</div>
-														</td>
-														<td>{{ $t.ExternalID }}</td>
-													</tr>
-												{{ end }}
-											</tbody>
-										</table>
-									</div>
-									{{ template "tablefooter" . }}
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
-			<script>
-				function validateForm() {
-					var channelsInput = document.getElementById("channels").value;
-					var contentInput = document.getElementById("content").value;
+                            <div class="mb-3">
+                              <label for="content" class="form-label">Content</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="content"
+                                id="content"
+                                value="{}"
+                              />
+                              <div id="contentHelp" class="form-text">
+                                Enter content in JSON format.
+                              </div>
+                              <div id="contentError" class="error-message"></div>
+                            </div>
+                            <div class="mb-3">
+                              <label for="clientCert" class="form-label">Client Cert</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="clientCert"
+                                id="clientCert"
+                                aria-describedby="tagHelp"
+                                value="clientCert"
+                              />
+                            </div>
+                            <div class="mb-3">
+                              <label for="clientKey" class="form-label">Client Key</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="clientKey"
+                                id="clientKey"
+                                aria-describedby="tagHelp"
+                                value="clientKey"
+                              />
+                            </div>
+                            <div class="mb-3">
+                              <label for="CACert" class="form-label">CA Cert</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="CACert"
+                                id="CACert"
+                                aria-describedby="tagHelp"
+                                value="CACert"
+                              />
+                            </div>
+                            <button type="submit" class="btn body-button">Submit</button>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+                <div class="table-responsive table-container">
+                  {{ template "tableheader" . }}
+                  <div class="itemsTable">
+                    <table id="itemsTable" class="table">
+                      <thead>
+                        <tr>
+                          <th scope="col">Name</th>
+                          <th scope="col">Thing ID</th>
+                          <th scope="col">External ID</th>
+                        </tr>
+                      </thead>
+                      <tbody>
+                        {{ range $i, $t := .Bootstraps }}
+                          <tr>
+                            <td>{{ $t.Name }}</td>
+                            <td>
+                              <div class="copy-con-container">
+                                <a href="{{ printf "/bootstraps/%s" $t.ThingID }}">
+                                  {{ $t.ThingID }}
+                                </a>
+                                <button class="copy-icon" onclick="copyToClipboard(this)">
+                                  <i class="far fa-copy"></i>
+                                </button>
+                              </div>
+                            </td>
+                            <td>{{ $t.ExternalID }}</td>
+                          </tr>
+                        {{ end }}
+                      </tbody>
+                    </table>
+                  </div>
+                  {{ template "tablefooter" . }}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
+      <script>
+        function validateForm() {
+          var channelsInput = document.getElementById("channels").value;
+          var contentInput = document.getElementById("content").value;
 
-					var channelsError = document.getElementById("channelsError");
-					var contentError = document.getElementById("contentError");
+          var channelsError = document.getElementById("channelsError");
+          var contentError = document.getElementById("contentError");
 
-					channelsError.innerHTML = "";
-					contentError.innerHTML = "";
+          channelsError.innerHTML = "";
+          contentError.innerHTML = "";
 
-					var content;
-					var channels;
+          var content;
+          var channels;
 
-					var isValid = true;
+          var isValid = true;
 
-					try {
-						channels = JSON.parse(channelsInput);
-					} catch (error) {
-						channelsError.innerHTML =
-							"Please enter valid channels as a string array!";
-						isValid = false;
-					}
+          try {
+            channels = JSON.parse(channelsInput);
+          } catch (error) {
+            channelsError.innerHTML = "Please enter valid channels as a string array!";
+            isValid = false;
+          }
 
-					if (
-						!Array.isArray(channels) ||
-						!channels.every(function (channels) {
-							return typeof channels === "string";
-						})
-					) {
-						channelsError.innerHTML = "Channels must be a string array!";
-						isValid = false;
-					}
+          if (
+            !Array.isArray(channels) ||
+            !channels.every(function (channels) {
+              return typeof channels === "string";
+            })
+          ) {
+            channelsError.innerHTML = "Channels must be a string array!";
+            isValid = false;
+          }
 
-					try {
-						content = JSON.parse(contentInput);
-						content = contentInput;
-					} catch (error) {
-						contentError.innerHTML =
-							"Please enter valid content in JSON format!";
-						isValid = false;
-					}
+          try {
+            content = JSON.parse(contentInput);
+            content = contentInput;
+          } catch (error) {
+            contentError.innerHTML = "Please enter valid content in JSON format!";
+            isValid = false;
+          }
 
-					return isValid;
-				}
+          return isValid;
+        }
 
-				const bootstrapsModal = new bootstrap.Modal(
-					document.getElementById("addBootstrapModal"),
-				);
+        const bootstrapsModal = new bootstrap.Modal(document.getElementById("addBootstrapModal"));
 
-				function openModal() {
-					bootstrapsModal.show();
-				}
+        function openModal() {
+          bootstrapsModal.show();
+        }
 
-				fetchIndividualEntity({
-					input: "thingFilter",
-					itemSelect: "infiniteScroll",
-					item: "things",
-				});
-			</script>
-		</body>
-	</html>
+        fetchIndividualEntity({
+          input: "thingFilter",
+          itemSelect: "infiniteScroll",
+          item: "things",
+        });
+      </script>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/channel.html b/ui/web/template/channel.html
index 7d9af95a0..a9d7a6c2d 100644
--- a/ui/web/template/channel.html
+++ b/ui/web/template/channel.html
@@ -2,170 +2,133 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "channel" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<a
-										href="/channels/{{ .Channel.ID }}/things"
-										type="button"
-										class="btn body-button"
-									>
-										Channel Things
-									</a>
-									<a
-										href="/channels/{{ .Channel.ID }}/users"
-										type="button"
-										class="btn body-button"
-									>
-										Channel Users
-									</a>
-									<a
-										href="/channels/{{ .Channel.ID }}/groups"
-										type="button"
-										class="btn body-button"
-									>
-										Channel Groups
-									</a>
-								</div>
-								<div class="table-responsive table-container">
-									<table id="itemsTable" class="table">
-										<thead>
-											<tr>
-												<th scope="row">CHANNEL</th>
-											</tr>
-										</thead>
-										<tbody>
-											{{ $disableButton := false }}
-											<tr>
-												<th>NAME</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="name"
-												>
-													{{ .Channel.Name }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														id="edit-name"
-														{{ if
-															$disableButton
-														}}
-															disabled
-														{{ end }}
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" id="save-name">
-															Save
-														</button>
-														<button class="cancel-btn" id="cancel-name">
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>ID</th>
-												<td>{{ .Channel.ID }}</td>
-												<td></td>
-											</tr>
-											<tr>
-												<th>Owner</th>
-												<td>{{ .Channel.OwnerID }}</td>
-												<td></td>
-											</tr>
-											<tr>
-												<th>Description</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="description"
-												>
-													{{ .Channel.Description }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														id="edit-description"
-														{{ if
-															$disableButton
-														}}
-															disabled
-														{{ end }}
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" id="save-description">
-															Save
-														</button>
-														<button class="cancel-btn" id="cancel-description">
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>Metadata</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="metadata"
-												>
-													{{ toJSON .Channel.Metadata }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														id="edit-metadata"
-														{{ if
-															$disableButton
-														}}
-															disabled
-														{{ end }}
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" id="save-metadata">
-															Save
-														</button>
-														<button class="cancel-btn" id="cancel-metadata">
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-										</tbody>
-									</table>
-									<div id="error-message" class="text-danger"></div>
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <a
+                    href="/channels/{{ .Channel.ID }}/things"
+                    type="button"
+                    class="btn body-button"
+                  >
+                    Channel Things
+                  </a>
+                  <a href="/channels/{{ .Channel.ID }}/users" type="button" class="btn body-button">
+                    Channel Users
+                  </a>
+                  <a
+                    href="/channels/{{ .Channel.ID }}/groups"
+                    type="button"
+                    class="btn body-button"
+                  >
+                    Channel Groups
+                  </a>
+                </div>
+                <div class="table-responsive table-container">
+                  <table id="itemsTable" class="table">
+                    <thead>
+                      <tr>
+                        <th scope="row">CHANNEL</th>
+                      </tr>
+                    </thead>
+                    <tbody>
+                      {{ $disableButton := false }}
+                      <tr>
+                        <th>NAME</th>
+                        <td class="editable" contenteditable="false" data-field="name">
+                          {{ .Channel.Name }}
+                        </td>
+                        <td>
+                          <button
+                            class="edit-btn"
+                            id="edit-name"
+                            {{ if
+                              $disableButton
+                            }}
+                              disabled
+                            {{ end }}
+                          >
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" id="save-name">Save</button>
+                            <button class="cancel-btn" id="cancel-name">Cancel</button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>ID</th>
+                        <td>{{ .Channel.ID }}</td>
+                        <td></td>
+                      </tr>
+                      <tr>
+                        <th>Owner</th>
+                        <td>{{ .Channel.OwnerID }}</td>
+                        <td></td>
+                      </tr>
+                      <tr>
+                        <th>Description</th>
+                        <td class="editable" contenteditable="false" data-field="description">
+                          {{ .Channel.Description }}
+                        </td>
+                        <td>
+                          <button
+                            class="edit-btn"
+                            id="edit-description"
+                            {{ if
+                              $disableButton
+                            }}
+                              disabled
+                            {{ end }}
+                          >
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" id="save-description">Save</button>
+                            <button class="cancel-btn" id="cancel-description">Cancel</button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>Metadata</th>
+                        <td class="editable" contenteditable="false" data-field="metadata">
+                          {{ toJSON .Channel.Metadata }}
+                        </td>
+                        <td>
+                          <button
+                            class="edit-btn"
+                            id="edit-metadata"
+                            {{ if
+                              $disableButton
+                            }}
+                              disabled
+                            {{ end }}
+                          >
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" id="save-metadata">Save</button>
+                            <button class="cancel-btn" id="cancel-metadata">Cancel</button>
+                          </div>
+                        </td>
+                      </tr>
+                    </tbody>
+                  </table>
+                  <div id="error-message" class="text-danger"></div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
     <script>
       attachEditRowListener(
 			{
@@ -180,6 +143,6 @@
 			}
 		);
     </script>
-		</body>
-	</html>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/channelgroups.html b/ui/web/template/channelgroups.html
index eea84035b..62d8f9fc6 100644
--- a/ui/web/template/channelgroups.html
+++ b/ui/web/template/channelgroups.html
@@ -2,202 +2,172 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "channelgroups" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<a
-										href="/channels/{{ .ChannelID }}"
-										type="button"
-										class="btn body-button"
-									>
-										Channel
-									</a>
-									<a
-										href="/channels/{{ .ChannelID }}/users"
-										type="button"
-										class="btn body-button"
-									>
-										Channel Users
-									</a>
-									<a
-										href="/channels/{{ .ChannelID }}/things"
-										type="button"
-										class="btn body-button"
-									>
-										Channel Things
-									</a>
-								</div>
-								<div class="table-responsive table-container">
-									<div class="d-flex flex-row justify-content-between">
-										<h4>Channel Groups</h4>
-										<button
-											role="button"
-											class="btn body-button"
-											onclick="openGroupModal()"
-										>
-											<i class="fa-solid fa-plus fs-4"></i>
-										</button>
-										<!-- modal -->
-										<div
-											class="modal fade"
-											id="addGroupModal"
-											tabindex="-1"
-											aria-labelledby="addGroupModalLabel"
-											aria-hidden="true"
-										>
-											<div class="modal-dialog modal-dialog-centered">
-												<div class="modal-content">
-													<div class="modal-header">
-														<h1
-															class="modal-title fs-5"
-															id="addGroupModalLabel"
-														>
-															Add Group
-														</h1>
-														<button
-															type="button"
-															class="btn-close"
-															data-bs-dismiss="modal"
-															aria-label="Close"
-														></button>
-													</div>
-													<form
-														action="/channels/{{ .ChannelID }}/groups/assign?item=channels"
-														method="post"
-													>
-														<div class="modal-body">
-															<div class="mb-3">
-																<label for="infiniteScroll" class="form-label">
-																	Group ID
-																</label>
-																<input
-																	type="text"
-																	name="groupFilter"
-																	id="groupFilter"
-																	placeholder="Filter by Group ID"
-																/>
-																<select
-																	class="form-select"
-																	name="groupID"
-																	id="infiniteScroll"
-																	size="5"
-																	required
-																>
-																	<option disabled>select a group</option>
-																</select>
-															</div>
-														</div>
-														<div class="modal-footer">
-															<button
-																type="button"
-																class="btn btn-secondary"
-																data-bs-dismiss="modal"
-															>
-																Cancel
-															</button>
-															<button type="submit" class="btn btn-primary">
-																Assign
-															</button>
-														</div>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
-									{{ template "tableheader" . }}
-									<div class="itemsTable">
-										<table class="table" id="itemsTable">
-											<thead>
-												<tr>
-													<th scope="col">Name</th>
-													<th scope="col">ID</th>
-													<th class="desc-col" scope="col">Description</th>
-													<th class="meta-col" scope="col">Metadata</th>
-													<th class="created-col" scope="col">Created At</th>
-													<th class="text-center" scope="col"></th>
-												</tr>
-											</thead>
-											<tbody>
-												{{ $channelID := .ChannelID }}
-												{{ range $i, $g := .Groups }}
-													{{ $disableButton := false }}
-													<tr>
-														<td>{{ $g.Name }}</td>
-														<td>
-															<div class="copy-con-container">
-																<a href="{{ printf "/groups/%s" $g.ID }}">
-																	{{ $g.ID }}
-																</a>
-																<button
-																	class="copy-icon"
-																	onclick="copyToClipboard(this)"
-																>
-																	<i class="far fa-copy"></i>
-																</button>
-															</div>
-														</td>
-														<td class="desc-col">{{ $g.Description }}</td>
-														<td class="meta-col">{{ toJSON $g.Metadata }}</td>
-														<td class="created-col">{{ $g.CreatedAt }}</td>
-														<td class="text-center">
-															<form
-																action="/channels/{{ $channelID }}/groups/unassign?item=channels"
-																method="post"
-															>
-																<input
-																	type="hidden"
-																	name="groupID"
-																	id="groupID"
-																	value="{{ $g.ID }}"
-																/>
-																<button
-																	type="submit"
-																	class="btn btn-sm"
-																	{{ if
-																		$disableButton
-																	}}
-																		disabled
-																	{{ end }}
-																>
-																	<i class="fas fa-trash-alt"></i>
-																</button>
-															</form>
-														</td>
-													</tr>
-												{{ end }}
-											</tbody>
-										</table>
-									</div>
-									{{ template "tablefooter" . }}
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
-			<script>
-				const groupModal = new bootstrap.Modal(
-					document.getElementById("addGroupModal"),
-				);
-				function openGroupModal() {
-					groupModal.show();
-				}
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <a href="/channels/{{ .ChannelID }}" type="button" class="btn body-button">
+                    Channel
+                  </a>
+                  <a href="/channels/{{ .ChannelID }}/users" type="button" class="btn body-button">
+                    Channel Users
+                  </a>
+                  <a href="/channels/{{ .ChannelID }}/things" type="button" class="btn body-button">
+                    Channel Things
+                  </a>
+                </div>
+                <div class="table-responsive table-container">
+                  <div class="d-flex flex-row justify-content-between">
+                    <h4>Channel Groups</h4>
+                    <button role="button" class="btn body-button" onclick="openGroupModal()">
+                      <i class="fa-solid fa-plus fs-4"></i>
+                    </button>
+                    <!-- modal -->
+                    <div
+                      class="modal fade"
+                      id="addGroupModal"
+                      tabindex="-1"
+                      aria-labelledby="addGroupModalLabel"
+                      aria-hidden="true"
+                    >
+                      <div class="modal-dialog modal-dialog-centered">
+                        <div class="modal-content">
+                          <div class="modal-header">
+                            <h1 class="modal-title fs-5" id="addGroupModalLabel">Add Group</h1>
+                            <button
+                              type="button"
+                              class="btn-close"
+                              data-bs-dismiss="modal"
+                              aria-label="Close"
+                            ></button>
+                          </div>
+                          <form
+                            action="/channels/{{ .ChannelID }}/groups/assign?item=channels"
+                            method="post"
+                          >
+                            <div class="modal-body">
+                              <div class="mb-3">
+                                <label for="infiniteScroll" class="form-label">Group ID</label>
+                                <input
+                                  type="text"
+                                  name="groupFilter"
+                                  id="groupFilter"
+                                  placeholder="Filter by Group ID"
+                                />
+                                <select
+                                  class="form-select"
+                                  name="groupID"
+                                  id="infiniteScroll"
+                                  size="5"
+                                  required
+                                >
+                                  <option disabled>select a group</option>
+                                </select>
+                              </div>
+                            </div>
+                            <div class="modal-footer">
+                              <button
+                                type="button"
+                                class="btn btn-secondary"
+                                data-bs-dismiss="modal"
+                              >
+                                Cancel
+                              </button>
+                              <button type="submit" class="btn btn-primary">Assign</button>
+                            </div>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  {{ template "tableheader" . }}
+                  <div class="itemsTable">
+                    <table class="table" id="itemsTable">
+                      <thead>
+                        <tr>
+                          <th scope="col">Name</th>
+                          <th scope="col">ID</th>
+                          <th class="desc-col" scope="col">Description</th>
+                          <th class="meta-col" scope="col">Metadata</th>
+                          <th class="created-col" scope="col">Created At</th>
+                          <th class="text-center" scope="col"></th>
+                        </tr>
+                      </thead>
+                      <tbody>
+                        {{ $channelID := .ChannelID }}
+                        {{ range $i, $g := .Groups }}
+                          {{ $disableButton := false }}
+                          <tr>
+                            <td>{{ $g.Name }}</td>
+                            <td>
+                              <div class="copy-con-container">
+                                <a href="{{ printf "/groups/%s" $g.ID }}">
+                                  {{ $g.ID }}
+                                </a>
+                                <button class="copy-icon" onclick="copyToClipboard(this)">
+                                  <i class="far fa-copy"></i>
+                                </button>
+                              </div>
+                            </td>
+                            <td class="desc-col">{{ $g.Description }}</td>
+                            <td class="meta-col">{{ toJSON $g.Metadata }}</td>
+                            <td class="created-col">{{ $g.CreatedAt }}</td>
+                            <td class="text-center">
+                              <form
+                                action="/channels/{{ $channelID }}/groups/unassign?item=channels"
+                                method="post"
+                              >
+                                <input
+                                  type="hidden"
+                                  name="groupID"
+                                  id="groupID"
+                                  value="{{ $g.ID }}"
+                                />
+                                <button
+                                  type="submit"
+                                  class="btn btn-sm"
+                                  {{ if
+                                    $disableButton
+                                  }}
+                                    disabled
+                                  {{ end }}
+                                >
+                                  <i class="fas fa-trash-alt"></i>
+                                </button>
+                              </form>
+                            </td>
+                          </tr>
+                        {{ end }}
+                      </tbody>
+                    </table>
+                  </div>
+                  {{ template "tablefooter" . }}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
+      <script>
+        const groupModal = new bootstrap.Modal(document.getElementById("addGroupModal"));
+        function openGroupModal() {
+          groupModal.show();
+        }
 
-				fetchIndividualEntity({
-					input: "groupFilter",
-					itemSelect: "infiniteScroll",
-					item: "groups",
-				});
-			</script>
-		</body>
-	</html>
+        fetchIndividualEntity({
+          input: "groupFilter",
+          itemSelect: "infiniteScroll",
+          item: "groups",
+        });
+      </script>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/channels.html b/ui/web/template/channels.html
index f0079449f..8d7908443 100644
--- a/ui/web/template/channels.html
+++ b/ui/web/template/channels.html
@@ -2,125 +2,109 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "channels" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<!-- Button trigger modal -->
-									<button
-										type="button"
-										class="btn body-button"
-										onclick="openModal('single')"
-									>
-										Add Channel
-									</button>
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <!-- Button trigger modal -->
+                  <button type="button" class="btn body-button" onclick="openModal('single')">
+                    Add Channel
+                  </button>
 
-									<!-- Modal -->
-									<div
-										class="modal fade"
-										id="addChannelModal"
-										tabindex="-1"
-										role="dialog"
-										aria-labelledby="addChannelModalLabel"
-										aria-hidden="true"
-									>
-										<div class="modal-dialog" role="document">
-											<div class="modal-content">
-												<div class="modal-header">
-													<h5 class="modal-title" id="addChannelModalLabel">
-														Add Channel
-													</h5>
-												</div>
-												<div class="modal-body">
-													<div id="alertMessage"></div>
-													<form method="post" id="channelform">
-														<div class="mb-3">
-															<label for="name" class="form-label">Name</label>
-															<input
-																type="text"
-																class="form-control"
-																name="name"
-																id="name"
-																placeholder="Channel Name"
-															/>
-															<div id="nameError" class="text-danger"></div>
-														</div>
-														<div class="mb-3">
-															<label for="infiniteScroll" class="form-label">
-																Parent Name
-															</label>
-															<input
-																type="text"
-																class="itemsFilter"
-																name="parentFilter"
-																id="parentFilter"
-																placeholder="Filter by parent name"
-															/>
-															<select
-																class="form-select"
-																name="parentID"
-																id="infiniteScroll"
-																size="5"
-															>
-																<option disabled>select a channel</option>
-															</select>
-														</div>
-														<div class="mb-3">
-															<label for="description" class="form-label">
-																Description
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="description"
-																id="description"
-																placeholder="Channel Description"
-															/>
-														</div>
-														<div class="mb-3">
-															<label for="metadata" class="form-label">
-																Metadata
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="metadata"
-																id="metadata"
-																value="{}"
-															/>
-															<div id="metadataHelp" class="form-text">
-																Enter channel metadata in JSON format.
-															</div>
-															<div id="metadataError" class="text-danger"></div>
-														</div>
-														<button
-															type="submit"
-															class="btn body-button"
-															id="create-channel-button"
-														>
-															Submit
-														</button>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
+                  <!-- Modal -->
+                  <div
+                    class="modal fade"
+                    id="addChannelModal"
+                    tabindex="-1"
+                    role="dialog"
+                    aria-labelledby="addChannelModalLabel"
+                    aria-hidden="true"
+                  >
+                    <div class="modal-dialog" role="document">
+                      <div class="modal-content">
+                        <div class="modal-header">
+                          <h5 class="modal-title" id="addChannelModalLabel">Add Channel</h5>
+                        </div>
+                        <div class="modal-body">
+                          <div id="alertMessage"></div>
+                          <form method="post" id="channelform">
+                            <div class="mb-3">
+                              <label for="name" class="form-label">Name</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="name"
+                                id="name"
+                                placeholder="Channel Name"
+                              />
+                              <div id="nameError" class="text-danger"></div>
+                            </div>
+                            <div class="mb-3">
+                              <label for="infiniteScroll" class="form-label">Parent Name</label>
+                              <input
+                                type="text"
+                                class="itemsFilter"
+                                name="parentFilter"
+                                id="parentFilter"
+                                placeholder="Filter by parent name"
+                              />
+                              <select
+                                class="form-select"
+                                name="parentID"
+                                id="infiniteScroll"
+                                size="5"
+                              >
+                                <option disabled>select a channel</option>
+                              </select>
+                            </div>
+                            <div class="mb-3">
+                              <label for="description" class="form-label">Description</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="description"
+                                id="description"
+                                placeholder="Channel Description"
+                              />
+                            </div>
+                            <div class="mb-3">
+                              <label for="metadata" class="form-label">Metadata</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="metadata"
+                                id="metadata"
+                                value="{}"
+                              />
+                              <div id="metadataHelp" class="form-text">
+                                Enter channel metadata in JSON format.
+                              </div>
+                              <div id="metadataError" class="text-danger"></div>
+                            </div>
+                            <button
+                              type="submit"
+                              class="btn body-button"
+                              id="create-channel-button"
+                            >
+                              Submit
+                            </button>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
 
-									<!-- Button trigger modal -->
-									<button
-										type="button"
-										class="btn body-button"
-										onclick="openModal('bulk')"
-									>
-										Add Channels
-									</button>
+                  <!-- Button trigger modal -->
+                  <button type="button" class="btn body-button" onclick="openModal('bulk')">
+                    Add Channels
+                  </button>
 
 									<!-- Modal -->
 									<div
@@ -260,41 +244,37 @@ <h5 class="modal-title" id="addChannelsModalLabel">
 					},
 				});
 
-				const channelModal = new bootstrap.Modal(
-					document.getElementById("addChannelModal"),
-				);
-				const channelsModal = new bootstrap.Modal(
-					document.getElementById("addChannelsModal"),
-				);
+        const channelModal = new bootstrap.Modal(document.getElementById("addChannelModal"));
+        const channelsModal = new bootstrap.Modal(document.getElementById("addChannelsModal"));
 
-				function openModal(modal) {
-					if (modal === "single") {
-						channelModal.show();
-					} else if (modal === "bulk") {
-						channelsModal.show();
-					}
-				}
+        function openModal(modal) {
+          if (modal === "single") {
+            channelModal.show();
+          } else if (modal === "bulk") {
+            channelsModal.show();
+          }
+        }
 
-				submitCreateForm({
-					url: "/channels",
-					formId: "channelform",
-					alertDiv: "alertMessage",
-					modal: channelModal,
-				});
+        submitCreateForm({
+          url: "/channels",
+          formId: "channelform",
+          alertDiv: "alertMessage",
+          modal: channelModal,
+        });
 
-				submitCreateForm({
-					url: "/channels/bulk",
-					formId: "bulkchannelsform",
-					alertDiv: "alertBulkMessage",
-					modal: channelsModal,
-				});
+        submitCreateForm({
+          url: "/channels/bulk",
+          formId: "bulkchannelsform",
+          alertDiv: "alertBulkMessage",
+          modal: channelsModal,
+        });
 
-				fetchIndividualEntity({
-					input: "parentFilter",
-					itemSelect: "infiniteScroll",
-					item: "channels",
-				});
-			</script>
-		</body>
-	</html>
+        fetchIndividualEntity({
+          input: "parentFilter",
+          itemSelect: "infiniteScroll",
+          item: "channels",
+        });
+      </script>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/channelthings.html b/ui/web/template/channelthings.html
index 1334325c4..a0e6c32c8 100644
--- a/ui/web/template/channelthings.html
+++ b/ui/web/template/channelthings.html
@@ -2,202 +2,172 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "channelthings" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<a
-										href="/channels/{{ .ChannelID }}"
-										type="button"
-										class="btn body-button"
-									>
-										Channel
-									</a>
-									<a
-										href="/channels/{{ .ChannelID }}/users"
-										type="button"
-										class="btn body-button"
-									>
-										Channel Users
-									</a>
-									<a
-										href="/channels/{{ .ChannelID }}/groups"
-										type="button"
-										class="btn body-button"
-									>
-										Channel Groups
-									</a>
-								</div>
-								<div class="table-responsive table-container">
-									<div class="d-flex flex-row justify-content-between">
-										<h4>Channel Things</h4>
-										<button
-											role="button"
-											class="btn body-button"
-											onclick="openThingModal()"
-										>
-											<i class="fa-solid fa-plus fs-4"></i>
-										</button>
-										<!-- modal -->
-										<div
-											class="modal fade"
-											id="addThingModal"
-											tabindex="-1"
-											aria-labelledby="addThingModalLabel"
-											aria-hidden="true"
-										>
-											<div class="modal-dialog modal-dialog-centered">
-												<div class="modal-content">
-													<div class="modal-header">
-														<h1
-															class="modal-title fs-5"
-															id="addThingModalLabel"
-														>
-															Add Thing
-														</h1>
-														<button
-															type="button"
-															class="btn-close"
-															data-bs-dismiss="modal"
-															aria-label="Close"
-														></button>
-													</div>
-													<form
-														action="/channels/{{ .ChannelID }}/things/connect?item=channels"
-														method="post"
-													>
-														<div class="modal-body">
-															<div class="mb-3">
-																<label for="infiniteScroll" class="form-label">
-																	Thing ID
-																</label>
-																<input
-																	type="text"
-																	name="thingFilter"
-																	id="thingFilter"
-																	placeholder="Filter by Thing ID"
-																/>
-																<select
-																	class="form-select"
-																	name="thingID"
-																	id="infiniteScroll"
-																	size="5"
-																	required
-																>
-																	<option disabled>select a thing</option>
-																</select>
-															</div>
-															<div class="modal-footer">
-																<button
-																	type="button"
-																	class="btn btn-secondary"
-																	data-bs-dismiss="modal"
-																>
-																	Cancel
-																</button>
-																<button type="submit" class="btn btn-primary">
-																	Connect
-																</button>
-															</div>
-														</div>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
-									{{ template "tableheader" . }}
-									<div class="itemsTable">
-										<table id="itemsTable" class="table">
-											<thead>
-												<tr>
-													<th scope="col">Name</th>
-													<th scope="col">ID</th>
-													<th class="tags-col" scope="col">Tags</th>
-													<th class="meta-col" scope="col">Metadata</th>
-													<th class="created-col" scope="col">Created At</th>
-													<th class="text-center" scope="col"></th>
-												</tr>
-											</thead>
-											<tbody>
-												{{ $channelID := .ChannelID }}
-												{{ range $i, $t := .Things }}
-													{{ $disableButton := false }}
-													<tr>
-														<td>{{ $t.Name }}</td>
-														<td>
-															<div class="copy-con-container">
-																<a href="{{ printf "/things/%s" $t.ID }}">
-																	{{ $t.ID }}
-																</a>
-																<button
-																	class="copy-icon"
-																	onclick="copyToClipboard(this)"
-																>
-																	<i class="far fa-copy"></i>
-																</button>
-															</div>
-														</td>
-														<td class="tags-col">{{ toSlice $t.Tags }}</td>
-														<td class="meta-col">{{ toJSON $t.Metadata }}</td>
-														<td class="created-col">{{ $t.CreatedAt }}</td>
-														<td class="text-center">
-															<form
-																action="/channels/{{ $channelID }}/things/disconnect?item=channels"
-																method="post"
-															>
-																<input
-																	type="hidden"
-																	name="thingID"
-																	id="thingID"
-																	value="{{ $t.ID }}"
-																/>
-																<button
-																	type="submit"
-																	class="btn btn-sm"
-																	{{ if
-																		$disableButton
-																	}}
-																		disabled
-																	{{ end }}
-																>
-																	<i class="fas fa-trash-alt"></i>
-																</button>
-															</form>
-														</td>
-													</tr>
-												{{ end }}
-											</tbody>
-										</table>
-									</div>
-									{{ template "tablefooter" . }}
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
-			<script>
-				const thingModal = new bootstrap.Modal(
-					document.getElementById("addThingModal"),
-				);
-				function openThingModal() {
-					thingModal.show();
-				}
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <a href="/channels/{{ .ChannelID }}" type="button" class="btn body-button">
+                    Channel
+                  </a>
+                  <a href="/channels/{{ .ChannelID }}/users" type="button" class="btn body-button">
+                    Channel Users
+                  </a>
+                  <a href="/channels/{{ .ChannelID }}/groups" type="button" class="btn body-button">
+                    Channel Groups
+                  </a>
+                </div>
+                <div class="table-responsive table-container">
+                  <div class="d-flex flex-row justify-content-between">
+                    <h4>Channel Things</h4>
+                    <button role="button" class="btn body-button" onclick="openThingModal()">
+                      <i class="fa-solid fa-plus fs-4"></i>
+                    </button>
+                    <!-- modal -->
+                    <div
+                      class="modal fade"
+                      id="addThingModal"
+                      tabindex="-1"
+                      aria-labelledby="addThingModalLabel"
+                      aria-hidden="true"
+                    >
+                      <div class="modal-dialog modal-dialog-centered">
+                        <div class="modal-content">
+                          <div class="modal-header">
+                            <h1 class="modal-title fs-5" id="addThingModalLabel">Add Thing</h1>
+                            <button
+                              type="button"
+                              class="btn-close"
+                              data-bs-dismiss="modal"
+                              aria-label="Close"
+                            ></button>
+                          </div>
+                          <form
+                            action="/channels/{{ .ChannelID }}/things/connect?item=channels"
+                            method="post"
+                          >
+                            <div class="modal-body">
+                              <div class="mb-3">
+                                <label for="infiniteScroll" class="form-label">Thing ID</label>
+                                <input
+                                  type="text"
+                                  name="thingFilter"
+                                  id="thingFilter"
+                                  placeholder="Filter by Thing ID"
+                                />
+                                <select
+                                  class="form-select"
+                                  name="thingID"
+                                  id="infiniteScroll"
+                                  size="5"
+                                  required
+                                >
+                                  <option disabled>select a thing</option>
+                                </select>
+                              </div>
+                              <div class="modal-footer">
+                                <button
+                                  type="button"
+                                  class="btn btn-secondary"
+                                  data-bs-dismiss="modal"
+                                >
+                                  Cancel
+                                </button>
+                                <button type="submit" class="btn btn-primary">Connect</button>
+                              </div>
+                            </div>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  {{ template "tableheader" . }}
+                  <div class="itemsTable">
+                    <table id="itemsTable" class="table">
+                      <thead>
+                        <tr>
+                          <th scope="col">Name</th>
+                          <th scope="col">ID</th>
+                          <th class="tags-col" scope="col">Tags</th>
+                          <th class="meta-col" scope="col">Metadata</th>
+                          <th class="created-col" scope="col">Created At</th>
+                          <th class="text-center" scope="col"></th>
+                        </tr>
+                      </thead>
+                      <tbody>
+                        {{ $channelID := .ChannelID }}
+                        {{ range $i, $t := .Things }}
+                          {{ $disableButton := false }}
+                          <tr>
+                            <td>{{ $t.Name }}</td>
+                            <td>
+                              <div class="copy-con-container">
+                                <a href="{{ printf "/things/%s" $t.ID }}">
+                                  {{ $t.ID }}
+                                </a>
+                                <button class="copy-icon" onclick="copyToClipboard(this)">
+                                  <i class="far fa-copy"></i>
+                                </button>
+                              </div>
+                            </td>
+                            <td class="tags-col">{{ toSlice $t.Tags }}</td>
+                            <td class="meta-col">{{ toJSON $t.Metadata }}</td>
+                            <td class="created-col">{{ $t.CreatedAt }}</td>
+                            <td class="text-center">
+                              <form
+                                action="/channels/{{ $channelID }}/things/disconnect?item=channels"
+                                method="post"
+                              >
+                                <input
+                                  type="hidden"
+                                  name="thingID"
+                                  id="thingID"
+                                  value="{{ $t.ID }}"
+                                />
+                                <button
+                                  type="submit"
+                                  class="btn btn-sm"
+                                  {{ if
+                                    $disableButton
+                                  }}
+                                    disabled
+                                  {{ end }}
+                                >
+                                  <i class="fas fa-trash-alt"></i>
+                                </button>
+                              </form>
+                            </td>
+                          </tr>
+                        {{ end }}
+                      </tbody>
+                    </table>
+                  </div>
+                  {{ template "tablefooter" . }}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
+      <script>
+        const thingModal = new bootstrap.Modal(document.getElementById("addThingModal"));
+        function openThingModal() {
+          thingModal.show();
+        }
 
-				fetchIndividualEntity({
-					input: "thingFilter",
-					itemSelect: "infiniteScroll",
-					item: "things",
-				});
-			</script>
-		</body>
-	</html>
+        fetchIndividualEntity({
+          input: "thingFilter",
+          itemSelect: "infiniteScroll",
+          item: "things",
+        });
+      </script>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/channelusers.html b/ui/web/template/channelusers.html
index c66619721..12d383c14 100644
--- a/ui/web/template/channelusers.html
+++ b/ui/web/template/channelusers.html
@@ -2,517 +2,471 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "channelusers" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<a
-										class="btn body-button"
-										href="/channels/{{ .ChannelID }}"
-										role="button"
-									>
-										Channel
-									</a>
-									<a
-										class="btn body-button"
-										href="/channels/{{ .ChannelID }}/things"
-										role="button"
-									>
-										Channel Things
-									</a>
-									<a
-										class="btn body-button"
-										href="/channels/{{ .ChannelID }}/groups"
-										role="button"
-									>
-										Channel Groups
-									</a>
-								</div>
-								<div class="table-responsive table-container">
-									<div class="d-flex flex-row justify-content-between">
-										<h4>Channel Users</h4>
-										<button
-											role="button"
-											class="btn body-button"
-											onclick="openUserModal()"
-										>
-											<i class="fa-solid fa-plus fs-4"></i>
-										</button>
-										<!-- modal -->
-										<div
-											class="modal fade"
-											id="addUserModal"
-											tabindex="-1"
-											aria-labelledby="addUserModalLabel"
-											aria-hidden="true"
-										>
-											<div class="modal-dialog modal-dialog-centered">
-												<div class="modal-content">
-													<div class="modal-header">
-														<h1 class="modal-title fs-5" id="addUserModalLabel">
-															Add User
-														</h1>
-														<button
-															type="button"
-															class="btn-close"
-															data-bs-dismiss="modal"
-															aria-label="Close"
-														></button>
-													</div>
-													<form
-														action="/channels/{{ .ChannelID }}/users/assign?item=channels"
-														method="post"
-													>
-														<div class="modal-body">
-															<div class="mb-3">
-																<label for="infiniteScroll" class="form-label">
-																	User ID
-																</label>
-																<input
-																	type="text"
-																	name="userFilter"
-																	id="userFilter"
-																	placeholder="Filter by User ID"
-																/>
-																<select
-																	class="form-select"
-																	name="userID"
-																	id="infiniteScroll"
-																	size="5"
-																	required
-																>
-																	<option disabled>select a User</option>
-																</select>
-															</div>
-															<div class="mb-3">
-																<label for="relation" class="form-label">
-																	Relation
-																</label>
-																<select
-																	class="form-control"
-																	name="relation"
-																	id="relation"
-																	aria-describedby="relationHelp"
-																	multiple
-																	required
-																>
-																	{{ range $i, $r := .Relations }}
-																		<option value="{{ $r }}">
-																			{{ $r }}
-																		</option>
-																	{{ end }}
-																</select>
-																<div id="relationHelp" class="form-text">
-																	Select Relation.
-																</div>
-															</div>
-															<div class="modal-footer">
-																<button
-																	type="button"
-																	class="btn btn-secondary"
-																	data-bs-dismiss="modal"
-																>
-																	Cancel
-																</button>
-																<button type="submit" class="btn btn-primary">
-																	Assign
-																</button>
-															</div>
-														</div>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <a class="btn body-button" href="/channels/{{ .ChannelID }}" role="button">
+                    Channel
+                  </a>
+                  <a class="btn body-button" href="/channels/{{ .ChannelID }}/things" role="button">
+                    Channel Things
+                  </a>
+                  <a class="btn body-button" href="/channels/{{ .ChannelID }}/groups" role="button">
+                    Channel Groups
+                  </a>
+                </div>
+                <div class="table-responsive table-container">
+                  <div class="d-flex flex-row justify-content-between">
+                    <h4>Channel Users</h4>
+                    <button role="button" class="btn body-button" onclick="openUserModal()">
+                      <i class="fa-solid fa-plus fs-4"></i>
+                    </button>
+                    <!-- modal -->
+                    <div
+                      class="modal fade"
+                      id="addUserModal"
+                      tabindex="-1"
+                      aria-labelledby="addUserModalLabel"
+                      aria-hidden="true"
+                    >
+                      <div class="modal-dialog modal-dialog-centered">
+                        <div class="modal-content">
+                          <div class="modal-header">
+                            <h1 class="modal-title fs-5" id="addUserModalLabel">Add User</h1>
+                            <button
+                              type="button"
+                              class="btn-close"
+                              data-bs-dismiss="modal"
+                              aria-label="Close"
+                            ></button>
+                          </div>
+                          <form
+                            action="/channels/{{ .ChannelID }}/users/assign?item=channels"
+                            method="post"
+                          >
+                            <div class="modal-body">
+                              <div class="mb-3">
+                                <label for="infiniteScroll" class="form-label">User ID</label>
+                                <input
+                                  type="text"
+                                  name="userFilter"
+                                  id="userFilter"
+                                  placeholder="Filter by User ID"
+                                />
+                                <select
+                                  class="form-select"
+                                  name="userID"
+                                  id="infiniteScroll"
+                                  size="5"
+                                  required
+                                >
+                                  <option disabled>select a User</option>
+                                </select>
+                              </div>
+                              <div class="mb-3">
+                                <label for="relation" class="form-label">Relation</label>
+                                <select
+                                  class="form-control"
+                                  name="relation"
+                                  id="relation"
+                                  aria-describedby="relationHelp"
+                                  multiple
+                                  required
+                                >
+                                  {{ range $i, $r := .Relations }}
+                                    <option value="{{ $r }}">
+                                      {{ $r }}
+                                    </option>
+                                  {{ end }}
+                                </select>
+                                <div id="relationHelp" class="form-text">Select Relation.</div>
+                              </div>
+                              <div class="modal-footer">
+                                <button
+                                  type="button"
+                                  class="btn btn-secondary"
+                                  data-bs-dismiss="modal"
+                                >
+                                  Cancel
+                                </button>
+                                <button type="submit" class="btn btn-primary">Assign</button>
+                              </div>
+                            </div>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
 
-									<ul class="nav nav-tabs" id="roleTab" role="tablist">
-										<li class="nav-item" role="presentation">
-											{{ $tabActive := "" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="view-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#view-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="view-tab-pane"
-												aria-selected="true"
-												onclick="openTab('')"
-											>
-												All
-											</button>
-										</li>
-										<li class="nav-item" role="presentation">
-											{{ $tabActive = "admin" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="admin-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#admin-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="admin-tab-pane"
-												aria-selected="true"
-												onclick="openTab('admin')"
-											>
-												Admin
-											</button>
-										</li>
-										<li class="nav-item" role="presentation">
-											{{ $tabActive = "editor" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="editor-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#editor-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="editor-tab-pane"
-												aria-selected="false"
-												onclick="openTab('editor')"
-											>
-												Editor
-											</button>
-										</li>
-										<li class="nav-item" role="presentation">
-											{{ $tabActive = "viewer" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="viewer-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#viewer-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="viewer-tab-pane"
-												aria-selected="false"
-												onclick="openTab('viewer')"
-											>
-												Viewer
-											</button>
-										</li>
-									</ul>
-									<div class="tab-content mt-3" id="roleTabContent">
-										{{ $channelID := .ChannelID }}
-										<div
-											class="tab-pane active"
-											id="view-tab-pane"
-											role="tabpanel"
-											aria-labelledby="view-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table id="itemsTable" class="table">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="tags-col" scope="col">Tags</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ range $i, $u := .Users }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $u.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/users/%s" $u.ID }}">
-																			{{ $u.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="tags-col">{{ toSlice $u.Tags }}</td>
-																<td class="meta-col">
-																	{{ toJSON $u.Metadata }}
-																</td>
-																<td class="created-col">{{ $u.CreatedAt }}</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-										<div
-											class="tab-pane"
-											id="admin-tab-pane"
-											role="tabpanel"
-											aria-labelledby="admin-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table id="itemsTable" class="table">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="tags-col" scope="col">Tags</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-															<th class="text-center" scope="col"></th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ range $i, $u := .Users }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $u.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/users/%s" $u.ID }}">
-																			{{ $u.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="tags-col">{{ toSlice $u.Tags }}</td>
-																<td class="meta-col">
-																	{{ toJSON $u.Metadata }}
-																</td>
-																<td class="created-col">{{ $u.CreatedAt }}</td>
-																<td class="text-center">
-																	<form
-																		action="/channels/{{ $channelID }}/users/unassign?item=channels"
-																		method="post"
-																	>
-																		<input
-																			type="hidden"
-																			name="userID"
-																			id="userID"
-																			value="{{ $u.ID }}"
-																		/>
-																		<input
-																			type="hidden"
-																			name="relation"
-																			id="relation"
-																			value="admin"
-																		/>
-																		<button
-																			type="submit"
-																			class="btn btn-sm"
-																			{{ if
-																				$disableButton
-																			}}
-																				disabled
-																			{{ end }}
-																		>
-																			<i class="fas fa-trash-alt"></i>
-																		</button>
-																	</form>
-																</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-										<div
-											class="tab-pane "
-											id="editor-tab-pane"
-											role="tabpanel"
-											aria-labelledby="editor-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table id="itemsTable" class="table">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="tags-col" scope="col">Tags</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-															<th class="text-center" scope="col"></th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ range $i, $u := .Users }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $u.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/users/%s" $u.ID }}">
-																			{{ $u.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="tags-col">{{ toSlice $u.Tags }}</td>
-																<td class="meta-col">
-																	{{ toJSON $u.Metadata }}
-																</td>
-																<td class="created-col">{{ $u.CreatedAt }}</td>
-																<td class="text-center">
-																	<form
-																		action="/channels/{{ $channelID }}/users/unassign?item=channels"
-																		method="post"
-																	>
-																		<input
-																			type="hidden"
-																			name="userID"
-																			id="userID"
-																			value="{{ $u.ID }}"
-																		/>
-																		<input
-																			type="hidden"
-																			name="relation"
-																			id="relation"
-																			value="editor"
-																		/>
-																		<button
-																			type="submit"
-																			class="btn btn-sm"
-																			{{ if
-																				$disableButton
-																			}}
-																				disabled
-																			{{ end }}
-																		>
-																			<i class="fas fa-trash-alt"></i>
-																		</button>
-																	</form>
-																</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-										<div
-											class="tab-pane"
-											id="viewer-tab-pane"
-											role="tabpanel"
-											aria-labelledby="viewer-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table id="itemsTable" class="table">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="tags-col" scope="col">Tags</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-															<th class="text-center" scope="col"></th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ range $i, $u := .Users }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $u.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/users/%s" $u.ID }}">
-																			{{ $u.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="tags-col">{{ toSlice $u.Tags }}</td>
-																<td class="meta-col">
-																	{{ toJSON $u.Metadata }}
-																</td>
-																<td class="created-col">{{ $u.CreatedAt }}</td>
-																<td class="text-center">
-																	<form
-																		action="/channels/{{ $channelID }}/users/unassign?item=channels"
-																		method="post"
-																	>
-																		<input
-																			type="hidden"
-																			name="userID"
-																			id="userID"
-																			value="{{ $u.ID }}"
-																		/>
-																		<input
-																			type="hidden"
-																			name="relation"
-																			id="relation"
-																			value="viewer"
-																		/>
-																		<button
-																			type="submit"
-																			class="btn btn-sm"
-																			{{ if
-																				$disableButton
-																			}}
-																				disabled
-																			{{ end }}
-																		>
-																			<i class="fas fa-trash-alt"></i>
-																		</button>
-																	</form>
-																</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-									</div>
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
+                  <ul class="nav nav-tabs" id="roleTab" role="tablist">
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive := "" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="view-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#view-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="view-tab-pane"
+                        aria-selected="true"
+                        onclick="openTab('')"
+                      >
+                        All
+                      </button>
+                    </li>
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive = "admin" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="admin-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#admin-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="admin-tab-pane"
+                        aria-selected="true"
+                        onclick="openTab('admin')"
+                      >
+                        Admin
+                      </button>
+                    </li>
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive = "editor" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="editor-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#editor-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="editor-tab-pane"
+                        aria-selected="false"
+                        onclick="openTab('editor')"
+                      >
+                        Editor
+                      </button>
+                    </li>
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive = "viewer" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="viewer-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#viewer-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="viewer-tab-pane"
+                        aria-selected="false"
+                        onclick="openTab('viewer')"
+                      >
+                        Viewer
+                      </button>
+                    </li>
+                  </ul>
+                  <div class="tab-content mt-3" id="roleTabContent">
+                    {{ $channelID := .ChannelID }}
+                    <div
+                      class="tab-pane active"
+                      id="view-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="view-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table id="itemsTable" class="table">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="tags-col" scope="col">Tags</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ range $i, $u := .Users }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $u.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/users/%s" $u.ID }}">
+                                      {{ $u.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="tags-col">{{ toSlice $u.Tags }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $u.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $u.CreatedAt }}</td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                    <div
+                      class="tab-pane"
+                      id="admin-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="admin-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table id="itemsTable" class="table">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="tags-col" scope="col">Tags</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                              <th class="text-center" scope="col"></th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ range $i, $u := .Users }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $u.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/users/%s" $u.ID }}">
+                                      {{ $u.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="tags-col">{{ toSlice $u.Tags }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $u.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $u.CreatedAt }}</td>
+                                <td class="text-center">
+                                  <form
+                                    action="/channels/{{ $channelID }}/users/unassign?item=channels"
+                                    method="post"
+                                  >
+                                    <input
+                                      type="hidden"
+                                      name="userID"
+                                      id="userID"
+                                      value="{{ $u.ID }}"
+                                    />
+                                    <input
+                                      type="hidden"
+                                      name="relation"
+                                      id="relation"
+                                      value="admin"
+                                    />
+                                    <button
+                                      type="submit"
+                                      class="btn btn-sm"
+                                      {{ if
+                                        $disableButton
+                                      }}
+                                        disabled
+                                      {{ end }}
+                                    >
+                                      <i class="fas fa-trash-alt"></i>
+                                    </button>
+                                  </form>
+                                </td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                    <div
+                      class="tab-pane "
+                      id="editor-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="editor-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table id="itemsTable" class="table">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="tags-col" scope="col">Tags</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                              <th class="text-center" scope="col"></th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ range $i, $u := .Users }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $u.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/users/%s" $u.ID }}">
+                                      {{ $u.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="tags-col">{{ toSlice $u.Tags }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $u.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $u.CreatedAt }}</td>
+                                <td class="text-center">
+                                  <form
+                                    action="/channels/{{ $channelID }}/users/unassign?item=channels"
+                                    method="post"
+                                  >
+                                    <input
+                                      type="hidden"
+                                      name="userID"
+                                      id="userID"
+                                      value="{{ $u.ID }}"
+                                    />
+                                    <input
+                                      type="hidden"
+                                      name="relation"
+                                      id="relation"
+                                      value="editor"
+                                    />
+                                    <button
+                                      type="submit"
+                                      class="btn btn-sm"
+                                      {{ if
+                                        $disableButton
+                                      }}
+                                        disabled
+                                      {{ end }}
+                                    >
+                                      <i class="fas fa-trash-alt"></i>
+                                    </button>
+                                  </form>
+                                </td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                    <div
+                      class="tab-pane"
+                      id="viewer-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="viewer-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table id="itemsTable" class="table">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="tags-col" scope="col">Tags</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                              <th class="text-center" scope="col"></th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ range $i, $u := .Users }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $u.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/users/%s" $u.ID }}">
+                                      {{ $u.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="tags-col">{{ toSlice $u.Tags }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $u.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $u.CreatedAt }}</td>
+                                <td class="text-center">
+                                  <form
+                                    action="/channels/{{ $channelID }}/users/unassign?item=channels"
+                                    method="post"
+                                  >
+                                    <input
+                                      type="hidden"
+                                      name="userID"
+                                      id="userID"
+                                      value="{{ $u.ID }}"
+                                    />
+                                    <input
+                                      type="hidden"
+                                      name="relation"
+                                      id="relation"
+                                      value="viewer"
+                                    />
+                                    <button
+                                      type="submit"
+                                      class="btn btn-sm"
+                                      {{ if
+                                        $disableButton
+                                      }}
+                                        disabled
+                                      {{ end }}
+                                    >
+                                      <i class="fas fa-trash-alt"></i>
+                                    </button>
+                                  </form>
+                                </td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
 			<script>
 				const userModal = new bootstrap.Modal(
 					document.getElementById("addUserModal"),
@@ -527,18 +481,18 @@ <h1 class="modal-title fs-5" id="addUserModalLabel">
 					item: "users",
 				});
 
-                function openTab(relation) {
+        function openTab(relation) {
 					event.preventDefault();
-                    var channelID = '{{.ChannelID}}';
-                    fetch(`/channels/${channelID}/users?relation=${relation}`, {
-                        method: "GET",
-                    })
-                        .then((response) => {
+					var channelID = '{{.ChannelID}}';
+					fetch(`/channels/${channelID}/users?relation=${relation}`, {
+							method: "GET",
+					})
+					.then((response) => {
 
-                        })
-                        .catch((error) => console.error("Error:", error));
+					})
+					.catch((error) => console.error("Error:", error));
 				}
 			</script>
-		</body>
-	</html>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/error.html b/ui/web/template/error.html
index 601e2ea5b..63c0ad3d9 100644
--- a/ui/web/template/error.html
+++ b/ui/web/template/error.html
@@ -1,27 +1,29 @@
 <!-- Copyright (c) Abstract Machines
 SPDX-License-Identifier: Apache-2.0 -->
 
-{{define "error"}}
-<!DOCTYPE html>
-<html lang="en">
-{{template "header"}}
-<body>
-    {{template "navbar"}}
-    <div class="main-content">
+{{ define "error" }}
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" }}
+      <div class="main-content">
         <div class="main">
-            <div class="row">
-                <div class="col-lg-8 mx-auto py-5">
-                    <div class="row">
-                        <div class="error-header py-5">
-                            <h1 class = "error-header">Sorry, there seems to be an issue with your request</h1>
-                        </div>
-                        <div class="alert alert-danger alert-dismissible">{{.Error}}</div>
-                        <a type="button" href="javascript:window. history. back();" class="btn body-button">Back</a>
-                    </div>
+          <div class="row">
+            <div class="col-lg-8 mx-auto py-5">
+              <div class="row">
+                <div class="error-header py-5">
+                  <h1 class="error-header">Sorry, there seems to be an issue with your request</h1>
                 </div>
+                <div class="alert alert-danger alert-dismissible">{{ .Error }}</div>
+                <a type="button" href="javascript:window. history. back();" class="btn body-button">
+                  Back
+                </a>
+              </div>
             </div>
+          </div>
         </div>
-    </div>
-</body>
-</html>
-{{end}}
+      </div>
+    </body>
+  </html>
+{{ end }}
diff --git a/ui/web/template/footer.html b/ui/web/template/footer.html
index c64b769fa..0c6e2e736 100644
--- a/ui/web/template/footer.html
+++ b/ui/web/template/footer.html
@@ -2,21 +2,18 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "footer" }}
-	<!-- Bootstrap core JavaScript
+  <!-- Bootstrap core JavaScript
 ================================================== -->
-	<!-- Placed at the end of the document so the pages load faster -->
-	<script
-		src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"
-		integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r"
-		crossorigin="anonymous"
-	></script>
-	<script
-		src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.min.js"
-		integrity="sha384-Rx+T1VzGupg4BHQYs2gCW9It+akI2MM/mndMCy36UVfodzcJcF0GGLxZIzObiEfa"
-		crossorigin="anonymous"
-	></script>
-	<script
-		type="text/javascript"
-		src="https://www.gstatic.com/charts/loader.js"
-	></script>
+  <!-- Placed at the end of the document so the pages load faster -->
+  <script
+    src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"
+    integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r"
+    crossorigin="anonymous"
+  ></script>
+  <script
+    src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.min.js"
+    integrity="sha384-Rx+T1VzGupg4BHQYs2gCW9It+akI2MM/mndMCy36UVfodzcJcF0GGLxZIzObiEfa"
+    crossorigin="anonymous"
+  ></script>
+  <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
 {{ end }}
diff --git a/ui/web/template/group.html b/ui/web/template/group.html
index ecca37d44..e7ae42567 100644
--- a/ui/web/template/group.html
+++ b/ui/web/template/group.html
@@ -2,158 +2,117 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "group" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<a
-										class="btn body-button"
-										href="/groups/{{ .Group.ID }}/users"
-										role="button"
-									>
-										Group Users
-									</a>
-									<a
-										class="btn body-button"
-										href="/groups/{{ .Group.ID }}/channels"
-										role="button"
-									>
-										Group Channels
-									</a>
-								</div>
-								<div class="table-responsive table-container">
-									<table id="itemsTable" class="table">
-										<thead>
-											<tr>
-												<th scope="row">GROUP</th>
-											</tr>
-										</thead>
-										<tbody>
-											{{ $disableButton := false }}
-											<tr>
-												<th>NAME</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="name"
-												>
-													{{ .Group.Name }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														id="edit-name"
-														{{ if
-															$disableButton
-														}}
-															disabled
-														{{ end }}
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" id="save-name">
-															Save
-														</button>
-														<button class="cancel-btn" id="cancel-name">
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>ID</th>
-												<td>{{ .Group.ID }}</td>
-												<td></td>
-											</tr>
-											<tr>
-												<th>Description</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="description"
-												>
-													{{ .Group.Description }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														id="edit-description"
-														{{ if
-															$disableButton
-														}}
-															disabled
-														{{ end }}
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" id="save-description">
-															Save
-														</button>
-														<button class="cancel-btn" id="cancel-description">
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>Metadata</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="metadata"
-												>
-													{{ toJSON .Group.Metadata }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														id="edit-metadata"
-														{{ if
-															$disableButton
-														}}
-															disabled
-														{{ end }}
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" id="save-metadata">
-															Save
-														</button>
-														<button class="cancel-btn" id="cancel-metadata">
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-										</tbody>
-									</table>
-									<div id="error-message" class="text-danger"></div>
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <a class="btn body-button" href="/groups/{{ .Group.ID }}/users" role="button">
+                    Group Users
+                  </a>
+                  <a class="btn body-button" href="/groups/{{ .Group.ID }}/channels" role="button">
+                    Group Channels
+                  </a>
+                </div>
+                <div class="table-responsive table-container">
+                  <table id="itemsTable" class="table">
+                    <thead>
+                      <tr>
+                        <th scope="row">GROUP</th>
+                      </tr>
+                    </thead>
+                    <tbody>
+                      {{ $disableButton := false }}
+                      <tr>
+                        <th>NAME</th>
+                        <td class="editable" contenteditable="false" data-field="name">
+                          {{ .Group.Name }}
+                        </td>
+                        <td>
+                          <button
+                            class="edit-btn"
+                            id="edit-name"
+                            {{ if
+                              $disableButton
+                            }}
+                              disabled
+                            {{ end }}
+                          >
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" id="save-name">Save</button>
+                            <button class="cancel-btn" id="cancel-name">Cancel</button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>ID</th>
+                        <td>{{ .Group.ID }}</td>
+                        <td></td>
+                      </tr>
+                      <tr>
+                        <th>Description</th>
+                        <td class="editable" contenteditable="false" data-field="description">
+                          {{ .Group.Description }}
+                        </td>
+                        <td>
+                          <button
+                            class="edit-btn"
+                            id="edit-description"
+                            {{ if
+                              $disableButton
+                            }}
+                              disabled
+                            {{ end }}
+                          >
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" id="save-description">Save</button>
+                            <button class="cancel-btn" id="cancel-description">Cancel</button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>Metadata</th>
+                        <td class="editable" contenteditable="false" data-field="metadata">
+                          {{ toJSON .Group.Metadata }}
+                        </td>
+                        <td>
+                          <button
+                            class="edit-btn"
+                            id="edit-metadata"
+                            {{ if
+                              $disableButton
+                            }}
+                              disabled
+                            {{ end }}
+                          >
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" id="save-metadata">Save</button>
+                            <button class="cancel-btn" id="cancel-metadata">Cancel</button>
+                          </div>
+                        </td>
+                      </tr>
+                    </tbody>
+                  </table>
+                  <div id="error-message" class="text-danger"></div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
     <script>
       attachEditRowListener(
 			{
@@ -168,6 +127,6 @@
 			}
 		);
     </script>
-		</body>
-	</html>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/groupchannels.html b/ui/web/template/groupchannels.html
index 6973610c8..26b5af2fa 100644
--- a/ui/web/template/groupchannels.html
+++ b/ui/web/template/groupchannels.html
@@ -2,195 +2,167 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "groupchannels" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<a
-										class="btn body-button"
-										href="/groups/{{ .GroupID }}"
-										role="button"
-									>
-										Group
-									</a>
-									<a
-										class="btn body-button"
-										href="/groups/{{ .GroupID }}/users"
-										role="button"
-									>
-										Group Users
-									</a>
-								</div>
-								<div class="table-responsive table-container">
-									<div class="d-flex flex-row justify-content-between">
-										<h4>Group Channels</h4>
-										<button
-											role="button"
-											class="btn body-button"
-											onclick="openChannelModal()"
-										>
-											<i class="fa-solid fa-plus fs-4"></i>
-										</button>
-										<!-- modal -->
-										<div
-											class="modal fade"
-											id="addChannelModal"
-											tabindex="-1"
-											aria-labelledby="addChannelModalLabel"
-											aria-hidden="true"
-										>
-											<div class="modal-dialog modal-dialog-centered">
-												<div class="modal-content">
-													<div class="modal-header">
-														<h1
-															class="modal-title fs-5"
-															id="addChannelModalLabel"
-														>
-															Add Channel
-														</h1>
-														<button
-															type="button"
-															class="btn-close"
-															data-bs-dismiss="modal"
-															aria-label="Close"
-														></button>
-													</div>
-													<form
-														action="/groups/{{ .GroupID }}/channels/assign?item=groups"
-														method="post"
-													>
-														<div class="modal-body">
-															<div class="mb-3">
-																<label for="infiniteScroll" class="form-label">
-																	Channel ID
-																</label>
-																<input
-																	type="text"
-																	name="channelFilter"
-																	id="channelFilter"
-																	placeholder="Filter by Channel ID"
-																/>
-																<select
-																	class="form-select"
-																	name="channelID"
-																	id="infiniteScroll"
-																	size="5"
-																	required
-																>
-																	<option disabled>select a channel</option>
-																</select>
-															</div>
-															<div class="modal-footer">
-																<button
-																	type="button"
-																	class="btn btn-secondary"
-																	data-bs-dismiss="modal"
-																>
-																	Cancel
-																</button>
-																<button type="submit" class="btn btn-primary">
-																	Add Channel
-																</button>
-															</div>
-														</div>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
-									{{ template "tableheader" . }}
-									<div class="itemsTable">
-										<table class="table" id="itemsTable">
-											<thead>
-												<tr>
-													<th scope="col">Name</th>
-													<th scope="col">ID</th>
-													<th class="desc-col" scope="col">Description</th>
-													<th class="meta-col" scope="col">Metadata</th>
-													<th class="created-col" scope="col">Created At</th>
-													<th class="text-center" scope="col"></th>
-												</tr>
-											</thead>
-											<tbody>
-												{{ $groupID := .GroupID }}
-												{{ range $i, $c := .Channels }}
-													{{ $disableButton := false }}
-													<tr>
-														<td>{{ $c.Name }}</td>
-														<td>
-															<div class="copy-con-container">
-																<a href="{{ printf "/groups/%s" $c.ID }}">
-																	{{ $c.ID }}
-																</a>
-																<button
-																	class="copy-icon"
-																	onclick="copyToClipboard(this)"
-																>
-																	<i class="far fa-copy"></i>
-																</button>
-															</div>
-														</td>
-														<td class="desc-col">{{ $c.Description }}</td>
-														<td class="meta-col">{{ toJSON $c.Metadata }}</td>
-														<td class="created-col">{{ $c.CreatedAt }}</td>
-														<td class="text-center">
-															<form
-																action="/groups/{{ $groupID }}/channels/unassign?item=groups"
-																method="post"
-															>
-																<input
-																	type="hidden"
-																	name="channelID"
-																	id="channelID"
-																	value="{{ $c.ID }}"
-																/>
-																<button
-																	type="submit"
-																	class="btn btn-sm"
-																	{{ if
-																		$disableButton
-																	}}
-																		disabled
-																	{{ end }}
-																>
-																	<i class="fas fa-trash-alt"></i>
-																</button>
-															</form>
-														</td>
-													</tr>
-												{{ end }}
-											</tbody>
-										</table>
-									</div>
-									{{ template "tablefooter" . }}
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
-			<script>
-				const channelModal = new bootstrap.Modal(
-					document.getElementById("addChannelModal"),
-				);
-				function openChannelModal() {
-					channelModal.show();
-				}
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <a class="btn body-button" href="/groups/{{ .GroupID }}" role="button">Group</a>
+                  <a class="btn body-button" href="/groups/{{ .GroupID }}/users" role="button">
+                    Group Users
+                  </a>
+                </div>
+                <div class="table-responsive table-container">
+                  <div class="d-flex flex-row justify-content-between">
+                    <h4>Group Channels</h4>
+                    <button role="button" class="btn body-button" onclick="openChannelModal()">
+                      <i class="fa-solid fa-plus fs-4"></i>
+                    </button>
+                    <!-- modal -->
+                    <div
+                      class="modal fade"
+                      id="addChannelModal"
+                      tabindex="-1"
+                      aria-labelledby="addChannelModalLabel"
+                      aria-hidden="true"
+                    >
+                      <div class="modal-dialog modal-dialog-centered">
+                        <div class="modal-content">
+                          <div class="modal-header">
+                            <h1 class="modal-title fs-5" id="addChannelModalLabel">Add Channel</h1>
+                            <button
+                              type="button"
+                              class="btn-close"
+                              data-bs-dismiss="modal"
+                              aria-label="Close"
+                            ></button>
+                          </div>
+                          <form
+                            action="/groups/{{ .GroupID }}/channels/assign?item=groups"
+                            method="post"
+                          >
+                            <div class="modal-body">
+                              <div class="mb-3">
+                                <label for="infiniteScroll" class="form-label">Channel ID</label>
+                                <input
+                                  type="text"
+                                  name="channelFilter"
+                                  id="channelFilter"
+                                  placeholder="Filter by Channel ID"
+                                />
+                                <select
+                                  class="form-select"
+                                  name="channelID"
+                                  id="infiniteScroll"
+                                  size="5"
+                                  required
+                                >
+                                  <option disabled>select a channel</option>
+                                </select>
+                              </div>
+                              <div class="modal-footer">
+                                <button
+                                  type="button"
+                                  class="btn btn-secondary"
+                                  data-bs-dismiss="modal"
+                                >
+                                  Cancel
+                                </button>
+                                <button type="submit" class="btn btn-primary">Add Channel</button>
+                              </div>
+                            </div>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  {{ template "tableheader" . }}
+                  <div class="itemsTable">
+                    <table class="table" id="itemsTable">
+                      <thead>
+                        <tr>
+                          <th scope="col">Name</th>
+                          <th scope="col">ID</th>
+                          <th class="desc-col" scope="col">Description</th>
+                          <th class="meta-col" scope="col">Metadata</th>
+                          <th class="created-col" scope="col">Created At</th>
+                          <th class="text-center" scope="col"></th>
+                        </tr>
+                      </thead>
+                      <tbody>
+                        {{ $groupID := .GroupID }}
+                        {{ range $i, $c := .Channels }}
+                          {{ $disableButton := false }}
+                          <tr>
+                            <td>{{ $c.Name }}</td>
+                            <td>
+                              <div class="copy-con-container">
+                                <a href="{{ printf "/groups/%s" $c.ID }}">
+                                  {{ $c.ID }}
+                                </a>
+                                <button class="copy-icon" onclick="copyToClipboard(this)">
+                                  <i class="far fa-copy"></i>
+                                </button>
+                              </div>
+                            </td>
+                            <td class="desc-col">{{ $c.Description }}</td>
+                            <td class="meta-col">{{ toJSON $c.Metadata }}</td>
+                            <td class="created-col">{{ $c.CreatedAt }}</td>
+                            <td class="text-center">
+                              <form
+                                action="/groups/{{ $groupID }}/channels/unassign?item=groups"
+                                method="post"
+                              >
+                                <input
+                                  type="hidden"
+                                  name="channelID"
+                                  id="channelID"
+                                  value="{{ $c.ID }}"
+                                />
+                                <button
+                                  type="submit"
+                                  class="btn btn-sm"
+                                  {{ if
+                                    $disableButton
+                                  }}
+                                    disabled
+                                  {{ end }}
+                                >
+                                  <i class="fas fa-trash-alt"></i>
+                                </button>
+                              </form>
+                            </td>
+                          </tr>
+                        {{ end }}
+                      </tbody>
+                    </table>
+                  </div>
+                  {{ template "tablefooter" . }}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
+      <script>
+        const channelModal = new bootstrap.Modal(document.getElementById("addChannelModal"));
+        function openChannelModal() {
+          channelModal.show();
+        }
 
-				fetchIndividualEntity({
-					input: "channelFilter",
-					itemSelect: "infiniteScroll",
-					item: "channels",
-				});
-			</script>
-		</body>
-	</html>
+        fetchIndividualEntity({
+          input: "channelFilter",
+          itemSelect: "infiniteScroll",
+          item: "channels",
+        });
+      </script>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/groups.html b/ui/web/template/groups.html
index da96eaf46..aae2b5943 100644
--- a/ui/web/template/groups.html
+++ b/ui/web/template/groups.html
@@ -2,123 +2,103 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "groups" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<!-- Button trigger modal -->
-									<button
-										type="button"
-										class="btn body-button"
-										onclick="openModal('single')"
-									>
-										Add Group
-									</button>
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <!-- Button trigger modal -->
+                  <button type="button" class="btn body-button" onclick="openModal('single')">
+                    Add Group
+                  </button>
 
-									<!-- Modal -->
-									<div
-										class="modal fade"
-										id="addGroupModal"
-										tabindex="-1"
-										role="dialog"
-										aria-labelledby="addGroupModalLabel"
-										aria-hidden="true"
-									>
-										<div class="modal-dialog" role="document">
-											<div class="modal-content">
-												<div class="modal-header">
-													<h5 class="modal-title" id="addGroupModalLabel">
-														Add Group
-													</h5>
-												</div>
-												<div class="modal-body">
-													<div id="alertMessage"></div>
-													<form method="post" id="groupform">
-														<div class="mb-3">
-															<label for="name" class="form-label">Name</label>
-															<input
-																type="text"
-																class="form-control"
-																name="name"
-																id="name"
-																placeholder="Group Name"
-															/>
-															<div id="nameError" class="text-danger"></div>
-														</div>
-														<div class="mb-3">
-															<label for="description" class="form-label">
-																Description
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="description"
-																id="description"
-																placeholder="Group Description"
-															/>
-														</div>
-														<div class="mb-3">
-															<label for="infiniteScroll" class="form-label">
-																Parent Name
-															</label>
-															<input
-																type="text"
-																class="itemsFilter"
-																name="parentFilter"
-																id="parentFilter"
-																placeholder="Filter by parent name"
-															/>
-															<select
-																class="form-select"
-																name="parentID"
-																id="infiniteScroll"
-																size="5"
-															>
-																<option disabled>select a group</option>
-															</select>
-														</div>
-														<div class="mb-3">
-															<label for="metadata" class="form-label">
-																Metadata
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="metadata"
-																id="metadata"
-																value="{}"
-															/>
-															<div id="metadataHelp" class="form-text">
-																Enter groups metadata in JSON format.
-															</div>
-															<div id="metadataError" class="text-danger"></div>
-														</div>
-														<button
-															type="submit"
-															class="btn body-button"
-															id="create-group-button"
-														>
-															Submit
-														</button>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
-									<button
-										type="button"
-										class="btn body-button"
-										onclick="openModal('bulk')"
-									>
-										Add Groups
-									</button>
+                  <!-- Modal -->
+                  <div
+                    class="modal fade"
+                    id="addGroupModal"
+                    tabindex="-1"
+                    role="dialog"
+                    aria-labelledby="addGroupModalLabel"
+                    aria-hidden="true"
+                  >
+                    <div class="modal-dialog" role="document">
+                      <div class="modal-content">
+                        <div class="modal-header">
+                          <h5 class="modal-title" id="addGroupModalLabel">Add Group</h5>
+                        </div>
+                        <div class="modal-body">
+                          <div id="alertMessage"></div>
+                          <form method="post" id="groupform">
+                            <div class="mb-3">
+                              <label for="name" class="form-label">Name</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="name"
+                                id="name"
+                                placeholder="Group Name"
+                              />
+                              <div id="nameError" class="text-danger"></div>
+                            </div>
+                            <div class="mb-3">
+                              <label for="description" class="form-label">Description</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="description"
+                                id="description"
+                                placeholder="Group Description"
+                              />
+                            </div>
+                            <div class="mb-3">
+                              <label for="infiniteScroll" class="form-label">Parent Name</label>
+                              <input
+                                type="text"
+                                class="itemsFilter"
+                                name="parentFilter"
+                                id="parentFilter"
+                                placeholder="Filter by parent name"
+                              />
+                              <select
+                                class="form-select"
+                                name="parentID"
+                                id="infiniteScroll"
+                                size="5"
+                              >
+                                <option disabled>select a group</option>
+                              </select>
+                            </div>
+                            <div class="mb-3">
+                              <label for="metadata" class="form-label">Metadata</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="metadata"
+                                id="metadata"
+                                value="{}"
+                              />
+                              <div id="metadataHelp" class="form-text">
+                                Enter groups metadata in JSON format.
+                              </div>
+                              <div id="metadataError" class="text-danger"></div>
+                            </div>
+                            <button type="submit" class="btn body-button" id="create-group-button">
+                              Submit
+                            </button>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <button type="button" class="btn body-button" onclick="openModal('bulk')">
+                    Add Groups
+                  </button>
 
 									<!-- Modal -->
 									<div
@@ -243,55 +223,51 @@ <h5 class="modal-title" id="addGroupsModalLabel">
 				</div>
 			</div>
 
-			{{ template "footer" }}
-			<script>
-				attachValidationListener({
-					buttonId: "create-group-button",
-					errorDivs: {
-						name: "nameError",
-						metadata: "metadataError",
-					},
-					validations: {
-						name: validateName,
-						metadata: validateMetadata,
-					},
-				});
+      {{ template "footer" }}
+      <script>
+        attachValidationListener({
+          buttonId: "create-group-button",
+          errorDivs: {
+            name: "nameError",
+            metadata: "metadataError",
+          },
+          validations: {
+            name: validateName,
+            metadata: validateMetadata,
+          },
+        });
 
-				const groupModal = new bootstrap.Modal(
-					document.getElementById("addGroupModal"),
-				);
-				const groupsModal = new bootstrap.Modal(
-					document.getElementById("addGroupsModal"),
-				);
+        const groupModal = new bootstrap.Modal(document.getElementById("addGroupModal"));
+        const groupsModal = new bootstrap.Modal(document.getElementById("addGroupsModal"));
 
-				function openModal(modal) {
-					if (modal === "single") {
-						groupModal.show();
-					} else if (modal === "bulk") {
-						groupsModal.show();
-					}
-				}
+        function openModal(modal) {
+          if (modal === "single") {
+            groupModal.show();
+          } else if (modal === "bulk") {
+            groupsModal.show();
+          }
+        }
 
-				submitCreateForm({
-					url: "/groups",
-					formId: "groupform",
-					alertDiv: "alertMessage",
-					modal: groupModal,
-				});
+        submitCreateForm({
+          url: "/groups",
+          formId: "groupform",
+          alertDiv: "alertMessage",
+          modal: groupModal,
+        });
 
-				submitCreateForm({
-					url: "/groups/bulk",
-					formId: "bulkgroupsform",
-					alertDiv: "alertBulkMessage",
-					modal: groupsModal,
-				});
+        submitCreateForm({
+          url: "/groups/bulk",
+          formId: "bulkgroupsform",
+          alertDiv: "alertBulkMessage",
+          modal: groupsModal,
+        });
 
-				fetchIndividualEntity({
-					input: "parentFilter",
-					itemSelect: "infiniteScroll",
-					item: "groups",
-				});
-			</script>
-		</body>
-	</html>
+        fetchIndividualEntity({
+          input: "parentFilter",
+          itemSelect: "infiniteScroll",
+          item: "groups",
+        });
+      </script>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/groupusers.html b/ui/web/template/groupusers.html
index ea72a05d9..ae60dc189 100644
--- a/ui/web/template/groupusers.html
+++ b/ui/web/template/groupusers.html
@@ -2,511 +2,467 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "groupusers" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<a
-										class="btn body-button"
-										href="/groups/{{ .GroupID }}"
-										role="button"
-									>
-										Group
-									</a>
-									<a
-										class="btn body-button"
-										href="/groups/{{ .GroupID }}/channels"
-										role="button"
-									>
-										Group Channels
-									</a>
-								</div>
-								<div class="table-responsive table-container">
-									<div class="d-flex flex-row justify-content-between">
-										<h4>Group Users</h4>
-										<button
-											role="button"
-											class="btn body-button"
-											onclick="openUserModal()"
-										>
-											<i class="fa-solid fa-plus fs-4"></i>
-										</button>
-										<!-- modal -->
-										<div
-											class="modal fade"
-											id="addUserModal"
-											tabindex="-1"
-											aria-labelledby="addUserModalLabel"
-											aria-hidden="true"
-										>
-											<div class="modal-dialog modal-dialog-centered">
-												<div class="modal-content">
-													<div class="modal-header">
-														<h1 class="modal-title fs-5" id="addUserModalLabel">
-															Add User
-														</h1>
-														<button
-															type="button"
-															class="btn-close"
-															data-bs-dismiss="modal"
-															aria-label="Close"
-														></button>
-													</div>
-													<form
-														action="/groups/{{ .GroupID }}/users/assign?item=groups"
-														method="post"
-													>
-														<div class="modal-body">
-															<div class="mb-3">
-																<label for="infiniteScroll" class="form-label">
-																	User ID
-																</label>
-																<input
-																	type="text"
-																	name="userFilter"
-																	id="userFilter"
-																	placeholder="Filter by User ID"
-																/>
-																<select
-																	class="form-select"
-																	name="userID"
-																	id="infiniteScroll"
-																	size="5"
-																	required
-																>
-																	<option disabled>select a User</option>
-																</select>
-															</div>
-															<div class="mb-3">
-																<label for="relation" class="form-label">
-																	Relation
-																</label>
-																<select
-																	class="form-control"
-																	name="relation"
-																	id="relation"
-																	aria-describedby="relationHelp"
-																	multiple
-																	required
-																>
-																	{{ range $i, $r := .Relations }}
-																		<option value="{{ $r }}">
-																			{{ $r }}
-																		</option>
-																	{{ end }}
-																</select>
-																<div id="relationHelp" class="form-text">
-																	Select Relation.
-																</div>
-															</div>
-															<div class="modal-footer">
-																<button
-																	type="button"
-																	class="btn btn-secondary"
-																	data-bs-dismiss="modal"
-																>
-																	Cancel
-																</button>
-																<button type="submit" class="btn btn-primary">
-																	Assign
-																</button>
-															</div>
-														</div>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <a class="btn body-button" href="/groups/{{ .GroupID }}" role="button">Group</a>
+                  <a class="btn body-button" href="/groups/{{ .GroupID }}/channels" role="button">
+                    Group Channels
+                  </a>
+                </div>
+                <div class="table-responsive table-container">
+                  <div class="d-flex flex-row justify-content-between">
+                    <h4>Group Users</h4>
+                    <button role="button" class="btn body-button" onclick="openUserModal()">
+                      <i class="fa-solid fa-plus fs-4"></i>
+                    </button>
+                    <!-- modal -->
+                    <div
+                      class="modal fade"
+                      id="addUserModal"
+                      tabindex="-1"
+                      aria-labelledby="addUserModalLabel"
+                      aria-hidden="true"
+                    >
+                      <div class="modal-dialog modal-dialog-centered">
+                        <div class="modal-content">
+                          <div class="modal-header">
+                            <h1 class="modal-title fs-5" id="addUserModalLabel">Add User</h1>
+                            <button
+                              type="button"
+                              class="btn-close"
+                              data-bs-dismiss="modal"
+                              aria-label="Close"
+                            ></button>
+                          </div>
+                          <form
+                            action="/groups/{{ .GroupID }}/users/assign?item=groups"
+                            method="post"
+                          >
+                            <div class="modal-body">
+                              <div class="mb-3">
+                                <label for="infiniteScroll" class="form-label">User ID</label>
+                                <input
+                                  type="text"
+                                  name="userFilter"
+                                  id="userFilter"
+                                  placeholder="Filter by User ID"
+                                />
+                                <select
+                                  class="form-select"
+                                  name="userID"
+                                  id="infiniteScroll"
+                                  size="5"
+                                  required
+                                >
+                                  <option disabled>select a User</option>
+                                </select>
+                              </div>
+                              <div class="mb-3">
+                                <label for="relation" class="form-label">Relation</label>
+                                <select
+                                  class="form-control"
+                                  name="relation"
+                                  id="relation"
+                                  aria-describedby="relationHelp"
+                                  multiple
+                                  required
+                                >
+                                  {{ range $i, $r := .Relations }}
+                                    <option value="{{ $r }}">
+                                      {{ $r }}
+                                    </option>
+                                  {{ end }}
+                                </select>
+                                <div id="relationHelp" class="form-text">Select Relation.</div>
+                              </div>
+                              <div class="modal-footer">
+                                <button
+                                  type="button"
+                                  class="btn btn-secondary"
+                                  data-bs-dismiss="modal"
+                                >
+                                  Cancel
+                                </button>
+                                <button type="submit" class="btn btn-primary">Assign</button>
+                              </div>
+                            </div>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
 
-									<ul class="nav nav-tabs" id="roleTab" role="tablist">
-										<li class="nav-item" role="presentation">
-											{{ $tabActive := "" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="view-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#view-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="view-tab-pane"
-												aria-selected="true"
-												onclick="openTab('')"
-											>
-												All
-											</button>
-										</li>
-										<li class="nav-item" role="presentation">
-											{{ $tabActive = "admin" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="admin-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#admin-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="admin-tab-pane"
-												aria-selected="true"
-												onclick="openTab('admin')"
-											>
-												Admin
-											</button>
-										</li>
-										<li class="nav-item" role="presentation">
-											{{ $tabActive = "editor" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="editor-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#editor-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="editor-tab-pane"
-												aria-selected="false"
-												onclick="openTab('editor')"
-											>
-												Editor
-											</button>
-										</li>
-										<li class="nav-item" role="presentation">
-											{{ $tabActive = "viewer" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="viewer-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#viewer-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="viewer-tab-pane"
-												aria-selected="false"
-												onclick="openTab('viewer')"
-											>
-												Viewer
-											</button>
-										</li>
-									</ul>
-									<div class="tab-content mt-3" id="roleTabContent">
-										{{ $groupID:= .GroupID }}
-										<div
-											class="tab-pane active"
-											id="view-tab-pane"
-											role="tabpanel"
-											aria-labelledby="view-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table id="itemsTable" class="table">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="tags-col" scope="col">Tags</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ $groupID:= .GroupID }}
-														{{ range $i, $u := .Users }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $u.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/users/%s" $u.ID }}">
-																			{{ $u.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="tags-col">{{ toSlice $u.Tags }}</td>
-																<td class="meta-col">
-																	{{ toJSON $u.Metadata }}
-																</td>
-																<td class="created-col">{{ $u.CreatedAt }}</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-										<div
-											class="tab-pane"
-											id="admin-tab-pane"
-											role="tabpanel"
-											aria-labelledby="admin-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table id="itemsTable" class="table">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="tags-col" scope="col">Tags</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-															<th class="text-center" scope="col"></th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ range $i, $u := .Users }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $u.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/users/%s" $u.ID }}">
-																			{{ $u.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="tags-col">{{ toSlice $u.Tags }}</td>
-																<td class="meta-col">
-																	{{ toJSON $u.Metadata }}
-																</td>
-																<td class="created-col">{{ $u.CreatedAt }}</td>
-																<td class="text-center">
-																	<form
-																		action="/groups/{{ $groupID }}/users/unassign?item=groups"
-																		method="post"
-																	>
-																		<input
-																			type="hidden"
-																			name="userID"
-																			id="userID"
-																			value="{{ $u.ID }}"
-																		/>
-																		<input
-																			type="hidden"
-																			name="relation"
-																			id="relation"
-																			value="admin"
-																		/>
-																		<button
-																			type="submit"
-																			class="btn btn-sm"
-																			{{ if
-																				$disableButton
-																			}}
-																				disabled
-																			{{ end }}
-																		>
-																			<i class="fas fa-trash-alt"></i>
-																		</button>
-																	</form>
-																</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-										<div
-											class="tab-pane "
-											id="editor-tab-pane"
-											role="tabpanel"
-											aria-labelledby="editor-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table id="itemsTable" class="table">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="tags-col" scope="col">Tags</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-															<th class="text-center" scope="col"></th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ range $i, $u := .Users }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $u.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/users/%s" $u.ID }}">
-																			{{ $u.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="tags-col">{{ toSlice $u.Tags }}</td>
-																<td class="meta-col">
-																	{{ toJSON $u.Metadata }}
-																</td>
-																<td class="created-col">{{ $u.CreatedAt }}</td>
-																<td class="text-center">
-																	<form
-																		action="/groups/{{ $groupID }}/users/unassign?item=groups"
-																		method="post"
-																	>
-																		<input
-																			type="hidden"
-																			name="userID"
-																			id="userID"
-																			value="{{ $u.ID }}"
-																		/>
-																		<input
-																			type="hidden"
-																			name="relation"
-																			id="relation"
-																			value="editor"
-																		/>
-																		<button
-																			type="submit"
-																			class="btn btn-sm"
-																			{{ if
-																				$disableButton
-																			}}
-																				disabled
-																			{{ end }}
-																		>
-																			<i class="fas fa-trash-alt"></i>
-																		</button>
-																	</form>
-																</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-										<div
-											class="tab-pane"
-											id="viewer-tab-pane"
-											role="tabpanel"
-											aria-labelledby="viewer-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table id="itemsTable" class="table">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="tags-col" scope="col">Tags</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-															<th class="text-center" scope="col"></th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ range $i, $u := .Users }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $u.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/users/%s" $u.ID }}">
-																			{{ $u.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="tags-col">{{ toSlice $u.Tags }}</td>
-																<td class="meta-col">
-																	{{ toJSON $u.Metadata }}
-																</td>
-																<td class="created-col">{{ $u.CreatedAt }}</td>
-																<td class="text-center">
-																	<form
-																		action="/groups/{{ $groupID }}/users/unassign?item=groups"
-																		method="post"
-																	>
-																		<input
-																			type="hidden"
-																			name="userID"
-																			id="userID"
-																			value="{{ $u.ID }}"
-																		/>
-																		<input
-																			type="hidden"
-																			name="relation"
-																			id="relation"
-																			value="viewer"
-																		/>
-																		<button
-																			type="submit"
-																			class="btn btn-sm"
-																			{{ if
-																				$disableButton
-																			}}
-																				disabled
-																			{{ end }}
-																		>
-																			<i class="fas fa-trash-alt"></i>
-																		</button>
-																	</form>
-																</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-									</div>
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
+                  <ul class="nav nav-tabs" id="roleTab" role="tablist">
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive := "" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="view-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#view-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="view-tab-pane"
+                        aria-selected="true"
+                        onclick="openTab('')"
+                      >
+                        All
+                      </button>
+                    </li>
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive = "admin" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="admin-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#admin-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="admin-tab-pane"
+                        aria-selected="true"
+                        onclick="openTab('admin')"
+                      >
+                        Admin
+                      </button>
+                    </li>
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive = "editor" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="editor-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#editor-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="editor-tab-pane"
+                        aria-selected="false"
+                        onclick="openTab('editor')"
+                      >
+                        Editor
+                      </button>
+                    </li>
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive = "viewer" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="viewer-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#viewer-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="viewer-tab-pane"
+                        aria-selected="false"
+                        onclick="openTab('viewer')"
+                      >
+                        Viewer
+                      </button>
+                    </li>
+                  </ul>
+                  <div class="tab-content mt-3" id="roleTabContent">
+                    {{ $groupID:= .GroupID }}
+                    <div
+                      class="tab-pane active"
+                      id="view-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="view-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table id="itemsTable" class="table">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="tags-col" scope="col">Tags</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ $groupID:= .GroupID }}
+                            {{ range $i, $u := .Users }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $u.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/users/%s" $u.ID }}">
+                                      {{ $u.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="tags-col">{{ toSlice $u.Tags }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $u.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $u.CreatedAt }}</td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                    <div
+                      class="tab-pane"
+                      id="admin-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="admin-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table id="itemsTable" class="table">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="tags-col" scope="col">Tags</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                              <th class="text-center" scope="col"></th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ range $i, $u := .Users }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $u.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/users/%s" $u.ID }}">
+                                      {{ $u.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="tags-col">{{ toSlice $u.Tags }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $u.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $u.CreatedAt }}</td>
+                                <td class="text-center">
+                                  <form
+                                    action="/groups/{{ $groupID }}/users/unassign?item=groups"
+                                    method="post"
+                                  >
+                                    <input
+                                      type="hidden"
+                                      name="userID"
+                                      id="userID"
+                                      value="{{ $u.ID }}"
+                                    />
+                                    <input
+                                      type="hidden"
+                                      name="relation"
+                                      id="relation"
+                                      value="admin"
+                                    />
+                                    <button
+                                      type="submit"
+                                      class="btn btn-sm"
+                                      {{ if
+                                        $disableButton
+                                      }}
+                                        disabled
+                                      {{ end }}
+                                    >
+                                      <i class="fas fa-trash-alt"></i>
+                                    </button>
+                                  </form>
+                                </td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                    <div
+                      class="tab-pane "
+                      id="editor-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="editor-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table id="itemsTable" class="table">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="tags-col" scope="col">Tags</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                              <th class="text-center" scope="col"></th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ range $i, $u := .Users }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $u.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/users/%s" $u.ID }}">
+                                      {{ $u.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="tags-col">{{ toSlice $u.Tags }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $u.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $u.CreatedAt }}</td>
+                                <td class="text-center">
+                                  <form
+                                    action="/groups/{{ $groupID }}/users/unassign?item=groups"
+                                    method="post"
+                                  >
+                                    <input
+                                      type="hidden"
+                                      name="userID"
+                                      id="userID"
+                                      value="{{ $u.ID }}"
+                                    />
+                                    <input
+                                      type="hidden"
+                                      name="relation"
+                                      id="relation"
+                                      value="editor"
+                                    />
+                                    <button
+                                      type="submit"
+                                      class="btn btn-sm"
+                                      {{ if
+                                        $disableButton
+                                      }}
+                                        disabled
+                                      {{ end }}
+                                    >
+                                      <i class="fas fa-trash-alt"></i>
+                                    </button>
+                                  </form>
+                                </td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                    <div
+                      class="tab-pane"
+                      id="viewer-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="viewer-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table id="itemsTable" class="table">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="tags-col" scope="col">Tags</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                              <th class="text-center" scope="col"></th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ range $i, $u := .Users }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $u.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/users/%s" $u.ID }}">
+                                      {{ $u.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="tags-col">{{ toSlice $u.Tags }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $u.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $u.CreatedAt }}</td>
+                                <td class="text-center">
+                                  <form
+                                    action="/groups/{{ $groupID }}/users/unassign?item=groups"
+                                    method="post"
+                                  >
+                                    <input
+                                      type="hidden"
+                                      name="userID"
+                                      id="userID"
+                                      value="{{ $u.ID }}"
+                                    />
+                                    <input
+                                      type="hidden"
+                                      name="relation"
+                                      id="relation"
+                                      value="viewer"
+                                    />
+                                    <button
+                                      type="submit"
+                                      class="btn btn-sm"
+                                      {{ if
+                                        $disableButton
+                                      }}
+                                        disabled
+                                      {{ end }}
+                                    >
+                                      <i class="fas fa-trash-alt"></i>
+                                    </button>
+                                  </form>
+                                </td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
 			<script>
 				const userModal = new bootstrap.Modal(
 					document.getElementById("addUserModal"),
@@ -523,16 +479,16 @@ <h1 class="modal-title fs-5" id="addUserModalLabel">
 
 				function openTab(relation) {
 					event.preventDefault();
-                    var groupID = '{{.GroupID}}';
-                    fetch(`/groups/${groupID}/users?relation=${relation}`, {
-                        method: "GET",
-                    })
-                        .then((response) => {
+          var groupID = '{{.GroupID}}';
+          fetch(`/groups/${groupID}/users?relation=${relation}`, {
+              method: "GET",
+          })
+          .then((response) => {
 
-                        })
-                        .catch((error) => console.error("Error:", error));
+          })
+          .catch((error) => console.error("Error:", error));
 				}
 			</script>
-		</body>
-	</html>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/header.html b/ui/web/template/header.html
index 07c3534bf..e906b381b 100644
--- a/ui/web/template/header.html
+++ b/ui/web/template/header.html
@@ -2,25 +2,25 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "header" }}
-	<head>
-		<meta charset="utf-8" />
-		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
-		<meta name="description" content="" />
-		<meta name="author" content="" />
+  <head>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <meta name="description" content="" />
+    <meta name="author" content="" />
 
-		<title>Magistrala</title>
-		<link rel="stylesheet" href="/css/styles.css" />
-		<link rel="icon" type="image/x-icon" href="/images/favicon.ico" />
-		<link
-			rel="stylesheet"
-			href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
-		/>
-		<link
-			href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css"
-			rel="stylesheet"
-			integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9"
-			crossorigin="anonymous"
-		/>
-		<script src="/js/main.js"></script>
-	</head>
+    <title>Magistrala</title>
+    <link rel="stylesheet" href="/css/styles.css" />
+    <link rel="icon" type="image/x-icon" href="/images/favicon.ico" />
+    <link
+      rel="stylesheet"
+      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
+    />
+    <link
+      href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css"
+      rel="stylesheet"
+      integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9"
+      crossorigin="anonymous"
+    />
+    <script src="/js/main.js"></script>
+  </head>
 {{ end }}
diff --git a/ui/web/template/index.html b/ui/web/template/index.html
index eb97da44b..ad5a656e6 100644
--- a/ui/web/template/index.html
+++ b/ui/web/template/index.html
@@ -2,91 +2,91 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "index" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content mt-5 pt-5">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row mb-5">
-								<div class="col-lg-3 col-md-6 mb-4">
-									<div class="card text-bg-light mb-3">
-										<div
-											class="card-single card-body d-flex justify-content-between p-5"
-											data-card="users"
-										>
-											<div>
-												<h1>{{ .Summary.TotalUsers }}</h1>
-												<span>Users</span>
-											</div>
-											<div>
-												<span class="fas fa-users"></span>
-											</div>
-										</div>
-									</div>
-								</div>
-								<div class="col-lg-3 col-md-6 mb-4">
-									<div class="card text-bg-light mb-3">
-										<div
-											class="card-single card-body d-flex justify-content-between p-5"
-											data-card="things"
-										>
-											<div>
-												<h1>{{ .Summary.TotalThings }}</h1>
-												<span>Things</span>
-											</div>
-											<div>
-												<span class="fas fa-microchip"></span>
-											</div>
-										</div>
-									</div>
-								</div>
-								<div class="col-lg-3 col-md-6 mb-4">
-									<div class="card text-bg-light mb-3">
-										<div
-											class="card-single card-body d-flex justify-content-between p-5"
-											data-card="groups"
-										>
-											<div>
-												<h1>{{ .Summary.TotalGroups }}</h1>
-												<span>Groups</span>
-											</div>
-											<div>
-												<span class="fas fa-layer-group"></span>
-											</div>
-										</div>
-									</div>
-								</div>
-								<div class="col-lg-3 col-md-6 mb-4">
-									<div class="card text-bg-light mb-3">
-										<div
-											class="card-single card-body d-flex justify-content-between p-5"
-											data-card="channels"
-										>
-											<div>
-												<h1>{{ .Summary.TotalChannels }}</h1>
-												<span>Channels</span>
-											</div>
-											<div>
-												<span class="fas fa-microchip"></span>
-											</div>
-										</div>
-									</div>
-								</div>
-							</div>
-							<div class="row">
-								<div class="card text-bg-light selected-grid">
-									<div class="default-content"></div>
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content mt-5 pt-5">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row mb-5">
+                <div class="col-lg-3 col-md-6 mb-4">
+                  <div class="card text-bg-light mb-3">
+                    <div
+                      class="card-single card-body d-flex justify-content-between p-5"
+                      data-card="users"
+                    >
+                      <div>
+                        <h1>{{ .Summary.TotalUsers }}</h1>
+                        <span>Users</span>
+                      </div>
+                      <div>
+                        <span class="fas fa-users"></span>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+                <div class="col-lg-3 col-md-6 mb-4">
+                  <div class="card text-bg-light mb-3">
+                    <div
+                      class="card-single card-body d-flex justify-content-between p-5"
+                      data-card="things"
+                    >
+                      <div>
+                        <h1>{{ .Summary.TotalThings }}</h1>
+                        <span>Things</span>
+                      </div>
+                      <div>
+                        <span class="fas fa-microchip"></span>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+                <div class="col-lg-3 col-md-6 mb-4">
+                  <div class="card text-bg-light mb-3">
+                    <div
+                      class="card-single card-body d-flex justify-content-between p-5"
+                      data-card="groups"
+                    >
+                      <div>
+                        <h1>{{ .Summary.TotalGroups }}</h1>
+                        <span>Groups</span>
+                      </div>
+                      <div>
+                        <span class="fas fa-layer-group"></span>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+                <div class="col-lg-3 col-md-6 mb-4">
+                  <div class="card text-bg-light mb-3">
+                    <div
+                      class="card-single card-body d-flex justify-content-between p-5"
+                      data-card="channels"
+                    >
+                      <div>
+                        <h1>{{ .Summary.TotalChannels }}</h1>
+                        <span>Channels</span>
+                      </div>
+                      <div>
+                        <span class="fas fa-microchip"></span>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </div>
+              <div class="row">
+                <div class="card text-bg-light selected-grid">
+                  <div class="default-content"></div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
     <script>
       var enabledUsers = parseInt("{{.Summary.EnabledUsers}}");
       var disabledUsers = parseInt("{{.Summary.DisabledUsers}}");
@@ -232,6 +232,6 @@ <h1>{{ .Summary.TotalChannels }}</h1>
         chart.draw(chartData, options);
       }
     </script>
-		</body>
-	</html>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/login.html b/ui/web/template/login.html
index 96739f861..1866189f4 100644
--- a/ui/web/template/login.html
+++ b/ui/web/template/login.html
@@ -2,184 +2,169 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "login" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body class="login-body">
-			<div class="container mt-5 pt-5">
-				<div class="row p-5">
-					<div class="login-card col-lg-4 p-md-5 mx-auto mt-5">
-						<div
-							class="row text-center mb-4 d-flex flex-column align-items-center"
-						>
-							<div class="mb-3 border-bottom pb-3">
-								<div class="d-flex justify-content-center mt-2">
-									<h1 class="mx-3">Magistrala</h1>
-								</div>
-							</div>
-							<div class="login-header mb-4">
-								<h2>LOGIN</h2>
-							</div>
-							<form
-								method="post"
-								id="form"
-								class="row border-bottom pb-3 mb-3"
-								onsubmit="submitLoginForm()"
-							>
-								<div class="col-md-12">
-									<div class="row mb-3">
-										<div class="col-md-12 input-field email-field">
-											<i class="fas fa-solid fa-envelope"></i>
-											<input
-												class="p-3 w-100"
-												type="email"
-												name="username"
-												id="username"
-												placeholder="Email Address"
-											/>
-										</div>
-										<div id="emailError" class="text-danger"></div>
-									</div>
-									<div class="row mb-3">
-										<div class="col-md-12 input-field password-field">
-											<i class="fas fa-solid fa-lock"></i>
-											<input
-												class="p-3 w-100"
-												type="password"
-												name="password"
-												id="password"
-												placeholder="Password"
-											/>
-										</div>
-										<div id="passwordError" class="text-danger"></div>
-									</div>
-									<div id="loginError" class="text-danger"></div>
-								</div>
-								<div class="col-md-12 d-grid py-3">
-									<button
-										type="submit"
-										class="login-btn py-3"
-										onclick="return validateForm()"
-									>
-										Log In
-									</button>
-								</div>
-							</form>
-							<div class="forgot-password">
-								<button
-									type="button"
-									id="fp-button"
-									class="btn btn-link text-light"
-									data-bs-toggle="modal"
-									data-bs-target="#forgotPasswordModal"
-								>
-									Forgot Password?
-								</button>
-							</div>
-						</div>
-					</div>
-				</div>
-				<div
-					class="modal fade"
-					id="forgotPasswordModal"
-					tabindex="-1"
-					role="dialog"
-					aria-labelledby="forgotPasswordModalLabel"
-					aria-hidden="true"
-				>
-					<div class="modal-dialog" role="document">
-						<div class="modal-content">
-							<div class="modal-header">
-								<h5 class="modal-title" id="forgotPasswordModalLabel">
-									Enter email
-								</h5>
-							</div>
-							<div class="modal-body">
-								<form
-									method="post"
-									action="/reset-request"
-									class="reset-pw-form"
-								>
-									<div class="mb-3">
-										<label for="email" class="form-label">Email</label>
-										<input
-											type="email"
-											class="form-control"
-											name="email"
-											id="email"
-											placeholder="Email"
-											required
-										/>
-									</div>
-									<button type="submit" class="btn submit-button">
-										Submit
-									</button>
-								</form>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
-			<script>
-				const passwordField = document.querySelector(".password-field");
-				const emailField = document.querySelector(".email-field");
-				const loginError = document.getElementById("loginError");
-				const passwordError = document.getElementById("passwordError");
-				const emailError = document.getElementById("emailError");
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body class="login-body">
+      <div class="container mt-5 pt-5">
+        <div class="row p-5">
+          <div class="login-card col-lg-4 p-md-5 mx-auto mt-5">
+            <div class="row text-center mb-4 d-flex flex-column align-items-center">
+              <div class="mb-3 border-bottom pb-3">
+                <div class="d-flex justify-content-center mt-2">
+                  <h1 class="mx-3">Magistrala</h1>
+                </div>
+              </div>
+              <div class="login-header mb-4">
+                <h2>LOGIN</h2>
+              </div>
+              <form
+                method="post"
+                id="form"
+                class="row border-bottom pb-3 mb-3"
+                onsubmit="submitLoginForm()"
+              >
+                <div class="col-md-12">
+                  <div class="row mb-3">
+                    <div class="col-md-12 input-field email-field">
+                      <i class="fas fa-solid fa-envelope"></i>
+                      <input
+                        class="p-3 w-100"
+                        type="email"
+                        name="username"
+                        id="username"
+                        placeholder="Email Address"
+                      />
+                    </div>
+                    <div id="emailError" class="text-danger"></div>
+                  </div>
+                  <div class="row mb-3">
+                    <div class="col-md-12 input-field password-field">
+                      <i class="fas fa-solid fa-lock"></i>
+                      <input
+                        class="p-3 w-100"
+                        type="password"
+                        name="password"
+                        id="password"
+                        placeholder="Password"
+                      />
+                    </div>
+                    <div id="passwordError" class="text-danger"></div>
+                  </div>
+                  <div id="loginError" class="text-danger"></div>
+                </div>
+                <div class="col-md-12 d-grid py-3">
+                  <button type="submit" class="login-btn py-3" onclick="return validateForm()">
+                    Log In
+                  </button>
+                </div>
+              </form>
+              <div class="forgot-password">
+                <button
+                  type="button"
+                  id="fp-button"
+                  class="btn btn-link text-light"
+                  data-bs-toggle="modal"
+                  data-bs-target="#forgotPasswordModal"
+                >
+                  Forgot Password?
+                </button>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div
+          class="modal fade"
+          id="forgotPasswordModal"
+          tabindex="-1"
+          role="dialog"
+          aria-labelledby="forgotPasswordModalLabel"
+          aria-hidden="true"
+        >
+          <div class="modal-dialog" role="document">
+            <div class="modal-content">
+              <div class="modal-header">
+                <h5 class="modal-title" id="forgotPasswordModalLabel">Enter email</h5>
+              </div>
+              <div class="modal-body">
+                <form method="post" action="/reset-request" class="reset-pw-form">
+                  <div class="mb-3">
+                    <label for="email" class="form-label">Email</label>
+                    <input
+                      type="email"
+                      class="form-control"
+                      name="email"
+                      id="email"
+                      placeholder="Email"
+                      required
+                    />
+                  </div>
+                  <button type="submit" class="btn submit-button">Submit</button>
+                </form>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
+      <script>
+        const passwordField = document.querySelector(".password-field");
+        const emailField = document.querySelector(".email-field");
+        const loginError = document.getElementById("loginError");
+        const passwordError = document.getElementById("passwordError");
+        const emailError = document.getElementById("emailError");
 
-				function validateForm() {
-					var password = document.getElementById("password").value;
-					var email = document.getElementById("username").value;
+        function validateForm() {
+          var password = document.getElementById("password").value;
+          var email = document.getElementById("username").value;
 
-					loginError.innerHTML = "";
-					passwordError.innerHTML = "";
-					emailError.innerHTML = "";
-					passwordField.classList.remove("border-red");
-					emailField.classList.remove("border-red");
-					var isValid = true;
+          loginError.innerHTML = "";
+          passwordError.innerHTML = "";
+          emailError.innerHTML = "";
+          passwordField.classList.remove("border-red");
+          emailField.classList.remove("border-red");
+          var isValid = true;
 
-					if (email === "") {
-						emailError.innerHTML = "email is required!";
-						emailField.classList.add("border-red");
-						isValid = false;
-					}
-					if (password.length < 8) {
-						passwordError.innerHTML =
-							"Password must have a minimum of 8 characters!";
-						passwordField.classList.add("border-red");
-						isValid = false;
-					}
-					return isValid;
-				}
+          if (email === "") {
+            emailError.innerHTML = "email is required!";
+            emailField.classList.add("border-red");
+            isValid = false;
+          }
+          if (password.length < 8) {
+            passwordError.innerHTML = "Password must have a minimum of 8 characters!";
+            passwordField.classList.add("border-red");
+            isValid = false;
+          }
+          return isValid;
+        }
 
-				function submitLoginForm() {
-					event.preventDefault();
-					var form = event.target;
-					fetch("/login", {
-						method: "POST",
-						body: new FormData(form),
-					})
-						.then((response) => {
-							if (response.status === 401) {
-								passwordField.classList.add("border-red");
-								emailField.classList.add("border-red");
-								errorMessage = "invalid email or password. Please try again!";
-								showAlert(errorMessage);
-							} else {
-								form.reset();
-								window.location.href = "/";
-							}
-						})
-						.catch((error) => {
-							console.error("error submitting login form: ", error);
-						});
-				}
+        function submitLoginForm() {
+          event.preventDefault();
+          var form = event.target;
+          fetch("/login", {
+            method: "POST",
+            body: new FormData(form),
+          })
+            .then((response) => {
+              if (response.status === 401) {
+                passwordField.classList.add("border-red");
+                emailField.classList.add("border-red");
+                errorMessage = "invalid email or password. Please try again!";
+                showAlert(errorMessage);
+              } else {
+                form.reset();
+                window.location.href = "/";
+              }
+            })
+            .catch((error) => {
+              console.error("error submitting login form: ", error);
+            });
+        }
 
-				function showAlert(errorMessage) {
-					loginError.innerHTML = errorMessage;
-				}
-			</script>
-		</body>
-	</html>
+        function showAlert(errorMessage) {
+          loginError.innerHTML = errorMessage;
+        }
+      </script>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/messagesread.html b/ui/web/template/messagesread.html
index a122e61ee..5f060ca77 100644
--- a/ui/web/template/messagesread.html
+++ b/ui/web/template/messagesread.html
@@ -1,143 +1,140 @@
 <!-- Copyright (c) Abstract Machines
 SPDX-License-Identifier: Apache-2.0 -->
 
-{{define "messagesread"}}
-<!doctype html>
-<html lang="en">
-  {{template "header"}}
+{{ define "messagesread" }}
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
 
-  <body>
-    {{template "navbar" .}}
 
-    <div class="main-content pt-3">
-      <div class="container">
-        <div class="row">
-          <div class="col-lg-12 mx-auto py-3">
-            <div class="row">
-              <div class="buttons mb-3">
-                <button type="button" class="btn body-button" onclick="openModal()">
-                  Read Message
-                </button>
-              </div>
-              <!-- Modal -->
-              <div
-                class="modal fade"
-                id="sendMessageModal"
-                tabindex="-1"
-                role="dialog"
-                aria-labelledby="sendMessageModalLabel"
-                aria-hidden="true"
-              >
-                <div class="modal-dialog" role="document">
-                  <div class="modal-content">
-                    <div class="modal-header">
-                      <h5 class="modal-title" id="sendMessageModalLabel">
-                        Read Message
-                      </h5>
-                    </div>
-                    <div class="modal-body">
-                      <div id="alertMessage"></div>
-                      <form method="get">
-                        <div class="mb-3">
-                          <label for="chanID" class="form-label">Channel ID</label>
-                          <input
-                            type="text"
-                            class="form-control"
-                            name="chanID"
-                            id="chanID"
-                            aria-describedby="chanIDHelp"
-                          />
-                          <div id="chanIDHelp" class="form-text">
-                            Enter Channel ID.
+    <body>
+      {{ template "navbar" . }}
+
+
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <button type="button" class="btn body-button" onclick="openModal()">
+                    Read Message
+                  </button>
+                </div>
+                <!-- Modal -->
+                <div
+                  class="modal fade"
+                  id="sendMessageModal"
+                  tabindex="-1"
+                  role="dialog"
+                  aria-labelledby="sendMessageModalLabel"
+                  aria-hidden="true"
+                >
+                  <div class="modal-dialog" role="document">
+                    <div class="modal-content">
+                      <div class="modal-header">
+                        <h5 class="modal-title" id="sendMessageModalLabel">Read Message</h5>
+                      </div>
+                      <div class="modal-body">
+                        <div id="alertMessage"></div>
+                        <form method="get">
+                          <div class="mb-3">
+                            <label for="chanID" class="form-label">Channel ID</label>
+                            <input
+                              type="text"
+                              class="form-control"
+                              name="chanID"
+                              id="chanID"
+                              aria-describedby="chanIDHelp"
+                            />
+                            <div id="chanIDHelp" class="form-text">Enter Channel ID.</div>
                           </div>
-                        </div>
-                        <div class="mb-3">
-                          <label for="thingKey" class="form-label">Thing Key</label>
-                          <input
-                            type="text"
-                            class="form-control"
-                            name="thingKey"
-                            id="thingKey"
-                            aria-describedby="thingKeyHelp"
-                          />
-                          <div id="thingKeyHelp" class="form-text">
-                            Enter thing key.
+                          <div class="mb-3">
+                            <label for="thingKey" class="form-label">Thing Key</label>
+                            <input
+                              type="text"
+                              class="form-control"
+                              name="thingKey"
+                              id="thingKey"
+                              aria-describedby="thingKeyHelp"
+                            />
+                            <div id="thingKeyHelp" class="form-text">Enter thing key.</div>
                           </div>
-                        </div>
-                        <button type="submit" class="btn body-button">Submit</button>
-                      </form>
+                          <button type="submit" class="btn body-button">Submit</button>
+                        </form>
+                      </div>
                     </div>
                   </div>
                 </div>
-              </div>
 
-              <div class="table-responsive table-container">
-                <div>
-                  <span> Channel ID: {{.ChanID}} </span>
-                </div>
-                {{template "tableheader" .}}
-                <div class="itemsTable">
-                  <table id="itemsTable" class="table">
-                    <thead>
-                      <tr>
-                        <th scope="col">#</th>
-                        <th scope="col">Subtopic</th>
-                        <th scope="col">Publisher</th>
-                        <th scope="col">Protocol</th>
-                        <th scope="col">Name</th>
-                        <th scope="col">Unit</th>
-                        <th scope="col">Value</th>
-                        <th scope="col">StringValue</th>
-                        <th scope="col">BoolValue</th>
-                        <th scope="col">DataValue</th>
-                        <th scope="col">Sum</th>
-                        <th scope="col">Time</th>
-                        <th scope="col">UpdateTime</th>
-                      </tr>
-                    </thead>
-                    <tbody>
-                      {{range $i, $c := .Msg}}
-                      <tr>
-                        <td>{{$i}}</td>
-                        <td>{{$c.Subtopic}}</td>
-                        <td>{{$c.Publisher}}</td>
-                        <td>{{$c.Protocol}}</td>
-                        <td>{{$c.Name}}</td>
-                        <td>{{$c.Unit}}</td>
-                        <td>{{if $c.Value}}{{$c.Value}}{{end}}</td>
-                        <td>{{if $c.StringValue}}{{$c.StringValue}}{{end}}</td>
-                        <td>{{if $c.BoolValue}}{{$c.BoolValue}}{{end}}</td>
-                        <td>{{if $c.DataValue}}{{$c.DataValue}}{{end}}</td>
-                        <td>{{if $c.Sum}}{{$c.Sum}}{{end}}</td>
-                        <td>{{unixTimeToHumanTime $c.Time}}</td>
-                        <td>
-                          {{if $c.UpdateTime}}{{ unixTimeToHumanTime
-                          $c.UpdateTime}}{{end}}
-                        </td>
-                      </tr>
-                      {{end}}
-                    </tbody>
-                  </table>
+                <div class="table-responsive table-container">
+                  <div>
+                    <span>Channel ID: {{ .ChanID }}</span>
+                  </div>
+                  {{ template "tableheader" . }}
+                  <div class="itemsTable">
+                    <table id="itemsTable" class="table">
+                      <thead>
+                        <tr>
+                          <th scope="col">#</th>
+                          <th scope="col">Subtopic</th>
+                          <th scope="col">Publisher</th>
+                          <th scope="col">Protocol</th>
+                          <th scope="col">Name</th>
+                          <th scope="col">Unit</th>
+                          <th scope="col">Value</th>
+                          <th scope="col">StringValue</th>
+                          <th scope="col">BoolValue</th>
+                          <th scope="col">DataValue</th>
+                          <th scope="col">Sum</th>
+                          <th scope="col">Time</th>
+                          <th scope="col">UpdateTime</th>
+                        </tr>
+                      </thead>
+                      <tbody>
+                        {{ range $i, $c := .Msg }}
+                          <tr>
+                            <td>{{ $i }}</td>
+                            <td>{{ $c.Subtopic }}</td>
+                            <td>{{ $c.Publisher }}</td>
+                            <td>{{ $c.Protocol }}</td>
+                            <td>{{ $c.Name }}</td>
+                            <td>{{ $c.Unit }}</td>
+                            <td>{{ if $c.Value }}{{ $c.Value }}{{ end }}</td>
+                            <td>{{ if $c.StringValue }}{{ $c.StringValue }}{{ end }}</td>
+                            <td>{{ if $c.BoolValue }}{{ $c.BoolValue }}{{ end }}</td>
+                            <td>{{ if $c.DataValue }}{{ $c.DataValue }}{{ end }}</td>
+                            <td>{{ if $c.Sum }}{{ $c.Sum }}{{ end }}</td>
+                            <td>{{ unixTimeToHumanTime $c.Time }}</td>
+                            <td>
+                              {{ if $c.UpdateTime }}
+                                {{ unixTimeToHumanTime
+                                  $c.UpdateTime
+                                }}
+                              {{ end }}
+                            </td>
+                          </tr>
+                        {{ end }}
+                      </tbody>
+                    </table>
+                  </div>
+                  {{ template "tablefooter" . }}
                 </div>
-                {{ template "tablefooter" .}}
               </div>
             </div>
-          </div>  
-        </div>  
+          </div>
+        </div>
       </div>
-    </div>
 
-    {{template "footer"}}
+      {{ template "footer" }}
 
-    <script>
-      const messageModal = new bootstrap.Modal(
-        document.getElementById("sendMessageModal"),
-      );
+      <script>
+        const messageModal = new bootstrap.Modal(document.getElementById("sendMessageModal"));
 
-      function openModal() {
-        messageModal.show();
-      }
-    </script>
-  </body>
-</html>
-{{end}}
+        function openModal() {
+          messageModal.show();
+        }
+      </script>
+    </body>
+  </html>
+{{ end }}
diff --git a/ui/web/template/navbar.html b/ui/web/template/navbar.html
index 368753888..cd7cd264d 100644
--- a/ui/web/template/navbar.html
+++ b/ui/web/template/navbar.html
@@ -2,204 +2,187 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "navbar" }}
-	<!-- Sidebbar -->
-	<ul
-		class="navbar-nav bg-gradient-primary sidebar sidebar-dark"
-		id="accordionSidebar"
-	>
-		<!-- Sidebar Brand -->
-		<a class="sidebar-brand d-flex justify-content-center pt-2" href="/">
-			<h1 class="mx-3">Magistrala</h1>
-		</a>
+  <!-- Sidebbar -->
+  <ul class="navbar-nav bg-gradient-primary sidebar sidebar-dark" id="accordionSidebar">
+    <!-- Sidebar Brand -->
+    <a class="sidebar-brand d-flex justify-content-center pt-2" href="/">
+      <h1 class="mx-3">Magistrala</h1>
+    </a>
 
-		<!-- Divider -->
-		<hr class="sidebar-divider my-0 text-light mb-3" />
+    <!-- Divider -->
+    <hr class="sidebar-divider my-0 text-light mb-3" />
 
-		<li class="nav-item mb-2 mx-2">
-			{{ $active := "dashboard" }}
-			<a
-				href="/"
-				class="nav-link {{ if eq .NavbarActive $active }}active{{ end }}"
-			>
-				<i class="fas fa-home"></i>
-				<span>Dashboard</span>
-			</a>
-		</li>
-		<li class="nav-item mb-2 mx-2">
-			{{ $active = "users" }}
-			<a
-				href="/users"
-				class=" nav-link {{ if (serviceUnavailable "users") }}
-					disabled-item
-				{{ end }} {{ if eq .NavbarActive $active }}active{{ end }}"
-			>
-				<i class="fas fa-users"></i>
-				<span>Users</span>
-			</a>
-		</li>
-		<li class="nav-item mb-2 mx-2">
-			{{ $active = "groups" }}
-			<a
-				href="/groups"
-				class="nav-link {{ if (serviceUnavailable "users") }}
-					disabled-item
-				{{ end }} {{ if eq .NavbarActive $active }}active{{ end }}"
-			>
-				<i class="fas fa-layer-group"></i>
-				<span>Groups</span>
-			</a>
-		</li>
-		<li class="nav-item mb-2 mx-2">
-			{{ $active = "things" }}
-			<a
-				href="/things"
-				class="nav-link {{ if (serviceUnavailable "things") }}
-					disabled-item
-				{{ end }} {{ if eq .NavbarActive $active }}active{{ end }}"
-			>
-				<i class="fas fa-microchip"></i>
-				<span>Things</span>
-			</a>
-		</li>
-		<li class="nav-item mb-2 mx-2">
-			{{ $active = "channels" }}
-			<a
-				href="/channels"
-				class="nav-link {{ if (serviceUnavailable "things") }}
-					disabled-item
-				{{ end }} {{ if eq .NavbarActive $active }}active{{ end }}"
-			>
-				<i class="fas fa-exchange-alt"></i>
-				<span>Channels</span>
-			</a>
-		</li>
-		<li class="nav-item mb-2 mx-2">
-			{{ $active = "readmessages" }}
-			<a
-				href="/messages/read"
-				class="nav-link {{ if (serviceUnavailable "things") }}
-					disabled-item
-				{{ end }} {{ if eq .NavbarActive $active }}active{{ end }}"
-			>
-				<i class="fas fa-envelope-open"></i>
-				<span>Messages</span>
-			</a>
-		</li>
-		<li class="nav-item mb-2 mx-2">
-			{{ $active = "bootstraps" }}
-			<a
-				href="/bootstraps"
-				class="nav-link {{ if (serviceUnavailable "bootstrap") }}
-					disabled-item
-				{{ end }} {{ if eq .NavbarActive $active }}active{{ end }}"
-			>
-				<i class="fas fa-solid fa-broadcast-tower"></i>
-				<span>Bootstrap</span>
-			</a>
-		</li>
+    <li class="nav-item mb-2 mx-2">
+      {{ $active := "dashboard" }}
+      <a href="/" class="nav-link {{ if eq .NavbarActive $active }}active{{ end }}">
+        <i class="fas fa-home"></i>
+        <span>Dashboard</span>
+      </a>
+    </li>
+    <li class="nav-item mb-2 mx-2">
+      {{ $active = "users" }}
+      <a
+        href="/users"
+        class=" nav-link {{ if (serviceUnavailable "users") }}
+          disabled-item
+        {{ end }} {{ if eq .NavbarActive $active }}active{{ end }}"
+      >
+        <i class="fas fa-users"></i>
+        <span>Users</span>
+      </a>
+    </li>
+    <li class="nav-item mb-2 mx-2">
+      {{ $active = "groups" }}
+      <a
+        href="/groups"
+        class="nav-link {{ if (serviceUnavailable "users") }}
+          disabled-item
+        {{ end }} {{ if eq .NavbarActive $active }}active{{ end }}"
+      >
+        <i class="fas fa-layer-group"></i>
+        <span>Groups</span>
+      </a>
+    </li>
+    <li class="nav-item mb-2 mx-2">
+      {{ $active = "things" }}
+      <a
+        href="/things"
+        class="nav-link {{ if (serviceUnavailable "things") }}
+          disabled-item
+        {{ end }} {{ if eq .NavbarActive $active }}active{{ end }}"
+      >
+        <i class="fas fa-microchip"></i>
+        <span>Things</span>
+      </a>
+    </li>
+    <li class="nav-item mb-2 mx-2">
+      {{ $active = "channels" }}
+      <a
+        href="/channels"
+        class="nav-link {{ if (serviceUnavailable "things") }}
+          disabled-item
+        {{ end }} {{ if eq .NavbarActive $active }}active{{ end }}"
+      >
+        <i class="fas fa-exchange-alt"></i>
+        <span>Channels</span>
+      </a>
+    </li>
+    <li class="nav-item mb-2 mx-2">
+      {{ $active = "readmessages" }}
+      <a
+        href="/messages/read"
+        class="nav-link {{ if (serviceUnavailable "things") }}
+          disabled-item
+        {{ end }} {{ if eq .NavbarActive $active }}active{{ end }}"
+      >
+        <i class="fas fa-envelope-open"></i>
+        <span>Messages</span>
+      </a>
+    </li>
+    <li class="nav-item mb-2 mx-2">
+      {{ $active = "bootstraps" }}
+      <a
+        href="/bootstraps"
+        class="nav-link {{ if (serviceUnavailable "bootstrap") }}
+          disabled-item
+        {{ end }} {{ if eq .NavbarActive $active }}active{{ end }}"
+      >
+        <i class="fas fa-solid fa-broadcast-tower"></i>
+        <span>Bootstrap</span>
+      </a>
+    </li>
 
-		<!-- Sidebar Toggler (Sidebar) -->
-		<div class="d-flex justify-content-center">
-			<button class="rounded-circle border-0" id="sidebarToggle"></button>
-		</div>
-	</ul>
+    <!-- Sidebar Toggler (Sidebar) -->
+    <div class="d-flex justify-content-center">
+      <button class="rounded-circle border-0" id="sidebarToggle"></button>
+    </div>
+  </ul>
 
-	<!-- End of sidebar -->
+  <!-- End of sidebar -->
 
-	<!-- Header navbar -->
-	<nav class="navbar navbar-expand topbar fixed-top">
-		<div class="container-fluid mb-3">
-			<div class="">
-				<!-- Sidebar Toggle (Topbar) -->
-				<button
-					id="sidebarToggleTop"
-					class="btn btn-link d-md-none rounded-circle mr-3 user-item"
-				>
-					<i class="fa fa-bars"></i>
-				</button>
-			</div>
+  <!-- Header navbar -->
+  <nav class="navbar navbar-expand topbar fixed-top">
+    <div class="container-fluid mb-3">
+      <div class="">
+        <!-- Sidebar Toggle (Topbar) -->
+        <button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3 user-item">
+          <i class="fa fa-bars"></i>
+        </button>
+      </div>
 
-			<div class="navbarSupportedContent">
-				<ul class="navbar-nav ms-auto d-flex align-items-center">
-					<li class="nav-item me-2">
-						<a
-							href="https://docs.mainflux.io/"
-							target="_blank"
-							class="doc-button btn"
-							role="button"
-						>
-							<span>Documentation</span>
-						</a>
-					</li>
-					<li class="nav-item dropstart me-3">
-						<a
-							class="user-item nav-link d-flex flex-row"
-							href="#"
-							role="button"
-							data-bs-toggle="dropdown"
-							aria-expanded="false"
-						>
-							<span class="me-2 d-none d-lg-inline text-muted-600 small">
-								{{ .User.Name }}
-							</span>
-							<i class="fa-solid fa-user"></i>
-						</a>
-						<ul class="dropdown-menu mt-5 position-absolute end-0 p-3">
-							<li class="d-flex justify-content-start mb-2">
-								<div class="align-self-center">
-									<i class="fa-regular fa-user fs-2"></i>
-								</div>
-								<div>
-									<span class="dropdown-item">{{ .User.Name }}</span>
-									<span class="dropdown-item text-muted">
-										{{ .User.Credentials.Identity }}
-									</span>
-								</div>
-							</li>
-							<li class="mb-2"><hr class="dropdown-divider" /></li>
-							<li class="mb-2">
-								<a
-									href="/password"
-									class="dropdown-item user-item-button p-2 mb-2"
-								>
-									<i class="fas fa-solid fa-lock me-2"></i>
-									<span>Update password</span>
-								</a>
-								<a
-									href="/logout"
-									class="dropdown-item user-item-button p-2 mb-2"
-								>
-									<i class="fa-solid fa-right-from-bracket me-2"></i>
-									<span>Log out</span>
-								</a>
-							</li>
-						</ul>
-					</li>
-				</ul>
-			</div>
-		</div>
-	</nav>
-	<script defer>
-		// Toggle the side navigation
-		document
-			.querySelectorAll("#sidebarToggle, #sidebarToggleTop")
-			.forEach(function (element) {
-				element.addEventListener("click", function (e) {
-					document.body.classList.toggle("sidebar-toggled");
-					document.querySelector(".sidebar").classList.toggle("toggled");
-				});
-			});
+      <div class="navbarSupportedContent">
+        <ul class="navbar-nav ms-auto d-flex align-items-center">
+          <li class="nav-item me-2">
+            <a
+              href="https://docs.mainflux.io/"
+              target="_blank"
+              class="doc-button btn"
+              role="button"
+            >
+              <span>Documentation</span>
+            </a>
+          </li>
+          <li class="nav-item dropstart me-3">
+            <a
+              class="user-item nav-link d-flex flex-row"
+              href="#"
+              role="button"
+              data-bs-toggle="dropdown"
+              aria-expanded="false"
+            >
+              <span class="me-2 d-none d-lg-inline text-muted-600 small">
+                {{ .User.Name }}
+              </span>
+              <i class="fa-solid fa-user"></i>
+            </a>
+            <ul class="dropdown-menu mt-5 position-absolute end-0 p-3">
+              <li class="d-flex justify-content-start mb-2">
+                <div class="align-self-center">
+                  <i class="fa-regular fa-user fs-2"></i>
+                </div>
+                <div>
+                  <span class="dropdown-item">{{ .User.Name }}</span>
+                  <span class="dropdown-item text-muted">
+                    {{ .User.Credentials.Identity }}
+                  </span>
+                </div>
+              </li>
+              <li class="mb-2"><hr class="dropdown-divider" /></li>
+              <li class="mb-2">
+                <a href="/password" class="dropdown-item user-item-button p-2 mb-2">
+                  <i class="fas fa-solid fa-lock me-2"></i>
+                  <span>Update password</span>
+                </a>
+                <a href="/logout" class="dropdown-item user-item-button p-2 mb-2">
+                  <i class="fa-solid fa-right-from-bracket me-2"></i>
+                  <span>Log out</span>
+                </a>
+              </li>
+            </ul>
+          </li>
+        </ul>
+      </div>
+    </div>
+  </nav>
+  <script defer>
+    // Toggle the side navigation
+    document.querySelectorAll("#sidebarToggle, #sidebarToggleTop").forEach(function (element) {
+      element.addEventListener("click", function (e) {
+        document.body.classList.toggle("sidebar-toggled");
+        document.querySelector(".sidebar").classList.toggle("toggled");
+      });
+    });
 
-		// Close any open menu accordions when window is resized below 768px
-		window.addEventListener("resize", function () {
-			// Toggle the side navigation when window is resized below 480px
-			if (
-				window.innerWidth < 480 &&
-				!document.querySelector(".sidebar").classList.contains("toggled")
-			) {
-				document.body.classList.add("sidebar-toggled");
-				document.querySelector(".sidebar").classList.add("toggled");
-			}
-		});
-	</script>
+    // Close any open menu accordions when window is resized below 768px
+    window.addEventListener("resize", function () {
+      // Toggle the side navigation when window is resized below 480px
+      if (
+        window.innerWidth < 480 &&
+        !document.querySelector(".sidebar").classList.contains("toggled")
+      ) {
+        document.body.classList.add("sidebar-toggled");
+        document.querySelector(".sidebar").classList.add("toggled");
+      }
+    });
+  </script>
 {{ end }}
diff --git a/ui/web/template/resetpassword.html b/ui/web/template/resetpassword.html
index 8af42f4b6..380896f7b 100644
--- a/ui/web/template/resetpassword.html
+++ b/ui/web/template/resetpassword.html
@@ -2,93 +2,87 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "resetPassword" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body class="login-body">
-			<div class="container mt-5 pt-5">
-				<div class="row p-5">
-					<div class="login-card col-lg-4 p-md-5 mx-auto mt-5">
-						<div
-							class="row text-center mb-4 d-flex flex-column align-items-center"
-						>
-							<div class="mb-3 border-bottom pb-3">
-								<div class="sidebar-brand d-flex justify-content-center mt-2">
-									<h1 class="mx-3">Magistrala</h1>
-								</div>
-							</div>
-							<div class="login-header mb-4">
-								<h2>Reset Password</h2>
-							</div>
-							<form
-								method="post"
-								id="form"
-								class="row border-bottom pb-3 mb-3"
-								onsubmit="return validateForm()"
-							>
-								<div class="col-md-12">
-									<div class="row mb-3">
-										<div class="col-md-12 input-field">
-											<i class="fas fa-solid fa-lock"></i>
-											<input
-												class="p-3 w-100"
-												type="password"
-												name="password"
-												id="password"
-												placeholder="Password"
-												required
-											/>
-											<div id="passwordError" class="text-danger"></div>
-										</div>
-									</div>
-									<div class="row mb-3">
-										<div class="col-md-12 input-field">
-											<i class="fas fa-solid fa-lock"></i>
-											<input
-												class="p-3 w-100"
-												type="password"
-												name="confirmPassword"
-												id="confirmPassword"
-												placeholder="confirm Password"
-												required
-											/>
-											<div id="confirmPasswordError" class="text-danger"></div>
-										</div>
-									</div>
-								</div>
-								<div class="col-md-12 d-grid py-3">
-									<button type="submit" class="login-btn py-3">
-										Reset Password
-									</button>
-								</div>
-							</form>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
-			<script>
-				function validateForm() {
-					var password = document.getElementById("password").value;
-					var confirmPassword =
-						document.getElementById("confirmPassword").value;
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body class="login-body">
+      <div class="container mt-5 pt-5">
+        <div class="row p-5">
+          <div class="login-card col-lg-4 p-md-5 mx-auto mt-5">
+            <div class="row text-center mb-4 d-flex flex-column align-items-center">
+              <div class="mb-3 border-bottom pb-3">
+                <div class="sidebar-brand d-flex justify-content-center mt-2">
+                  <h1 class="mx-3">Magistrala</h1>
+                </div>
+              </div>
+              <div class="login-header mb-4">
+                <h2>Reset Password</h2>
+              </div>
+              <form
+                method="post"
+                id="form"
+                class="row border-bottom pb-3 mb-3"
+                onsubmit="return validateForm()"
+              >
+                <div class="col-md-12">
+                  <div class="row mb-3">
+                    <div class="col-md-12 input-field">
+                      <i class="fas fa-solid fa-lock"></i>
+                      <input
+                        class="p-3 w-100"
+                        type="password"
+                        name="password"
+                        id="password"
+                        placeholder="Password"
+                        required
+                      />
+                      <div id="passwordError" class="text-danger"></div>
+                    </div>
+                  </div>
+                  <div class="row mb-3">
+                    <div class="col-md-12 input-field">
+                      <i class="fas fa-solid fa-lock"></i>
+                      <input
+                        class="p-3 w-100"
+                        type="password"
+                        name="confirmPassword"
+                        id="confirmPassword"
+                        placeholder="confirm Password"
+                        required
+                      />
+                      <div id="confirmPasswordError" class="text-danger"></div>
+                    </div>
+                  </div>
+                </div>
+                <div class="col-md-12 d-grid py-3">
+                  <button type="submit" class="login-btn py-3">Reset Password</button>
+                </div>
+              </form>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
+      <script>
+        function validateForm() {
+          var password = document.getElementById("password").value;
+          var confirmPassword = document.getElementById("confirmPassword").value;
 
-					passwordError.innerHTML = "";
-					confirmPasswordError.innerHTML = "";
-					var isValid = true;
+          passwordError.innerHTML = "";
+          confirmPasswordError.innerHTML = "";
+          var isValid = true;
 
-					if (password.length < 8) {
-						passwordError.innerHTML =
-							"Password must have a minimum of 8 characters!";
-						isValid = false;
-					}
-					if (confirmPassword != password) {
-						confirmPasswordError.innerHTML = "Passwords do not match!";
-						isValid = false;
-					}
-					return isValid;
-				}
-			</script>
-		</body>
-	</html>
+          if (password.length < 8) {
+            passwordError.innerHTML = "Password must have a minimum of 8 characters!";
+            isValid = false;
+          }
+          if (confirmPassword != password) {
+            confirmPasswordError.innerHTML = "Passwords do not match!";
+            isValid = false;
+          }
+          return isValid;
+        }
+      </script>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/tablefooter.html b/ui/web/template/tablefooter.html
index 2b7e5d374..31c3e8c54 100644
--- a/ui/web/template/tablefooter.html
+++ b/ui/web/template/tablefooter.html
@@ -2,62 +2,62 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "tablefooter" }}
-	{{ $currentPage := .CurrentPage }}
-	{{ $totalPages :=
-		.Pages
-	}}
-	<script>
-		document.addEventListener("DOMContentLoaded", function () {
-			var selectedLimit = localStorage.getItem("selectedLimit");
-			if (selectedLimit) {
-				var paginationLinks = document.querySelectorAll(".pagination a");
+  {{ $currentPage := .CurrentPage }}
+  {{ $totalPages :=
+    .Pages
+  }}
+  <script>
+    document.addEventListener("DOMContentLoaded", function () {
+      var selectedLimit = localStorage.getItem("selectedLimit");
+      if (selectedLimit) {
+        var paginationLinks = document.querySelectorAll(".pagination a");
 
-				paginationLinks.forEach(function (link) {
-					var href = link.getAttribute("href");
-					link.setAttribute("href", href + "&limit=" + selectedLimit);
-				});
-			}
-		});
-	</script>
-	<nav class="border-top" aria-label="Page navigation example">
-		<ul class="pagination justify-content-end mt-3">
-			{{ $prevPage := sub $currentPage 1 }}
-			{{ if le $prevPage 0 }}
-				<li class="page-item disabled">
-					<span class="page-link">Previous</span>
-				</li>
-			{{ else }}
-				<li class="page-item">
-					<a class="page-link" href="?page={{ $prevPage }}">Previous</a>
-				</li>
-			{{ end }}
-			{{ $startPage := max 1 (sub $currentPage 2) }}
-			{{ $endPage := min
-				$totalPages (add $currentPage 2)
-			}}
-			{{ range fromTo $startPage $endPage }}
-				{{ if eq . $currentPage }}
-					<li class="page-item active">
-						<span class="page-link">{{ . }}</span>
-					</li>
-				{{ else }}
-					<li class="page-item">
-						<a class="page-link" href="?page={{ . }}">{{ . }}</a>
-					</li>
-				{{ end }}
-			{{ end }}
-			{{ $nextPage := add $currentPage 1 }}
-			{{ if ge $nextPage
-				$totalPages
-			}}
-				<li class="page-item disabled">
-					<span class="page-link">Next</span>
-				</li>
-			{{ else }}
-				<li class="page-item">
-					<a class="page-link" href="?page={{ $nextPage }}">Next</a>
-				</li>
-			{{ end }}
-		</ul>
-	</nav>
+        paginationLinks.forEach(function (link) {
+          var href = link.getAttribute("href");
+          link.setAttribute("href", href + "&limit=" + selectedLimit);
+        });
+      }
+    });
+  </script>
+  <nav class="border-top" aria-label="Page navigation example">
+    <ul class="pagination justify-content-end mt-3">
+      {{ $prevPage := sub $currentPage 1 }}
+      {{ if le $prevPage 0 }}
+        <li class="page-item disabled">
+          <span class="page-link">Previous</span>
+        </li>
+      {{ else }}
+        <li class="page-item">
+          <a class="page-link" href="?page={{ $prevPage }}">Previous</a>
+        </li>
+      {{ end }}
+      {{ $startPage := max 1 (sub $currentPage 2) }}
+      {{ $endPage := min
+        $totalPages (add $currentPage 2)
+      }}
+      {{ range fromTo $startPage $endPage }}
+        {{ if eq . $currentPage }}
+          <li class="page-item active">
+            <span class="page-link">{{ . }}</span>
+          </li>
+        {{ else }}
+          <li class="page-item">
+            <a class="page-link" href="?page={{ . }}">{{ . }}</a>
+          </li>
+        {{ end }}
+      {{ end }}
+      {{ $nextPage := add $currentPage 1 }}
+      {{ if ge $nextPage
+        $totalPages
+      }}
+        <li class="page-item disabled">
+          <span class="page-link">Next</span>
+        </li>
+      {{ else }}
+        <li class="page-item">
+          <a class="page-link" href="?page={{ $nextPage }}">Next</a>
+        </li>
+      {{ end }}
+    </ul>
+  </nav>
 {{ end }}
diff --git a/ui/web/template/tableheader.html b/ui/web/template/tableheader.html
index d2eafb1a0..373361eaf 100644
--- a/ui/web/template/tableheader.html
+++ b/ui/web/template/tableheader.html
@@ -2,59 +2,35 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "tableheader" }}
-	{{ $currentPage := .CurrentPage }}
-	<div class="d-flex flex-row justify-content-start mb-2">
-		<div class="dropdown border">
-			<button
-				class="btn btn-light dropdown-toggle"
-				type="button"
-				id="itemsPerPageDropdown"
-				data-bs-toggle="dropdown"
-				aria-expanded="false"
-			>
-				{{ .Limit }}
-			</button>
-			<ul class="dropdown-menu" aria-labelledby="itemsPerPageDropdown">
-				<li>
-					<a
-						class="dropdown-item"
-						href="?page={{ $currentPage }}&limit=5"
-						id="limit5"
-					>
-						5
-					</a>
-				</li>
-				<li>
-					<a
-						class="dropdown-item"
-						href="?page={{ $currentPage }}&limit=10"
-						id="limit10"
-					>
-						10
-					</a>
-				</li>
-				<li>
-					<a
-						class="dropdown-item"
-						href="?page={{ $currentPage }}&limit=20"
-						id="limit20"
-					>
-						20
-					</a>
-				</li>
-				<li>
-					<a
-						class="dropdown-item"
-						href="?page={{ $currentPage }}&limit=50"
-						id="limit50"
-					>
-						50
-					</a>
-				</li>
-			</ul>
-		</div>
-		<span class="align-self-center mx-2">Items per page</span>
-	</div>
+  {{ $currentPage := .CurrentPage }}
+  <div class="d-flex flex-row justify-content-start mb-2">
+    <div class="dropdown border">
+      <button
+        class="btn btn-light dropdown-toggle"
+        type="button"
+        id="itemsPerPageDropdown"
+        data-bs-toggle="dropdown"
+        aria-expanded="false"
+      >
+        {{ .Limit }}
+      </button>
+      <ul class="dropdown-menu" aria-labelledby="itemsPerPageDropdown">
+        <li>
+          <a class="dropdown-item" href="?page={{ $currentPage }}&limit=5" id="limit5">5</a>
+        </li>
+        <li>
+          <a class="dropdown-item" href="?page={{ $currentPage }}&limit=10" id="limit10">10</a>
+        </li>
+        <li>
+          <a class="dropdown-item" href="?page={{ $currentPage }}&limit=20" id="limit20">20</a>
+        </li>
+        <li>
+          <a class="dropdown-item" href="?page={{ $currentPage }}&limit=50" id="limit50">50</a>
+        </li>
+      </ul>
+    </div>
+    <span class="align-self-center mx-2">Items per page</span>
+  </div>
 <script>
   document.addEventListener("DOMContentLoaded", function () {
     // Get the dropdown items
diff --git a/ui/web/template/terminal.html b/ui/web/template/terminal.html
index fb1c7cb54..bbc15138c 100644
--- a/ui/web/template/terminal.html
+++ b/ui/web/template/terminal.html
@@ -2,61 +2,61 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "remoteTerminal" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<style>
-			.terminal {
-				color: #fff;
-				width: 100%;
-				height: 300px;
-				background-color: #272822;
-				padding: 10px;
-				overflow-y: scroll;
-			}
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <style>
+      .terminal {
+        color: #fff;
+        width: 100%;
+        height: 300px;
+        background-color: #272822;
+        padding: 10px;
+        overflow-y: scroll;
+      }
 
-			.input-line {
-				display: flex;
-				background-color: #272822;
-			}
+      .input-line {
+        display: flex;
+        background-color: #272822;
+      }
 
-			.input-prefix {
-				color: #f92672;
-				margin-right: 5px;
-			}
+      .input-prefix {
+        color: #f92672;
+        margin-right: 5px;
+      }
 
-			.input-field {
-				width: 90%;
-				flex: 1;
-				color: #fff;
-				background-color: #272822;
-				padding: 10px;
-				border: none;
-				outline: none;
-			}
-		</style>
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="terminal">
-									<!-- Existing terminal content here -->
-								</div>
-								<div class="input-line">
-									<form action="/bootstraps/1/terminal/input" method="POST">
-										<span class="input-prefix">&gt;</span>
-										<input class="input-field" name="command" autofocus />
-									</form>
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
+      .input-field {
+        width: 90%;
+        flex: 1;
+        color: #fff;
+        background-color: #272822;
+        padding: 10px;
+        border: none;
+        outline: none;
+      }
+    </style>
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="terminal">
+                  <!-- Existing terminal content here -->
+                </div>
+                <div class="input-line">
+                  <form action="/bootstraps/1/terminal/input" method="POST">
+                    <span class="input-prefix">&gt;</span>
+                    <input class="input-field" name="command" autofocus />
+                  </form>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
     <script>
       document.addEventListener("DOMContentLoaded", function () {
         var form = document.querySelector("form");
@@ -88,6 +88,6 @@
         });
       });
     </script>
-		</body>
-	</html>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/thing.html b/ui/web/template/thing.html
index c75ebb9c7..11efc99dc 100644
--- a/ui/web/template/thing.html
+++ b/ui/web/template/thing.html
@@ -2,226 +2,163 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "thing" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<a
-										class="btn body-button"
-										href="/things/{{ .Thing.ID }}/channels"
-										role="button"
-									>
-										Thing Channels
-									</a>
-									<a
-										class="btn body-button"
-										href="/things/{{ .Thing.ID }}/users"
-										role="button"
-									>
-										Thing Users
-									</a>
-								</div>
-								<div class="table-responsive table-container">
-									<table id="itemsTable" class="table">
-										<thead>
-											<tr>
-												<th scope="row">THING</th>
-											</tr>
-										</thead>
-										<tbody>
-											{{ $disableButton := false }}
-											<tr>
-												<th>Name</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="name"
-												>
-													{{ .Thing.Name }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														id="edit-name"
-														{{ if
-															$disableButton
-														}}
-															disabled
-														{{ end }}
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" id="save-name">
-															Save
-														</button>
-														<button class="cancel-btn" id="cancel-name">
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>ID</th>
-												<td>{{ .Thing.ID }}</td>
-												<td></td>
-											</tr>
-											<tr>
-												<th>Secret</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="secret"
-												>
-													{{ .Thing.Credentials.Secret }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														id="edit-secret"
-														{{ if
-															$disableButton
-														}}
-															disabled
-														{{ end }}
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" id="save-secret">
-															Save
-														</button>
-														<button class="cancel-btn" id="cancel-secret">
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>Tags</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="tags"
-												>
-													{{ toSlice .Thing.Tags }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														id="edit-tags"
-														{{ if
-															$disableButton
-														}}
-															disabled
-														{{ end }}
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" id="save-tags">
-															Save
-														</button>
-														<button class="cancel-btn" id="cancel-tags">
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>Owner</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="owner"
-												>
-													{{ .Thing.Owner }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														id="edit-owner"
-														{{ if
-															$disableButton
-														}}
-															disabled
-														{{ end }}
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" id="save-owner">
-															Save
-														</button>
-														<button class="cancel-btn" id="cancel-owner">
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>Metadata</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="metadata"
-												>
-													{{ toJSON .Thing.Metadata }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														id="edit-metadata"
-														{{ if
-															$disableButton
-														}}
-															disabled
-														{{ end }}
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" id="save-metadata">
-															Save
-														</button>
-														<button class="cancel-btn" id="cancel-metadata">
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-										</tbody>
-									</table>
-									<div id="error-message" class="text-danger"></div>
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <a class="btn body-button" href="/things/{{ .Thing.ID }}/channels" role="button">
+                    Thing Channels
+                  </a>
+                  <a class="btn body-button" href="/things/{{ .Thing.ID }}/users" role="button">
+                    Thing Users
+                  </a>
+                </div>
+                <div class="table-responsive table-container">
+                  <table id="itemsTable" class="table">
+                    <thead>
+                      <tr>
+                        <th scope="row">THING</th>
+                      </tr>
+                    </thead>
+                    <tbody>
+                      {{ $disableButton := false }}
+                      <tr>
+                        <th>Name</th>
+                        <td class="editable" contenteditable="false" data-field="name">
+                          {{ .Thing.Name }}
+                        </td>
+                        <td>
+                          <button
+                            class="edit-btn"
+                            id="edit-name"
+                            {{ if
+                              $disableButton
+                            }}
+                              disabled
+                            {{ end }}
+                          >
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" id="save-name">Save</button>
+                            <button class="cancel-btn" id="cancel-name">Cancel</button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>ID</th>
+                        <td>{{ .Thing.ID }}</td>
+                        <td></td>
+                      </tr>
+                      <tr>
+                        <th>Secret</th>
+                        <td class="editable" contenteditable="false" data-field="secret">
+                          {{ .Thing.Credentials.Secret }}
+                        </td>
+                        <td>
+                          <button
+                            class="edit-btn"
+                            id="edit-secret"
+                            {{ if
+                              $disableButton
+                            }}
+                              disabled
+                            {{ end }}
+                          >
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" id="save-secret">Save</button>
+                            <button class="cancel-btn" id="cancel-secret">Cancel</button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>Tags</th>
+                        <td class="editable" contenteditable="false" data-field="tags">
+                          {{ toSlice .Thing.Tags }}
+                        </td>
+                        <td>
+                          <button
+                            class="edit-btn"
+                            id="edit-tags"
+                            {{ if
+                              $disableButton
+                            }}
+                              disabled
+                            {{ end }}
+                          >
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" id="save-tags">Save</button>
+                            <button class="cancel-btn" id="cancel-tags">Cancel</button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>Owner</th>
+                        <td class="editable" contenteditable="false" data-field="owner">
+                          {{ .Thing.Owner }}
+                        </td>
+                        <td>
+                          <button
+                            class="edit-btn"
+                            id="edit-owner"
+                            {{ if
+                              $disableButton
+                            }}
+                              disabled
+                            {{ end }}
+                          >
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" id="save-owner">Save</button>
+                            <button class="cancel-btn" id="cancel-owner">Cancel</button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>Metadata</th>
+                        <td class="editable" contenteditable="false" data-field="metadata">
+                          {{ toJSON .Thing.Metadata }}
+                        </td>
+                        <td>
+                          <button
+                            class="edit-btn"
+                            id="edit-metadata"
+                            {{ if
+                              $disableButton
+                            }}
+                              disabled
+                            {{ end }}
+                          >
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" id="save-metadata">Save</button>
+                            <button class="cancel-btn" id="cancel-metadata">Cancel</button>
+                          </div>
+                        </td>
+                      </tr>
+                    </tbody>
+                  </table>
+                  <div id="error-message" class="text-danger"></div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
     <script>
 		attachEditRowListener(
 			{
@@ -238,6 +175,6 @@
 			}
 		);
     </script>
-		</body>
-	</html>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/thingchannels.html b/ui/web/template/thingchannels.html
index 774b5b417..186b991e4 100644
--- a/ui/web/template/thingchannels.html
+++ b/ui/web/template/thingchannels.html
@@ -2,276 +2,238 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "thingchannels" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<a
-										class="btn body-button"
-										href="/things/{{ .Thing.ID }}"
-										role="button"
-									>
-										Thing
-									</a>
-									<a
-										class="btn body-button"
-										href="/things/{{ .Thing.ID }}/users"
-										role="button"
-									>
-										Thing Users
-									</a>
-								</div>
-								<div class="table-responsive table-container">
-									<div class="d-flex flex-row justify-content-between">
-										<h4>Thing Channels</h4>
-										<button
-											role="button"
-											class="btn body-button"
-											onclick="openChannelModal()"
-										>
-											<i class="fa-solid fa-plus fs-4"></i>
-										</button>
-										<!-- modal -->
-										<div
-											class="modal fade"
-											id="addChannelModal"
-											tabindex="-1"
-											aria-labelledby="addChannelModalLabel"
-											aria-hidden="true"
-										>
-											<div class="modal-dialog modal-dialog-centered">
-												<div class="modal-content">
-													<div class="modal-header">
-														<h1
-															class="modal-title fs-5"
-															id="addChannelModalLabel"
-														>
-															Add Channel
-														</h1>
-														<button
-															type="button"
-															class="btn-close"
-															data-bs-dismiss="modal"
-															aria-label="Close"
-														></button>
-													</div>
-													<form
-														action="/things/{{ .Thing.ID }}/channels/connect?item=things"
-														method="post"
-													>
-														<div class="modal-body">
-															<div class="mb-3">
-																<label for="infiniteScroll" class="form-label">
-																	Channel ID
-																</label>
-																<input
-																	type="text"
-																	name="channelFilter"
-																	id="channelFilter"
-																	placeholder="Filter by Channel ID"
-																/>
-																<select
-																	class="form-select"
-																	name="channelID"
-																	id="infiniteScroll"
-																	size="5"
-																	required
-																>
-																	<option disabled>select a channel</option>
-																</select>
-															</div>
-															<div class="modal-footer">
-																<button
-																	type="button"
-																	class="btn btn-secondary"
-																	data-bs-dismiss="modal"
-																>
-																	Cancel
-																</button>
-																<button type="submit" class="btn btn-primary">
-																	Assign
-																</button>
-															</div>
-														</div>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
-									{{ template "tableheader" . }}
-									<div class="itemsTable">
-										<table class="table" id="itemsTable">
-											<thead>
-												<tr>
-													<th scope="col">Name</th>
-													<th scope="col">ID</th>
-													<th class="desc-col" scope="col">Description</th>
-													<th class="meta-col" scope="col">Metadata</th>
-													<th class="created-col" scope="col">Created At</th>
-													<th class="text-center" scope="col"></th>
-												</tr>
-											</thead>
-											<tbody>
-												{{ $thing := .Thing }}
-												{{ range $i, $c := .Channels }}
-													{{ $disableButton := false }}
-													<tr>
-														<td>{{ $c.Name }}</td>
-														<td>
-															<div class="copy-con-container">
-																<a href="{{ printf "/channels/%s" $c.ID }}">
-																	{{ $c.ID }}
-																</a>
-																<button
-																	class="copy-icon"
-																	onclick="copyToClipboard(this)"
-																>
-																	<i class="far fa-copy"></i>
-																</button>
-															</div>
-														</td>
-														<td class="desc-col">{{ $c.Description }}</td>
-														<td class="meta-col">{{ toJSON $c.Metadata }}</td>
-														<td class="created-col">{{ $c.CreatedAt }}</td>
-														<td class="d-flex flex-row">
-															<button
-																type="button"
-																class="btn btn-sm doc-button"
-																data-bs-toggle="modal"
-																data-bs-target="#sendMesageModal{{ $i }}"
-															>
-																Send Message
-															</button>
-															<form
-																action="/things/{{ $thing.ID }}/channels/disconnect?item=things"
-																method="post"
-															>
-																<input
-																	type="hidden"
-																	name="channelID"
-																	id="channelID"
-																	value="{{ $c.ID }}"
-																/>
-																<button
-																	type="submit"
-																	class="btn btn-sm"
-																	{{ if
-																		$disableButton
-																	}}
-																		disabled
-																	{{ end }}
-																>
-																	<i class="fas fa-trash-alt"></i>
-																</button>
-															</form>
-														</td>
-													</tr>
-													<!-- modal -->
-													<div
-														class="modal fade"
-														id="sendMesageModal{{ $i }}"
-														tabindex="-1"
-														aria-labelledby="sendMesageModalLabel{{ $i }}"
-														aria-hidden="true"
-													>
-														<div class="modal-dialog">
-															<div class="modal-content">
-																<div class="modal-header">
-																	<h1
-																		class="modal-title fs-5"
-																		id="sendMesageModalLabel{{ $i }}"
-																	>
-																		Send Message
-																	</h1>
-																	<button
-																		type="button"
-																		class="btn-close"
-																		data-bs-dismiss="modal"
-																		aria-label="Close"
-																	></button>
-																</div>
-																<form action="/messages" method="post">
-																	<div class="modal-body">
-																		<input
-																			type="hidden"
-																			name="channelID"
-																			id="channelID"
-																			value="{{ $c }}"
-																		/>
-																		<input
-																			type="hidden"
-																			name="thingKey"
-																			id="thingKey"
-																			value="{{ $thing.Credentials.Secret }}"
-																		/>
-																		<div class="mb-3">
-																			<label for="message" class="form-label">
-																				Message
-																			</label>
-																			<textarea
-																				class="form-control"
-																				name="message"
-																				id="message"
-																				aria-describedby="messageHelp"
-																			></textarea>
-																			<div id="messageHelp" class="form-text">
-																				Enter Message.
-																			</div>
-																		</div>
-																	</div>
-																	<div class="modal-footer">
-																		<button
-																			type="button"
-																			class="btn btn-secondary"
-																			data-bs-dismiss="modal"
-																		>
-																			Close
-																		</button>
-																		<button
-																			type="submit"
-																			class="btn doc-button"
-																		>
-																			Send Message
-																		</button>
-																	</div>
-																</form>
-															</div>
-														</div>
-													</div>
-												{{ end }}
-											</tbody>
-										</table>
-									</div>
-									{{ template "tablefooter" . }}
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <a class="btn body-button" href="/things/{{ .Thing.ID }}" role="button">Thing</a>
+                  <a class="btn body-button" href="/things/{{ .Thing.ID }}/users" role="button">
+                    Thing Users
+                  </a>
+                </div>
+                <div class="table-responsive table-container">
+                  <div class="d-flex flex-row justify-content-between">
+                    <h4>Thing Channels</h4>
+                    <button role="button" class="btn body-button" onclick="openChannelModal()">
+                      <i class="fa-solid fa-plus fs-4"></i>
+                    </button>
+                    <!-- modal -->
+                    <div
+                      class="modal fade"
+                      id="addChannelModal"
+                      tabindex="-1"
+                      aria-labelledby="addChannelModalLabel"
+                      aria-hidden="true"
+                    >
+                      <div class="modal-dialog modal-dialog-centered">
+                        <div class="modal-content">
+                          <div class="modal-header">
+                            <h1 class="modal-title fs-5" id="addChannelModalLabel">Add Channel</h1>
+                            <button
+                              type="button"
+                              class="btn-close"
+                              data-bs-dismiss="modal"
+                              aria-label="Close"
+                            ></button>
+                          </div>
+                          <form
+                            action="/things/{{ .Thing.ID }}/channels/connect?item=things"
+                            method="post"
+                          >
+                            <div class="modal-body">
+                              <div class="mb-3">
+                                <label for="infiniteScroll" class="form-label">Channel ID</label>
+                                <input
+                                  type="text"
+                                  name="channelFilter"
+                                  id="channelFilter"
+                                  placeholder="Filter by Channel ID"
+                                />
+                                <select
+                                  class="form-select"
+                                  name="channelID"
+                                  id="infiniteScroll"
+                                  size="5"
+                                  required
+                                >
+                                  <option disabled>select a channel</option>
+                                </select>
+                              </div>
+                              <div class="modal-footer">
+                                <button
+                                  type="button"
+                                  class="btn btn-secondary"
+                                  data-bs-dismiss="modal"
+                                >
+                                  Cancel
+                                </button>
+                                <button type="submit" class="btn btn-primary">Assign</button>
+                              </div>
+                            </div>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  {{ template "tableheader" . }}
+                  <div class="itemsTable">
+                    <table class="table" id="itemsTable">
+                      <thead>
+                        <tr>
+                          <th scope="col">Name</th>
+                          <th scope="col">ID</th>
+                          <th class="desc-col" scope="col">Description</th>
+                          <th class="meta-col" scope="col">Metadata</th>
+                          <th class="created-col" scope="col">Created At</th>
+                          <th class="text-center" scope="col"></th>
+                        </tr>
+                      </thead>
+                      <tbody>
+                        {{ $thing := .Thing }}
+                        {{ range $i, $c := .Channels }}
+                          {{ $disableButton := false }}
+                          <tr>
+                            <td>{{ $c.Name }}</td>
+                            <td>
+                              <div class="copy-con-container">
+                                <a href="{{ printf "/channels/%s" $c.ID }}">
+                                  {{ $c.ID }}
+                                </a>
+                                <button class="copy-icon" onclick="copyToClipboard(this)">
+                                  <i class="far fa-copy"></i>
+                                </button>
+                              </div>
+                            </td>
+                            <td class="desc-col">{{ $c.Description }}</td>
+                            <td class="meta-col">{{ toJSON $c.Metadata }}</td>
+                            <td class="created-col">{{ $c.CreatedAt }}</td>
+                            <td class="d-flex flex-row">
+                              <button
+                                type="button"
+                                class="btn btn-sm doc-button"
+                                data-bs-toggle="modal"
+                                data-bs-target="#sendMesageModal{{ $i }}"
+                              >
+                                Send Message
+                              </button>
+                              <form
+                                action="/things/{{ $thing.ID }}/channels/disconnect?item=things"
+                                method="post"
+                              >
+                                <input
+                                  type="hidden"
+                                  name="channelID"
+                                  id="channelID"
+                                  value="{{ $c.ID }}"
+                                />
+                                <button
+                                  type="submit"
+                                  class="btn btn-sm"
+                                  {{ if
+                                    $disableButton
+                                  }}
+                                    disabled
+                                  {{ end }}
+                                >
+                                  <i class="fas fa-trash-alt"></i>
+                                </button>
+                              </form>
+                            </td>
+                          </tr>
+                          <!-- modal -->
+                          <div
+                            class="modal fade"
+                            id="sendMesageModal{{ $i }}"
+                            tabindex="-1"
+                            aria-labelledby="sendMesageModalLabel{{ $i }}"
+                            aria-hidden="true"
+                          >
+                            <div class="modal-dialog">
+                              <div class="modal-content">
+                                <div class="modal-header">
+                                  <h1 class="modal-title fs-5" id="sendMesageModalLabel{{ $i }}">
+                                    Send Message
+                                  </h1>
+                                  <button
+                                    type="button"
+                                    class="btn-close"
+                                    data-bs-dismiss="modal"
+                                    aria-label="Close"
+                                  ></button>
+                                </div>
+                                <form action="/messages" method="post">
+                                  <div class="modal-body">
+                                    <input
+                                      type="hidden"
+                                      name="channelID"
+                                      id="channelID"
+                                      value="{{ $c }}"
+                                    />
+                                    <input
+                                      type="hidden"
+                                      name="thingKey"
+                                      id="thingKey"
+                                      value="{{ $thing.Credentials.Secret }}"
+                                    />
+                                    <div class="mb-3">
+                                      <label for="message" class="form-label">Message</label>
+                                      <textarea
+                                        class="form-control"
+                                        name="message"
+                                        id="message"
+                                        aria-describedby="messageHelp"
+                                      ></textarea>
+                                      <div id="messageHelp" class="form-text">Enter Message.</div>
+                                    </div>
+                                  </div>
+                                  <div class="modal-footer">
+                                    <button
+                                      type="button"
+                                      class="btn btn-secondary"
+                                      data-bs-dismiss="modal"
+                                    >
+                                      Close
+                                    </button>
+                                    <button type="submit" class="btn doc-button">
+                                      Send Message
+                                    </button>
+                                  </div>
+                                </form>
+                              </div>
+                            </div>
+                          </div>
+                        {{ end }}
+                      </tbody>
+                    </table>
+                  </div>
+                  {{ template "tablefooter" . }}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
 
-			{{ template "footer" }}
-			<script>
-				const channelModal = new bootstrap.Modal(
-					document.getElementById("addChannelModal"),
-				);
-				function openChannelModal() {
-					channelModal.show();
-				}
+      {{ template "footer" }}
+      <script>
+        const channelModal = new bootstrap.Modal(document.getElementById("addChannelModal"));
+        function openChannelModal() {
+          channelModal.show();
+        }
 
-				fetchIndividualEntity({
-					input: "channelFilter",
-					itemSelect: "infiniteScroll",
-					item: "channels",
-				});
-			</script>
-		</body>
-	</html>
+        fetchIndividualEntity({
+          input: "channelFilter",
+          itemSelect: "infiniteScroll",
+          item: "channels",
+        });
+      </script>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/things.html b/ui/web/template/things.html
index 76dbc8b85..15b16af62 100644
--- a/ui/web/template/things.html
+++ b/ui/web/template/things.html
@@ -2,145 +2,123 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "things" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<!-- Button trigger modal -->
-									<button
-										type="button"
-										class="btn body-button"
-										onclick="openModal('single')"
-									>
-										Add Thing
-									</button>
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <!-- Button trigger modal -->
+                  <button type="button" class="btn body-button" onclick="openModal('single')">
+                    Add Thing
+                  </button>
 
-									<!-- Modal -->
-									<div
-										class="modal fade"
-										id="addThingModal"
-										tabindex="-1"
-										role="dialog"
-										aria-labelledby="addThingModalLabel"
-										aria-hidden="true"
-									>
-										<div class="modal-dialog" role="document">
-											<div class="modal-content">
-												<div class="modal-header">
-													<h5 class="modal-title" id="addThingModalLabel">
-														Add Thing
-													</h5>
-												</div>
-												<div class="modal-body">
-													<div id="alertMessage"></div>
-													<form id="thingform">
-														<div class="mb-3">
-															<label for="name" class="form-label">Name</label>
-															<input
-																type="text"
-																class="form-control"
-																name="name"
-																id="name"
-																placeholder="Device Name"
-															/>
-															<div id="nameError" class="text-danger"></div>
-														</div>
-														<div class="mb-3">
-															<label for="thingID" class="form-label">
-																Thing ID
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="thingID"
-																id="thingID"
-																placeholder="Thing ID"
-															/>
-														</div>
-														<div class="mb-3">
-															<label for="identity" class="form-label">
-																Identity
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="identity"
-																id="identity"
-																placeholder="Thing Identity"
-															/>
-														</div>
-														<div class="mb-3">
-															<label for="secret" class="form-label">
-																Secret
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="secret"
-																id="secret"
-																placeholder="Thing Secret"
-															/>
-															<div id="secretError" class="error-message"></div>
-														</div>
-														<div class="mb-3">
-															<label for="tags" class="form-label">Tags</label>
-															<input
-																type="text"
-																class="form-control"
-																name="tags"
-																id="tags"
-																aria-describedby="tagHelp"
-																value="[]"
-															/>
-															<div id="tagHelp" class="form-text">
-																Enter device tags as a string slice.
-															</div>
-															<div id="tagsError" class="text-danger"></div>
-														</div>
-														<div class="mb-3">
-															<label for="metadata" class="form-label">
-																Metadata
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="metadata"
-																id="metadata"
-																value="{}"
-															/>
-															<div id="metadataHelp" class="form-text">
-																Enter device metadata in JSON format.
-															</div>
-															<div id="metadataError" class="text-danger"></div>
-														</div>
-														<button
-															type="submit"
-															class="btn body-button"
-															id="create-thing-button"
-														>
-															Submit
-														</button>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
+                  <!-- Modal -->
+                  <div
+                    class="modal fade"
+                    id="addThingModal"
+                    tabindex="-1"
+                    role="dialog"
+                    aria-labelledby="addThingModalLabel"
+                    aria-hidden="true"
+                  >
+                    <div class="modal-dialog" role="document">
+                      <div class="modal-content">
+                        <div class="modal-header">
+                          <h5 class="modal-title" id="addThingModalLabel">Add Thing</h5>
+                        </div>
+                        <div class="modal-body">
+                          <div id="alertMessage"></div>
+                          <form id="thingform">
+                            <div class="mb-3">
+                              <label for="name" class="form-label">Name</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="name"
+                                id="name"
+                                placeholder="Device Name"
+                              />
+                              <div id="nameError" class="text-danger"></div>
+                            </div>
+                            <div class="mb-3">
+                              <label for="thingID" class="form-label">Thing ID</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="thingID"
+                                id="thingID"
+                                placeholder="Thing ID"
+                              />
+                            </div>
+                            <div class="mb-3">
+                              <label for="identity" class="form-label">Identity</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="identity"
+                                id="identity"
+                                placeholder="Thing Identity"
+                              />
+                            </div>
+                            <div class="mb-3">
+                              <label for="secret" class="form-label">Secret</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="secret"
+                                id="secret"
+                                placeholder="Thing Secret"
+                              />
+                              <div id="secretError" class="error-message"></div>
+                            </div>
+                            <div class="mb-3">
+                              <label for="tags" class="form-label">Tags</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="tags"
+                                id="tags"
+                                aria-describedby="tagHelp"
+                                value="[]"
+                              />
+                              <div id="tagHelp" class="form-text">
+                                Enter device tags as a string slice.
+                              </div>
+                              <div id="tagsError" class="text-danger"></div>
+                            </div>
+                            <div class="mb-3">
+                              <label for="metadata" class="form-label">Metadata</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="metadata"
+                                id="metadata"
+                                value="{}"
+                              />
+                              <div id="metadataHelp" class="form-text">
+                                Enter device metadata in JSON format.
+                              </div>
+                              <div id="metadataError" class="text-danger"></div>
+                            </div>
+                            <button type="submit" class="btn body-button" id="create-thing-button">
+                              Submit
+                            </button>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
 
-									<!-- Button trigger modal -->
-									<button
-										type="button"
-										class="btn body-button"
-										onclick="openModal('bulk')"
-									>
-										Add Things
-									</button>
+                  <!-- Button trigger modal -->
+                  <button type="button" class="btn body-button" onclick="openModal('bulk')">
+                    Add Things
+                  </button>
 
 									<!-- Modal -->
 									<div
@@ -282,35 +260,31 @@ <h5 class="modal-title" id="addThingsModalLabel">
 					},
 				});
 
-				const thingModal = new bootstrap.Modal(
-					document.getElementById("addThingModal"),
-				);
-				const thingsModal = new bootstrap.Modal(
-					document.getElementById("addThingsModal"),
-				);
+        const thingModal = new bootstrap.Modal(document.getElementById("addThingModal"));
+        const thingsModal = new bootstrap.Modal(document.getElementById("addThingsModal"));
 
-				function openModal(modal) {
-					if (modal === "single") {
-						thingModal.show();
-					} else if (modal === "bulk") {
-						thingsModal.show();
-					}
-				}
+        function openModal(modal) {
+          if (modal === "single") {
+            thingModal.show();
+          } else if (modal === "bulk") {
+            thingsModal.show();
+          }
+        }
 
-				submitCreateForm({
-					url: "/things",
-					formId: "thingform",
-					alertDiv: "alertMessage",
-					modal: thingModal,
-				});
+        submitCreateForm({
+          url: "/things",
+          formId: "thingform",
+          alertDiv: "alertMessage",
+          modal: thingModal,
+        });
 
-				submitCreateForm({
-					url: "/things/bulk",
-					formId: "bulkThingsForm",
-					alertDiv: "alertBulkMessage",
-					modal: thingsModal,
-				});
-			</script>
-		</body>
-	</html>
+        submitCreateForm({
+          url: "/things/bulk",
+          formId: "bulkThingsForm",
+          alertDiv: "alertBulkMessage",
+          modal: thingsModal,
+        });
+      </script>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/thingusers.html b/ui/web/template/thingusers.html
index 72038a9c0..9c460b7f6 100644
--- a/ui/web/template/thingusers.html
+++ b/ui/web/template/thingusers.html
@@ -2,219 +2,182 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "thingusers" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<a
-										class="btn body-button"
-										href="/things/{{ .ThingID }}"
-										role="button"
-									>
-										Thing
-									</a>
-									<a
-										class="btn body-button"
-										href="/things/{{ .ThingID }}/channels"
-										role="button"
-									>
-										Thing Channels
-									</a>
-								</div>
-								<div class="table-responsive table-container">
-									<div class="d-flex flex-row justify-content-between">
-										<h4>Thing Users</h4>
-										<button
-											role="button"
-											class="btn body-button"
-											onclick="openUserModal()"
-										>
-											<i class="fa-solid fa-plus fs-4"></i>
-										</button>
-										<!-- modal -->
-										<div
-											class="modal fade"
-											id="addUserModal"
-											tabindex="-1"
-											aria-labelledby="addUserModalLabel"
-											aria-hidden="true"
-										>
-											<div class="modal-dialog modal-dialog-centered">
-												<div class="modal-content">
-													<div class="modal-header">
-														<h1 class="modal-title fs-5" id="addUserModalLabel">
-															Share Thing
-														</h1>
-														<button
-															type="button"
-															class="btn-close"
-															data-bs-dismiss="modal"
-															aria-label="Close"
-														></button>
-													</div>
-													<form
-														action="/things/{{ .ThingID }}/share?item=things"
-														method="post"
-													>
-														<div class="modal-body">
-															<div class="mb-3">
-																<label for="infiniteScroll" class="form-label">
-																	User ID
-																</label>
-																<input
-																	type="text"
-																	name="userFilter"
-																	id="userFilter"
-																	placeholder="Filter by User ID"
-																/>
-																<select
-																	class="form-select"
-																	name="userID"
-																	id="infiniteScroll"
-																	size="5"
-																	required
-																>
-																	<option disabled>select a User</option>
-																</select>
-															</div>
-															<div class="mb-3">
-																<label for="relation" class="form-label">
-																	Relation
-																</label>
-																<select
-																	class="form-control"
-																	name="relation"
-																	id="relation"
-																	aria-describedby="relationHelp"
-																	multiple
-																	required
-																>
-																	{{ range $r := .Relations }}
-																		<option value="{{ $r }}">
-																			{{ $r }}
-																		</option>
-																	{{ end }}
-																</select>
-																<div id="relationHelp" class="form-text">
-																	Select Relation.
-																</div>
-															</div>
-															<div class="modal-footer">
-																<button
-																	type="button"
-																	class="btn btn-secondary"
-																	data-bs-dismiss="modal"
-																>
-																	Cancel
-																</button>
-																<button type="submit" class="btn btn-primary">
-																	Assign
-																</button>
-															</div>
-														</div>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
-									{{ template "tableheader" . }}
-									<div class="itemsTable">
-										<table id="itemsTable" class="table">
-											<thead>
-												<tr>
-													<th scope="col">Name</th>
-													<th scope="col">ID</th>
-													<th class="tags-col" scope="col">Tags</th>
-													<th class="meta-col" scope="col">Metadata</th>
-													<th class="created-col" scope="col">Created At</th>
-													<th class="text-center" scope="col"></th>
-												</tr>
-											</thead>
-											<tbody>
-												{{ $thingID := .ThingID }}
-												{{ range $i, $u := .Users }}
-													{{ $disableButton := false }}
-													<tr>
-														<td>{{ $u.Name }}</td>
-														<td>
-															<div class="copy-con-container">
-																<a href="{{ printf "/users/%s" $u.ID }}">
-																	{{ $u.ID }}
-																</a>
-																<button
-																	class="copy-icon"
-																	onclick="copyToClipboard(this)"
-																>
-																	<i class="far fa-copy"></i>
-																</button>
-															</div>
-														</td>
-														<td class="tags-col">{{ toSlice $u.Tags }}</td>
-														<td class="meta-col">{{ toJSON $u.Metadata }}</td>
-														<td class="created-col">{{ $u.CreatedAt }}</td>
-														<td class="text-center">
-															<form
-																action="/things/{{ $thingID }}/unshare?item=things"
-																method="post"
-															>
-																<input
-																	type="hidden"
-																	name="userID"
-																	id="userID"
-																	value="{{ $u.ID }}"
-																/>
-																<input
-																	type="hidden"
-																	name="relation"
-																	id="relation"
-																	value="owner"
-																/>
-																<button
-																	type="submit"
-																	class="btn btn-sm"
-																	{{ if
-																		$disableButton
-																	}}
-																		disabled
-																	{{ end }}
-																>
-																	<i class="fas fa-trash-alt"></i>
-																</button>
-															</form>
-														</td>
-													</tr>
-												{{ end }}
-											</tbody>
-										</table>
-									</div>
-									{{ template "tablefooter" . }}
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
-			<script>
-				const userModal = new bootstrap.Modal(
-					document.getElementById("addUserModal"),
-				);
-				function openUserModal() {
-					userModal.show();
-				}
-				fetchIndividualEntity({
-					input: "userFilter",
-					itemSelect: "infiniteScroll",
-					item: "users",
-				});
-			</script>
-		</body>
-	</html>
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <a class="btn body-button" href="/things/{{ .ThingID }}" role="button">Thing</a>
+                  <a class="btn body-button" href="/things/{{ .ThingID }}/channels" role="button">
+                    Thing Channels
+                  </a>
+                </div>
+                <div class="table-responsive table-container">
+                  <div class="d-flex flex-row justify-content-between">
+                    <h4>Thing Users</h4>
+                    <button role="button" class="btn body-button" onclick="openUserModal()">
+                      <i class="fa-solid fa-plus fs-4"></i>
+                    </button>
+                    <!-- modal -->
+                    <div
+                      class="modal fade"
+                      id="addUserModal"
+                      tabindex="-1"
+                      aria-labelledby="addUserModalLabel"
+                      aria-hidden="true"
+                    >
+                      <div class="modal-dialog modal-dialog-centered">
+                        <div class="modal-content">
+                          <div class="modal-header">
+                            <h1 class="modal-title fs-5" id="addUserModalLabel">Share Thing</h1>
+                            <button
+                              type="button"
+                              class="btn-close"
+                              data-bs-dismiss="modal"
+                              aria-label="Close"
+                            ></button>
+                          </div>
+                          <form action="/things/{{ .ThingID }}/share?item=things" method="post">
+                            <div class="modal-body">
+                              <div class="mb-3">
+                                <label for="infiniteScroll" class="form-label">User ID</label>
+                                <input
+                                  type="text"
+                                  name="userFilter"
+                                  id="userFilter"
+                                  placeholder="Filter by User ID"
+                                />
+                                <select
+                                  class="form-select"
+                                  name="userID"
+                                  id="infiniteScroll"
+                                  size="5"
+                                  required
+                                >
+                                  <option disabled>select a User</option>
+                                </select>
+                              </div>
+                              <div class="mb-3">
+                                <label for="relation" class="form-label">Relation</label>
+                                <select
+                                  class="form-control"
+                                  name="relation"
+                                  id="relation"
+                                  aria-describedby="relationHelp"
+                                  multiple
+                                  required
+                                >
+                                  {{ range $r := .Relations }}
+                                    <option value="{{ $r }}">
+                                      {{ $r }}
+                                    </option>
+                                  {{ end }}
+                                </select>
+                                <div id="relationHelp" class="form-text">Select Relation.</div>
+                              </div>
+                              <div class="modal-footer">
+                                <button
+                                  type="button"
+                                  class="btn btn-secondary"
+                                  data-bs-dismiss="modal"
+                                >
+                                  Cancel
+                                </button>
+                                <button type="submit" class="btn btn-primary">Assign</button>
+                              </div>
+                            </div>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  {{ template "tableheader" . }}
+                  <div class="itemsTable">
+                    <table id="itemsTable" class="table">
+                      <thead>
+                        <tr>
+                          <th scope="col">Name</th>
+                          <th scope="col">ID</th>
+                          <th class="tags-col" scope="col">Tags</th>
+                          <th class="meta-col" scope="col">Metadata</th>
+                          <th class="created-col" scope="col">Created At</th>
+                          <th class="text-center" scope="col"></th>
+                        </tr>
+                      </thead>
+                      <tbody>
+                        {{ $thingID := .ThingID }}
+                        {{ range $i, $u := .Users }}
+                          {{ $disableButton := false }}
+                          <tr>
+                            <td>{{ $u.Name }}</td>
+                            <td>
+                              <div class="copy-con-container">
+                                <a href="{{ printf "/users/%s" $u.ID }}">
+                                  {{ $u.ID }}
+                                </a>
+                                <button class="copy-icon" onclick="copyToClipboard(this)">
+                                  <i class="far fa-copy"></i>
+                                </button>
+                              </div>
+                            </td>
+                            <td class="tags-col">{{ toSlice $u.Tags }}</td>
+                            <td class="meta-col">{{ toJSON $u.Metadata }}</td>
+                            <td class="created-col">{{ $u.CreatedAt }}</td>
+                            <td class="text-center">
+                              <form
+                                action="/things/{{ $thingID }}/unshare?item=things"
+                                method="post"
+                              >
+                                <input
+                                  type="hidden"
+                                  name="userID"
+                                  id="userID"
+                                  value="{{ $u.ID }}"
+                                />
+                                <input type="hidden" name="relation" id="relation" value="owner" />
+                                <button
+                                  type="submit"
+                                  class="btn btn-sm"
+                                  {{ if
+                                    $disableButton
+                                  }}
+                                    disabled
+                                  {{ end }}
+                                >
+                                  <i class="fas fa-trash-alt"></i>
+                                </button>
+                              </form>
+                            </td>
+                          </tr>
+                        {{ end }}
+                      </tbody>
+                    </table>
+                  </div>
+                  {{ template "tablefooter" . }}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
+      <script>
+        const userModal = new bootstrap.Modal(document.getElementById("addUserModal"));
+        function openUserModal() {
+          userModal.show();
+        }
+        fetchIndividualEntity({
+          input: "userFilter",
+          itemSelect: "infiniteScroll",
+          item: "users",
+        });
+      </script>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/updatepassword.html b/ui/web/template/updatepassword.html
index 36ce93d1c..858654b79 100644
--- a/ui/web/template/updatepassword.html
+++ b/ui/web/template/updatepassword.html
@@ -2,115 +2,108 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "updatePassword" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container mt-5 pt-5">
-					<div class="row">
-						<div class="login-card col-lg-4 p-md-5 mx-auto mt-5">
-							<div
-								class="row text-center mb-4 d-flex flex-column align-items-center"
-							>
-								<div class="login-header border-bottom pb-3 mb-5 mt-3">
-									<h2>Update Password</h2>
-								</div>
-								<form
-									class="row border-bottom pb-3 mb-3"
-									onsubmit="return submitUpdatePasswordForm()"
-								>
-									<div class="col-md-12">
-										<div class="row mb-3">
-											<div class="col-md-12 input-field">
-												<i class="fas fa-solid fa-lock"></i>
-												<input
-													class="p-3 w-100"
-													type="password"
-													name="oldpass"
-													id="oldpass"
-													placeholder="Old password"
-													required
-												/>
-												<div id="oldpassError" class="text-danger"></div>
-											</div>
-										</div>
-										<div class="row mb-3">
-											<div class="col-md-12 input-field">
-												<i class="fas fa-solid fa-lock"></i>
-												<input
-													class="p-3 w-100"
-													type="password"
-													name="newpass"
-													id="newpass"
-													placeholder="New password"
-													required
-												/>
-												<div id="newpassError" class="text-danger"></div>
-											</div>
-										</div>
-									</div>
-									<div class="col-md-12 d-grid py-3">
-										<button
-											type="submit"
-											class="login-btn py-3"
-											onclick="return validateForm()"
-										>
-											Submit
-										</button>
-									</div>
-								</form>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
-			<script>
-				function validateForm() {
-					var newpass = document.getElementById("newpass").value;
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container mt-5 pt-5">
+          <div class="row">
+            <div class="login-card col-lg-4 p-md-5 mx-auto mt-5">
+              <div class="row text-center mb-4 d-flex flex-column align-items-center">
+                <div class="login-header border-bottom pb-3 mb-5 mt-3">
+                  <h2>Update Password</h2>
+                </div>
+                <form
+                  class="row border-bottom pb-3 mb-3"
+                  onsubmit="return submitUpdatePasswordForm()"
+                >
+                  <div class="col-md-12">
+                    <div class="row mb-3">
+                      <div class="col-md-12 input-field">
+                        <i class="fas fa-solid fa-lock"></i>
+                        <input
+                          class="p-3 w-100"
+                          type="password"
+                          name="oldpass"
+                          id="oldpass"
+                          placeholder="Old password"
+                          required
+                        />
+                        <div id="oldpassError" class="text-danger"></div>
+                      </div>
+                    </div>
+                    <div class="row mb-3">
+                      <div class="col-md-12 input-field">
+                        <i class="fas fa-solid fa-lock"></i>
+                        <input
+                          class="p-3 w-100"
+                          type="password"
+                          name="newpass"
+                          id="newpass"
+                          placeholder="New password"
+                          required
+                        />
+                        <div id="newpassError" class="text-danger"></div>
+                      </div>
+                    </div>
+                  </div>
+                  <div class="col-md-12 d-grid py-3">
+                    <button type="submit" class="login-btn py-3" onclick="return validateForm()">
+                      Submit
+                    </button>
+                  </div>
+                </form>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
+      <script>
+        function validateForm() {
+          var newpass = document.getElementById("newpass").value;
 
-					newpassError.innerHTML = "";
-					var isValid = true;
+          newpassError.innerHTML = "";
+          var isValid = true;
 
-					if (newpass.length < 8) {
-						newpassError.innerHTML =
-							"Password must have a minimum of 8 characters!";
-						isValid = false;
-					}
-					return isValid;
-				}
+          if (newpass.length < 8) {
+            newpassError.innerHTML = "Password must have a minimum of 8 characters!";
+            isValid = false;
+          }
+          return isValid;
+        }
 
-				function submitUpdatePasswordForm() {
-					event.preventDefault();
-					var form = event.target;
-					fetch("/password", {
-						method: "POST",
-						body: new FormData(form),
-					})
-						.then((response) => {
-							if (response.status === 401) {
-								errorMessage = "invalid old password!";
-								showAlert(errorMessage);
-								return false;
-							} else {
-								form.reset();
-								window.location.href = "/login";
-								return true;
-							}
-						})
-						.catch((error) => {
-							console.error("error submitting password update form: ", error);
-							return false;
-						});
-				}
+        function submitUpdatePasswordForm() {
+          event.preventDefault();
+          var form = event.target;
+          fetch("/password", {
+            method: "POST",
+            body: new FormData(form),
+          })
+            .then((response) => {
+              if (response.status === 401) {
+                errorMessage = "invalid old password!";
+                showAlert(errorMessage);
+                return false;
+              } else {
+                form.reset();
+                window.location.href = "/login";
+                return true;
+              }
+            })
+            .catch((error) => {
+              console.error("error submitting password update form: ", error);
+              return false;
+            });
+        }
 
-				function showAlert(errorMessage) {
-					var loginError = document.getElementById("oldpassError");
-					loginError.innerHTML = errorMessage;
-				}
-			</script>
-		</body>
-	</html>
+        function showAlert(errorMessage) {
+          var loginError = document.getElementById("oldpassError");
+          loginError.innerHTML = errorMessage;
+        }
+      </script>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/user.html b/ui/web/template/user.html
index aea0349bb..e4ed0c3df 100644
--- a/ui/web/template/user.html
+++ b/ui/web/template/user.html
@@ -2,206 +2,150 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "user" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<a
-										href="/users/{{ .UserID }}/groups"
-										type="button"
-										class="btn body-button"
-									>
-										User Groups
-									</a>
-									<a
-										href="/users/{{ .UserID }}/things"
-										type="button"
-										class="btn body-button"
-									>
-										User Things
-									</a>
-									<a
-										href="/users/{{ .UserID }}/channels"
-										type="button"
-										class="btn body-button"
-									>
-										User Channels
-									</a>
-								</div>
-								<div class="table-responsive table-container">
-									<table id="itemsTable" class="table">
-										<thead>
-											<tr>
-												<th scope="row">USER</th>
-											</tr>
-										</thead>
-										<tbody>
-											{{ $disableButton := false }}
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <a href="/users/{{ .UserID }}/groups" type="button" class="btn body-button">
+                    User Groups
+                  </a>
+                  <a href="/users/{{ .UserID }}/things" type="button" class="btn body-button">
+                    User Things
+                  </a>
+                  <a href="/users/{{ .UserID }}/channels" type="button" class="btn body-button">
+                    User Channels
+                  </a>
+                </div>
+                <div class="table-responsive table-container">
+                  <table id="itemsTable" class="table">
+                    <thead>
+                      <tr>
+                        <th scope="row">USER</th>
+                      </tr>
+                    </thead>
+                    <tbody>
+                      {{ $disableButton := false }}
 
 
-											<tr>
-												<th>Name</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="name"
-												>
-													{{ .ViewedUser.Name }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														id="edit-name"
-														{{ if
-															$disableButton
-														}}
-															disabled
-														{{ end }}
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" id="save-name">
-															Save
-														</button>
-														<button class="cancel-btn" id="cancel-name">
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>ID</th>
-												<td>{{ .ViewedUser.ID }}</td>
-												<td></td>
-											</tr>
-											<tr>
-												<th>Owner</th>
-												<td>{{ .ViewedUser.Owner }}</td>
-												<td></td>
-											</tr>
-											<tr>
-												<th>Identity</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="identity"
-												>
-													{{ .ViewedUser.Credentials.Identity }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														id="edit-identity"
-														{{ if
-															$disableButton
-														}}
-															disabled
-														{{ end }}
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" id="save-identity">
-															Save
-														</button>
-														<button class="cancel-btn" id="cancel-identity">
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>Tags</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="tags"
-												>
-													{{ toSlice .ViewedUser.Tags }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														id="edit-tags"
-														{{ if
-															$disableButton
-														}}
-															disabled
-														{{ end }}
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" id="save-tags">
-															Save
-														</button>
-														<button class="cancel-btn" id="cancel-tags">
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-											<tr>
-												<th>Metadata</th>
-												<td
-													class="editable"
-													contenteditable="false"
-													data-field="metadata"
-												>
-													{{ toJSON .ViewedUser.Metadata }}
-												</td>
-												<td>
-													<button
-														class="edit-btn"
-														id="edit-metadata"
-														{{ if
-															$disableButton
-														}}
-															disabled
-														{{ end }}
-													>
-														<i class="fas fa-pencil-alt"></i>
-													</button>
-													<div
-														class="save-cancel-buttons"
-														style="display: none"
-													>
-														<button class="save-btn" id="save-metadata">
-															Save
-														</button>
-														<button class="cancel-btn" id="cancel-metadata">
-															Cancel
-														</button>
-													</div>
-												</td>
-											</tr>
-										</tbody>
-									</table>
-									<div id="error-message" class="text-danger"></div>
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
+                      <tr>
+                        <th>Name</th>
+                        <td class="editable" contenteditable="false" data-field="name">
+                          {{ .ViewedUser.Name }}
+                        </td>
+                        <td>
+                          <button
+                            class="edit-btn"
+                            id="edit-name"
+                            {{ if
+                              $disableButton
+                            }}
+                              disabled
+                            {{ end }}
+                          >
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" id="save-name">Save</button>
+                            <button class="cancel-btn" id="cancel-name">Cancel</button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>ID</th>
+                        <td>{{ .ViewedUser.ID }}</td>
+                        <td></td>
+                      </tr>
+                      <tr>
+                        <th>Owner</th>
+                        <td>{{ .ViewedUser.Owner }}</td>
+                        <td></td>
+                      </tr>
+                      <tr>
+                        <th>Identity</th>
+                        <td class="editable" contenteditable="false" data-field="identity">
+                          {{ .ViewedUser.Credentials.Identity }}
+                        </td>
+                        <td>
+                          <button
+                            class="edit-btn"
+                            id="edit-identity"
+                            {{ if
+                              $disableButton
+                            }}
+                              disabled
+                            {{ end }}
+                          >
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" id="save-identity">Save</button>
+                            <button class="cancel-btn" id="cancel-identity">Cancel</button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>Tags</th>
+                        <td class="editable" contenteditable="false" data-field="tags">
+                          {{ toSlice .ViewedUser.Tags }}
+                        </td>
+                        <td>
+                          <button
+                            class="edit-btn"
+                            id="edit-tags"
+                            {{ if
+                              $disableButton
+                            }}
+                              disabled
+                            {{ end }}
+                          >
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" id="save-tags">Save</button>
+                            <button class="cancel-btn" id="cancel-tags">Cancel</button>
+                          </div>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>Metadata</th>
+                        <td class="editable" contenteditable="false" data-field="metadata">
+                          {{ toJSON .ViewedUser.Metadata }}
+                        </td>
+                        <td>
+                          <button
+                            class="edit-btn"
+                            id="edit-metadata"
+                            {{ if
+                              $disableButton
+                            }}
+                              disabled
+                            {{ end }}
+                          >
+                            <i class="fas fa-pencil-alt"></i>
+                          </button>
+                          <div class="save-cancel-buttons" style="display: none">
+                            <button class="save-btn" id="save-metadata">Save</button>
+                            <button class="cancel-btn" id="cancel-metadata">Cancel</button>
+                          </div>
+                        </td>
+                      </tr>
+                    </tbody>
+                  </table>
+                  <div id="error-message" class="text-danger"></div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
     <script>
 		attachEditRowListener(
 			{
@@ -217,6 +161,6 @@
 			}
 		);
     </script>
-		</body>
-	</html>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/userchannels.html b/ui/web/template/userchannels.html
index 0be2dd44c..53a20ef23 100644
--- a/ui/web/template/userchannels.html
+++ b/ui/web/template/userchannels.html
@@ -2,520 +2,469 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "userchannels" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<a
-										href="/users/{{ .UserID }}"
-										type="button"
-										class="btn body-button"
-									>
-										User
-									</a>
-									<a
-										href="/users/{{ .UserID }}/groups"
-										type="button"
-										class="btn body-button"
-									>
-										User Groups
-									</a>
-									<a
-										href="/users/{{ .UserID }}/things"
-										type="button"
-										class="btn body-button"
-									>
-										View User things
-									</a>
-								</div>
-								<div class="table-responsive table-container">
-									<div class="d-flex flex-row justify-content-between">
-										<h4>User Channels</h4>
-										<button
-											role="button"
-											class="btn body-button"
-											onclick="openChannelModal()"
-										>
-											<i class="fa-solid fa-plus fs-4"></i>
-										</button>
-										<!-- modal -->
-										<div
-											class="modal fade"
-											id="addChannelModal"
-											tabindex="-1"
-											aria-labelledby="addChannelModalLabel"
-											aria-hidden="true"
-										>
-											<div class="modal-dialog modal-dialog-centered">
-												<div class="modal-content">
-													<div class="modal-header">
-														<h1
-															class="modal-title fs-5"
-															id="addChannelModalLabel"
-														>
-															Add Channel
-														</h1>
-														<button
-															type="button"
-															class="btn-close"
-															data-bs-dismiss="modal"
-															aria-label="Close"
-														></button>
-													</div>
-													<form
-														action="/users/{{ .UserID }}/channels/assign?item=users"
-														method="post"
-													>
-														<div class="modal-body">
-															<div class="mb-3">
-																<label for="infiniteScroll" class="form-label">
-																	Channel ID
-																</label>
-																<input
-																	type="text"
-																	name="channelFilter"
-																	id="channelFilter"
-																	placeholder="Filter by Channel ID"
-																/>
-																<select
-																	class="form-select"
-																	name="channelID"
-																	id="infiniteScroll"
-																	size="5"
-																	required
-																>
-																	<option disabled>select a channel</option>
-																</select>
-															</div>
-															<div class="mb-3">
-																<label for="relation" class="form-label">
-																	Relation
-																</label>
-																<select
-																	class="form-control"
-																	name="relation"
-																	id="relation"
-																	aria-describedby="relationHelp"
-																	multiple
-																	required
-																>
-																	{{ range $i, $r := .Relations }}
-																		<option value="{{ $r }}">
-																			{{ $r }}
-																		</option>
-																	{{ end }}
-																</select>
-																<div id="relationHelp" class="form-text">
-																	Select Relation.
-																</div>
-															</div>
-															<div class="modal-footer">
-																<button
-																	type="button"
-																	class="btn btn-secondary"
-																	data-bs-dismiss="modal"
-																>
-																	Cancel
-																</button>
-																<button type="submit" class="btn btn-primary">
-																	Assign
-																</button>
-															</div>
-														</div>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <a href="/users/{{ .UserID }}" type="button" class="btn body-button">User</a>
+                  <a href="/users/{{ .UserID }}/groups" type="button" class="btn body-button">
+                    User Groups
+                  </a>
+                  <a href="/users/{{ .UserID }}/things" type="button" class="btn body-button">
+                    View User things
+                  </a>
+                </div>
+                <div class="table-responsive table-container">
+                  <div class="d-flex flex-row justify-content-between">
+                    <h4>User Channels</h4>
+                    <button role="button" class="btn body-button" onclick="openChannelModal()">
+                      <i class="fa-solid fa-plus fs-4"></i>
+                    </button>
+                    <!-- modal -->
+                    <div
+                      class="modal fade"
+                      id="addChannelModal"
+                      tabindex="-1"
+                      aria-labelledby="addChannelModalLabel"
+                      aria-hidden="true"
+                    >
+                      <div class="modal-dialog modal-dialog-centered">
+                        <div class="modal-content">
+                          <div class="modal-header">
+                            <h1 class="modal-title fs-5" id="addChannelModalLabel">Add Channel</h1>
+                            <button
+                              type="button"
+                              class="btn-close"
+                              data-bs-dismiss="modal"
+                              aria-label="Close"
+                            ></button>
+                          </div>
+                          <form
+                            action="/users/{{ .UserID }}/channels/assign?item=users"
+                            method="post"
+                          >
+                            <div class="modal-body">
+                              <div class="mb-3">
+                                <label for="infiniteScroll" class="form-label">Channel ID</label>
+                                <input
+                                  type="text"
+                                  name="channelFilter"
+                                  id="channelFilter"
+                                  placeholder="Filter by Channel ID"
+                                />
+                                <select
+                                  class="form-select"
+                                  name="channelID"
+                                  id="infiniteScroll"
+                                  size="5"
+                                  required
+                                >
+                                  <option disabled>select a channel</option>
+                                </select>
+                              </div>
+                              <div class="mb-3">
+                                <label for="relation" class="form-label">Relation</label>
+                                <select
+                                  class="form-control"
+                                  name="relation"
+                                  id="relation"
+                                  aria-describedby="relationHelp"
+                                  multiple
+                                  required
+                                >
+                                  {{ range $i, $r := .Relations }}
+                                    <option value="{{ $r }}">
+                                      {{ $r }}
+                                    </option>
+                                  {{ end }}
+                                </select>
+                                <div id="relationHelp" class="form-text">Select Relation.</div>
+                              </div>
+                              <div class="modal-footer">
+                                <button
+                                  type="button"
+                                  class="btn btn-secondary"
+                                  data-bs-dismiss="modal"
+                                >
+                                  Cancel
+                                </button>
+                                <button type="submit" class="btn btn-primary">Assign</button>
+                              </div>
+                            </div>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
 
-									<ul class="nav nav-tabs" id="roleTab" role="tablist">
-										<li class="nav-item" role="presentation">
-											{{ $tabActive := "" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="view-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#view-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="view-tab-pane"
-												aria-selected="true"
-												onclick="openTab('')"
-											>
-												All
-											</button>
-										</li>
-										<li class="nav-item" role="presentation">
-											{{ $tabActive = "admin" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="admin-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#admin-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="admin-tab-pane"
-												aria-selected="true"
-												onclick="openTab('admin')"
-											>
-												Admin
-											</button>
-										</li>
-										<li class="nav-item" role="presentation">
-											{{ $tabActive = "editor" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="editor-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#editor-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="editor-tab-pane"
-												aria-selected="false"
-												onclick="openTab('editor')"
-											>
-												Editor
-											</button>
-										</li>
-										<li class="nav-item" role="presentation">
-											{{ $tabActive = "viewer" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="viewer-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#viewer-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="viewer-tab-pane"
-												aria-selected="false"
-												onclick="openTab('viewer')"
-											>
-												Viewer
-											</button>
-										</li>
-									</ul>
-									<div class="tab-content mt-3" id="roleTabContent">
-										{{ $userID := .UserID }}
-										<div
-											class="tab-pane active"
-											id="view-tab-pane"
-											role="tabpanel"
-											aria-labelledby="view-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table class="table" id="itemsTable">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="desc-col" scope="col">Description</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ range $i, $c := .Channels }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $c.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/channels/%s" $c.ID }}">
-																			{{ $c.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="desc-col">{{ $c.Description }}</td>
-																<td class="meta-col">
-																	{{ toJSON $c.Metadata }}
-																</td>
-																<td class="created-col">{{ $c.CreatedAt }}</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-										<div
-											class="tab-pane"
-											id="admin-tab-pane"
-											role="tabpanel"
-											aria-labelledby="admin-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table class="table" id="itemsTable">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="desc-col" scope="col">Description</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-															<th class="text-center" scope="col"></th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ range $i, $c := .Channels }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $c.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/channels/%s" $c.ID }}">
-																			{{ $c.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="desc-col">{{ $c.Description }}</td>
-																<td class="meta-col">
-																	{{ toJSON $c.Metadata }}
-																</td>
-																<td class="created-col">{{ $c.CreatedAt }}</td>
-																<td class="text-center">
-																	<form
-																		action="/users/{{ $userID }}/channels/unassign?item=users"
-																		method="post"
-																	>
-																		<input
-																			type="hidden"
-																			name="channelID"
-																			id="channelID"
-																			value="{{ $c.ID }}"
-																		/>
-																		<input
-																			type="hidden"
-																			name="relation"
-																			id="relation"
-																			value="admin"
-																		/>
-																		<button
-																			type="submit"
-																			class="btn btn-sm"
-																			{{ if
-																				$disableButton
-																			}}
-																				disabled
-																			{{ end }}
-																		>
-																			<i class="fas fa-trash-alt"></i>
-																		</button>
-																	</form>
-																</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-										<div
-											class="tab-pane "
-											id="editor-tab-pane"
-											role="tabpanel"
-											aria-labelledby="editor-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table class="table" id="itemsTable">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="desc-col" scope="col">Description</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-															<th class="text-center" scope="col"></th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ range $i, $c := .Channels }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $c.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/channels/%s" $c.ID }}">
-																			{{ $c.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="desc-col">{{ $c.Description }}</td>
-																<td class="meta-col">
-																	{{ toJSON $c.Metadata }}
-																</td>
-																<td class="created-col">{{ $c.CreatedAt }}</td>
-																<td class="text-center">
-																	<form
-																		action="/users/{{ $userID }}/channels/unassign?item=users"
-																		method="post"
-																	>
-																		<input
-																			type="hidden"
-																			name="channelID"
-																			id="channelID"
-																			value="{{ $c.ID }}"
-																		/>
-																		<input
-																			type="hidden"
-																			name="relation"
-																			id="relation"
-																			value="editor"
-																		/>
-																		<button
-																			type="submit"
-																			class="btn btn-sm"
-																			{{ if
-																				$disableButton
-																			}}
-																				disabled
-																			{{ end }}
-																		>
-																			<i class="fas fa-trash-alt"></i>
-																		</button>
-																	</form>
-																</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-										<div
-											class="tab-pane"
-											id="viewer-tab-pane"
-											role="tabpanel"
-											aria-labelledby="viewer-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table class="table" id="itemsTable">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="desc-col" scope="col">Description</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-															<th class="text-center" scope="col"></th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ range $i, $c := .Channels }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $c.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/channels/%s" $c.ID }}">
-																			{{ $c.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="desc-col">{{ $c.Description }}</td>
-																<td class="meta-col">
-																	{{ toJSON $c.Metadata }}
-																</td>
-																<td class="created-col">{{ $c.CreatedAt }}</td>
-																<td class="text-center">
-																	<form
-																		action="/users/{{ $userID }}/channels/unassign?item=users"
-																		method="post"
-																	>
-																		<input
-																			type="hidden"
-																			name="channelID"
-																			id="channelID"
-																			value="{{ $c.ID }}"
-																		/>
-																		<input
-																			type="hidden"
-																			name="relation"
-																			id="relation"
-																			value="viewer"
-																		/>
-																		<button
-																			type="submit"
-																			class="btn btn-sm"
-																			{{ if
-																				$disableButton
-																			}}
-																				disabled
-																			{{ end }}
-																		>
-																			<i class="fas fa-trash-alt"></i>
-																		</button>
-																	</form>
-																</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-									</div>
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
+                  <ul class="nav nav-tabs" id="roleTab" role="tablist">
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive := "" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="view-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#view-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="view-tab-pane"
+                        aria-selected="true"
+                        onclick="openTab('')"
+                      >
+                        All
+                      </button>
+                    </li>
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive = "admin" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="admin-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#admin-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="admin-tab-pane"
+                        aria-selected="true"
+                        onclick="openTab('admin')"
+                      >
+                        Admin
+                      </button>
+                    </li>
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive = "editor" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="editor-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#editor-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="editor-tab-pane"
+                        aria-selected="false"
+                        onclick="openTab('editor')"
+                      >
+                        Editor
+                      </button>
+                    </li>
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive = "viewer" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="viewer-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#viewer-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="viewer-tab-pane"
+                        aria-selected="false"
+                        onclick="openTab('viewer')"
+                      >
+                        Viewer
+                      </button>
+                    </li>
+                  </ul>
+                  <div class="tab-content mt-3" id="roleTabContent">
+                    {{ $userID := .UserID }}
+                    <div
+                      class="tab-pane active"
+                      id="view-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="view-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table class="table" id="itemsTable">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="desc-col" scope="col">Description</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ range $i, $c := .Channels }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $c.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/channels/%s" $c.ID }}">
+                                      {{ $c.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="desc-col">{{ $c.Description }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $c.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $c.CreatedAt }}</td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                    <div
+                      class="tab-pane"
+                      id="admin-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="admin-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table class="table" id="itemsTable">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="desc-col" scope="col">Description</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                              <th class="text-center" scope="col"></th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ range $i, $c := .Channels }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $c.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/channels/%s" $c.ID }}">
+                                      {{ $c.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="desc-col">{{ $c.Description }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $c.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $c.CreatedAt }}</td>
+                                <td class="text-center">
+                                  <form
+                                    action="/users/{{ $userID }}/channels/unassign?item=users"
+                                    method="post"
+                                  >
+                                    <input
+                                      type="hidden"
+                                      name="channelID"
+                                      id="channelID"
+                                      value="{{ $c.ID }}"
+                                    />
+                                    <input
+                                      type="hidden"
+                                      name="relation"
+                                      id="relation"
+                                      value="admin"
+                                    />
+                                    <button
+                                      type="submit"
+                                      class="btn btn-sm"
+                                      {{ if
+                                        $disableButton
+                                      }}
+                                        disabled
+                                      {{ end }}
+                                    >
+                                      <i class="fas fa-trash-alt"></i>
+                                    </button>
+                                  </form>
+                                </td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                    <div
+                      class="tab-pane "
+                      id="editor-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="editor-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table class="table" id="itemsTable">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="desc-col" scope="col">Description</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                              <th class="text-center" scope="col"></th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ range $i, $c := .Channels }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $c.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/channels/%s" $c.ID }}">
+                                      {{ $c.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="desc-col">{{ $c.Description }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $c.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $c.CreatedAt }}</td>
+                                <td class="text-center">
+                                  <form
+                                    action="/users/{{ $userID }}/channels/unassign?item=users"
+                                    method="post"
+                                  >
+                                    <input
+                                      type="hidden"
+                                      name="channelID"
+                                      id="channelID"
+                                      value="{{ $c.ID }}"
+                                    />
+                                    <input
+                                      type="hidden"
+                                      name="relation"
+                                      id="relation"
+                                      value="editor"
+                                    />
+                                    <button
+                                      type="submit"
+                                      class="btn btn-sm"
+                                      {{ if
+                                        $disableButton
+                                      }}
+                                        disabled
+                                      {{ end }}
+                                    >
+                                      <i class="fas fa-trash-alt"></i>
+                                    </button>
+                                  </form>
+                                </td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                    <div
+                      class="tab-pane"
+                      id="viewer-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="viewer-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table class="table" id="itemsTable">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="desc-col" scope="col">Description</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                              <th class="text-center" scope="col"></th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ range $i, $c := .Channels }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $c.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/channels/%s" $c.ID }}">
+                                      {{ $c.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="desc-col">{{ $c.Description }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $c.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $c.CreatedAt }}</td>
+                                <td class="text-center">
+                                  <form
+                                    action="/users/{{ $userID }}/channels/unassign?item=users"
+                                    method="post"
+                                  >
+                                    <input
+                                      type="hidden"
+                                      name="channelID"
+                                      id="channelID"
+                                      value="{{ $c.ID }}"
+                                    />
+                                    <input
+                                      type="hidden"
+                                      name="relation"
+                                      id="relation"
+                                      value="viewer"
+                                    />
+                                    <button
+                                      type="submit"
+                                      class="btn btn-sm"
+                                      {{ if
+                                        $disableButton
+                                      }}
+                                        disabled
+                                      {{ end }}
+                                    >
+                                      <i class="fas fa-trash-alt"></i>
+                                    </button>
+                                  </form>
+                                </td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
 			<script>
 				const channelModal = new bootstrap.Modal(
 					document.getElementById("addChannelModal"),
@@ -530,18 +479,18 @@ <h4>User Channels</h4>
 					item: "channels",
 				});
 
-                function openTab(relation) {
+        function openTab(relation) {
 					event.preventDefault();
-                    var userID = '{{.UserID}}';
-                    fetch(`/users/${userID}/channels?relation=${relation}`, {
-                        method: "GET",
-                    })
-                        .then((response) => {
+					var userID = '{{.UserID}}';
+					fetch(`/users/${userID}/channels?relation=${relation}`, {
+							method: "GET",
+						})
+						.then((response) => {
 
-                        })
-                        .catch((error) => console.error("Error:", error));
+						})
+						.catch((error) => console.error("Error:", error));
 				}
 			</script>
-		</body>
-	</html>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/usergroups.html b/ui/web/template/usergroups.html
index 16f9f3cd5..30979fdb5 100644
--- a/ui/web/template/usergroups.html
+++ b/ui/web/template/usergroups.html
@@ -2,521 +2,470 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "usergroups" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<a
-										href="/users/{{ .UserID }}"
-										type="button"
-										class="btn body-button"
-									>
-										User
-									</a>
-									<a
-										href="/users/{{ .UserID }}/things"
-										type="button"
-										class="btn body-button"
-									>
-										User Things
-									</a>
-									<a
-										href="/users/{{ .UserID }}/channels"
-										type="button"
-										class="btn body-button"
-									>
-										User Channels
-									</a>
-								</div>
-								<div class="table-responsive table-container">
-									<div class="d-flex flex-row justify-content-between">
-										<h4>User Groups</h4>
-										<button
-											role="button"
-											class="btn body-button"
-											onclick="openGroupModal()"
-										>
-											<i class="fa-solid fa-plus fs-4"></i>
-										</button>
-										<!-- modal -->
-										<div
-											class="modal fade"
-											id="addGroupModal"
-											tabindex="-1"
-											aria-labelledby="addGroupModalLabel"
-											aria-hidden="true"
-										>
-											<div class="modal-dialog modal-dialog-centered">
-												<div class="modal-content">
-													<div class="modal-header">
-														<h1
-															class="modal-title fs-5"
-															id="addGroupModalLabel"
-														>
-															Add Group
-														</h1>
-														<button
-															type="button"
-															class="btn-close"
-															data-bs-dismiss="modal"
-															aria-label="Close"
-														></button>
-													</div>
-													<form
-														action="/users/{{ .UserID }}/groups/assign?item=users"
-														method="post"
-													>
-														<div class="modal-body">
-															<div class="mb-3">
-																<label for="infiniteScroll" class="form-label">
-																	Group ID
-																</label>
-																<input
-																	type="text"
-																	name="groupFilter"
-																	id="groupFilter"
-																	placeholder="Filter by Group ID"
-																/>
-																<select
-																	class="form-select"
-																	name="groupID"
-																	id="infiniteScroll"
-																	size="5"
-																	required
-																>
-																	<option disabled>select a group</option>
-																</select>
-															</div>
-															<div class="mb-3">
-																<label for="relation" class="form-label">
-																	Relation
-																</label>
-																<select
-																	class="form-control"
-																	name="relation"
-																	id="relation"
-																	aria-describedby="relationHelp"
-																	multiple
-																	required
-																>
-																	{{ range $i, $r := .Relations }}
-																		<option value="{{ $r }}">
-																			{{ $r }}
-																		</option>
-																	{{ end }}
-																</select>
-																<div id="relationHelp" class="form-text">
-																	Select Relation.
-																</div>
-															</div>
-															<div class="modal-footer">
-																<button
-																	type="button"
-																	class="btn btn-secondary"
-																	data-bs-dismiss="modal"
-																>
-																	Cancel
-																</button>
-																<button type="submit" class="btn btn-primary">
-																	Assign
-																</button>
-															</div>
-														</div>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <a href="/users/{{ .UserID }}" type="button" class="btn body-button">User</a>
+                  <a href="/users/{{ .UserID }}/things" type="button" class="btn body-button">
+                    User Things
+                  </a>
+                  <a href="/users/{{ .UserID }}/channels" type="button" class="btn body-button">
+                    User Channels
+                  </a>
+                </div>
+                <div class="table-responsive table-container">
+                  <div class="d-flex flex-row justify-content-between">
+                    <h4>User Groups</h4>
+                    <button role="button" class="btn body-button" onclick="openGroupModal()">
+                      <i class="fa-solid fa-plus fs-4"></i>
+                    </button>
+                    <!-- modal -->
+                    <div
+                      class="modal fade"
+                      id="addGroupModal"
+                      tabindex="-1"
+                      aria-labelledby="addGroupModalLabel"
+                      aria-hidden="true"
+                    >
+                      <div class="modal-dialog modal-dialog-centered">
+                        <div class="modal-content">
+                          <div class="modal-header">
+                            <h1 class="modal-title fs-5" id="addGroupModalLabel">Add Group</h1>
+                            <button
+                              type="button"
+                              class="btn-close"
+                              data-bs-dismiss="modal"
+                              aria-label="Close"
+                            ></button>
+                          </div>
+                          <form
+                            action="/users/{{ .UserID }}/groups/assign?item=users"
+                            method="post"
+                          >
+                            <div class="modal-body">
+                              <div class="mb-3">
+                                <label for="infiniteScroll" class="form-label">Group ID</label>
+                                <input
+                                  type="text"
+                                  name="groupFilter"
+                                  id="groupFilter"
+                                  placeholder="Filter by Group ID"
+                                />
+                                <select
+                                  class="form-select"
+                                  name="groupID"
+                                  id="infiniteScroll"
+                                  size="5"
+                                  required
+                                >
+                                  <option disabled>select a group</option>
+                                </select>
+                              </div>
+                              <div class="mb-3">
+                                <label for="relation" class="form-label">Relation</label>
+                                <select
+                                  class="form-control"
+                                  name="relation"
+                                  id="relation"
+                                  aria-describedby="relationHelp"
+                                  multiple
+                                  required
+                                >
+                                  {{ range $i, $r := .Relations }}
+                                    <option value="{{ $r }}">
+                                      {{ $r }}
+                                    </option>
+                                  {{ end }}
+                                </select>
+                                <div id="relationHelp" class="form-text">Select Relation.</div>
+                              </div>
+                              <div class="modal-footer">
+                                <button
+                                  type="button"
+                                  class="btn btn-secondary"
+                                  data-bs-dismiss="modal"
+                                >
+                                  Cancel
+                                </button>
+                                <button type="submit" class="btn btn-primary">Assign</button>
+                              </div>
+                            </div>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
 
-									<ul class="nav nav-tabs" id="roleTab" role="tablist">
-										<li class="nav-item" role="presentation">
-											{{ $tabActive := "" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="view-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#view-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="view-tab-pane"
-												aria-selected="true"
-												onclick="openTab('')"
-											>
-												All
-											</button>
-										</li>
-										<li class="nav-item" role="presentation">
-											{{ $tabActive = "admin" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="admin-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#admin-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="admin-tab-pane"
-												aria-selected="true"
-												onclick="openTab('admin')"
-											>
-												Admin
-											</button>
-										</li>
-										<li class="nav-item" role="presentation">
-											{{ $tabActive = "editor" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="editor-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#editor-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="editor-tab-pane"
-												aria-selected="false"
-												onclick="openTab('editor')"
-											>
-												Editor
-											</button>
-										</li>
-										<li class="nav-item" role="presentation">
-											{{ $tabActive = "viewer" }}
-											<button
-												class="nav-link {{ if eq .TabActive $tabActive }}
-													active
-												{{ end }}"
-												id="viewer-tab"
-												data-bs-toggle="tab"
-												data-bs-target="#viewer-tab-pane"
-												type="button"
-												role="tab"
-												aria-controls="viewer-tab-pane"
-												aria-selected="false"
-												onclick="openTab('viewer')"
-											>
-												Viewer
-											</button>
-										</li>
-									</ul>
-									<div class="tab-content mt-3" id="roleTabContent">
-										{{ $userID := .UserID }}
-										<div
-											class="tab-pane active"
-											id="view-tab-pane"
-											role="tabpanel"
-											aria-labelledby="view-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table class="table" id="itemsTable">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="desc-col" scope="col">Description</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ range $i, $g := .Groups }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $g.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/groups/%s" $g.ID }}">
-																			{{ $g.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="desc-col">{{ $g.Description }}</td>
-																<td class="meta-col">
-																	{{ toJSON $g.Metadata }}
-																</td>
-																<td class="created-col">{{ $g.CreatedAt }}</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-										<div
-											class="tab-pane"
-											id="admin-tab-pane"
-											role="tabpanel"
-											aria-labelledby="admin-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table class="table" id="itemsTable">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="desc-col" scope="col">Description</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-															<th class="text-center" scope="col"></th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ range $i, $g := .Groups }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $g.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/groups/%s" $g.ID }}">
-																			{{ $g.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="desc-col">{{ $g.Description }}</td>
-																<td class="meta-col">
-																	{{ toJSON $g.Metadata }}
-																</td>
-																<td class="created-col">{{ $g.CreatedAt }}</td>
-																<td class="text-center">
-																	<form
-																		action="/users/{{ $userID }}/groups/unassign?item=users"
-																		method="post"
-																	>
-																		<input
-																			type="hidden"
-																			name="groupID"
-																			id="groupID"
-																			value="{{ $g.ID }}"
-																		/>
-																		<input
-																			type="hidden"
-																			name="relation"
-																			id="relation"
-																			value="admin"
-																		/>
-																		<button
-																			type="submit"
-																			class="btn btn-sm"
-																			{{ if
-																				$disableButton
-																			}}
-																				disabled
-																			{{ end }}
-																		>
-																			<i class="fas fa-trash-alt"></i>
-																		</button>
-																	</form>
-																</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-										<div
-											class="tab-pane "
-											id="editor-tab-pane"
-											role="tabpanel"
-											aria-labelledby="editor-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table class="table" id="itemsTable">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="desc-col" scope="col">Description</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-															<th class="text-center" scope="col"></th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ range $i, $g := .Groups }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $g.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/groups/%s" $g.ID }}">
-																			{{ $g.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="desc-col">{{ $g.Description }}</td>
-																<td class="meta-col">
-																	{{ toJSON $g.Metadata }}
-																</td>
-																<td class="created-col">{{ $g.CreatedAt }}</td>
-																<td class="text-center">
-																	<form
-																		action="/users/{{ $userID }}/groups/unassign?item=users"
-																		method="post"
-																	>
-																		<input
-																			type="hidden"
-																			name="groupID"
-																			id="groupID"
-																			value="{{ $g.ID }}"
-																		/>
-																		<input
-																			type="hidden"
-																			name="relation"
-																			id="relation"
-																			value="editor"
-																		/>
-																		<button
-																			type="submit"
-																			class="btn btn-sm"
-																			{{ if
-																				$disableButton
-																			}}
-																				disabled
-																			{{ end }}
-																		>
-																			<i class="fas fa-trash-alt"></i>
-																		</button>
-																	</form>
-																</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-										<div
-											class="tab-pane"
-											id="viewer-tab-pane"
-											role="tabpanel"
-											aria-labelledby="viewer-tab"
-											tabindex="0"
-										>
-											{{ template "tableheader" . }}
-											<div class="itemsTable">
-												<table class="table" id="itemsTable">
-													<thead>
-														<tr>
-															<th scope="col">Name</th>
-															<th scope="col">ID</th>
-															<th class="desc-col" scope="col">Description</th>
-															<th class="meta-col" scope="col">Metadata</th>
-															<th class="created-col" scope="col">
-																Created At
-															</th>
-															<th class="text-center" scope="col"></th>
-														</tr>
-													</thead>
-													<tbody>
-														{{ $userID := .UserID }}
-														{{ range $i, $g := .Groups }}
-															{{ $disableButton := false }}
-															<tr>
-																<td>{{ $g.Name }}</td>
-																<td>
-																	<div class="copy-con-container">
-																		<a href="{{ printf "/groups/%s" $g.ID }}">
-																			{{ $g.ID }}
-																		</a>
-																		<button
-																			class="copy-icon"
-																			onclick="copyToClipboard(this)"
-																		>
-																			<i class="far fa-copy"></i>
-																		</button>
-																	</div>
-																</td>
-																<td class="desc-col">{{ $g.Description }}</td>
-																<td class="meta-col">
-																	{{ toJSON $g.Metadata }}
-																</td>
-																<td class="created-col">{{ $g.CreatedAt }}</td>
-																<td class="text-center">
-																	<form
-																		action="/users/{{ $userID }}/groups/unassign?item=users"
-																		method="post"
-																	>
-																		<input
-																			type="hidden"
-																			name="groupID"
-																			id="groupID"
-																			value="{{ $g.ID }}"
-																		/>
-																		<input
-																			type="hidden"
-																			name="relation"
-																			id="relation"
-																			value="viewer"
-																		/>
-																		<button
-																			type="submit"
-																			class="btn btn-sm"
-																			{{ if
-																				$disableButton
-																			}}
-																				disabled
-																			{{ end }}
-																		>
-																			<i class="fas fa-trash-alt"></i>
-																		</button>
-																	</form>
-																</td>
-															</tr>
-														{{ end }}
-													</tbody>
-												</table>
-											</div>
-											{{ template "tablefooter" . }}
-										</div>
-									</div>
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
+                  <ul class="nav nav-tabs" id="roleTab" role="tablist">
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive := "" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="view-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#view-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="view-tab-pane"
+                        aria-selected="true"
+                        onclick="openTab('')"
+                      >
+                        All
+                      </button>
+                    </li>
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive = "admin" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="admin-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#admin-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="admin-tab-pane"
+                        aria-selected="true"
+                        onclick="openTab('admin')"
+                      >
+                        Admin
+                      </button>
+                    </li>
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive = "editor" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="editor-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#editor-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="editor-tab-pane"
+                        aria-selected="false"
+                        onclick="openTab('editor')"
+                      >
+                        Editor
+                      </button>
+                    </li>
+                    <li class="nav-item" role="presentation">
+                      {{ $tabActive = "viewer" }}
+                      <button
+                        class="nav-link {{ if eq .TabActive $tabActive }}
+                          active
+                        {{ end }}"
+                        id="viewer-tab"
+                        data-bs-toggle="tab"
+                        data-bs-target="#viewer-tab-pane"
+                        type="button"
+                        role="tab"
+                        aria-controls="viewer-tab-pane"
+                        aria-selected="false"
+                        onclick="openTab('viewer')"
+                      >
+                        Viewer
+                      </button>
+                    </li>
+                  </ul>
+                  <div class="tab-content mt-3" id="roleTabContent">
+                    {{ $userID := .UserID }}
+                    <div
+                      class="tab-pane active"
+                      id="view-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="view-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table class="table" id="itemsTable">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="desc-col" scope="col">Description</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ range $i, $g := .Groups }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $g.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/groups/%s" $g.ID }}">
+                                      {{ $g.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="desc-col">{{ $g.Description }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $g.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $g.CreatedAt }}</td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                    <div
+                      class="tab-pane"
+                      id="admin-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="admin-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table class="table" id="itemsTable">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="desc-col" scope="col">Description</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                              <th class="text-center" scope="col"></th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ range $i, $g := .Groups }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $g.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/groups/%s" $g.ID }}">
+                                      {{ $g.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="desc-col">{{ $g.Description }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $g.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $g.CreatedAt }}</td>
+                                <td class="text-center">
+                                  <form
+                                    action="/users/{{ $userID }}/groups/unassign?item=users"
+                                    method="post"
+                                  >
+                                    <input
+                                      type="hidden"
+                                      name="groupID"
+                                      id="groupID"
+                                      value="{{ $g.ID }}"
+                                    />
+                                    <input
+                                      type="hidden"
+                                      name="relation"
+                                      id="relation"
+                                      value="admin"
+                                    />
+                                    <button
+                                      type="submit"
+                                      class="btn btn-sm"
+                                      {{ if
+                                        $disableButton
+                                      }}
+                                        disabled
+                                      {{ end }}
+                                    >
+                                      <i class="fas fa-trash-alt"></i>
+                                    </button>
+                                  </form>
+                                </td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                    <div
+                      class="tab-pane "
+                      id="editor-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="editor-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table class="table" id="itemsTable">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="desc-col" scope="col">Description</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                              <th class="text-center" scope="col"></th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ range $i, $g := .Groups }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $g.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/groups/%s" $g.ID }}">
+                                      {{ $g.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="desc-col">{{ $g.Description }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $g.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $g.CreatedAt }}</td>
+                                <td class="text-center">
+                                  <form
+                                    action="/users/{{ $userID }}/groups/unassign?item=users"
+                                    method="post"
+                                  >
+                                    <input
+                                      type="hidden"
+                                      name="groupID"
+                                      id="groupID"
+                                      value="{{ $g.ID }}"
+                                    />
+                                    <input
+                                      type="hidden"
+                                      name="relation"
+                                      id="relation"
+                                      value="editor"
+                                    />
+                                    <button
+                                      type="submit"
+                                      class="btn btn-sm"
+                                      {{ if
+                                        $disableButton
+                                      }}
+                                        disabled
+                                      {{ end }}
+                                    >
+                                      <i class="fas fa-trash-alt"></i>
+                                    </button>
+                                  </form>
+                                </td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                    <div
+                      class="tab-pane"
+                      id="viewer-tab-pane"
+                      role="tabpanel"
+                      aria-labelledby="viewer-tab"
+                      tabindex="0"
+                    >
+                      {{ template "tableheader" . }}
+                      <div class="itemsTable">
+                        <table class="table" id="itemsTable">
+                          <thead>
+                            <tr>
+                              <th scope="col">Name</th>
+                              <th scope="col">ID</th>
+                              <th class="desc-col" scope="col">Description</th>
+                              <th class="meta-col" scope="col">Metadata</th>
+                              <th class="created-col" scope="col">Created At</th>
+                              <th class="text-center" scope="col"></th>
+                            </tr>
+                          </thead>
+                          <tbody>
+                            {{ $userID := .UserID }}
+                            {{ range $i, $g := .Groups }}
+                              {{ $disableButton := false }}
+                              <tr>
+                                <td>{{ $g.Name }}</td>
+                                <td>
+                                  <div class="copy-con-container">
+                                    <a href="{{ printf "/groups/%s" $g.ID }}">
+                                      {{ $g.ID }}
+                                    </a>
+                                    <button class="copy-icon" onclick="copyToClipboard(this)">
+                                      <i class="far fa-copy"></i>
+                                    </button>
+                                  </div>
+                                </td>
+                                <td class="desc-col">{{ $g.Description }}</td>
+                                <td class="meta-col">
+                                  {{ toJSON $g.Metadata }}
+                                </td>
+                                <td class="created-col">{{ $g.CreatedAt }}</td>
+                                <td class="text-center">
+                                  <form
+                                    action="/users/{{ $userID }}/groups/unassign?item=users"
+                                    method="post"
+                                  >
+                                    <input
+                                      type="hidden"
+                                      name="groupID"
+                                      id="groupID"
+                                      value="{{ $g.ID }}"
+                                    />
+                                    <input
+                                      type="hidden"
+                                      name="relation"
+                                      id="relation"
+                                      value="viewer"
+                                    />
+                                    <button
+                                      type="submit"
+                                      class="btn btn-sm"
+                                      {{ if
+                                        $disableButton
+                                      }}
+                                        disabled
+                                      {{ end }}
+                                    >
+                                      <i class="fas fa-trash-alt"></i>
+                                    </button>
+                                  </form>
+                                </td>
+                              </tr>
+                            {{ end }}
+                          </tbody>
+                        </table>
+                      </div>
+                      {{ template "tablefooter" . }}
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
 			<script>
 				const groupModal = new bootstrap.Modal(
 					document.getElementById("addGroupModal"),
@@ -533,16 +482,16 @@ <h4>User Groups</h4>
 
 				function openTab(relation) {
 					event.preventDefault();
-                    var userID = '{{.UserID}}';
-                    fetch(`/users/${userID}/groups?relation=${relation}`, {
-                        method: "GET",
-                    })
-                        .then((response) => {
+					var userID = '{{.UserID}}';
+					fetch(`/users/${userID}/groups?relation=${relation}`, {
+							method: "GET",
+					})
+					.then((response) => {
 
-                        })
-                        .catch((error) => console.error("Error:", error));
+					})
+					.catch((error) => console.error("Error:", error));
 				}
 			</script>
-		</body>
-	</html>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/users.html b/ui/web/template/users.html
index ed7791c50..6348078a8 100644
--- a/ui/web/template/users.html
+++ b/ui/web/template/users.html
@@ -2,131 +2,111 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "users" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<button
-										class="btn body-button"
-										type="button"
-										onclick="openModal('single')"
-									>
-										Add User
-									</button>
-									<button
-										class="btn body-button"
-										type="button"
-										onclick="openModal('bulk')"
-									>
-										Add Users
-									</button>
-									<!-- modals -->
-									<!-- add user modal -->
-									<div
-										class="modal fade"
-										id="addUserModal"
-										tabindex="-1"
-										role="dialog"
-										aria-labelledby="addUserModalLabel"
-										aria-hidden="true"
-									>
-										<div class="modal-dialog" role="document">
-											<div class="modal-content">
-												<div class="modal-header">
-													<h5 class="modal-title" id="addUserModalLabel">
-														Add User
-													</h5>
-												</div>
-												<div class="modal-body">
-													<div id="alertMessage"></div>
-													<form id="userform">
-														<div class="mb-3">
-															<label for="name" class="form-label">Name</label>
-															<input
-																type="text"
-																class="form-control"
-																name="name"
-																id="name"
-																placeholder="User Name"
-															/>
-															<div id="nameError" class="text-danger"></div>
-														</div>
-														<div class="mb-3">
-															<label for="identity" class="form-label">
-																Identity
-															</label>
-															<input
-																type="email"
-																class="form-control"
-																name="identity"
-																id="identity"
-																placeholder="User Identity"
-															/>
-															<div id="identityError" class="text-danger"></div>
-														</div>
-														<div class="mb-3">
-															<label for="secret" class="form-label">
-																Secret
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="secret"
-																id="secret"
-																placeholder="User Secret"
-															/>
-															<div id="secretError" class="text-danger"></div>
-														</div>
-														<div class="mb-3">
-															<label for="tags" class="form-label">Tags</label>
-															<input
-																type="text"
-																class="form-control"
-																name="tags"
-																id="tags"
-																aria-describedby="tagHelp"
-																value="[]"
-															/>
-															<div id="tagHelp" class="form-text">
-																Enter user tags as a string slice.
-															</div>
-															<div id="tagsError" class="text-danger"></div>
-														</div>
-														<div class="mb-3">
-															<label for="metadata" class="form-label">
-																Metadata
-															</label>
-															<input
-																type="text"
-																class="form-control"
-																name="metadata"
-																id="metadata"
-																value="{}"
-															/>
-															<div id="metadataHelp" class="form-text">
-																Enter user metadata in JSON format.
-															</div>
-															<div id="metadataError" class="text-danger"></div>
-														</div>
-														<button
-															type="submit"
-															class="btn body-button"
-															id="create-user-button"
-														>
-															Submit
-														</button>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <button class="btn body-button" type="button" onclick="openModal('single')">
+                    Add User
+                  </button>
+                  <button class="btn body-button" type="button" onclick="openModal('bulk')">
+                    Add Users
+                  </button>
+                  <!-- modals -->
+                  <!-- add user modal -->
+                  <div
+                    class="modal fade"
+                    id="addUserModal"
+                    tabindex="-1"
+                    role="dialog"
+                    aria-labelledby="addUserModalLabel"
+                    aria-hidden="true"
+                  >
+                    <div class="modal-dialog" role="document">
+                      <div class="modal-content">
+                        <div class="modal-header">
+                          <h5 class="modal-title" id="addUserModalLabel">Add User</h5>
+                        </div>
+                        <div class="modal-body">
+                          <div id="alertMessage"></div>
+                          <form id="userform">
+                            <div class="mb-3">
+                              <label for="name" class="form-label">Name</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="name"
+                                id="name"
+                                placeholder="User Name"
+                              />
+                              <div id="nameError" class="text-danger"></div>
+                            </div>
+                            <div class="mb-3">
+                              <label for="identity" class="form-label">Identity</label>
+                              <input
+                                type="email"
+                                class="form-control"
+                                name="identity"
+                                id="identity"
+                                placeholder="User Identity"
+                              />
+                              <div id="identityError" class="text-danger"></div>
+                            </div>
+                            <div class="mb-3">
+                              <label for="secret" class="form-label">Secret</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="secret"
+                                id="secret"
+                                placeholder="User Secret"
+                              />
+                              <div id="secretError" class="text-danger"></div>
+                            </div>
+                            <div class="mb-3">
+                              <label for="tags" class="form-label">Tags</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="tags"
+                                id="tags"
+                                aria-describedby="tagHelp"
+                                value="[]"
+                              />
+                              <div id="tagHelp" class="form-text">
+                                Enter user tags as a string slice.
+                              </div>
+                              <div id="tagsError" class="text-danger"></div>
+                            </div>
+                            <div class="mb-3">
+                              <label for="metadata" class="form-label">Metadata</label>
+                              <input
+                                type="text"
+                                class="form-control"
+                                name="metadata"
+                                id="metadata"
+                                value="{}"
+                              />
+                              <div id="metadataHelp" class="form-text">
+                                Enter user metadata in JSON format.
+                              </div>
+                              <div id="metadataError" class="text-danger"></div>
+                            </div>
+                            <button type="submit" class="btn body-button" id="create-user-button">
+                              Submit
+                            </button>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
 
 									<!-- add users modal -->
 									<div
@@ -271,35 +251,31 @@ <h5 class="modal-title" id="addUsersModalLabel">
 					},
 				});
 
-				const userModal = new bootstrap.Modal(
-					document.getElementById("addUserModal"),
-				);
-				const usersModal = new bootstrap.Modal(
-					document.getElementById("addUsersModal"),
-				);
+        const userModal = new bootstrap.Modal(document.getElementById("addUserModal"));
+        const usersModal = new bootstrap.Modal(document.getElementById("addUsersModal"));
 
-				function openModal(modal) {
-					if (modal === "single") {
-						userModal.show();
-					} else if (modal === "bulk") {
-						usersModal.show();
-					}
-				}
+        function openModal(modal) {
+          if (modal === "single") {
+            userModal.show();
+          } else if (modal === "bulk") {
+            usersModal.show();
+          }
+        }
 
-				submitCreateForm({
-					url: "/users",
-					formId: "userform",
-					alertDiv: "alertMessage",
-					modal: userModal,
-				});
+        submitCreateForm({
+          url: "/users",
+          formId: "userform",
+          alertDiv: "alertMessage",
+          modal: userModal,
+        });
 
-				submitCreateForm({
-					url: "/users/bulk",
-					formId: "bulkusersform",
-					alertDiv: "alertBulkMessage",
-					modal: usersModal,
-				});
-			</script>
-		</body>
-	</html>
+        submitCreateForm({
+          url: "/users/bulk",
+          formId: "bulkusersform",
+          alertDiv: "alertBulkMessage",
+          modal: usersModal,
+        });
+      </script>
+    </body>
+  </html>
 {{ end }}
diff --git a/ui/web/template/userthings.html b/ui/web/template/userthings.html
index afcd4c842..0a3a85f1d 100644
--- a/ui/web/template/userthings.html
+++ b/ui/web/template/userthings.html
@@ -2,229 +2,185 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "userthings" }}
-	<!doctype html>
-	<html lang="en">
-		{{ template "header" }}
-		<body>
-			{{ template "navbar" . }}
-			<div class="main-content pt-3">
-				<div class="container">
-					<div class="row">
-						<div class="col-lg-12 mx-auto py-3">
-							<div class="row">
-								<div class="buttons mb-3">
-									<a
-										href="/users/{{ .UserID }}"
-										type="button"
-										class="btn body-button"
-									>
-										User
-									</a>
-									<a
-										href="/users/{{ .UserID }}/groups"
-										type="button"
-										class="btn body-button"
-									>
-										User Groups
-									</a>
-									<a
-										href="/users/{{ .UserID }}/channels"
-										type="button"
-										class="btn body-button"
-									>
-										User Channels
-									</a>
-								</div>
-								<div class="table-responsive table-container">
-									<div class="d-flex flex-row justify-content-between">
-										<h4>User Things</h4>
-										<button
-											role="button"
-											class="btn body-button"
-											onclick="openThingModal()"
-										>
-											<i class="fa-solid fa-plus fs-4"></i>
-										</button>
-										<!-- modal -->
-										<div
-											class="modal fade"
-											id="addThingModal"
-											tabindex="-1"
-											aria-labelledby="addThingModalLabel"
-											aria-hidden="true"
-										>
-											<div class="modal-dialog modal-dialog-centered">
-												<div class="modal-content">
-													<div class="modal-header">
-														<h1
-															class="modal-title fs-5"
-															id="addThingModalLabel"
-														>
-															Add Thing
-														</h1>
-														<button
-															type="button"
-															class="btn-close"
-															data-bs-dismiss="modal"
-															aria-label="Close"
-														></button>
-													</div>
-													<form
-														action="/users/{{ .UserID }}/things/share?item=users"
-														method="post"
-													>
-														<div class="modal-body">
-															<div class="mb-3">
-																<label for="infiniteScroll" class="form-label">
-																	Thing ID
-																</label>
-																<input
-																	type="text"
-																	name="thingFilter"
-																	id="thingFilter"
-																	placeholder="Filter by Thing ID"
-																/>
-																<select
-																	class="form-select"
-																	name="thingID"
-																	id="infiniteScroll"
-																	size="5"
-																	required
-																>
-																	<option disabled>select a thing</option>
-																</select>
-															</div>
-															<div class="mb-3">
-																<label for="relation" class="form-label">
-																	Relation
-																</label>
-																<select
-																	class="form-control"
-																	name="relation"
-																	id="relation"
-																	aria-describedby="relationHelp"
-																	multiple
-																	required
-																>
-																	{{ range $i, $r := .Relations }}
-																		<option value="{{ $r }}">
-																			{{ $r }}
-																		</option>
-																	{{ end }}
-																</select>
-																<div id="relationHelp" class="form-text">
-																	Select Relation.
-																</div>
-															</div>
-															<div class="modal-footer">
-																<button
-																	type="button"
-																	class="btn btn-secondary"
-																	data-bs-dismiss="modal"
-																>
-																	Cancel
-																</button>
-																<button type="submit" class="btn btn-primary">
-																	Assign
-																</button>
-															</div>
-														</div>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
-									{{ template "tableheader" . }}
-									<div class="itemsTable">
-										<table id="itemsTable" class="table">
-											<thead>
-												<tr>
-													<th scope="col">Name</th>
-													<th scope="col">ID</th>
-													<th class="tags-col" scope="col">Tags</th>
-													<th class="meta-col" scope="col">Metadata</th>
-													<th class="created-col" scope="col">Created At</th>
-													<th class="text-center" scope="col"></th>
-												</tr>
-											</thead>
-											<tbody>
-												{{ $userID := .UserID }}
-												{{ range $i, $t := .Things }}
-													{{ $disableButton := false }}
-													<tr>
-														<td>{{ $t.Name }}</td>
-														<td>
-															<div class="copy-con-container">
-																<a href="{{ printf "/things/%s" $t.ID }}">
-																	{{ $t.ID }}
-																</a>
-																<button
-																	class="copy-icon"
-																	onclick="copyToClipboard(this)"
-																>
-																	<i class="far fa-copy"></i>
-																</button>
-															</div>
-														</td>
-														<td class="tags-col">{{ toSlice $t.Tags }}</td>
-														<td class="meta-col">{{ toJSON $t.Metadata }}</td>
-														<td class="created-col">{{ $t.CreatedAt }}</td>
-														<td class="text-center">
-															<form
-																action="/users/{{ $userID }}/things/unshare?item=users"
-																method="post"
-															>
-																<input
-																	type="hidden"
-																	name="thingID"
-																	id="thingID"
-																	value="{{ $t.ID }}"
-																/>
-																<input
-																	type="hidden"
-																	name="relation"
-																	id="relation"
-																	value="owner"
-																/>
-																<button
-																	type="submit"
-																	class="btn btn-sm"
-																	{{ if
-																		$disableButton
-																	}}
-																		disabled
-																	{{ end }}
-																>
-																	<i class="fas fa-trash-alt"></i>
-																</button>
-															</form>
-														</td>
-													</tr>
-												{{ end }}
-											</tbody>
-										</table>
-									</div>
-									{{ template "tablefooter" . }}
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
-			<script>
-				const thingModal = new bootstrap.Modal(
-					document.getElementById("addThingModal"),
-				);
-				function openThingModal() {
-					thingModal.show();
-				}
-				fetchIndividualEntity({
-					input: "thingFilter",
-					itemSelect: "things",
-					item: "things",
-				});
-			</script>
-		</body>
-	</html>
+  <!doctype html>
+  <html lang="en">
+    {{ template "header" }}
+    <body>
+      {{ template "navbar" . }}
+      <div class="main-content pt-3">
+        <div class="container">
+          <div class="row">
+            <div class="col-lg-12 mx-auto py-3">
+              <div class="row">
+                <div class="buttons mb-3">
+                  <a href="/users/{{ .UserID }}" type="button" class="btn body-button">User</a>
+                  <a href="/users/{{ .UserID }}/groups" type="button" class="btn body-button">
+                    User Groups
+                  </a>
+                  <a href="/users/{{ .UserID }}/channels" type="button" class="btn body-button">
+                    User Channels
+                  </a>
+                </div>
+                <div class="table-responsive table-container">
+                  <div class="d-flex flex-row justify-content-between">
+                    <h4>User Things</h4>
+                    <button role="button" class="btn body-button" onclick="openThingModal()">
+                      <i class="fa-solid fa-plus fs-4"></i>
+                    </button>
+                    <!-- modal -->
+                    <div
+                      class="modal fade"
+                      id="addThingModal"
+                      tabindex="-1"
+                      aria-labelledby="addThingModalLabel"
+                      aria-hidden="true"
+                    >
+                      <div class="modal-dialog modal-dialog-centered">
+                        <div class="modal-content">
+                          <div class="modal-header">
+                            <h1 class="modal-title fs-5" id="addThingModalLabel">Add Thing</h1>
+                            <button
+                              type="button"
+                              class="btn-close"
+                              data-bs-dismiss="modal"
+                              aria-label="Close"
+                            ></button>
+                          </div>
+                          <form action="/users/{{ .UserID }}/things/share?item=users" method="post">
+                            <div class="modal-body">
+                              <div class="mb-3">
+                                <label for="infiniteScroll" class="form-label">Thing ID</label>
+                                <input
+                                  type="text"
+                                  name="thingFilter"
+                                  id="thingFilter"
+                                  placeholder="Filter by Thing ID"
+                                />
+                                <select
+                                  class="form-select"
+                                  name="thingID"
+                                  id="infiniteScroll"
+                                  size="5"
+                                  required
+                                >
+                                  <option disabled>select a thing</option>
+                                </select>
+                              </div>
+                              <div class="mb-3">
+                                <label for="relation" class="form-label">Relation</label>
+                                <select
+                                  class="form-control"
+                                  name="relation"
+                                  id="relation"
+                                  aria-describedby="relationHelp"
+                                  multiple
+                                  required
+                                >
+                                  {{ range $i, $r := .Relations }}
+                                    <option value="{{ $r }}">
+                                      {{ $r }}
+                                    </option>
+                                  {{ end }}
+                                </select>
+                                <div id="relationHelp" class="form-text">Select Relation.</div>
+                              </div>
+                              <div class="modal-footer">
+                                <button
+                                  type="button"
+                                  class="btn btn-secondary"
+                                  data-bs-dismiss="modal"
+                                >
+                                  Cancel
+                                </button>
+                                <button type="submit" class="btn btn-primary">Assign</button>
+                              </div>
+                            </div>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  {{ template "tableheader" . }}
+                  <div class="itemsTable">
+                    <table id="itemsTable" class="table">
+                      <thead>
+                        <tr>
+                          <th scope="col">Name</th>
+                          <th scope="col">ID</th>
+                          <th class="tags-col" scope="col">Tags</th>
+                          <th class="meta-col" scope="col">Metadata</th>
+                          <th class="created-col" scope="col">Created At</th>
+                          <th class="text-center" scope="col"></th>
+                        </tr>
+                      </thead>
+                      <tbody>
+                        {{ $userID := .UserID }}
+                        {{ range $i, $t := .Things }}
+                          {{ $disableButton := false }}
+                          <tr>
+                            <td>{{ $t.Name }}</td>
+                            <td>
+                              <div class="copy-con-container">
+                                <a href="{{ printf "/things/%s" $t.ID }}">
+                                  {{ $t.ID }}
+                                </a>
+                                <button class="copy-icon" onclick="copyToClipboard(this)">
+                                  <i class="far fa-copy"></i>
+                                </button>
+                              </div>
+                            </td>
+                            <td class="tags-col">{{ toSlice $t.Tags }}</td>
+                            <td class="meta-col">{{ toJSON $t.Metadata }}</td>
+                            <td class="created-col">{{ $t.CreatedAt }}</td>
+                            <td class="text-center">
+                              <form
+                                action="/users/{{ $userID }}/things/unshare?item=users"
+                                method="post"
+                              >
+                                <input
+                                  type="hidden"
+                                  name="thingID"
+                                  id="thingID"
+                                  value="{{ $t.ID }}"
+                                />
+                                <input type="hidden" name="relation" id="relation" value="owner" />
+                                <button
+                                  type="submit"
+                                  class="btn btn-sm"
+                                  {{ if
+                                    $disableButton
+                                  }}
+                                    disabled
+                                  {{ end }}
+                                >
+                                  <i class="fas fa-trash-alt"></i>
+                                </button>
+                              </form>
+                            </td>
+                          </tr>
+                        {{ end }}
+                      </tbody>
+                    </table>
+                  </div>
+                  {{ template "tablefooter" . }}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
+      <script>
+        const thingModal = new bootstrap.Modal(document.getElementById("addThingModal"));
+        function openThingModal() {
+          thingModal.show();
+        }
+        fetchIndividualEntity({
+          input: "thingFilter",
+          itemSelect: "things",
+          item: "things",
+        });
+      </script>
+    </body>
+  </html>
 {{ end }}

From ad6328320bd373eac9b6700ece4aa078591a1bdd Mon Sep 17 00:00:00 2001
From: ianmuchyri <ianmuchiri8@gmail.com>
Date: Mon, 27 Nov 2023 20:12:42 +0300
Subject: [PATCH 06/11] update js formatting

Signed-off-by: ianmuchyri <ianmuchiri8@gmail.com>
---
 ui/web/static/js/main.js | 700 +++++++++++++++++++--------------------
 1 file changed, 347 insertions(+), 353 deletions(-)

diff --git a/ui/web/static/js/main.js b/ui/web/static/js/main.js
index 068a5e63d..7ece41510 100644
--- a/ui/web/static/js/main.js
+++ b/ui/web/static/js/main.js
@@ -3,167 +3,167 @@
 
 //function to copy the ID to the clipboard
 function copyToClipboard(button) {
-	var clientIDElement = button.previousElementSibling.firstChild;
-	var clientId = clientIDElement.textContent;
-
-	navigator.clipboard.writeText(clientId).then(
-		function () {
-			//change the copy icon to indicate success
-			button.innerHTML = `<i class="fas fa-check success-icon">`;
-			setTimeout(function () {
-				//revert the copy icon after a short delay
-				button.innerHTML = `<i class ="far fa-copy">`;
-			}, 1000);
-		},
-		function (error) {
-			//handle error
-			console.error("failed to copy to clipboard: ", error);
-		},
-	);
+  var clientIDElement = button.previousElementSibling.firstChild;
+  var clientId = clientIDElement.textContent;
+
+  navigator.clipboard.writeText(clientId).then(
+    function () {
+      //change the copy icon to indicate success
+      button.innerHTML = `<i class="fas fa-check success-icon">`;
+      setTimeout(function () {
+        //revert the copy icon after a short delay
+        button.innerHTML = `<i class ="far fa-copy">`;
+      }, 1000);
+    },
+    function (error) {
+      //handle error
+      console.error("failed to copy to clipboard: ", error);
+    },
+  );
 }
 
 // Form validation functions
 
 function validateName(name, errorDiv, event) {
-	removeErrorMessage(errorDiv);
-	if (name.trim() === "") {
-		event.preventDefault();
-		displayErrorMessage("Name is Required", errorDiv);
-		return false;
-	}
-	return true;
+  removeErrorMessage(errorDiv);
+  if (name.trim() === "") {
+    event.preventDefault();
+    displayErrorMessage("Name is Required", errorDiv);
+    return false;
+  }
+  return true;
 }
 
 const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
 function validateEmail(email, errorDiv, event) {
-	removeErrorMessage(errorDiv);
-	if (email.trim() === "") {
-		event.preventDefault();
-		displayErrorMessage("Email is Required", errorDiv);
-		return false;
-	} else if (!email.match(emailRegex)) {
-		event.preventDefault();
-		displayErrorMessage("Invalid email format", errorDiv);
-		return false;
-	}
-	return true;
+  removeErrorMessage(errorDiv);
+  if (email.trim() === "") {
+    event.preventDefault();
+    displayErrorMessage("Email is Required", errorDiv);
+    return false;
+  } else if (!email.match(emailRegex)) {
+    event.preventDefault();
+    displayErrorMessage("Invalid email format", errorDiv);
+    return false;
+  }
+  return true;
 }
 
 const minLength = 8;
 function validatePassword(password, errorDiv, event) {
-	removeErrorMessage(errorDiv);
-	if (password.trim().length < minLength) {
-		event.preventDefault();
-		var errorMessage = `Password must be at least ${minLength} characters long`;
-		displayErrorMessage(errorMessage, errorDiv);
-		return false;
-	}
-	return true;
+  removeErrorMessage(errorDiv);
+  if (password.trim().length < minLength) {
+    event.preventDefault();
+    var errorMessage = `Password must be at least ${minLength} characters long`;
+    displayErrorMessage(errorMessage, errorDiv);
+    return false;
+  }
+  return true;
 }
 
 function validateMetadata(metadata, errorDiv, event) {
-	removeErrorMessage(errorDiv);
-	try {
-		if (metadata.trim() !== "") {
-			JSON.parse(metadata);
-		}
-	} catch (error) {
-		event.preventDefault();
-		displayErrorMessage("Metadata is not a valid JSON object", errorDiv);
-		return false;
-	}
-	return true;
+  removeErrorMessage(errorDiv);
+  try {
+    if (metadata.trim() !== "") {
+      JSON.parse(metadata);
+    }
+  } catch (error) {
+    event.preventDefault();
+    displayErrorMessage("Metadata is not a valid JSON object", errorDiv);
+    return false;
+  }
+  return true;
 }
 
 function validateTags(tags, errorDiv, event) {
-	removeErrorMessage(errorDiv);
-	var tagsArray;
-	try {
-		if (tags.trim() !== "") {
-			tagsArray = JSON.parse(tags);
-		}
-		if (
-			!Array.isArray(tagsArray) ||
-			!tagsArray.every(function (tag) {
-				return typeof tag === "string";
-			})
-		) {
-			event.preventDefault();
-			displayErrorMessage("tags must be strings in an array", errorDiv);
-			return false;
-		}
-	} catch (error) {
-		event.preventDefault();
-		displayErrorMessage("tags must be a string array", errorDiv);
-		return false;
-	}
-
-	return true;
+  removeErrorMessage(errorDiv);
+  var tagsArray;
+  try {
+    if (tags.trim() !== "") {
+      tagsArray = JSON.parse(tags);
+    }
+    if (
+      !Array.isArray(tagsArray) ||
+      !tagsArray.every(function (tag) {
+        return typeof tag === "string";
+      })
+    ) {
+      event.preventDefault();
+      displayErrorMessage("tags must be strings in an array", errorDiv);
+      return false;
+    }
+  } catch (error) {
+    event.preventDefault();
+    displayErrorMessage("tags must be a string array", errorDiv);
+    return false;
+  }
+
+  return true;
 }
 
 function displayErrorMessage(errorMessage, divName) {
-	const errorDiv = document.getElementById(divName);
-	errorDiv.style.display = "block";
-	errorDiv.innerHTML = errorMessage;
+  const errorDiv = document.getElementById(divName);
+  errorDiv.style.display = "block";
+  errorDiv.innerHTML = errorMessage;
 }
 
 function removeErrorMessage(divName) {
-	const errorDiv = document.getElementById(divName);
-	errorDiv.style.display = "none";
+  const errorDiv = document.getElementById(divName);
+  errorDiv.style.display = "none";
 }
 
 function attachValidationListener(config) {
-	const button = document.getElementById(config.buttonId);
-
-	button.addEventListener("click", function (event) {
-		for (const key in config.validations) {
-			if (config.validations.hasOwnProperty(key)) {
-				const validationFunc = config.validations[key];
-				const elementValue = document.getElementById(key).value;
-				validationFunc(elementValue, config.errorDivs[key], event);
-			}
-		}
-	});
+  const button = document.getElementById(config.buttonId);
+
+  button.addEventListener("click", function (event) {
+    for (const key in config.validations) {
+      if (config.validations.hasOwnProperty(key)) {
+        const validationFunc = config.validations[key];
+        const elementValue = document.getElementById(key).value;
+        validationFunc(elementValue, config.errorDivs[key], event);
+      }
+    }
+  });
 }
 
 // Form subsmission functions
 // config parameters are: formId, url, alertDiv, modal
 function submitCreateForm(config) {
-	const form = document.getElementById(config.formId);
-	form.addEventListener("submit", function (event) {
-		event.preventDefault();
-		const formData = new FormData(form);
-
-		fetch(config.url, {
-			method: "POST",
-			body: formData,
-		})
-			.then(function (response) {
-				switch (response.status) {
-					case 409:
-						showAlert("entity already exists!", config.alertDiv);
-						break;
-					case 400:
-						showAlert("invalid file contents!", config.alertDiv);
-						break;
-					case 415:
-						showAlert("invalid file type!", config.alertDiv);
-						break;
-					default:
-						form.reset();
-						config.modal.hide();
-						window.location.reload();
-				}
-			})
-			.catch((error) => {
-				console.error("error submitting form: ", error);
-			});
-	});
+  const form = document.getElementById(config.formId);
+  form.addEventListener("submit", function (event) {
+    event.preventDefault();
+    const formData = new FormData(form);
+
+    fetch(config.url, {
+      method: "POST",
+      body: formData,
+    })
+      .then(function (response) {
+        switch (response.status) {
+          case 409:
+            showAlert("entity already exists!", config.alertDiv);
+            break;
+          case 400:
+            showAlert("invalid file contents!", config.alertDiv);
+            break;
+          case 415:
+            showAlert("invalid file type!", config.alertDiv);
+            break;
+          default:
+            form.reset();
+            config.modal.hide();
+            window.location.reload();
+        }
+      })
+      .catch((error) => {
+        console.error("error submitting form: ", error);
+      });
+  });
 }
 
 function showAlert(errorMessage, alertDiv) {
-	const alert = document.getElementById(alertDiv);
-	alert.innerHTML = `
+  const alert = document.getElementById(alertDiv);
+  alert.innerHTML = `
 	<div class="alert alert-danger alert-dismissable fade show d-flex flex-row justify-content-between" role="alert">
 	  <div>${errorMessage}</div>
 	  <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>
@@ -174,293 +174,287 @@ function showAlert(errorMessage, alertDiv) {
 
 // make a cell editable.
 function makeEditable(cell) {
-	cell.setAttribute("contenteditable", "true");
-	cell.dataset.originalContent = cell.innerHTML;
+  cell.setAttribute("contenteditable", "true");
+  cell.dataset.originalContent = cell.innerHTML;
 }
 
 // make cell uneditable.
 function makeUneditable(cell) {
-	const originalContent = cell.dataset.originalContent;
-	cell.innerHTML = originalContent;
-	cell.setAttribute("contenteditable", "false");
+  const originalContent = cell.dataset.originalContent;
+  cell.innerHTML = originalContent;
+  cell.setAttribute("contenteditable", "false");
 }
 
 // function show the save/cancel buttons and hide the edit button.
 function showSaveCancelButtons(editBtn, saveCancelBtn) {
-	editBtn.style.display = "none";
-	saveCancelBtn.style.display = "inline-block";
+  editBtn.style.display = "none";
+  saveCancelBtn.style.display = "inline-block";
 }
 
 // function to show the edit button anf hide the save/cancel buttons.
 function showEditButton(editBtn, saveCancelBtn) {
-	editBtn.style.display = "inline-block";
-	saveCancelBtn.style.display = "none";
+  editBtn.style.display = "inline-block";
+  saveCancelBtn.style.display = "none";
 }
 
 // config parameters are: button, field
 function editRow(config) {
-	const button = document.getElementById(config.button);
+  const button = document.getElementById(config.button);
 
-	button.addEventListener("click", function () {
-		makeEditable(config.cell);
-		showSaveCancelButtons(config.editBtn, config.saveCancelBtn);
-	});
+  button.addEventListener("click", function () {
+    makeEditable(config.cell);
+    showSaveCancelButtons(config.editBtn, config.saveCancelBtn);
+  });
 }
 
 function cancelEditRow(config) {
-	const button = document.getElementById(config.button);
+  const button = document.getElementById(config.button);
 
-	button.addEventListener("click", function () {
-		makeUneditable(config.cell);
-		showEditButton(config.editBtn, config.saveCancelBtn);
-		removeErrorMessage(config.alertDiv);
-	});
+  button.addEventListener("click", function () {
+    makeUneditable(config.cell);
+    showEditButton(config.editBtn, config.saveCancelBtn);
+    removeErrorMessage(config.alertDiv);
+  });
 }
 
 function submitUpdateForm(config) {
-	fetch(config.url, {
-		method: "POST",
-		body: config.data,
-		headers: {
-			"Content-Type": "application/json",
-		},
-	}).then((response) => {
-		switch (response.status) {
-			case 409:
-				showAlert("entity already exists!", config.alertDiv);
-				break;
-			default:
-				window.location.reload();
-		}
-	});
+  fetch(config.url, {
+    method: "POST",
+    body: config.data,
+    headers: {
+      "Content-Type": "application/json",
+    },
+  }).then((response) => {
+    switch (response.status) {
+      case 409:
+        showAlert("entity already exists!", config.alertDiv);
+        break;
+      default:
+        window.location.reload();
+    }
+  });
 }
 
 function updateName(config) {
-	const button = document.getElementById(config.button);
-
-	button.addEventListener("click", function (event) {
-		const updatedValue = config.cell.textContent.trim();
-		if (validateName(updatedValue, config.alertDiv, event)) {
-			const url = `/${config.entity}/${config.id}`;
-			const data = JSON.stringify({ [config.field]: updatedValue });
-
-			submitUpdateForm({
-				url: url,
-				data: data,
-				alertDiv: config.alertDiv,
-			});
-		}
-	});
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function (event) {
+    const updatedValue = config.cell.textContent.trim();
+    if (validateName(updatedValue, config.alertDiv, event)) {
+      const url = `/${config.entity}/${config.id}`;
+      const data = JSON.stringify({ [config.field]: updatedValue });
+
+      submitUpdateForm({
+        url: url,
+        data: data,
+        alertDiv: config.alertDiv,
+      });
+    }
+  });
 }
 
 function updateIdentity(config) {
-	const button = document.getElementById(config.button);
-
-	button.addEventListener("click", function (event) {
-		const updatedValue = config.cell.textContent.trim();
-		if (validateEmail(updatedValue, config.alertDiv, event)) {
-			const url = `/${config.entity}/${config.id}/identity`;
-			const data = JSON.stringify({ [config.field]: updatedValue });
-
-			submitUpdateForm({
-				url: url,
-				data: data,
-				alertDiv: config.alertDiv,
-			});
-		}
-	});
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function (event) {
+    const updatedValue = config.cell.textContent.trim();
+    if (validateEmail(updatedValue, config.alertDiv, event)) {
+      const url = `/${config.entity}/${config.id}/identity`;
+      const data = JSON.stringify({ [config.field]: updatedValue });
+
+      submitUpdateForm({
+        url: url,
+        data: data,
+        alertDiv: config.alertDiv,
+      });
+    }
+  });
 }
 
 function updateMetadata(config) {
-	const button = document.getElementById(config.button);
-
-	button.addEventListener("click", function (event) {
-		const updatedValue = config.cell.textContent.trim();
-		if (validateMetadata(updatedValue, config.alertDiv, event)) {
-			const url = `/${config.entity}/${config.id}`;
-			const data = JSON.stringify({ [config.field]: JSON.parse(updatedValue) });
-
-			submitUpdateForm({
-				url: url,
-				data: data,
-				alertDiv: config.alertDiv,
-			});
-		}
-	});
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function (event) {
+    const updatedValue = config.cell.textContent.trim();
+    if (validateMetadata(updatedValue, config.alertDiv, event)) {
+      const url = `/${config.entity}/${config.id}`;
+      const data = JSON.stringify({ [config.field]: JSON.parse(updatedValue) });
+
+      submitUpdateForm({
+        url: url,
+        data: data,
+        alertDiv: config.alertDiv,
+      });
+    }
+  });
 }
 
 function updateTags(config) {
-	const button = document.getElementById(config.button);
-
-	button.addEventListener("click", function (event) {
-		const updatedValue = config.cell.textContent.trim();
-		if (validateTags(updatedValue, config.alertDiv, event)) {
-			const url = `/${config.entity}/${config.id}/tags`;
-			const data = JSON.stringify({ [config.field]: JSON.parse(updatedValue) });
-
-			submitUpdateForm({
-				url: url,
-				data: data,
-				alertDiv: config.alertDiv,
-			});
-		}
-	});
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function (event) {
+    const updatedValue = config.cell.textContent.trim();
+    if (validateTags(updatedValue, config.alertDiv, event)) {
+      const url = `/${config.entity}/${config.id}/tags`;
+      const data = JSON.stringify({ [config.field]: JSON.parse(updatedValue) });
+
+      submitUpdateForm({
+        url: url,
+        data: data,
+        alertDiv: config.alertDiv,
+      });
+    }
+  });
 }
 
 function updateSecret(config) {
-	const button = document.getElementById(config.button);
-
-	button.addEventListener("click", function (event) {
-		const updatedValue = config.cell.textContent.trim();
-		if (validatePassword(updatedValue, config.alertDiv, event)) {
-			const url = `/${config.entity}/${config.id}/secret`;
-			const data = JSON.stringify({ [config.field]: updatedValue });
-
-			submitUpdateForm({
-				url: url,
-				data: data,
-				alertDiv: config.alertDiv,
-			});
-		}
-	});
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function (event) {
+    const updatedValue = config.cell.textContent.trim();
+    if (validatePassword(updatedValue, config.alertDiv, event)) {
+      const url = `/${config.entity}/${config.id}/secret`;
+      const data = JSON.stringify({ [config.field]: updatedValue });
+
+      submitUpdateForm({
+        url: url,
+        data: data,
+        alertDiv: config.alertDiv,
+      });
+    }
+  });
 }
 
 function updateOwner(config) {
-	const button = document.getElementById(config.button);
-
-	button.addEventListener("click", function () {
-		const updatedValue = config.cell.textContent.trim();
-		const url = `/${config.entity}/${config.id}/owner`;
-		const data = JSON.stringify({ [config.field]: updatedValue });
-
-		submitUpdateForm({
-			url: url,
-			data: data,
-			alertDiv: config.alertDiv,
-		});
-	});
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function () {
+    const updatedValue = config.cell.textContent.trim();
+    const url = `/${config.entity}/${config.id}/owner`;
+    const data = JSON.stringify({ [config.field]: updatedValue });
+
+    submitUpdateForm({
+      url: url,
+      data: data,
+      alertDiv: config.alertDiv,
+    });
+  });
 }
 
 function updateDescription(config) {
-	const button = document.getElementById(config.button);
-
-	button.addEventListener("click", function () {
-		const updatedValue = config.cell.textContent.trim();
-		const url = `/${config.entity}/${config.id}`;
-		const data = JSON.stringify({ [config.field]: updatedValue });
-
-		submitUpdateForm({
-			url: url,
-			data: data,
-			alertDiv: config.alertDiv,
-		});
-	});
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function () {
+    const updatedValue = config.cell.textContent.trim();
+    const url = `/${config.entity}/${config.id}`;
+    const data = JSON.stringify({ [config.field]: updatedValue });
+
+    submitUpdateForm({
+      url: url,
+      data: data,
+      alertDiv: config.alertDiv,
+    });
+  });
 }
 
 function attachEditRowListener(config) {
-	for (const key in config.rows) {
-		if (config.rows.hasOwnProperty(key)) {
-			const cell = document.querySelector(`td[data-field="${key}"]`);
-			const editBtn = cell.parentNode.querySelector(".edit-btn");
-			const saveCancelBtn = cell.parentNode.querySelector(
-				".save-cancel-buttons",
-			);
-			editRow({
-				button: `edit-${key}`,
-				cell: cell,
-				editBtn: editBtn,
-				saveCancelBtn: saveCancelBtn,
-			});
-			cancelEditRow({
-				button: `cancel-${key}`,
-				cell: cell,
-				editBtn: editBtn,
-				saveCancelBtn: saveCancelBtn,
-				alertDiv: config.errorDiv,
-			});
-			const saveRow = config.rows[key];
-			saveRow({
-				button: `save-${key}`,
-				field: key,
-				cell: cell,
-				editBtn: editBtn,
-				saveCancelBtn: saveCancelBtn,
-				id: config.id,
-				entity: config.entity,
-				alertDiv: config.errorDiv,
-			});
-		}
-	}
+  for (const key in config.rows) {
+    if (config.rows.hasOwnProperty(key)) {
+      const cell = document.querySelector(`td[data-field="${key}"]`);
+      const editBtn = cell.parentNode.querySelector(".edit-btn");
+      const saveCancelBtn = cell.parentNode.querySelector(".save-cancel-buttons");
+      editRow({
+        button: `edit-${key}`,
+        cell: cell,
+        editBtn: editBtn,
+        saveCancelBtn: saveCancelBtn,
+      });
+      cancelEditRow({
+        button: `cancel-${key}`,
+        cell: cell,
+        editBtn: editBtn,
+        saveCancelBtn: saveCancelBtn,
+        alertDiv: config.errorDiv,
+      });
+      const saveRow = config.rows[key];
+      saveRow({
+        button: `save-${key}`,
+        field: key,
+        cell: cell,
+        editBtn: editBtn,
+        saveCancelBtn: saveCancelBtn,
+        id: config.id,
+        entity: config.entity,
+        alertDiv: config.errorDiv,
+      });
+    }
+  }
 }
 
 function fetchIndividualEntity(config) {
-	document.addEventListener("DOMContentLoaded", function () {
-		getEntities(config.item, "");
-		infiniteScroll(config.item);
-	});
-	
-	const input = document.getElementById(config.input);
-
-	input.addEventListener("input", function (event) {
-		const itemSelect = document.getElementById(config.itemSelect);
-		if (event.target.value === "") {
-			itemSelect.innerHTML = `<option disabled>select a ${config.type}</option>`;
-			getEntities(config.item, "");
-			infiniteScroll(config.item);
-		} else {
-			itemSelect.innerHTML = "";
-			getEntities(config.item, event.target.value);
-		}
-	});
+  document.addEventListener("DOMContentLoaded", function () {
+    getEntities(config.item, "");
+    infiniteScroll(config.item);
+  });
+
+  const input = document.getElementById(config.input);
+
+  input.addEventListener("input", function (event) {
+    const itemSelect = document.getElementById(config.itemSelect);
+    if (event.target.value === "") {
+      itemSelect.innerHTML = `<option disabled>select a ${config.type}</option>`;
+      getEntities(config.item, "");
+      infiniteScroll(config.item);
+    } else {
+      itemSelect.innerHTML = "";
+      getEntities(config.item, event.target.value);
+    }
+  });
 }
 
 function getEntities(item, name) {
-	fetchData(item, name, 1);
+  fetchData(item, name, 1);
 }
 
 function infiniteScroll(item) {
-	var selectElement = document.getElementById("infiniteScroll");
-	var singleOptionHeight = selectElement.querySelector("option").offsetHeight;
-	var selectBoxHeight = selectElement.offsetHeight;
-	var numOptionsBeforeLoad = 2;
-	var lastScrollTop = 0;
-	var currentPageNo = 1;
-	var currentScroll = 0;
-
-	selectElement.addEventListener("scroll", function () {
-		var st = selectElement.scrollTop;
-		var totalHeight =
-			selectElement.querySelectorAll("option").length * singleOptionHeight;
-
-		if (st > lastScrollTop) {
-			currentScroll = st + selectBoxHeight;
-			if (
-				currentScroll + numOptionsBeforeLoad * singleOptionHeight >=
-				totalHeight
-			) {
-				currentPageNo++;
-				fetchData(item, "", currentPageNo);
-			}
-		}
-
-		lastScrollTop = st;
-	});
+  var selectElement = document.getElementById("infiniteScroll");
+  var singleOptionHeight = selectElement.querySelector("option").offsetHeight;
+  var selectBoxHeight = selectElement.offsetHeight;
+  var numOptionsBeforeLoad = 2;
+  var lastScrollTop = 0;
+  var currentPageNo = 1;
+  var currentScroll = 0;
+
+  selectElement.addEventListener("scroll", function () {
+    var st = selectElement.scrollTop;
+    var totalHeight = selectElement.querySelectorAll("option").length * singleOptionHeight;
+
+    if (st > lastScrollTop) {
+      currentScroll = st + selectBoxHeight;
+      if (currentScroll + numOptionsBeforeLoad * singleOptionHeight >= totalHeight) {
+        currentPageNo++;
+        fetchData(item, "", currentPageNo);
+      }
+    }
+
+    lastScrollTop = st;
+  });
 }
 
 let limit = 5;
 function fetchData(item, name, page) {
-	fetch(`/entities?item=${item}&limit=${limit}&name=${name}&page=${page}`, {
-		method: "GET",
-	})
-		.then((response) => response.json())
-		.then((data) => {
-			const selectElement = document.getElementById("infiniteScroll");
-			data.data.forEach((entity) => {
-				const option = document.createElement("option");
-				option.value = entity.id;
-				option.text = entity.name;
-				selectElement.appendChild(option);
-			});
-		})
-		.catch((error) => console.error("Error:", error));
+  fetch(`/entities?item=${item}&limit=${limit}&name=${name}&page=${page}`, {
+    method: "GET",
+  })
+    .then((response) => response.json())
+    .then((data) => {
+      const selectElement = document.getElementById("infiniteScroll");
+      data.data.forEach((entity) => {
+        const option = document.createElement("option");
+        option.value = entity.id;
+        option.text = entity.name;
+        selectElement.appendChild(option);
+      });
+    })
+    .catch((error) => console.error("Error:", error));
 }

From f2ae078b66d8cc1450763cfe2a593ed1069d2d0f Mon Sep 17 00:00:00 2001
From: ianmuchyri <ianmuchiri8@gmail.com>
Date: Tue, 28 Nov 2023 11:48:13 +0300
Subject: [PATCH 07/11] update bootstrap

Signed-off-by: ianmuchyri <ianmuchiri8@gmail.com>
---
 ui/web/static/js/main.js       |  86 ++++++++++++---
 ui/web/template/bootstrap.html | 195 +++++----------------------------
 ui/web/template/channels.html  |   2 +-
 ui/web/template/groups.html    |   2 +-
 ui/web/template/things.html    |   4 +-
 ui/web/template/users.html     |   4 +-
 6 files changed, 104 insertions(+), 189 deletions(-)

diff --git a/ui/web/static/js/main.js b/ui/web/static/js/main.js
index 7ece41510..07b4ce060 100644
--- a/ui/web/static/js/main.js
+++ b/ui/web/static/js/main.js
@@ -61,21 +61,21 @@ function validatePassword(password, errorDiv, event) {
   return true;
 }
 
-function validateMetadata(metadata, errorDiv, event) {
+function validateJSON(data, errorDiv, event) {
   removeErrorMessage(errorDiv);
   try {
-    if (metadata.trim() !== "") {
-      JSON.parse(metadata);
+    if (data.trim() !== "") {
+      JSON.parse(data);
     }
   } catch (error) {
     event.preventDefault();
-    displayErrorMessage("Metadata is not a valid JSON object", errorDiv);
+    displayErrorMessage("not a valid JSON object", errorDiv);
     return false;
   }
   return true;
 }
 
-function validateTags(tags, errorDiv, event) {
+function validateStringArray(tags, errorDiv, event) {
   removeErrorMessage(errorDiv);
   var tagsArray;
   try {
@@ -89,12 +89,12 @@ function validateTags(tags, errorDiv, event) {
       })
     ) {
       event.preventDefault();
-      displayErrorMessage("tags must be strings in an array", errorDiv);
+      displayErrorMessage("must be strings in an array", errorDiv);
       return false;
     }
   } catch (error) {
     event.preventDefault();
-    displayErrorMessage("tags must be a string array", errorDiv);
+    displayErrorMessage("must be a string array", errorDiv);
     return false;
   }
 
@@ -220,7 +220,7 @@ function cancelEditRow(config) {
 function submitUpdateForm(config) {
   fetch(config.url, {
     method: "POST",
-    body: config.data,
+    body: JSON.stringify(config.data),
     headers: {
       "Content-Type": "application/json",
     },
@@ -242,7 +242,7 @@ function updateName(config) {
     const updatedValue = config.cell.textContent.trim();
     if (validateName(updatedValue, config.alertDiv, event)) {
       const url = `/${config.entity}/${config.id}`;
-      const data = JSON.stringify({ [config.field]: updatedValue });
+      const data = { [config.field]: updatedValue };
 
       submitUpdateForm({
         url: url,
@@ -260,7 +260,7 @@ function updateIdentity(config) {
     const updatedValue = config.cell.textContent.trim();
     if (validateEmail(updatedValue, config.alertDiv, event)) {
       const url = `/${config.entity}/${config.id}/identity`;
-      const data = JSON.stringify({ [config.field]: updatedValue });
+      const data = { [config.field]: updatedValue };
 
       submitUpdateForm({
         url: url,
@@ -276,9 +276,9 @@ function updateMetadata(config) {
 
   button.addEventListener("click", function (event) {
     const updatedValue = config.cell.textContent.trim();
-    if (validateMetadata(updatedValue, config.alertDiv, event)) {
+    if (validateJSON(updatedValue, config.alertDiv, event)) {
       const url = `/${config.entity}/${config.id}`;
-      const data = JSON.stringify({ [config.field]: JSON.parse(updatedValue) });
+      const data = { [config.field]: JSON.parse(updatedValue) };
 
       submitUpdateForm({
         url: url,
@@ -294,9 +294,9 @@ function updateTags(config) {
 
   button.addEventListener("click", function (event) {
     const updatedValue = config.cell.textContent.trim();
-    if (validateTags(updatedValue, config.alertDiv, event)) {
+    if (validateStringArray(updatedValue, config.alertDiv, event)) {
       const url = `/${config.entity}/${config.id}/tags`;
-      const data = JSON.stringify({ [config.field]: JSON.parse(updatedValue) });
+      const data = { [config.field]: JSON.parse(updatedValue) };
 
       submitUpdateForm({
         url: url,
@@ -314,7 +314,7 @@ function updateSecret(config) {
     const updatedValue = config.cell.textContent.trim();
     if (validatePassword(updatedValue, config.alertDiv, event)) {
       const url = `/${config.entity}/${config.id}/secret`;
-      const data = JSON.stringify({ [config.field]: updatedValue });
+      const data = { [config.field]: updatedValue };
 
       submitUpdateForm({
         url: url,
@@ -331,7 +331,7 @@ function updateOwner(config) {
   button.addEventListener("click", function () {
     const updatedValue = config.cell.textContent.trim();
     const url = `/${config.entity}/${config.id}/owner`;
-    const data = JSON.stringify({ [config.field]: updatedValue });
+    const data = { [config.field]: updatedValue };
 
     submitUpdateForm({
       url: url,
@@ -347,7 +347,7 @@ function updateDescription(config) {
   button.addEventListener("click", function () {
     const updatedValue = config.cell.textContent.trim();
     const url = `/${config.entity}/${config.id}`;
-    const data = JSON.stringify({ [config.field]: updatedValue });
+    const data = { [config.field]: updatedValue };
 
     submitUpdateForm({
       url: url,
@@ -357,6 +357,58 @@ function updateDescription(config) {
   });
 }
 
+// Bootstrap update functions
+function updateContent(config) {
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function () {
+    const updatedValue = config.cell.textContent.trim();
+    const url = `/${config.entity}/${config.id}`;
+    const data = { [config.field]: updatedValue };
+
+    submitUpdateForm({
+      url: url,
+      data: data,
+      alertDiv: config.alertDiv,
+    });
+  });
+}
+
+function updateClientCerts(config) {
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function () {
+    const updatedValue = config.cell.textContent.trim();
+    const url = `/${config.entity}/${config.id}/certs`;
+    const data = { [config.field]: updatedValue };
+
+    submitUpdateForm({
+      url: url,
+      data: data,
+      alertDiv: config.alertDiv,
+    });
+  });
+}
+
+function updateConnections(config) {
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function (event) {
+    const updatedValue = config.cell.textContent.trim();
+
+    if (validateStringArray(updatedValue, config.alertDiv, event)) {
+      const url = `/${config.entity}/${config.id}/connections`;
+      const data = { [config.field]: JSON.parse(updatedValue) };
+
+      submitUpdateForm({
+        url: url,
+        data: data,
+        alertDiv: config.alertDiv,
+      });
+    }
+  });
+}
+
 function attachEditRowListener(config) {
   for (const key in config.rows) {
     if (config.rows.hasOwnProperty(key)) {
diff --git a/ui/web/template/bootstrap.html b/ui/web/template/bootstrap.html
index 61a6cb1e5..a377c346b 100644
--- a/ui/web/template/bootstrap.html
+++ b/ui/web/template/bootstrap.html
@@ -35,14 +35,12 @@
                           {{ .Bootstrap.Name }}
                         </td>
                         <td>
-                          <button class="edit-btn" onclick="editRow('name')">
+                          <button class="edit-btn" id="edit-name">
                             <i class="fas fa-pencil-alt"></i>
                           </button>
                           <div class="save-cancel-buttons" style="display: none">
-                            <button class="save-btn" onclick="saveRow('name')">Save</button>
-                            <button class="cancel-btn" onclick="cancelEditRow('name')">
-                              Cancel
-                            </button>
+                            <button class="save-btn" id="save-name">Save</button>
+                            <button class="cancel-btn" id="cancel-name">Cancel</button>
                           </div>
                         </td>
                       </tr>
@@ -52,14 +50,12 @@
                           {{ .Bootstrap.Content }}
                         </td>
                         <td>
-                          <button class="edit-btn" onclick="editRow('content')">
+                          <button class="edit-btn" id="edit-content">
                             <i class="fas fa-pencil-alt"></i>
                           </button>
                           <div class="save-cancel-buttons" style="display: none">
-                            <button class="save-btn" onclick="saveRow('content')">Save</button>
-                            <button class="cancel-btn" onclick="cancelEditRow('content')">
-                              Cancel
-                            </button>
+                            <button class="save-btn" id="save-content">Save</button>
+                            <button class="cancel-btn" id="cancel-content">Cancel</button>
                           </div>
                         </td>
                       </tr>
@@ -69,14 +65,12 @@
                           {{ toSlice .Bootstrap.Channels }}
                         </td>
                         <td>
-                          <button class="edit-btn" onclick="editRow('channels')">
+                          <button class="edit-btn" id="edit-channels">
                             <i class="fas fa-pencil-alt"></i>
                           </button>
                           <div class="save-cancel-buttons" style="display: none">
-                            <button class="save-btn" onclick="saveRow('channels')">Save</button>
-                            <button class="cancel-btn" onclick="cancelEditRow('channels')">
-                              Cancel
-                            </button>
+                            <button class="save-btn" id="save-channels">Save</button>
+                            <button class="cancel-btn" id="cancel-channels">Cancel</button>
                           </div>
                         </td>
                       </tr>
@@ -86,14 +80,12 @@
                           {{ .Bootstrap.ClientCert }}
                         </td>
                         <td>
-                          <button class="edit-btn" onclick="editRow('clientCert')">
+                          <button class="edit-btn" id="edit-clientCert">
                             <i class="fas fa-pencil-alt"></i>
                           </button>
                           <div class="save-cancel-buttons" style="display: none">
-                            <button class="save-btn" onclick="saveRow('clientCert')">Save</button>
-                            <button class="cancel-btn" onclick="cancelEditRow('clientCert')">
-                              Cancel
-                            </button>
+                            <button class="save-btn" id="save-clientCert">Save</button>
+                            <button class="cancel-btn" id="cancel-clientCert">Cancel</button>
                           </div>
                         </td>
                       </tr>
@@ -103,14 +95,12 @@
                           {{ .Bootstrap.ClientKey }}
                         </td>
                         <td>
-                          <button class="edit-btn" onclick="editRow('clientKey')">
+                          <button class="edit-btn" id="edit-clientKey">
                             <i class="fas fa-pencil-alt"></i>
                           </button>
                           <div class="save-cancel-buttons" style="display: none">
-                            <button class="save-btn" onclick="saveRow('clientKey')">Save</button>
-                            <button class="cancel-btn" onclick="cancelEditRow('clientKey')">
-                              Cancel
-                            </button>
+                            <button class="save-btn" id="save-clientKey">Save</button>
+                            <button class="cancel-btn" id="cancel-clientKey">Cancel</button>
                           </div>
                         </td>
                       </tr>
@@ -120,14 +110,12 @@
                           {{ .Bootstrap.CACert }}
                         </td>
                         <td>
-                          <button class="edit-btn" onclick="editRow('CACert')">
+                          <button class="edit-btn" id="edit-CACert">
                             <i class="fas fa-pencil-alt"></i>
                           </button>
                           <div class="save-cancel-buttons" style="display: none">
-                            <button class="save-btn" onclick="saveRow('CACert')">Save</button>
-                            <button class="cancel-btn" onclick="cancelEditRow('CACert')">
-                              Cancel
-                            </button>
+                            <button class="save-btn" id="save-CACert">Save</button>
+                            <button class="cancel-btn" id="cancel-CACert">Cancel</button>
                           </div>
                         </td>
                       </tr>
@@ -142,143 +130,18 @@
       </div>
       {{ template "footer" }}
     <script>
-      function makeEditable(cell) {
-        cell.setAttribute("contenteditable", "true");
-        cell.dataset.originalContent = cell.innerHTML;
-      }
-
-      function makeUneditable(cell) {
-        const originalContent = cell.dataset.originalContent;
-        cell.innerHTML = originalContent;
-        cell.setAttribute("contenteditable", "false");
-      }
-
-      function showButtons(editBtn, saveCancelBtn) {
-        editBtn.style.display = "none";
-        saveCancelBtn.style.display = "inline-block";
-      }
-
-      function hideButtons(editBtn, saveCancelBtn) {
-        editBtn.style.display = "inline-block";
-        saveCancelBtn.style.display = "none";
-      }
-
-      function editRow(field) {
-        const cell = document.querySelector(`td[data-field='${field}']`);
-        const editBtn = cell.parentNode.querySelector(".edit-btn");
-        const saveCancelBtn = cell.parentNode.querySelector(
-          ".save-cancel-buttons",
-        );
-
-        // Make the row editable
-        makeEditable(cell);
-
-        // Hide the edit button and show save and cancel buttons
-        showButtons(editBtn, saveCancelBtn);
-      }
-
-      function saveRow(field) {
-        const cell = document.querySelector(`td[data-field='${field}']`);
-        const editBtn = cell.parentNode.querySelector(".edit-btn");
-        const saveCancelBtn = cell.parentNode.querySelector(
-          ".save-cancel-buttons",
-        );
-        const errorMessage = document.getElementById("error-message");
-
-        // Get the updated value from the nameCell
-        const updatedValue = cell.textContent.trim();
-
-        // Send the updated value to the server using a POST request
-        let url;
-        let data;
-        if (field === "name") {
-          url = "/bootstraps/{{.Bootstrap.ThingID}}";
-          data = { [field]: updatedValue, content: "{{.Bootstrap.Content}}" };
-        } else if (field == "content") {
-          try {
-            const content = JSON.parse(updatedValue);
-            url = "/bootstraps/{{.Bootstrap.ThingID}}";
-            data = { [field]: updatedValue, name: "{{.Bootstrap.Name}}" };
-          } catch (error) {
-            errorMessage.textContent = "Content must be a valid JSON object!";
-            return;
-          }
-        } else if (
-          field == "clientCert" ||
-          field == "clientKey" ||
-          field == "CACert"
-        ) {
-          url = "/bootstraps/{{.Bootstrap.ThingID}}/certs";
-          data = { [field]: updatedValue };
-        } else if (field === "channels") {
-          try {
-            const channels = JSON.parse(updatedValue);
-            if (
-              !Array.isArray(channels) ||
-              !channels.every(function (channel) {
-                return typeof channel === "string";
-              })
-            ) {
-              errorMessage.textContent = "Channels must be a string array";
-              return;
-            }
-            url = "/bootstraps/{{.Bootstrap.ThingID}}/connections";
-            data = { [field]: channels };
-          } catch (error) {
-            errorMessage.textContent = "Channels must be a valid string array";
-            return;
-          }
+      attachEditRowListener({
+        entity: "bootstraps",
+        id: "{{ .Bootstrap.ThingID }}",
+        rows: {
+          name:updateName,
+          content:updateContent,
+          channels:updateConnections,
+          clientCert:updateClientCerts,
+          clientKey:updateClientCerts,
+          CACert:updateClientCerts,
         }
-
-        errorMessage.textContent = "";
-
-        if (url) {
-			errorMessage.textContent="";
-			fetch(url, {
-				method: "POST",
-				body: JSON.stringify(data),
-				headers: {
-				"Content-Type": "application/json",
-				},
-			})
-            .then((response) => {
-              if (response.ok) {
-                // Make the row uneditable
-                cell.setAttribute("contenteditable", "false");
-
-                // Show edit button and hide save and cancel buttons
-                hideButtons(editBtn, saveCancelBtn);
-              }
-            })
-            .catch((error) => {
-              // Restore original values in the row if there is an error
-              makeUneditable(cell);
-
-              // Show edit button and hide save and cancel buttons
-              hideButtons(editBtn, saveCancelBtn);
-
-              console.error("Error", error);
-            });
-        } else {
-          console.error("Invalid field:", field);
-        }
-      }
-
-      function cancelEditRow(field) {
-        const cell = document.querySelector(`td[data-field='${field}']`);
-        const editBtn = cell.parentNode.querySelector(".edit-btn");
-        const saveCancelBtn = cell.parentNode.querySelector(
-          ".save-cancel-buttons",
-        );
-        const errorMessage = document.getElementById("error-message");
-
-        errorMessage.textContent = "";
-        // Restore original values in the row
-        makeUneditable(cell);
-
-        // Show the edit button and hide the save and cancel buttons
-        hideButtons(editBtn, saveCancelBtn);
-      }
+      });
     </script>
     </body>
   </html>
diff --git a/ui/web/template/channels.html b/ui/web/template/channels.html
index 8d7908443..6a67066e6 100644
--- a/ui/web/template/channels.html
+++ b/ui/web/template/channels.html
@@ -240,7 +240,7 @@ <h5 class="modal-title" id="addChannelsModalLabel">
 					},
 					validations: {
 						name: validateName,
-						metadata: validateMetadata,
+						metadata: validateJSON,
 					},
 				});
 
diff --git a/ui/web/template/groups.html b/ui/web/template/groups.html
index aae2b5943..33a82d047 100644
--- a/ui/web/template/groups.html
+++ b/ui/web/template/groups.html
@@ -233,7 +233,7 @@ <h5 class="modal-title" id="addGroupsModalLabel">
           },
           validations: {
             name: validateName,
-            metadata: validateMetadata,
+            metadata: validateJSON,
           },
         });
 
diff --git a/ui/web/template/things.html b/ui/web/template/things.html
index 15b16af62..dfd06a71b 100644
--- a/ui/web/template/things.html
+++ b/ui/web/template/things.html
@@ -255,8 +255,8 @@ <h5 class="modal-title" id="addThingsModalLabel">
 					},
 					validations: {
 						name: validateName,
-						metadata: validateMetadata,
-						tags: validateTags,
+						metadata: validateJSON,
+						tags: validateStringArray,
 					},
 				});
 
diff --git a/ui/web/template/users.html b/ui/web/template/users.html
index 6348078a8..6c9b1c018 100644
--- a/ui/web/template/users.html
+++ b/ui/web/template/users.html
@@ -246,8 +246,8 @@ <h5 class="modal-title" id="addUsersModalLabel">
 						name: validateName,
 						identity: validateEmail,
 						secret: validatePassword,
-						metadata: validateMetadata,
-						tags: validateTags,
+						metadata: validateJSON,
+						tags: validateStringArray,
 					},
 				});
 

From 3ee065c2aa72090ac0dd363e560d6d24a9f0a9d5 Mon Sep 17 00:00:00 2001
From: ianmuchyri <ianmuchiri8@gmail.com>
Date: Tue, 28 Nov 2023 13:51:28 +0300
Subject: [PATCH 08/11] split javascript files

Signed-off-by: ianmuchyri <ianmuchiri8@gmail.com>
---
 ui/web/static/js/clipboard.js       |  23 ++
 ui/web/static/js/errors.js          |  13 +
 ui/web/static/js/forms.js           |  63 ++++
 ui/web/static/js/infinitescroll.js  |  70 ++++
 ui/web/static/js/main.js            | 512 ----------------------------
 ui/web/static/js/update.js          | 278 +++++++++++++++
 ui/web/static/js/validation.js      | 105 ++++++
 ui/web/template/bootstrap.html      |   9 +-
 ui/web/template/bootstraps.html     |  85 ++---
 ui/web/template/channel.html        |  35 +-
 ui/web/template/channelgroups.html  |   9 +-
 ui/web/template/channels.html       | 275 ++++++++-------
 ui/web/template/channelthings.html  |   9 +-
 ui/web/template/channelusers.html   |  21 +-
 ui/web/template/error.html          |   5 +-
 ui/web/template/group.html          |  10 +-
 ui/web/template/groupchannels.html  |   9 +-
 ui/web/template/groups.html         | 266 +++++++--------
 ui/web/template/groupusers.html     |  21 +-
 ui/web/template/header.html         |  37 +-
 ui/web/template/index.html          |   5 +-
 ui/web/template/login.html          |   5 +-
 ui/web/template/messagesread.html   |   9 +-
 ui/web/template/resetpassword.html  |   5 +-
 ui/web/template/terminal.html       |   5 +-
 ui/web/template/thing.html          |  38 ++-
 ui/web/template/thingchannels.html  |   9 +-
 ui/web/template/things.html         | 282 +++++++--------
 ui/web/template/thingusers.html     |  10 +-
 ui/web/template/updatepassword.html |   6 +-
 ui/web/template/user.html           |  37 +-
 ui/web/template/userchannels.html   |  21 +-
 ui/web/template/usergroups.html     |  21 +-
 ui/web/template/users.html          | 292 ++++++++--------
 ui/web/template/userthings.html     |  10 +-
 35 files changed, 1376 insertions(+), 1234 deletions(-)
 create mode 100644 ui/web/static/js/clipboard.js
 create mode 100644 ui/web/static/js/errors.js
 create mode 100644 ui/web/static/js/forms.js
 create mode 100644 ui/web/static/js/infinitescroll.js
 delete mode 100644 ui/web/static/js/main.js
 create mode 100644 ui/web/static/js/update.js
 create mode 100644 ui/web/static/js/validation.js

diff --git a/ui/web/static/js/clipboard.js b/ui/web/static/js/clipboard.js
new file mode 100644
index 000000000..49a71acb1
--- /dev/null
+++ b/ui/web/static/js/clipboard.js
@@ -0,0 +1,23 @@
+// Copyright (c) Abstract Machines
+// SPDX-License-Identifier: Apache-2.0
+
+//function to copy the ID to the clipboard
+function copyToClipboard(button) {
+  var clientIDElement = button.previousElementSibling.firstChild;
+  var clientId = clientIDElement.textContent;
+
+  navigator.clipboard.writeText(clientId).then(
+    function () {
+      //change the copy icon to indicate success
+      button.innerHTML = `<i class="fas fa-check success-icon">`;
+      setTimeout(function () {
+        //revert the copy icon after a short delay
+        button.innerHTML = `<i class ="far fa-copy">`;
+      }, 1000);
+    },
+    function (error) {
+      //handle error
+      console.error("failed to copy to clipboard: ", error);
+    },
+  );
+}
diff --git a/ui/web/static/js/errors.js b/ui/web/static/js/errors.js
new file mode 100644
index 000000000..156ee545c
--- /dev/null
+++ b/ui/web/static/js/errors.js
@@ -0,0 +1,13 @@
+// Copyright (c) Abstract Machines
+// SPDX-License-Identifier: Apache-2.0
+
+export function displayErrorMessage(errorMessage, divName) {
+  const errorDiv = document.getElementById(divName);
+  errorDiv.style.display = "block";
+  errorDiv.innerHTML = errorMessage;
+}
+
+export function removeErrorMessage(divName) {
+  const errorDiv = document.getElementById(divName);
+  errorDiv.style.display = "none";
+}
diff --git a/ui/web/static/js/forms.js b/ui/web/static/js/forms.js
new file mode 100644
index 000000000..7f64a20ee
--- /dev/null
+++ b/ui/web/static/js/forms.js
@@ -0,0 +1,63 @@
+// Copyright (c) Abstract Machines
+// SPDX-License-Identifier: Apache-2.0
+
+// config parameters are: formId, url, alertDiv, modal
+export function submitCreateForm(config) {
+  const form = document.getElementById(config.formId);
+  form.addEventListener("submit", function (event) {
+    event.preventDefault();
+    const formData = new FormData(form);
+
+    fetch(config.url, {
+      method: "POST",
+      body: formData,
+    })
+      .then(function (response) {
+        switch (response.status) {
+          case 409:
+            showAlert("entity already exists!", config.alertDiv);
+            break;
+          case 400:
+            showAlert("invalid file contents!", config.alertDiv);
+            break;
+          case 415:
+            showAlert("invalid file type!", config.alertDiv);
+            break;
+          default:
+            form.reset();
+            config.modal.hide();
+            window.location.reload();
+        }
+      })
+      .catch((error) => {
+        console.error("error submitting form: ", error);
+      });
+  });
+}
+
+export function submitUpdateForm(config) {
+  fetch(config.url, {
+    method: "POST",
+    body: JSON.stringify(config.data),
+    headers: {
+      "Content-Type": "application/json",
+    },
+  }).then((response) => {
+    switch (response.status) {
+      case 409:
+        showAlert("entity already exists!", config.alertDiv);
+        break;
+      default:
+        window.location.reload();
+    }
+  });
+}
+
+function showAlert(errorMessage, alertDiv) {
+  const alert = document.getElementById(alertDiv);
+  alert.innerHTML = `
+	<div class="alert alert-danger alert-dismissable fade show d-flex flex-row justify-content-between" role="alert">
+	  <div>${errorMessage}</div>
+	  <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>
+	</div> `;
+}
diff --git a/ui/web/static/js/infinitescroll.js b/ui/web/static/js/infinitescroll.js
new file mode 100644
index 000000000..ab5c5e4ab
--- /dev/null
+++ b/ui/web/static/js/infinitescroll.js
@@ -0,0 +1,70 @@
+// Copyright (c) Abstract Machines
+// SPDX-License-Identifier: Apache-2.0
+
+export function fetchIndividualEntity(config) {
+  document.addEventListener("DOMContentLoaded", function () {
+    getEntities(config.item, "");
+    infiniteScroll(config.item);
+  });
+
+  const input = document.getElementById(config.input);
+
+  input.addEventListener("input", function (event) {
+    const itemSelect = document.getElementById(config.itemSelect);
+    if (event.target.value === "") {
+      itemSelect.innerHTML = `<option disabled>select a ${config.type}</option>`;
+      getEntities(config.item, "");
+      infiniteScroll(config.item);
+    } else {
+      itemSelect.innerHTML = "";
+      getEntities(config.item, event.target.value);
+    }
+  });
+}
+
+function getEntities(item, name) {
+  fetchData(item, name, 1);
+}
+
+function infiniteScroll(item) {
+  var selectElement = document.getElementById("infiniteScroll");
+  var singleOptionHeight = selectElement.querySelector("option").offsetHeight;
+  var selectBoxHeight = selectElement.offsetHeight;
+  var numOptionsBeforeLoad = 2;
+  var lastScrollTop = 0;
+  var currentPageNo = 1;
+  var currentScroll = 0;
+
+  selectElement.addEventListener("scroll", function () {
+    var st = selectElement.scrollTop;
+    var totalHeight = selectElement.querySelectorAll("option").length * singleOptionHeight;
+
+    if (st > lastScrollTop) {
+      currentScroll = st + selectBoxHeight;
+      if (currentScroll + numOptionsBeforeLoad * singleOptionHeight >= totalHeight) {
+        currentPageNo++;
+        fetchData(item, "", currentPageNo);
+      }
+    }
+
+    lastScrollTop = st;
+  });
+}
+
+let limit = 5;
+function fetchData(item, name, page) {
+  fetch(`/entities?item=${item}&limit=${limit}&name=${name}&page=${page}`, {
+    method: "GET",
+  })
+    .then((response) => response.json())
+    .then((data) => {
+      const selectElement = document.getElementById("infiniteScroll");
+      data.data.forEach((entity) => {
+        const option = document.createElement("option");
+        option.value = entity.id;
+        option.text = entity.name;
+        selectElement.appendChild(option);
+      });
+    })
+    .catch((error) => console.error("Error:", error));
+}
diff --git a/ui/web/static/js/main.js b/ui/web/static/js/main.js
deleted file mode 100644
index 07b4ce060..000000000
--- a/ui/web/static/js/main.js
+++ /dev/null
@@ -1,512 +0,0 @@
-// Copyright (c) Abstract Machines
-// SPDX-License-Identifier: Apache-2.0
-
-//function to copy the ID to the clipboard
-function copyToClipboard(button) {
-  var clientIDElement = button.previousElementSibling.firstChild;
-  var clientId = clientIDElement.textContent;
-
-  navigator.clipboard.writeText(clientId).then(
-    function () {
-      //change the copy icon to indicate success
-      button.innerHTML = `<i class="fas fa-check success-icon">`;
-      setTimeout(function () {
-        //revert the copy icon after a short delay
-        button.innerHTML = `<i class ="far fa-copy">`;
-      }, 1000);
-    },
-    function (error) {
-      //handle error
-      console.error("failed to copy to clipboard: ", error);
-    },
-  );
-}
-
-// Form validation functions
-
-function validateName(name, errorDiv, event) {
-  removeErrorMessage(errorDiv);
-  if (name.trim() === "") {
-    event.preventDefault();
-    displayErrorMessage("Name is Required", errorDiv);
-    return false;
-  }
-  return true;
-}
-
-const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
-function validateEmail(email, errorDiv, event) {
-  removeErrorMessage(errorDiv);
-  if (email.trim() === "") {
-    event.preventDefault();
-    displayErrorMessage("Email is Required", errorDiv);
-    return false;
-  } else if (!email.match(emailRegex)) {
-    event.preventDefault();
-    displayErrorMessage("Invalid email format", errorDiv);
-    return false;
-  }
-  return true;
-}
-
-const minLength = 8;
-function validatePassword(password, errorDiv, event) {
-  removeErrorMessage(errorDiv);
-  if (password.trim().length < minLength) {
-    event.preventDefault();
-    var errorMessage = `Password must be at least ${minLength} characters long`;
-    displayErrorMessage(errorMessage, errorDiv);
-    return false;
-  }
-  return true;
-}
-
-function validateJSON(data, errorDiv, event) {
-  removeErrorMessage(errorDiv);
-  try {
-    if (data.trim() !== "") {
-      JSON.parse(data);
-    }
-  } catch (error) {
-    event.preventDefault();
-    displayErrorMessage("not a valid JSON object", errorDiv);
-    return false;
-  }
-  return true;
-}
-
-function validateStringArray(tags, errorDiv, event) {
-  removeErrorMessage(errorDiv);
-  var tagsArray;
-  try {
-    if (tags.trim() !== "") {
-      tagsArray = JSON.parse(tags);
-    }
-    if (
-      !Array.isArray(tagsArray) ||
-      !tagsArray.every(function (tag) {
-        return typeof tag === "string";
-      })
-    ) {
-      event.preventDefault();
-      displayErrorMessage("must be strings in an array", errorDiv);
-      return false;
-    }
-  } catch (error) {
-    event.preventDefault();
-    displayErrorMessage("must be a string array", errorDiv);
-    return false;
-  }
-
-  return true;
-}
-
-function displayErrorMessage(errorMessage, divName) {
-  const errorDiv = document.getElementById(divName);
-  errorDiv.style.display = "block";
-  errorDiv.innerHTML = errorMessage;
-}
-
-function removeErrorMessage(divName) {
-  const errorDiv = document.getElementById(divName);
-  errorDiv.style.display = "none";
-}
-
-function attachValidationListener(config) {
-  const button = document.getElementById(config.buttonId);
-
-  button.addEventListener("click", function (event) {
-    for (const key in config.validations) {
-      if (config.validations.hasOwnProperty(key)) {
-        const validationFunc = config.validations[key];
-        const elementValue = document.getElementById(key).value;
-        validationFunc(elementValue, config.errorDivs[key], event);
-      }
-    }
-  });
-}
-
-// Form subsmission functions
-// config parameters are: formId, url, alertDiv, modal
-function submitCreateForm(config) {
-  const form = document.getElementById(config.formId);
-  form.addEventListener("submit", function (event) {
-    event.preventDefault();
-    const formData = new FormData(form);
-
-    fetch(config.url, {
-      method: "POST",
-      body: formData,
-    })
-      .then(function (response) {
-        switch (response.status) {
-          case 409:
-            showAlert("entity already exists!", config.alertDiv);
-            break;
-          case 400:
-            showAlert("invalid file contents!", config.alertDiv);
-            break;
-          case 415:
-            showAlert("invalid file type!", config.alertDiv);
-            break;
-          default:
-            form.reset();
-            config.modal.hide();
-            window.location.reload();
-        }
-      })
-      .catch((error) => {
-        console.error("error submitting form: ", error);
-      });
-  });
-}
-
-function showAlert(errorMessage, alertDiv) {
-  const alert = document.getElementById(alertDiv);
-  alert.innerHTML = `
-	<div class="alert alert-danger alert-dismissable fade show d-flex flex-row justify-content-between" role="alert">
-	  <div>${errorMessage}</div>
-	  <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="close"></button>
-	</div> `;
-}
-
-// Functions to make a row editable.
-
-// make a cell editable.
-function makeEditable(cell) {
-  cell.setAttribute("contenteditable", "true");
-  cell.dataset.originalContent = cell.innerHTML;
-}
-
-// make cell uneditable.
-function makeUneditable(cell) {
-  const originalContent = cell.dataset.originalContent;
-  cell.innerHTML = originalContent;
-  cell.setAttribute("contenteditable", "false");
-}
-
-// function show the save/cancel buttons and hide the edit button.
-function showSaveCancelButtons(editBtn, saveCancelBtn) {
-  editBtn.style.display = "none";
-  saveCancelBtn.style.display = "inline-block";
-}
-
-// function to show the edit button anf hide the save/cancel buttons.
-function showEditButton(editBtn, saveCancelBtn) {
-  editBtn.style.display = "inline-block";
-  saveCancelBtn.style.display = "none";
-}
-
-// config parameters are: button, field
-function editRow(config) {
-  const button = document.getElementById(config.button);
-
-  button.addEventListener("click", function () {
-    makeEditable(config.cell);
-    showSaveCancelButtons(config.editBtn, config.saveCancelBtn);
-  });
-}
-
-function cancelEditRow(config) {
-  const button = document.getElementById(config.button);
-
-  button.addEventListener("click", function () {
-    makeUneditable(config.cell);
-    showEditButton(config.editBtn, config.saveCancelBtn);
-    removeErrorMessage(config.alertDiv);
-  });
-}
-
-function submitUpdateForm(config) {
-  fetch(config.url, {
-    method: "POST",
-    body: JSON.stringify(config.data),
-    headers: {
-      "Content-Type": "application/json",
-    },
-  }).then((response) => {
-    switch (response.status) {
-      case 409:
-        showAlert("entity already exists!", config.alertDiv);
-        break;
-      default:
-        window.location.reload();
-    }
-  });
-}
-
-function updateName(config) {
-  const button = document.getElementById(config.button);
-
-  button.addEventListener("click", function (event) {
-    const updatedValue = config.cell.textContent.trim();
-    if (validateName(updatedValue, config.alertDiv, event)) {
-      const url = `/${config.entity}/${config.id}`;
-      const data = { [config.field]: updatedValue };
-
-      submitUpdateForm({
-        url: url,
-        data: data,
-        alertDiv: config.alertDiv,
-      });
-    }
-  });
-}
-
-function updateIdentity(config) {
-  const button = document.getElementById(config.button);
-
-  button.addEventListener("click", function (event) {
-    const updatedValue = config.cell.textContent.trim();
-    if (validateEmail(updatedValue, config.alertDiv, event)) {
-      const url = `/${config.entity}/${config.id}/identity`;
-      const data = { [config.field]: updatedValue };
-
-      submitUpdateForm({
-        url: url,
-        data: data,
-        alertDiv: config.alertDiv,
-      });
-    }
-  });
-}
-
-function updateMetadata(config) {
-  const button = document.getElementById(config.button);
-
-  button.addEventListener("click", function (event) {
-    const updatedValue = config.cell.textContent.trim();
-    if (validateJSON(updatedValue, config.alertDiv, event)) {
-      const url = `/${config.entity}/${config.id}`;
-      const data = { [config.field]: JSON.parse(updatedValue) };
-
-      submitUpdateForm({
-        url: url,
-        data: data,
-        alertDiv: config.alertDiv,
-      });
-    }
-  });
-}
-
-function updateTags(config) {
-  const button = document.getElementById(config.button);
-
-  button.addEventListener("click", function (event) {
-    const updatedValue = config.cell.textContent.trim();
-    if (validateStringArray(updatedValue, config.alertDiv, event)) {
-      const url = `/${config.entity}/${config.id}/tags`;
-      const data = { [config.field]: JSON.parse(updatedValue) };
-
-      submitUpdateForm({
-        url: url,
-        data: data,
-        alertDiv: config.alertDiv,
-      });
-    }
-  });
-}
-
-function updateSecret(config) {
-  const button = document.getElementById(config.button);
-
-  button.addEventListener("click", function (event) {
-    const updatedValue = config.cell.textContent.trim();
-    if (validatePassword(updatedValue, config.alertDiv, event)) {
-      const url = `/${config.entity}/${config.id}/secret`;
-      const data = { [config.field]: updatedValue };
-
-      submitUpdateForm({
-        url: url,
-        data: data,
-        alertDiv: config.alertDiv,
-      });
-    }
-  });
-}
-
-function updateOwner(config) {
-  const button = document.getElementById(config.button);
-
-  button.addEventListener("click", function () {
-    const updatedValue = config.cell.textContent.trim();
-    const url = `/${config.entity}/${config.id}/owner`;
-    const data = { [config.field]: updatedValue };
-
-    submitUpdateForm({
-      url: url,
-      data: data,
-      alertDiv: config.alertDiv,
-    });
-  });
-}
-
-function updateDescription(config) {
-  const button = document.getElementById(config.button);
-
-  button.addEventListener("click", function () {
-    const updatedValue = config.cell.textContent.trim();
-    const url = `/${config.entity}/${config.id}`;
-    const data = { [config.field]: updatedValue };
-
-    submitUpdateForm({
-      url: url,
-      data: data,
-      alertDiv: config.alertDiv,
-    });
-  });
-}
-
-// Bootstrap update functions
-function updateContent(config) {
-  const button = document.getElementById(config.button);
-
-  button.addEventListener("click", function () {
-    const updatedValue = config.cell.textContent.trim();
-    const url = `/${config.entity}/${config.id}`;
-    const data = { [config.field]: updatedValue };
-
-    submitUpdateForm({
-      url: url,
-      data: data,
-      alertDiv: config.alertDiv,
-    });
-  });
-}
-
-function updateClientCerts(config) {
-  const button = document.getElementById(config.button);
-
-  button.addEventListener("click", function () {
-    const updatedValue = config.cell.textContent.trim();
-    const url = `/${config.entity}/${config.id}/certs`;
-    const data = { [config.field]: updatedValue };
-
-    submitUpdateForm({
-      url: url,
-      data: data,
-      alertDiv: config.alertDiv,
-    });
-  });
-}
-
-function updateConnections(config) {
-  const button = document.getElementById(config.button);
-
-  button.addEventListener("click", function (event) {
-    const updatedValue = config.cell.textContent.trim();
-
-    if (validateStringArray(updatedValue, config.alertDiv, event)) {
-      const url = `/${config.entity}/${config.id}/connections`;
-      const data = { [config.field]: JSON.parse(updatedValue) };
-
-      submitUpdateForm({
-        url: url,
-        data: data,
-        alertDiv: config.alertDiv,
-      });
-    }
-  });
-}
-
-function attachEditRowListener(config) {
-  for (const key in config.rows) {
-    if (config.rows.hasOwnProperty(key)) {
-      const cell = document.querySelector(`td[data-field="${key}"]`);
-      const editBtn = cell.parentNode.querySelector(".edit-btn");
-      const saveCancelBtn = cell.parentNode.querySelector(".save-cancel-buttons");
-      editRow({
-        button: `edit-${key}`,
-        cell: cell,
-        editBtn: editBtn,
-        saveCancelBtn: saveCancelBtn,
-      });
-      cancelEditRow({
-        button: `cancel-${key}`,
-        cell: cell,
-        editBtn: editBtn,
-        saveCancelBtn: saveCancelBtn,
-        alertDiv: config.errorDiv,
-      });
-      const saveRow = config.rows[key];
-      saveRow({
-        button: `save-${key}`,
-        field: key,
-        cell: cell,
-        editBtn: editBtn,
-        saveCancelBtn: saveCancelBtn,
-        id: config.id,
-        entity: config.entity,
-        alertDiv: config.errorDiv,
-      });
-    }
-  }
-}
-
-function fetchIndividualEntity(config) {
-  document.addEventListener("DOMContentLoaded", function () {
-    getEntities(config.item, "");
-    infiniteScroll(config.item);
-  });
-
-  const input = document.getElementById(config.input);
-
-  input.addEventListener("input", function (event) {
-    const itemSelect = document.getElementById(config.itemSelect);
-    if (event.target.value === "") {
-      itemSelect.innerHTML = `<option disabled>select a ${config.type}</option>`;
-      getEntities(config.item, "");
-      infiniteScroll(config.item);
-    } else {
-      itemSelect.innerHTML = "";
-      getEntities(config.item, event.target.value);
-    }
-  });
-}
-
-function getEntities(item, name) {
-  fetchData(item, name, 1);
-}
-
-function infiniteScroll(item) {
-  var selectElement = document.getElementById("infiniteScroll");
-  var singleOptionHeight = selectElement.querySelector("option").offsetHeight;
-  var selectBoxHeight = selectElement.offsetHeight;
-  var numOptionsBeforeLoad = 2;
-  var lastScrollTop = 0;
-  var currentPageNo = 1;
-  var currentScroll = 0;
-
-  selectElement.addEventListener("scroll", function () {
-    var st = selectElement.scrollTop;
-    var totalHeight = selectElement.querySelectorAll("option").length * singleOptionHeight;
-
-    if (st > lastScrollTop) {
-      currentScroll = st + selectBoxHeight;
-      if (currentScroll + numOptionsBeforeLoad * singleOptionHeight >= totalHeight) {
-        currentPageNo++;
-        fetchData(item, "", currentPageNo);
-      }
-    }
-
-    lastScrollTop = st;
-  });
-}
-
-let limit = 5;
-function fetchData(item, name, page) {
-  fetch(`/entities?item=${item}&limit=${limit}&name=${name}&page=${page}`, {
-    method: "GET",
-  })
-    .then((response) => response.json())
-    .then((data) => {
-      const selectElement = document.getElementById("infiniteScroll");
-      data.data.forEach((entity) => {
-        const option = document.createElement("option");
-        option.value = entity.id;
-        option.text = entity.name;
-        selectElement.appendChild(option);
-      });
-    })
-    .catch((error) => console.error("Error:", error));
-}
diff --git a/ui/web/static/js/update.js b/ui/web/static/js/update.js
new file mode 100644
index 000000000..21d9f5a46
--- /dev/null
+++ b/ui/web/static/js/update.js
@@ -0,0 +1,278 @@
+// Copyright (c) Abstract Machines
+// SPDX-License-Identifier: Apache-2.0
+
+import { submitUpdateForm } from "./forms.js";
+import {
+  validateName,
+  validateEmail,
+  validateJSON,
+  validateStringArray,
+  validatePassword,
+} from "./validation.js";
+
+function updateName(config) {
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function (event) {
+    const updatedValue = config.cell.textContent.trim();
+    if (validateName(updatedValue, config.alertDiv, event)) {
+      const url = `/${config.entity}/${config.id}`;
+      const data = { [config.field]: updatedValue };
+
+      submitUpdateForm({
+        url: url,
+        data: data,
+        alertDiv: config.alertDiv,
+      });
+    }
+  });
+}
+
+function updateIdentity(config) {
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function (event) {
+    const updatedValue = config.cell.textContent.trim();
+    if (validateEmail(updatedValue, config.alertDiv, event)) {
+      const url = `/${config.entity}/${config.id}/identity`;
+      const data = { [config.field]: updatedValue };
+
+      submitUpdateForm({
+        url: url,
+        data: data,
+        alertDiv: config.alertDiv,
+      });
+    }
+  });
+}
+
+function updateMetadata(config) {
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function (event) {
+    const updatedValue = config.cell.textContent.trim();
+    if (validateJSON(updatedValue, config.alertDiv, event)) {
+      const url = `/${config.entity}/${config.id}`;
+      const data = { [config.field]: JSON.parse(updatedValue) };
+
+      submitUpdateForm({
+        url: url,
+        data: data,
+        alertDiv: config.alertDiv,
+      });
+    }
+  });
+}
+
+function updateTags(config) {
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function (event) {
+    const updatedValue = config.cell.textContent.trim();
+    if (validateStringArray(updatedValue, config.alertDiv, event)) {
+      const url = `/${config.entity}/${config.id}/tags`;
+      const data = { [config.field]: JSON.parse(updatedValue) };
+
+      submitUpdateForm({
+        url: url,
+        data: data,
+        alertDiv: config.alertDiv,
+      });
+    }
+  });
+}
+
+function updateSecret(config) {
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function (event) {
+    const updatedValue = config.cell.textContent.trim();
+    if (validatePassword(updatedValue, config.alertDiv, event)) {
+      const url = `/${config.entity}/${config.id}/secret`;
+      const data = { [config.field]: updatedValue };
+
+      submitUpdateForm({
+        url: url,
+        data: data,
+        alertDiv: config.alertDiv,
+      });
+    }
+  });
+}
+
+function updateOwner(config) {
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function () {
+    const updatedValue = config.cell.textContent.trim();
+    const url = `/${config.entity}/${config.id}/owner`;
+    const data = { [config.field]: updatedValue };
+
+    submitUpdateForm({
+      url: url,
+      data: data,
+      alertDiv: config.alertDiv,
+    });
+  });
+}
+
+function updateDescription(config) {
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function () {
+    const updatedValue = config.cell.textContent.trim();
+    const url = `/${config.entity}/${config.id}`;
+    const data = { [config.field]: updatedValue };
+
+    submitUpdateForm({
+      url: url,
+      data: data,
+      alertDiv: config.alertDiv,
+    });
+  });
+}
+
+// Bootstrap update functions
+function updateContent(config) {
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function () {
+    const updatedValue = config.cell.textContent.trim();
+    const url = `/${config.entity}/${config.id}`;
+    const data = { [config.field]: updatedValue };
+
+    submitUpdateForm({
+      url: url,
+      data: data,
+      alertDiv: config.alertDiv,
+    });
+  });
+}
+
+function updateClientCerts(config) {
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function () {
+    const updatedValue = config.cell.textContent.trim();
+    const url = `/${config.entity}/${config.id}/certs`;
+    const data = { [config.field]: updatedValue };
+
+    submitUpdateForm({
+      url: url,
+      data: data,
+      alertDiv: config.alertDiv,
+    });
+  });
+}
+
+function updateConnections(config) {
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function (event) {
+    const updatedValue = config.cell.textContent.trim();
+
+    if (validateStringArray(updatedValue, config.alertDiv, event)) {
+      const url = `/${config.entity}/${config.id}/connections`;
+      const data = { [config.field]: JSON.parse(updatedValue) };
+
+      submitUpdateForm({
+        url: url,
+        data: data,
+        alertDiv: config.alertDiv,
+      });
+    }
+  });
+}
+
+// make a cell editable.
+function makeEditable(cell) {
+  cell.setAttribute("contenteditable", "true");
+  cell.dataset.originalContent = cell.innerHTML;
+}
+
+// make cell uneditable.
+function makeUneditable(cell) {
+  const originalContent = cell.dataset.originalContent;
+  cell.innerHTML = originalContent;
+  cell.setAttribute("contenteditable", "false");
+}
+
+// function show the save/cancel buttons and hide the edit button.
+function showSaveCancelButtons(editBtn, saveCancelBtn) {
+  editBtn.style.display = "none";
+  saveCancelBtn.style.display = "inline-block";
+}
+
+// function to show the edit button anf hide the save/cancel buttons.
+function showEditButton(editBtn, saveCancelBtn) {
+  editBtn.style.display = "inline-block";
+  saveCancelBtn.style.display = "none";
+}
+
+// config parameters are: button, field
+function editRow(config) {
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function () {
+    makeEditable(config.cell);
+    showSaveCancelButtons(config.editBtn, config.saveCancelBtn);
+  });
+}
+
+function cancelEditRow(config) {
+  const button = document.getElementById(config.button);
+
+  button.addEventListener("click", function () {
+    makeUneditable(config.cell);
+    showEditButton(config.editBtn, config.saveCancelBtn);
+    removeErrorMessage(config.alertDiv);
+  });
+}
+
+function attachEditRowListener(config) {
+  for (const key in config.rows) {
+    if (config.rows.hasOwnProperty(key)) {
+      const cell = document.querySelector(`td[data-field="${key}"]`);
+      const editBtn = cell.parentNode.querySelector(".edit-btn");
+      const saveCancelBtn = cell.parentNode.querySelector(".save-cancel-buttons");
+      editRow({
+        button: `edit-${key}`,
+        cell: cell,
+        editBtn: editBtn,
+        saveCancelBtn: saveCancelBtn,
+      });
+      cancelEditRow({
+        button: `cancel-${key}`,
+        cell: cell,
+        editBtn: editBtn,
+        saveCancelBtn: saveCancelBtn,
+        alertDiv: config.errorDiv,
+      });
+      const saveRow = config.rows[key];
+      saveRow({
+        button: `save-${key}`,
+        field: key,
+        cell: cell,
+        editBtn: editBtn,
+        saveCancelBtn: saveCancelBtn,
+        id: config.id,
+        entity: config.entity,
+        alertDiv: config.errorDiv,
+      });
+    }
+  }
+}
+
+export {
+  updateName,
+  updateIdentity,
+  updateMetadata,
+  updateTags,
+  updateSecret,
+  updateOwner,
+  updateDescription,
+  updateContent,
+  updateClientCerts,
+  updateConnections,
+  attachEditRowListener,
+};
diff --git a/ui/web/static/js/validation.js b/ui/web/static/js/validation.js
new file mode 100644
index 000000000..8d83f2450
--- /dev/null
+++ b/ui/web/static/js/validation.js
@@ -0,0 +1,105 @@
+// Copyright (c) Abstract Machines
+// SPDX-License-Identifier: Apache-2.0
+
+import { displayErrorMessage, removeErrorMessage } from "./errors.js";
+
+const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
+const minLength = 8;
+
+function validateName(name, errorDiv, event) {
+  removeErrorMessage(errorDiv);
+  if (name.trim() === "") {
+    event.preventDefault();
+    displayErrorMessage("Name is Required", errorDiv);
+    return false;
+  }
+  return true;
+}
+
+function validateEmail(email, errorDiv, event) {
+  removeErrorMessage(errorDiv);
+  if (email.trim() === "") {
+    event.preventDefault();
+    displayErrorMessage("Email is Required", errorDiv);
+    return false;
+  } else if (!email.match(emailRegex)) {
+    event.preventDefault();
+    displayErrorMessage("Invalid email format", errorDiv);
+    return false;
+  }
+  return true;
+}
+
+function validatePassword(password, errorDiv, event) {
+  removeErrorMessage(errorDiv);
+  if (password.trim().length < minLength) {
+    event.preventDefault();
+    var errorMessage = `Password must be at least ${minLength} characters long`;
+    displayErrorMessage(errorMessage, errorDiv);
+    return false;
+  }
+  return true;
+}
+
+function validateJSON(data, errorDiv, event) {
+  removeErrorMessage(errorDiv);
+  try {
+    if (data.trim() !== "") {
+      JSON.parse(data);
+    }
+  } catch (error) {
+    event.preventDefault();
+    displayErrorMessage("not a valid JSON object", errorDiv);
+    return false;
+  }
+  return true;
+}
+
+function validateStringArray(tags, errorDiv, event) {
+  removeErrorMessage(errorDiv);
+  var tagsArray;
+  try {
+    if (tags.trim() !== "") {
+      tagsArray = JSON.parse(tags);
+    }
+    if (
+      !Array.isArray(tagsArray) ||
+      !tagsArray.every(function (tag) {
+        return typeof tag === "string";
+      })
+    ) {
+      event.preventDefault();
+      displayErrorMessage("must be strings in an array", errorDiv);
+      return false;
+    }
+  } catch (error) {
+    event.preventDefault();
+    displayErrorMessage("must be a string array", errorDiv);
+    return false;
+  }
+
+  return true;
+}
+
+function attachValidationListener(config) {
+  const button = document.getElementById(config.buttonId);
+
+  button.addEventListener("click", function (event) {
+    for (const key in config.validations) {
+      if (config.validations.hasOwnProperty(key)) {
+        const validationFunc = config.validations[key];
+        const elementValue = document.getElementById(key).value;
+        validationFunc(elementValue, config.errorDivs[key], event);
+      }
+    }
+  });
+}
+
+export {
+  validateName,
+  validateEmail,
+  validatePassword,
+  validateJSON,
+  validateStringArray,
+  attachValidationListener,
+};
diff --git a/ui/web/template/bootstrap.html b/ui/web/template/bootstrap.html
index a377c346b..a821146e5 100644
--- a/ui/web/template/bootstrap.html
+++ b/ui/web/template/bootstrap.html
@@ -4,7 +4,11 @@
 {{ define "bootstrap" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Bootstrap</title>
+      {{ template "header" }}
+      <script src="/js/update.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -129,7 +133,8 @@
         </div>
       </div>
       {{ template "footer" }}
-    <script>
+    <script type="module">
+      import { attachEditRowListener, updateName, updateContent, updateConnections, updateClientCerts } from "/js/update.js";
       attachEditRowListener({
         entity: "bootstraps",
         id: "{{ .Bootstrap.ThingID }}",
diff --git a/ui/web/template/bootstraps.html b/ui/web/template/bootstraps.html
index 1e0f7e70e..f728a18fe 100644
--- a/ui/web/template/bootstraps.html
+++ b/ui/web/template/bootstraps.html
@@ -4,7 +4,13 @@
 {{ define "bootstraps" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Bootstraps</title>
+      {{ template "header" }}
+      <script src="/js/forms.js" type="module"></script>
+      <script src="/js/validation.js" type="module"></script>
+      <script src="/js/infinitescroll.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -32,7 +38,7 @@ <h5 class="modal-title" id="addBootstrapModalLabel">
                           </h5>
                         </div>
                         <div class="modal-body">
-                          <form method="post" onsubmit="return validateForm()">
+                          <form method="post">
                             <div class="mb-3">
                               <label for="name" class="form-label">Bootstrap Name</label>
                               <input
@@ -97,7 +103,7 @@ <h5 class="modal-title" id="addBootstrapModalLabel">
                               <div id="channelsHelp" class="form-text">
                                 Enter channels as a string slice.
                               </div>
-                              <div id="channelsError" class="error-message"></div>
+                              <div id="channelsError" class="text-danger"></div>
                             </div>
 
                             <div class="mb-3">
@@ -112,7 +118,7 @@ <h5 class="modal-title" id="addBootstrapModalLabel">
                               <div id="contentHelp" class="form-text">
                                 Enter content in JSON format.
                               </div>
-                              <div id="contentError" class="error-message"></div>
+                              <div id="contentError" class="text-danger"></div>
                             </div>
                             <div class="mb-3">
                               <label for="clientCert" class="form-label">Client Cert</label>
@@ -147,7 +153,13 @@ <h5 class="modal-title" id="addBootstrapModalLabel">
                                 value="CACert"
                               />
                             </div>
-                            <button type="submit" class="btn body-button">Submit</button>
+                            <button
+                              type="submit"
+                              id="create-bootstrap-button"
+                              class="btn body-button"
+                            >
+                              Submit
+                            </button>
                           </form>
                         </div>
                       </div>
@@ -194,54 +206,31 @@ <h5 class="modal-title" id="addBootstrapModalLabel">
       </div>
       {{ template "footer" }}
       <script>
-        function validateForm() {
-          var channelsInput = document.getElementById("channels").value;
-          var contentInput = document.getElementById("content").value;
-
-          var channelsError = document.getElementById("channelsError");
-          var contentError = document.getElementById("contentError");
-
-          channelsError.innerHTML = "";
-          contentError.innerHTML = "";
-
-          var content;
-          var channels;
-
-          var isValid = true;
-
-          try {
-            channels = JSON.parse(channelsInput);
-          } catch (error) {
-            channelsError.innerHTML = "Please enter valid channels as a string array!";
-            isValid = false;
-          }
-
-          if (
-            !Array.isArray(channels) ||
-            !channels.every(function (channels) {
-              return typeof channels === "string";
-            })
-          ) {
-            channelsError.innerHTML = "Channels must be a string array!";
-            isValid = false;
-          }
-
-          try {
-            content = JSON.parse(contentInput);
-            content = contentInput;
-          } catch (error) {
-            contentError.innerHTML = "Please enter valid content in JSON format!";
-            isValid = false;
-          }
-
-          return isValid;
-        }
-
         const bootstrapsModal = new bootstrap.Modal(document.getElementById("addBootstrapModal"));
 
         function openModal() {
           bootstrapsModal.show();
         }
+      </script>
+      <script type="module">
+        import {
+          attachValidationListener,
+          validateStringArray,
+          validateJSON,
+        } from "/js/validation.js";
+        import { fetchIndividualEntity } from "/js/infinitescroll.js";
+
+        attachValidationListener({
+          buttonId: "create-bootstrap-button",
+          errorDivs: {
+            channels: "channelsError",
+            content: "contentError",
+          },
+          validations: {
+            channels: validateStringArray,
+            content: validateJSON,
+          },
+        });
 
         fetchIndividualEntity({
           input: "thingFilter",
diff --git a/ui/web/template/channel.html b/ui/web/template/channel.html
index a9d7a6c2d..b8c43aebb 100644
--- a/ui/web/template/channel.html
+++ b/ui/web/template/channel.html
@@ -4,7 +4,11 @@
 {{ define "channel" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Channel</title>
+      {{ template "header" }}
+      <script src="/js/update.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -129,20 +133,21 @@
         </div>
       </div>
       {{ template "footer" }}
-    <script>
-      attachEditRowListener(
-			{
-				entity: "channels",
-				id: "{{ .Channel.ID }}",
-				rows: {
-					name:updateName,
-					description: updateDescription,
-					metadata:updateMetadata,
-				},
-				errorDiv: "error-message",
-			}
-		);
-    </script>
+      <script type="module">
+        import { attachEditRowListener, updateName, updateDescription, updateMetadata} from "/js/update.js";
+
+        attachEditRowListener(
+        {
+          entity: "channels",
+          id: "{{ .Channel.ID }}",
+          rows: {
+            name:updateName,
+            description: updateDescription,
+            metadata:updateMetadata,
+          },
+          errorDiv: "error-message",
+        });
+      </script>
     </body>
   </html>
 {{ end }}
diff --git a/ui/web/template/channelgroups.html b/ui/web/template/channelgroups.html
index 62d8f9fc6..69757abfe 100644
--- a/ui/web/template/channelgroups.html
+++ b/ui/web/template/channelgroups.html
@@ -4,7 +4,11 @@
 {{ define "channelgroups" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Channel Groups</title>
+      {{ template "header" }}
+      <script src="/js/infinitescroll.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -161,6 +165,9 @@ <h1 class="modal-title fs-5" id="addGroupModalLabel">Add Group</h1>
         function openGroupModal() {
           groupModal.show();
         }
+      </script>
+      <script type="module">
+        import { fetchIndividualEntity } from "/js/infinitescroll.js";
 
         fetchIndividualEntity({
           input: "groupFilter",
diff --git a/ui/web/template/channels.html b/ui/web/template/channels.html
index 6a67066e6..1dc7faf30 100644
--- a/ui/web/template/channels.html
+++ b/ui/web/template/channels.html
@@ -4,7 +4,13 @@
 {{ define "channels" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Channels</title>
+      {{ template "header" }}
+      <script src="/js/forms.js" type="module"></script>
+      <script src="/js/validation.js" type="module"></script>
+      <script src="/js/infinitescroll.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -106,144 +112,118 @@ <h5 class="modal-title" id="addChannelModalLabel">Add Channel</h5>
                     Add Channels
                   </button>
 
-									<!-- Modal -->
-									<div
-										class="modal fade"
-										id="addChannelsModal"
-										tabindex="-1"
-										role="dialog"
-										aria-labelledby="addChannelsModalLabel"
-										aria-hidden="true"
-									>
-										<div class="modal-dialog" role="document">
-											<div class="modal-content">
-												<div class="modal-header">
-													<h5 class="modal-title" id="addChannelsModalLabel">
-														Add Channels
-													</h5>
-												</div>
-												<div class="modal-body">
-													<div id="alertBulkMessage"></div>
-													<form
-														method="post"
-														enctype="multipart/form-data"
-														id="bulkchannelsform"
-													>
-														<div class="form-group">
-															<label for="channelsFile">
-																Add csv file containing channels names with
-																metadata. The metadata field can be empty. Find
-																a sample csv file
-																<a
-																	href="https://github.com/absmach/magistrala-ui/blob/main/samples/channels.csv"
-																	target="_blank"
-																>
-																	here
-																</a>
-															</label>
-															<input
-																type="file"
-																class="form-control-file"
-																id="channelsFile"
-																name="channelsFile"
-																required
-															/>
-															<button
-																type="submit"
-																value="upload"
-																class="btn body-button"
-															>
-																Submit
-															</button>
-														</div>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
-								</div>
-								<div class="table-responsive table-container">
-									{{ template "tableheader" . }}
-									<div class="itemsTable">
-										<table id="itemsTable" class="table">
-											<thead>
-												<tr>
-													<th scope="col">Name</th>
-													<th scope="col">ID</th>
-													<th class="desc-col" scope="col">Description</th>
-													<th class="meta-col" scope="col">Metadata</th>
-													<th class="created-col" scope="col">Created At</th>
-													<th class="text-center" scope="col"></th>
-												</tr>
-											</thead>
-											<tbody>
-												{{ range $i, $c := .Channels }}
-													{{ $disableButton := false }}
-													<tr>
-														<td>{{ $c.Name }}</td>
-														<td>
-															<div class="copy-con-container">
-																<a href="{{ printf "/channels/%s" $c.ID }}">
-																	{{ $c.ID }}
-																</a>
-																<button
-																	class="copy-icon"
-																	onclick="copyToClipboard(this)"
-																>
-																	<i class="far fa-copy"></i>
-																</button>
-															</div>
-														</td>
-														<td class="desc-col">{{ $c.Description }}</td>
-														<td class="meta-col">{{ toJSON $c.Metadata }}</td>
-														<td class="created-col">{{ $c.CreatedAt }}</td>
-														<td class="text-center">
-															<form action="/channels/disabled" method="post">
-																<input
-																	type="hidden"
-																	name="channelID"
-																	id="channelID"
-																	value="{{ $c.ID }}"
-																/>
-																<button
-																	type="submit"
-																	class="btn btn-sm"
-																	{{ if
-																		$disableButton
-																	}}
-																		disabled
-																	{{ end }}
-																>
-																	<i class="fas fa-trash-alt"></i>
-																</button>
-															</form>
-														</td>
-													</tr>
-												{{ end }}
-											</tbody>
-										</table>
-									</div>
-									{{ template "tablefooter" . }}
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
-			<script>
-				attachValidationListener({
-					buttonId: "create-channel-button",
-					errorDivs: {
-						name: "nameError",
-						metadata: "metadataError",
-					},
-					validations: {
-						name: validateName,
-						metadata: validateJSON,
-					},
-				});
-
+                  <!-- Modal -->
+                  <div
+                    class="modal fade"
+                    id="addChannelsModal"
+                    tabindex="-1"
+                    role="dialog"
+                    aria-labelledby="addChannelsModalLabel"
+                    aria-hidden="true"
+                  >
+                    <div class="modal-dialog" role="document">
+                      <div class="modal-content">
+                        <div class="modal-header">
+                          <h5 class="modal-title" id="addChannelsModalLabel">Add Channels</h5>
+                        </div>
+                        <div class="modal-body">
+                          <div id="alertBulkMessage"></div>
+                          <form method="post" enctype="multipart/form-data" id="bulkchannelsform">
+                            <div class="form-group">
+                              <label for="channelsFile">
+                                Add csv file containing channels names with metadata. The metadata
+                                field can be empty. Find a sample csv file
+                                <a
+                                  href="https://github.com/absmach/magistrala-ui/blob/main/samples/channels.csv"
+                                  target="_blank"
+                                >
+                                  here
+                                </a>
+                              </label>
+                              <input
+                                type="file"
+                                class="form-control-file"
+                                id="channelsFile"
+                                name="channelsFile"
+                                required
+                              />
+                              <button type="submit" value="upload" class="btn body-button">
+                                Submit
+                              </button>
+                            </div>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+                <div class="table-responsive table-container">
+                  {{ template "tableheader" . }}
+                  <div class="itemsTable">
+                    <table id="itemsTable" class="table">
+                      <thead>
+                        <tr>
+                          <th scope="col">Name</th>
+                          <th scope="col">ID</th>
+                          <th class="desc-col" scope="col">Description</th>
+                          <th class="meta-col" scope="col">Metadata</th>
+                          <th class="created-col" scope="col">Created At</th>
+                          <th class="text-center" scope="col"></th>
+                        </tr>
+                      </thead>
+                      <tbody>
+                        {{ range $i, $c := .Channels }}
+                          {{ $disableButton := false }}
+                          <tr>
+                            <td>{{ $c.Name }}</td>
+                            <td>
+                              <div class="copy-con-container">
+                                <a href="{{ printf "/channels/%s" $c.ID }}">
+                                  {{ $c.ID }}
+                                </a>
+                                <button class="copy-icon" onclick="copyToClipboard(this)">
+                                  <i class="far fa-copy"></i>
+                                </button>
+                              </div>
+                            </td>
+                            <td class="desc-col">{{ $c.Description }}</td>
+                            <td class="meta-col">{{ toJSON $c.Metadata }}</td>
+                            <td class="created-col">{{ $c.CreatedAt }}</td>
+                            <td class="text-center">
+                              <form action="/channels/disabled" method="post">
+                                <input
+                                  type="hidden"
+                                  name="channelID"
+                                  id="channelID"
+                                  value="{{ $c.ID }}"
+                                />
+                                <button
+                                  type="submit"
+                                  class="btn btn-sm"
+                                  {{ if
+                                    $disableButton
+                                  }}
+                                    disabled
+                                  {{ end }}
+                                >
+                                  <i class="fas fa-trash-alt"></i>
+                                </button>
+                              </form>
+                            </td>
+                          </tr>
+                        {{ end }}
+                      </tbody>
+                    </table>
+                  </div>
+                  {{ template "tablefooter" . }}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
+      <script>
         const channelModal = new bootstrap.Modal(document.getElementById("addChannelModal"));
         const channelsModal = new bootstrap.Modal(document.getElementById("addChannelsModal"));
 
@@ -254,6 +234,23 @@ <h5 class="modal-title" id="addChannelsModalLabel">
             channelsModal.show();
           }
         }
+      </script>
+      <script type="module">
+        import { attachValidationListener, validateName, validateJSON } from "/js/validation.js";
+        import { submitCreateForm } from "/js/forms.js";
+        import { fetchIndividualEntity } from "/js/infinitescroll.js";
+
+        attachValidationListener({
+          buttonId: "create-channel-button",
+          errorDivs: {
+            name: "nameError",
+            metadata: "metadataError",
+          },
+          validations: {
+            name: validateName,
+            metadata: validateJSON,
+          },
+        });
 
         submitCreateForm({
           url: "/channels",
diff --git a/ui/web/template/channelthings.html b/ui/web/template/channelthings.html
index a0e6c32c8..2be7ff125 100644
--- a/ui/web/template/channelthings.html
+++ b/ui/web/template/channelthings.html
@@ -4,7 +4,11 @@
 {{ define "channelthings" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Channel Things</title>
+      {{ template "header" }}
+      <script src="/js/infinitescroll.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -161,6 +165,9 @@ <h1 class="modal-title fs-5" id="addThingModalLabel">Add Thing</h1>
         function openThingModal() {
           thingModal.show();
         }
+      </script>
+      <script type="module">
+        import { fetchIndividualEntity } from "/js/infinitescroll.js";
 
         fetchIndividualEntity({
           input: "thingFilter",
diff --git a/ui/web/template/channelusers.html b/ui/web/template/channelusers.html
index 12d383c14..845907f62 100644
--- a/ui/web/template/channelusers.html
+++ b/ui/web/template/channelusers.html
@@ -4,7 +4,11 @@
 {{ define "channelusers" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Channel Users</title>
+      {{ template "header" }}
+      <script src="/js/infinitescroll.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -475,12 +479,6 @@ <h1 class="modal-title fs-5" id="addUserModalLabel">Add User</h1>
 					userModal.show();
 				}
 
-				fetchIndividualEntity({
-					input: "userFilter",
-					itemSelect: "infiniteScroll",
-					item: "users",
-				});
-
         function openTab(relation) {
 					event.preventDefault();
 					var channelID = '{{.ChannelID}}';
@@ -493,6 +491,15 @@ <h1 class="modal-title fs-5" id="addUserModalLabel">Add User</h1>
 					.catch((error) => console.error("Error:", error));
 				}
 			</script>
+      <script type="module">
+        import { fetchIndividualEntity } from "/js/infinitescroll.js";
+
+        fetchIndividualEntity({
+          input: "userFilter",
+          itemSelect: "infiniteScroll",
+          item: "users",
+        });
+      </script>
     </body>
   </html>
 {{ end }}
diff --git a/ui/web/template/error.html b/ui/web/template/error.html
index 63c0ad3d9..bd83d8150 100644
--- a/ui/web/template/error.html
+++ b/ui/web/template/error.html
@@ -4,7 +4,10 @@
 {{ define "error" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Error</title>
+      {{ template "header" }}
+    </head>
     <body>
       {{ template "navbar" }}
       <div class="main-content">
diff --git a/ui/web/template/group.html b/ui/web/template/group.html
index e7ae42567..ab1f59c47 100644
--- a/ui/web/template/group.html
+++ b/ui/web/template/group.html
@@ -4,7 +4,11 @@
 {{ define "group" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Group</title>
+      {{ template "header" }}
+      <script src="/js/update.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -113,7 +117,9 @@
         </div>
       </div>
       {{ template "footer" }}
-    <script>
+    <script type="module">
+      import { attachEditRowListener, updateName, updateDescription, updateMetadata} from "/js/update.js";
+
       attachEditRowListener(
 			{
 				entity: "groups",
diff --git a/ui/web/template/groupchannels.html b/ui/web/template/groupchannels.html
index 26b5af2fa..daf8eaee7 100644
--- a/ui/web/template/groupchannels.html
+++ b/ui/web/template/groupchannels.html
@@ -4,7 +4,11 @@
 {{ define "groupchannels" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Group Channels</title>
+      {{ template "header" }}
+      <script src="/js/infinitescroll.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -156,6 +160,9 @@ <h1 class="modal-title fs-5" id="addChannelModalLabel">Add Channel</h1>
         function openChannelModal() {
           channelModal.show();
         }
+      </script>
+      <script type="module">
+        import { fetchIndividualEntity } from "/js/infinitescroll.js";
 
         fetchIndividualEntity({
           input: "channelFilter",
diff --git a/ui/web/template/groups.html b/ui/web/template/groups.html
index 33a82d047..ffc641fb0 100644
--- a/ui/web/template/groups.html
+++ b/ui/web/template/groups.html
@@ -4,7 +4,13 @@
 {{ define "groups" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Groups</title>
+      {{ template "header" }}
+      <script src="/js/forms.js" type="module"></script>
+      <script src="/js/validation.js" type="module"></script>
+      <script src="/js/infinitescroll.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -100,131 +106,134 @@ <h5 class="modal-title" id="addGroupModalLabel">Add Group</h5>
                     Add Groups
                   </button>
 
-									<!-- Modal -->
-									<div
-										class="modal fade"
-										id="addGroupsModal"
-										tabindex="-1"
-										role="dialog"
-										aria-labelledby="addGroupsModalLabel"
-										aria-hidden="true"
-									>
-										<div class="modal-dialog" role="document">
-											<div class="modal-content">
-												<div class="modal-header">
-													<h5 class="modal-title" id="addGroupsModalLabel">
-														Add Groups
-													</h5>
-												</div>
-												<div class="modal-body">
-													<div id="alertBulkMessage"></div>
-													<form
-														enctype="multipart/form-data"
-														id="bulkgroupsform"
-													>
-														<div class="form-group">
-															<label for="groupsFile">
-																Add csv file containing groups names. Find a
-																sample csv file
-																<a
-																	href="https://github.com/absmach/magistrala-ui/blob/main/samples/groups.csv"
-																	target="_blank"
-																>
-																	here
-																</a>
-															</label>
-															<input
-																type="file"
-																class="form-control-file"
-																id="groupsFile"
-																name="groupsFile"
-																required
-															/>
-															<button
-																type="submit"
-																value="upload"
-																class="btn body-button"
-															>
-																Submit
-															</button>
-														</div>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
-								</div>
-								<div class="table-responsive table-container">
-									{{ template "tableheader" . }}
-									<div class="itemsTable">
-										<table id="itemsTable" class="table">
-											<thead>
-												<tr>
-													<th scope="col">Name</th>
-													<th scope="col">ID</th>
-													<th class="desc-col" scope="col">Description</th>
-													<th class="meta-col" scope="col">Metadata</th>
-													<th class="created-col" scope="col">Created At</th>
-													<th class="text-center" scope="col"></th>
-												</tr>
-											</thead>
-											<tbody>
-												{{ range $i, $g := .Groups }}
-													{{ $disableButton := false }}
-													<tr>
-														<td>{{ $g.Name }}</td>
-														<td>
-															<div class="copy-con-container">
-																<a href="{{ printf "/groups/%s" $g.ID }}">
-																	{{ $g.ID }}
-																</a>
-																<button
-																	class="copy-icon"
-																	onclick="copyToClipboard(this)"
-																>
-																	<i class="far fa-copy"></i>
-																</button>
-															</div>
-														</td>
-														<td class="desc-col">{{ $g.Description }}</td>
-														<td class="meta-col">{{ toJSON $g.Metadata }}</td>
-														<td class="created-col">{{ $g.CreatedAt }}</td>
-														<td class="text-center">
-															<form action="/groups/disabled" method="post">
-																<input
-																	type="hidden"
-																	name="groupID"
-																	id="groupID"
-																	value="{{ $g.ID }}"
-																/>
-																<button
-																	type="submit"
-																	class="btn btn-sm"
-																	{{ if
-																		$disableButton
-																	}}
-																		disabled
-																	{{ end }}
-																>
-																	<i class="fas fa-trash-alt"></i>
-																</button>
-															</form>
-														</td>
-													</tr>
-												{{ end }}
-											</tbody>
-										</table>
-									</div>
-									{{ template "tablefooter" . }}
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
+                  <!-- Modal -->
+                  <div
+                    class="modal fade"
+                    id="addGroupsModal"
+                    tabindex="-1"
+                    role="dialog"
+                    aria-labelledby="addGroupsModalLabel"
+                    aria-hidden="true"
+                  >
+                    <div class="modal-dialog" role="document">
+                      <div class="modal-content">
+                        <div class="modal-header">
+                          <h5 class="modal-title" id="addGroupsModalLabel">Add Groups</h5>
+                        </div>
+                        <div class="modal-body">
+                          <div id="alertBulkMessage"></div>
+                          <form enctype="multipart/form-data" id="bulkgroupsform">
+                            <div class="form-group">
+                              <label for="groupsFile">
+                                Add csv file containing groups names. Find a sample csv file
+                                <a
+                                  href="https://github.com/absmach/magistrala-ui/blob/main/samples/groups.csv"
+                                  target="_blank"
+                                >
+                                  here
+                                </a>
+                              </label>
+                              <input
+                                type="file"
+                                class="form-control-file"
+                                id="groupsFile"
+                                name="groupsFile"
+                                required
+                              />
+                              <button type="submit" value="upload" class="btn body-button">
+                                Submit
+                              </button>
+                            </div>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+                <div class="table-responsive table-container">
+                  {{ template "tableheader" . }}
+                  <div class="itemsTable">
+                    <table id="itemsTable" class="table">
+                      <thead>
+                        <tr>
+                          <th scope="col">Name</th>
+                          <th scope="col">ID</th>
+                          <th class="desc-col" scope="col">Description</th>
+                          <th class="meta-col" scope="col">Metadata</th>
+                          <th class="created-col" scope="col">Created At</th>
+                          <th class="text-center" scope="col"></th>
+                        </tr>
+                      </thead>
+                      <tbody>
+                        {{ range $i, $g := .Groups }}
+                          {{ $disableButton := false }}
+                          <tr>
+                            <td>{{ $g.Name }}</td>
+                            <td>
+                              <div class="copy-con-container">
+                                <a href="{{ printf "/groups/%s" $g.ID }}">
+                                  {{ $g.ID }}
+                                </a>
+                                <button class="copy-icon" onclick="copyToClipboard(this)">
+                                  <i class="far fa-copy"></i>
+                                </button>
+                              </div>
+                            </td>
+                            <td class="desc-col">{{ $g.Description }}</td>
+                            <td class="meta-col">{{ toJSON $g.Metadata }}</td>
+                            <td class="created-col">{{ $g.CreatedAt }}</td>
+                            <td class="text-center">
+                              <form action="/groups/disabled" method="post">
+                                <input
+                                  type="hidden"
+                                  name="groupID"
+                                  id="groupID"
+                                  value="{{ $g.ID }}"
+                                />
+                                <button
+                                  type="submit"
+                                  class="btn btn-sm"
+                                  {{ if
+                                    $disableButton
+                                  }}
+                                    disabled
+                                  {{ end }}
+                                >
+                                  <i class="fas fa-trash-alt"></i>
+                                </button>
+                              </form>
+                            </td>
+                          </tr>
+                        {{ end }}
+                      </tbody>
+                    </table>
+                  </div>
+                  {{ template "tablefooter" . }}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
 
       {{ template "footer" }}
       <script>
+        const groupModal = new bootstrap.Modal(document.getElementById("addGroupModal"));
+        const groupsModal = new bootstrap.Modal(document.getElementById("addGroupsModal"));
+
+        function openModal(modal) {
+          if (modal === "single") {
+            groupModal.show();
+          } else if (modal === "bulk") {
+            groupsModal.show();
+          }
+        }
+      </script>
+      <script type="module">
+        import { attachValidationListener, validateName, validateJSON } from "/js/validation.js";
+        import { submitCreateForm } from "/js/forms.js";
+        import { fetchIndividualEntity } from "/js/infinitescroll.js";
+
         attachValidationListener({
           buttonId: "create-group-button",
           errorDivs: {
@@ -237,17 +246,6 @@ <h5 class="modal-title" id="addGroupsModalLabel">
           },
         });
 
-        const groupModal = new bootstrap.Modal(document.getElementById("addGroupModal"));
-        const groupsModal = new bootstrap.Modal(document.getElementById("addGroupsModal"));
-
-        function openModal(modal) {
-          if (modal === "single") {
-            groupModal.show();
-          } else if (modal === "bulk") {
-            groupsModal.show();
-          }
-        }
-
         submitCreateForm({
           url: "/groups",
           formId: "groupform",
diff --git a/ui/web/template/groupusers.html b/ui/web/template/groupusers.html
index ae60dc189..270af2de5 100644
--- a/ui/web/template/groupusers.html
+++ b/ui/web/template/groupusers.html
@@ -4,7 +4,11 @@
 {{ define "groupusers" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Group Users</title>
+      {{ template "header" }}
+      <script src="/js/infinitescroll.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -471,12 +475,6 @@ <h1 class="modal-title fs-5" id="addUserModalLabel">Add User</h1>
 					userModal.show();
 				}
 
-				fetchIndividualEntity({
-					input: "userFilter",
-					itemSelect: "infiniteScroll",
-					item: "users",
-				});
-
 				function openTab(relation) {
 					event.preventDefault();
           var groupID = '{{.GroupID}}';
@@ -489,6 +487,15 @@ <h1 class="modal-title fs-5" id="addUserModalLabel">Add User</h1>
           .catch((error) => console.error("Error:", error));
 				}
 			</script>
+      <script type="module">
+        import { fetchIndividualEntity } from "/js/infinitescroll.js";
+
+        fetchIndividualEntity({
+          input: "userFilter",
+          itemSelect: "infiniteScroll",
+          item: "users",
+        });
+      </script>
     </body>
   </html>
 {{ end }}
diff --git a/ui/web/template/header.html b/ui/web/template/header.html
index e906b381b..8f7c8d5c4 100644
--- a/ui/web/template/header.html
+++ b/ui/web/template/header.html
@@ -2,25 +2,20 @@
 SPDX-License-Identifier: Apache-2.0 -->
 
 {{ define "header" }}
-  <head>
-    <meta charset="utf-8" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <meta name="description" content="" />
-    <meta name="author" content="" />
-
-    <title>Magistrala</title>
-    <link rel="stylesheet" href="/css/styles.css" />
-    <link rel="icon" type="image/x-icon" href="/images/favicon.ico" />
-    <link
-      rel="stylesheet"
-      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
-    />
-    <link
-      href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css"
-      rel="stylesheet"
-      integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9"
-      crossorigin="anonymous"
-    />
-    <script src="/js/main.js"></script>
-  </head>
+  <meta charset="utf-8" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+  <meta name="description" content="" />
+  <meta name="author" content="" />
+  <link rel="stylesheet" href="/css/styles.css" />
+  <link rel="icon" type="image/x-icon" href="/images/favicon.ico" />
+  <link
+    rel="stylesheet"
+    href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
+  />
+  <link
+    href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css"
+    rel="stylesheet"
+    integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9"
+    crossorigin="anonymous"
+  />
 {{ end }}
diff --git a/ui/web/template/index.html b/ui/web/template/index.html
index ad5a656e6..7b731d0e3 100644
--- a/ui/web/template/index.html
+++ b/ui/web/template/index.html
@@ -4,7 +4,10 @@
 {{ define "index" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Magistrala</title>
+      {{ template "header" }}
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content mt-5 pt-5">
diff --git a/ui/web/template/login.html b/ui/web/template/login.html
index 1866189f4..67aadcf0a 100644
--- a/ui/web/template/login.html
+++ b/ui/web/template/login.html
@@ -4,7 +4,10 @@
 {{ define "login" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Login</title>
+      {{ template "header" }}
+    </head>
     <body class="login-body">
       <div class="container mt-5 pt-5">
         <div class="row p-5">
diff --git a/ui/web/template/messagesread.html b/ui/web/template/messagesread.html
index 5f060ca77..4b008b119 100644
--- a/ui/web/template/messagesread.html
+++ b/ui/web/template/messagesread.html
@@ -4,13 +4,13 @@
 {{ define "messagesread" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
-
+    <head>
+      <title>Messages</title>
+      {{ template "header" }}
 
+    </head>
     <body>
       {{ template "navbar" . }}
-
-
       <div class="main-content pt-3">
         <div class="container">
           <div class="row">
@@ -128,6 +128,7 @@ <h5 class="modal-title" id="sendMessageModalLabel">Read Message</h5>
 
       {{ template "footer" }}
 
+
       <script>
         const messageModal = new bootstrap.Modal(document.getElementById("sendMessageModal"));
 
diff --git a/ui/web/template/resetpassword.html b/ui/web/template/resetpassword.html
index 380896f7b..6152b138d 100644
--- a/ui/web/template/resetpassword.html
+++ b/ui/web/template/resetpassword.html
@@ -4,7 +4,10 @@
 {{ define "resetPassword" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Password Reset</title>
+      {{ template "header" }}
+    </head>
     <body class="login-body">
       <div class="container mt-5 pt-5">
         <div class="row p-5">
diff --git a/ui/web/template/terminal.html b/ui/web/template/terminal.html
index bbc15138c..4973d4575 100644
--- a/ui/web/template/terminal.html
+++ b/ui/web/template/terminal.html
@@ -4,7 +4,10 @@
 {{ define "remoteTerminal" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Terminal</title>
+      {{ template "header" }}
+    </head>
     <style>
       .terminal {
         color: #fff;
diff --git a/ui/web/template/thing.html b/ui/web/template/thing.html
index 11efc99dc..9a6499b61 100644
--- a/ui/web/template/thing.html
+++ b/ui/web/template/thing.html
@@ -4,7 +4,11 @@
 {{ define "thing" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Thing</title>
+      {{ template "header" }}
+      <script src="/js/update.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -159,21 +163,23 @@
         </div>
       </div>
       {{ template "footer" }}
-    <script>
-		attachEditRowListener(
-			{
-				entity: "things",
-				id: "{{ .Thing.ID }}",
-				rows: {
-					name:updateName,
-					secret: updateSecret,
-					tags:updateTags,
-					owner: updateOwner,
-					metadata:updateMetadata,
-				},
-				errorDiv: "error-message",
-			}
-		);
+    <script type="module">
+      import { attachEditRowListener, updateName, updateSecret, updateTags,updateOwner, updateMetadata} from "/js/update.js";
+
+      attachEditRowListener(
+        {
+          entity: "things",
+          id: "{{ .Thing.ID }}",
+          rows: {
+            name:updateName,
+            secret: updateSecret,
+            tags:updateTags,
+            owner: updateOwner,
+            metadata:updateMetadata,
+          },
+          errorDiv: "error-message",
+        }
+      );
     </script>
     </body>
   </html>
diff --git a/ui/web/template/thingchannels.html b/ui/web/template/thingchannels.html
index 186b991e4..f937fdc5f 100644
--- a/ui/web/template/thingchannels.html
+++ b/ui/web/template/thingchannels.html
@@ -4,7 +4,11 @@
 {{ define "thingchannels" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Thing Channels</title>
+      {{ template "header" }}
+      <script src="/js/infinitescroll.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -227,6 +231,9 @@ <h1 class="modal-title fs-5" id="sendMesageModalLabel{{ $i }}">
         function openChannelModal() {
           channelModal.show();
         }
+      </script>
+      <script type="module">
+        import { fetchIndividualEntity } from "/js/infinitescroll.js";
 
         fetchIndividualEntity({
           input: "channelFilter",
diff --git a/ui/web/template/things.html b/ui/web/template/things.html
index dfd06a71b..b8c32e8f9 100644
--- a/ui/web/template/things.html
+++ b/ui/web/template/things.html
@@ -4,7 +4,12 @@
 {{ define "things" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Things</title>
+      {{ template "header" }}
+      <script src="/js/forms.js" type="module"></script>
+      <script src="/js/validation.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -120,146 +125,118 @@ <h5 class="modal-title" id="addThingModalLabel">Add Thing</h5>
                     Add Things
                   </button>
 
-									<!-- Modal -->
-									<div
-										class="modal fade"
-										id="addThingsModal"
-										tabindex="-1"
-										role="dialog"
-										aria-labelledby="addThingsModalLabel"
-										aria-hidden="true"
-									>
-										<div class="modal-dialog" role="document">
-											<div class="modal-content">
-												<div class="modal-header">
-													<h5 class="modal-title" id="addThingsModalLabel">
-														Add Things
-													</h5>
-												</div>
-												<div class="modal-body">
-													<div id="alertBulkMessage"></div>
-													<form
-														method="post"
-														enctype="multipart/form-data"
-														id="bulkThingsForm"
-													>
-														<div class="form-group">
-															<label for="thingsFile">
-																Add csv file containing thing names with
-																metadata. The metadata field can be empty. Find
-																a sample csv file
-																<a
-																	href="https://github.com/absmach/magistrala-ui/blob/main/samples/things.csv"
-																	target="_blank"
-																>
-																	here
-																</a>
-															</label>
-															<input
-																type="file"
-																class="form-control-file"
-																id="thingsFile"
-																name="thingsFile"
-																required
-															/>
-															<button
-																type="submit"
-																value="upload"
-																class="btn body-button"
-															>
-																Submit
-															</button>
-														</div>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
-								</div>
-								<div class="table-responsive table-container">
-									{{ template "tableheader" . }}
-									<div class="itemsTable">
-										<table id="itemsTable" class="table">
-											<thead>
-												<tr>
-													<th scope="col">Name</th>
-													<th scope="col">ID</th>
-													<th class="tags-col" scope="col">Tags</th>
-													<th class="meta-col" scope="col">Metadata</th>
-													<th class="created-col" scope="col">Created At</th>
-													<th class="text-center" scope="col"></th>
-												</tr>
-											</thead>
-											<tbody>
-												{{ range $i, $t := .Things }}
-													{{ $disableButton := false }}
-													<tr>
-														<td>{{ $t.Name }}</td>
-														<td>
-															<div class="copy-con-container">
-																<a href="{{ printf "/things/%s" $t.ID }}">
-																	{{ $t.ID }}
-																</a>
-																<button
-																	class="copy-icon"
-																	onclick="copyToClipboard(this)"
-																>
-																	<i class="far fa-copy"></i>
-																</button>
-															</div>
-														</td>
-														<td class="tags-col">{{ toSlice $t.Tags }}</td>
-														<td class="meta-col">{{ toJSON $t.Metadata }}</td>
-														<td class="created-col">{{ $t.CreatedAt }}</td>
-														<td class="text-center">
-															<form action="/things/disabled" method="post">
-																<input
-																	type="hidden"
-																	name="thingID"
-																	id="thingID"
-																	value="{{ $t.ID }}"
-																/>
-																<button
-																	type="submit"
-																	class="btn btn-sm"
-																	{{ if
-																		$disableButton
-																	}}
-																		disabled
-																	{{ end }}
-																>
-																	<i class="fas fa-trash-alt"></i>
-																</button>
-															</form>
-														</td>
-													</tr>
-												{{ end }}
-											</tbody>
-										</table>
-									</div>
-									{{ template "tablefooter" . }}
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
-			<script>
-				attachValidationListener({
-					buttonId: "create-thing-button",
-					errorDivs: {
-						name: "nameError",
-						metadata: "metadataError",
-						tags: "tagsError",
-					},
-					validations: {
-						name: validateName,
-						metadata: validateJSON,
-						tags: validateStringArray,
-					},
-				});
-
+                  <!-- Modal -->
+                  <div
+                    class="modal fade"
+                    id="addThingsModal"
+                    tabindex="-1"
+                    role="dialog"
+                    aria-labelledby="addThingsModalLabel"
+                    aria-hidden="true"
+                  >
+                    <div class="modal-dialog" role="document">
+                      <div class="modal-content">
+                        <div class="modal-header">
+                          <h5 class="modal-title" id="addThingsModalLabel">Add Things</h5>
+                        </div>
+                        <div class="modal-body">
+                          <div id="alertBulkMessage"></div>
+                          <form method="post" enctype="multipart/form-data" id="bulkThingsForm">
+                            <div class="form-group">
+                              <label for="thingsFile">
+                                Add csv file containing thing names with metadata. The metadata
+                                field can be empty. Find a sample csv file
+                                <a
+                                  href="https://github.com/absmach/magistrala-ui/blob/main/samples/things.csv"
+                                  target="_blank"
+                                >
+                                  here
+                                </a>
+                              </label>
+                              <input
+                                type="file"
+                                class="form-control-file"
+                                id="thingsFile"
+                                name="thingsFile"
+                                required
+                              />
+                              <button type="submit" value="upload" class="btn body-button">
+                                Submit
+                              </button>
+                            </div>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+                <div class="table-responsive table-container">
+                  {{ template "tableheader" . }}
+                  <div class="itemsTable">
+                    <table id="itemsTable" class="table">
+                      <thead>
+                        <tr>
+                          <th scope="col">Name</th>
+                          <th scope="col">ID</th>
+                          <th class="tags-col" scope="col">Tags</th>
+                          <th class="meta-col" scope="col">Metadata</th>
+                          <th class="created-col" scope="col">Created At</th>
+                          <th class="text-center" scope="col"></th>
+                        </tr>
+                      </thead>
+                      <tbody>
+                        {{ range $i, $t := .Things }}
+                          {{ $disableButton := false }}
+                          <tr>
+                            <td>{{ $t.Name }}</td>
+                            <td>
+                              <div class="copy-con-container">
+                                <a href="{{ printf "/things/%s" $t.ID }}">
+                                  {{ $t.ID }}
+                                </a>
+                                <button class="copy-icon" onclick="copyToClipboard(this)">
+                                  <i class="far fa-copy"></i>
+                                </button>
+                              </div>
+                            </td>
+                            <td class="tags-col">{{ toSlice $t.Tags }}</td>
+                            <td class="meta-col">{{ toJSON $t.Metadata }}</td>
+                            <td class="created-col">{{ $t.CreatedAt }}</td>
+                            <td class="text-center">
+                              <form action="/things/disabled" method="post">
+                                <input
+                                  type="hidden"
+                                  name="thingID"
+                                  id="thingID"
+                                  value="{{ $t.ID }}"
+                                />
+                                <button
+                                  type="submit"
+                                  class="btn btn-sm"
+                                  {{ if
+                                    $disableButton
+                                  }}
+                                    disabled
+                                  {{ end }}
+                                >
+                                  <i class="fas fa-trash-alt"></i>
+                                </button>
+                              </form>
+                            </td>
+                          </tr>
+                        {{ end }}
+                      </tbody>
+                    </table>
+                  </div>
+                  {{ template "tablefooter" . }}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
+      <script>
         const thingModal = new bootstrap.Modal(document.getElementById("addThingModal"));
         const thingsModal = new bootstrap.Modal(document.getElementById("addThingsModal"));
 
@@ -270,6 +247,29 @@ <h5 class="modal-title" id="addThingsModalLabel">
             thingsModal.show();
           }
         }
+      </script>
+      <script type="module">
+        import {
+          attachValidationListener,
+          validateName,
+          validateJSON,
+          validateStringArray,
+        } from "/js/validation.js";
+        import { submitCreateForm } from "/js/forms.js";
+
+        attachValidationListener({
+          buttonId: "create-thing-button",
+          errorDivs: {
+            name: "nameError",
+            metadata: "metadataError",
+            tags: "tagsError",
+          },
+          validations: {
+            name: validateName,
+            metadata: validateJSON,
+            tags: validateStringArray,
+          },
+        });
 
         submitCreateForm({
           url: "/things",
diff --git a/ui/web/template/thingusers.html b/ui/web/template/thingusers.html
index 9c460b7f6..1f8db06f8 100644
--- a/ui/web/template/thingusers.html
+++ b/ui/web/template/thingusers.html
@@ -4,7 +4,11 @@
 {{ define "thingusers" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Thing Users</title>
+      {{ template "header" }}
+      <script src="/js/infinitescroll.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -172,6 +176,10 @@ <h1 class="modal-title fs-5" id="addUserModalLabel">Share Thing</h1>
         function openUserModal() {
           userModal.show();
         }
+      </script>
+      <script type="module">
+        import { fetchIndividualEntity } from "/js/infinitescroll.js";
+
         fetchIndividualEntity({
           input: "userFilter",
           itemSelect: "infiniteScroll",
diff --git a/ui/web/template/updatepassword.html b/ui/web/template/updatepassword.html
index 858654b79..c30459be1 100644
--- a/ui/web/template/updatepassword.html
+++ b/ui/web/template/updatepassword.html
@@ -4,7 +4,11 @@
 {{ define "updatePassword" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Password Update</title>
+      {{ template "header" }}
+      <script src="/js/main.js" type= "text/javascript"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
diff --git a/ui/web/template/user.html b/ui/web/template/user.html
index e4ed0c3df..e3a86f14a 100644
--- a/ui/web/template/user.html
+++ b/ui/web/template/user.html
@@ -4,7 +4,11 @@
 {{ define "user" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>User</title>
+      {{ template "header" }}
+      <script src="/js/update.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -146,21 +150,22 @@
         </div>
       </div>
       {{ template "footer" }}
-    <script>
-		attachEditRowListener(
-			{
-				entity: "users",
-				id: "{{ .UserID }}",
-				rows: {
-					name:updateName,
-					identity:updateIdentity,
-					tags:updateTags,
-					metadata:updateMetadata,
-				},
-				errorDiv: "error-message",
-			}
-		);
-    </script>
+      <script type="module">
+        import { attachEditRowListener, updateName, updateIdentity, updateTags, updateMetadata} from "/js/update.js";
+
+        attachEditRowListener(
+          {
+            entity: "users",
+            id: "{{ .UserID }}",
+            rows: {
+              name:updateName,
+              identity:updateIdentity,
+              tags:updateTags,
+              metadata:updateMetadata,
+            },
+            errorDiv: "error-message",
+          });
+      </script>
     </body>
   </html>
 {{ end }}
diff --git a/ui/web/template/userchannels.html b/ui/web/template/userchannels.html
index 53a20ef23..8b0739098 100644
--- a/ui/web/template/userchannels.html
+++ b/ui/web/template/userchannels.html
@@ -4,7 +4,11 @@
 {{ define "userchannels" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>User Channels</title>
+      {{ template "header" }}
+      <script src="/js/infinitescroll.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -473,12 +477,6 @@ <h1 class="modal-title fs-5" id="addChannelModalLabel">Add Channel</h1>
 					channelModal.show();
 				}
 
-				fetchIndividualEntity({
-					input: "channelFilter",
-					itemSelect: "infiniteScroll",
-					item: "channels",
-				});
-
         function openTab(relation) {
 					event.preventDefault();
 					var userID = '{{.UserID}}';
@@ -491,6 +489,15 @@ <h1 class="modal-title fs-5" id="addChannelModalLabel">Add Channel</h1>
 						.catch((error) => console.error("Error:", error));
 				}
 			</script>
+      <script type="module">
+        import { fetchIndividualEntity } from "/js/infinitescroll.js";
+
+        fetchIndividualEntity({
+          input: "channelFilter",
+          itemSelect: "infiniteScroll",
+          item: "channels",
+        });
+      </script>
     </body>
   </html>
 {{ end }}
diff --git a/ui/web/template/usergroups.html b/ui/web/template/usergroups.html
index 30979fdb5..b52153c11 100644
--- a/ui/web/template/usergroups.html
+++ b/ui/web/template/usergroups.html
@@ -4,7 +4,11 @@
 {{ define "usergroups" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>User Groups</title>
+      {{ template "header" }}
+      <script src="/js/infinitescroll.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -474,12 +478,6 @@ <h1 class="modal-title fs-5" id="addGroupModalLabel">Add Group</h1>
 					groupModal.show();
 				}
 
-				fetchIndividualEntity({
-					input: "groupFilter",
-					itemSelect: "infiniteScroll",
-					item: "groups",
-				});
-
 				function openTab(relation) {
 					event.preventDefault();
 					var userID = '{{.UserID}}';
@@ -492,6 +490,15 @@ <h1 class="modal-title fs-5" id="addGroupModalLabel">Add Group</h1>
 					.catch((error) => console.error("Error:", error));
 				}
 			</script>
+      <script type="module">
+        import { fetchIndividualEntity } from "/js/infinitescroll.js";
+
+        fetchIndividualEntity({
+          input: "groupFilter",
+          itemSelect: "infiniteScroll",
+          item: "groups",
+        });
+      </script>
     </body>
   </html>
 {{ end }}
diff --git a/ui/web/template/users.html b/ui/web/template/users.html
index 6c9b1c018..ba5b180bb 100644
--- a/ui/web/template/users.html
+++ b/ui/web/template/users.html
@@ -4,7 +4,12 @@
 {{ define "users" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>Users</title>
+      {{ template "header" }}
+      <script src="/js/forms.js" type="module"></script>
+      <script src="/js/validation.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -108,149 +113,119 @@ <h5 class="modal-title" id="addUserModalLabel">Add User</h5>
                     </div>
                   </div>
 
-									<!-- add users modal -->
-									<div
-										class="modal fade"
-										id="addUsersModal"
-										tabindex="-1"
-										role="dialog"
-										aria-labelledby="addUsersModalLabel"
-										aria-hidden="true"
-									>
-										<div class="modal-dialog" role="document">
-											<div class="modal-content">
-												<div class="modal-header">
-													<h5 class="modal-title" id="addUsersModalLabel">
-														Add Users
-													</h5>
-												</div>
-												<div class="modal-body">
-													<div id="alertBulkMessage"></div>
-													<form
-														enctype="multipart/form-data"
-														id="bulkusersform"
-													>
-														<div class="form-group">
-															<label for="usersFile">
-																Add csv file containing users names and
-																passwords. Find a sample csv file
-																<a
-																	href="https://github.com/absmach/magistrala-ui/blob/main/samples/users.csv"
-																	target="_blank"
-																>
-																	here
-																</a>
-															</label>
-															<input
-																type="file"
-																class="form-control-file"
-																id="usersFile"
-																name="usersFile"
-																required
-															/>
-															<button
-																type="submit"
-																value="upload"
-																class="btn body-button"
-															>
-																Submit
-															</button>
-														</div>
-													</form>
-												</div>
-											</div>
-										</div>
-									</div>
-									<!-- modals end -->
-								</div>
-								<div class="table-responsive table-container">
-									{{ template "tableheader" . }}
-									<div class="itemsTable">
-										<table id="itemsTable" class="table">
-											<thead>
-												<tr>
-													<th scope="col">Name</th>
-													<th scope="col">ID</th>
-													<th class="tags-col" scope="col">Tags</th>
-													<th class="meta-col" scope="col">Metadata</th>
-													<th class="created-col" scope="col">Created At</th>
-													<th class="text-center" scope="col"></th>
-												</tr>
-											</thead>
-											<tbody>
-												{{ range $i, $u := .Users }}
-													{{ $disableButton := false }}
-													<tr>
-														<td>{{ $u.Name }}</td>
-														<td>
-															<div class="copy-con-container">
-																<a href="{{ printf "/users/%s" $u.ID }}">
-																	{{ $u.ID }}
-																</a>
-																<button
-																	class="copy-icon"
-																	onclick="copyToClipboard(this)"
-																>
-																	<i class="far fa-copy"></i>
-																</button>
-															</div>
-														</td>
-														<td class="tags-col">{{ toSlice $u.Tags }}</td>
-														<td class="meta-col">{{ toJSON $u.Metadata }}</td>
-														<td class="created-col">{{ $u.CreatedAt }}</td>
-														<td class="text-center">
-															<form action="/users/disabled" method="post">
-																<input
-																	type="hidden"
-																	name="userID"
-																	id="userID"
-																	value="{{ $u.ID }}"
-																/>
-																<button
-																	type="submit"
-																	class="btn btn-sm"
-																	{{ if
-																		$disableButton
-																	}}
-																		disabled
-																	{{ end }}
-																>
-																	<i class="fas fa-trash-alt"></i>
-																</button>
-															</form>
-														</td>
-													</tr>
-												{{ end }}
-											</tbody>
-										</table>
-									</div>
-									{{ template "tablefooter" . }}
-								</div>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-			{{ template "footer" }}
-			<script>
-				attachValidationListener({
-					buttonId: "create-user-button",
-					errorDivs: {
-						name: "nameError",
-						identity: "identityError",
-						secret: "secretError",
-						metadata: "metadataError",
-						tags: "tagsError",
-					},
-					validations: {
-						name: validateName,
-						identity: validateEmail,
-						secret: validatePassword,
-						metadata: validateJSON,
-						tags: validateStringArray,
-					},
-				});
-
+                  <!-- add users modal -->
+                  <div
+                    class="modal fade"
+                    id="addUsersModal"
+                    tabindex="-1"
+                    role="dialog"
+                    aria-labelledby="addUsersModalLabel"
+                    aria-hidden="true"
+                  >
+                    <div class="modal-dialog" role="document">
+                      <div class="modal-content">
+                        <div class="modal-header">
+                          <h5 class="modal-title" id="addUsersModalLabel">Add Users</h5>
+                        </div>
+                        <div class="modal-body">
+                          <div id="alertBulkMessage"></div>
+                          <form enctype="multipart/form-data" id="bulkusersform">
+                            <div class="form-group">
+                              <label for="usersFile">
+                                Add csv file containing users names and passwords. Find a sample csv
+                                file
+                                <a
+                                  href="https://github.com/absmach/magistrala-ui/blob/main/samples/users.csv"
+                                  target="_blank"
+                                >
+                                  here
+                                </a>
+                              </label>
+                              <input
+                                type="file"
+                                class="form-control-file"
+                                id="usersFile"
+                                name="usersFile"
+                                required
+                              />
+                              <button type="submit" value="upload" class="btn body-button">
+                                Submit
+                              </button>
+                            </div>
+                          </form>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                  <!-- modals end -->
+                </div>
+                <div class="table-responsive table-container">
+                  {{ template "tableheader" . }}
+                  <div class="itemsTable">
+                    <table id="itemsTable" class="table">
+                      <thead>
+                        <tr>
+                          <th scope="col">Name</th>
+                          <th scope="col">ID</th>
+                          <th class="tags-col" scope="col">Tags</th>
+                          <th class="meta-col" scope="col">Metadata</th>
+                          <th class="created-col" scope="col">Created At</th>
+                          <th class="text-center" scope="col"></th>
+                        </tr>
+                      </thead>
+                      <tbody>
+                        {{ range $i, $u := .Users }}
+                          {{ $disableButton := false }}
+                          <tr>
+                            <td>{{ $u.Name }}</td>
+                            <td>
+                              <div class="copy-con-container">
+                                <a href="{{ printf "/users/%s" $u.ID }}">
+                                  {{ $u.ID }}
+                                </a>
+                                <button class="copy-icon" onclick="copyToClipboard(this)">
+                                  <i class="far fa-copy"></i>
+                                </button>
+                              </div>
+                            </td>
+                            <td class="tags-col">{{ toSlice $u.Tags }}</td>
+                            <td class="meta-col">{{ toJSON $u.Metadata }}</td>
+                            <td class="created-col">{{ $u.CreatedAt }}</td>
+                            <td class="text-center">
+                              <form action="/users/disabled" method="post">
+                                <input
+                                  type="hidden"
+                                  name="userID"
+                                  id="userID"
+                                  value="{{ $u.ID }}"
+                                />
+                                <button
+                                  type="submit"
+                                  class="btn btn-sm"
+                                  {{ if
+                                    $disableButton
+                                  }}
+                                    disabled
+                                  {{ end }}
+                                >
+                                  <i class="fas fa-trash-alt"></i>
+                                </button>
+                              </form>
+                            </td>
+                          </tr>
+                        {{ end }}
+                      </tbody>
+                    </table>
+                  </div>
+                  {{ template "tablefooter" . }}
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {{ template "footer" }}
+      <script>
         const userModal = new bootstrap.Modal(document.getElementById("addUserModal"));
         const usersModal = new bootstrap.Modal(document.getElementById("addUsersModal"));
 
@@ -261,6 +236,35 @@ <h5 class="modal-title" id="addUsersModalLabel">
             usersModal.show();
           }
         }
+      </script>
+      <script type="module">
+        import {
+          attachValidationListener,
+          validateName,
+          validateEmail,
+          validatePassword,
+          validateJSON,
+          validateStringArray,
+        } from "/js/validation.js";
+        import { submitCreateForm } from "/js/forms.js";
+
+        attachValidationListener({
+          buttonId: "create-user-button",
+          errorDivs: {
+            name: "nameError",
+            identity: "identityError",
+            secret: "secretError",
+            metadata: "metadataError",
+            tags: "tagsError",
+          },
+          validations: {
+            name: validateName,
+            identity: validateEmail,
+            secret: validatePassword,
+            metadata: validateJSON,
+            tags: validateStringArray,
+          },
+        });
 
         submitCreateForm({
           url: "/users",
diff --git a/ui/web/template/userthings.html b/ui/web/template/userthings.html
index 0a3a85f1d..df0591252 100644
--- a/ui/web/template/userthings.html
+++ b/ui/web/template/userthings.html
@@ -4,7 +4,11 @@
 {{ define "userthings" }}
   <!doctype html>
   <html lang="en">
-    {{ template "header" }}
+    <head>
+      <title>User Things</title>
+      {{ template "header" }}
+      <script src="/js/infinitescroll.js" type="module"></script>
+    </head>
     <body>
       {{ template "navbar" . }}
       <div class="main-content pt-3">
@@ -175,6 +179,10 @@ <h1 class="modal-title fs-5" id="addThingModalLabel">Add Thing</h1>
         function openThingModal() {
           thingModal.show();
         }
+      </script>
+      <script type="module">
+        import { fetchIndividualEntity } from "/js/infinitescroll.js";
+
         fetchIndividualEntity({
           input: "thingFilter",
           itemSelect: "things",

From 344dd21fa3309db1ee3f2a4b4063bb741b207125 Mon Sep 17 00:00:00 2001
From: ianmuchyri <ianmuchiri8@gmail.com>
Date: Tue, 28 Nov 2023 17:40:48 +0300
Subject: [PATCH 09/11] update endpoints returns

Signed-off-by: ianmuchyri <ianmuchiri8@gmail.com>
---
 ui/api/endpoint.go | 27 +++++++++------------------
 1 file changed, 9 insertions(+), 18 deletions(-)

diff --git a/ui/api/endpoint.go b/ui/api/endpoint.go
index 327bff60e..9b364dcc5 100644
--- a/ui/api/endpoint.go
+++ b/ui/api/endpoint.go
@@ -992,8 +992,7 @@ func createChannelEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": channelsAPIEndpoint},
+			code: http.StatusCreated,
 		}, nil
 	}
 }
@@ -1010,8 +1009,7 @@ func createChannelsEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": channelsAPIEndpoint},
+			code: http.StatusCreated,
 		}, nil
 	}
 }
@@ -1073,8 +1071,7 @@ func updateChannelEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": channelsAPIEndpoint + "/" + req.id},
+			code: http.StatusOK,
 		}, nil
 	}
 }
@@ -1246,8 +1243,7 @@ func createGroupEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": groupsAPIEndpoint},
+			code: http.StatusCreated,
 		}, nil
 	}
 }
@@ -1264,8 +1260,7 @@ func createGroupsEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": groupsAPIEndpoint},
+			code: http.StatusCreated,
 		}, nil
 	}
 }
@@ -1327,8 +1322,7 @@ func updateGroupEndpoint(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": groupsAPIEndpoint + "/" + req.id},
+			code: http.StatusOK,
 		}, nil
 	}
 }
@@ -1536,8 +1530,7 @@ func updateBootstrap(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": bootstrapAPIEndpoint + "/" + req.id},
+			code: http.StatusOK,
 		}, nil
 	}
 }
@@ -1558,8 +1551,7 @@ func updateBootstrapConnections(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": bootstrapAPIEndpoint + "/" + req.id},
+			code: http.StatusOK,
 		}, nil
 	}
 }
@@ -1582,8 +1574,7 @@ func updateBootstrapCerts(svc ui.Service) endpoint.Endpoint {
 		}
 
 		return uiRes{
-			code:    http.StatusSeeOther,
-			headers: map[string]string{"Location": bootstrapAPIEndpoint + "/" + req.thingID},
+			code: http.StatusOK,
 		}, nil
 	}
 }

From 2f37a0cf1762dc3df27a1e9648cb134722bbfc26 Mon Sep 17 00:00:00 2001
From: ianmuchyri <ianmuchiri8@gmail.com>
Date: Wed, 29 Nov 2023 11:01:02 +0300
Subject: [PATCH 10/11] add clipboard js file

Signed-off-by: ianmuchyri <ianmuchiri8@gmail.com>
---
 ui/web/template/footer.html | 1 +
 1 file changed, 1 insertion(+)

diff --git a/ui/web/template/footer.html b/ui/web/template/footer.html
index 0c6e2e736..ab6583678 100644
--- a/ui/web/template/footer.html
+++ b/ui/web/template/footer.html
@@ -16,4 +16,5 @@
     crossorigin="anonymous"
   ></script>
   <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
+  <script src="/js/clipboard.js" type="text/javascript"></script>
 {{ end }}

From c6dbe42e192b7ba33298d7d1be7c169a9be908f8 Mon Sep 17 00:00:00 2001
From: ianmuchyri <ianmuchiri8@gmail.com>
Date: Wed, 29 Nov 2023 12:00:35 +0300
Subject: [PATCH 11/11] remove unused param

Signed-off-by: ianmuchyri <ianmuchiri8@gmail.com>
---
 .prettierrc | 1 -
 1 file changed, 1 deletion(-)

diff --git a/.prettierrc b/.prettierrc
index 6ceed361a..b641d2f1e 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -9,7 +9,6 @@
     }
   ],
   "goTemplateBracketSpacing": true,
-  "useTabs": false,
   "printWidth": 100,
   "semi": true,
   "tabWidth": 2,