commit 19eaff6d1cc7d0556b3dfd2acf59a879fd1d66b9
parent e41db65b1d7f39bc7f0dde4e7eccf3378d318581
Author: William Lindholm <william_lindholm@outlook.com>
Date: Sat, 11 Nov 2023 00:37:03 +0100
Changed ajaxtable to allow for multiple instances per page.
Diffstat:
7 files changed, 106 insertions(+), 82 deletions(-)
diff --git a/WebInterface/routes.py b/WebInterface/routes.py
@@ -10,7 +10,19 @@ def home():
if not session.get('logged_in'):
return redirect(url_for('web_interface.login'))
- return render_template('/page/home.html', page_title='Messages', api_endpoint='messages')
+ messages_context = {
+ "api_endpoint": "messages",
+ "id_prefix": "message-",
+ "headers": [("ID", "10%"), ("Relevance", "20%"), ("Name", "30%"), ("Content", "40%")]
+ }
+
+ spam_context = {
+ "api_endpoint": "messages",
+ "id_prefix": "spam-",
+ "headers": [("ID", "10%"), ("Relevance", "10%"), ("Name", "30%"), ("Content", "50%")]
+ }
+
+ return render_template('/page/home.html', page_title='Messages', messages_context=messages_context, spam_context=spam_context)
@web_interface.route('/integrations')
diff --git a/database/database.db b/database/database.db
Binary files differ.
diff --git a/static/css/main.css b/static/css/main.css
@@ -83,46 +83,27 @@ h1.mobile {
height: 100%;
}
-.delete-icon {
- color: red;
- transition: transform 0.2s ease, color 0.2s ease;
-}
-
-.delete-icon:hover {
- color: darkred;
-}
-
-.flag-icon {
- color: orange;
- transition: transform 0.2s ease, color 0.2s ease;
-}
-
-.flag-icon:hover {
- color: grey;
-}
-
-.table-instance {
- table-layout: fixed;
- width: 100%;
+.row {
min-width: 500px;
- cursor: pointer;
+ max-width: 100%;
}
table tr, table td {
margin: 0 !important;
-}
-.pagination li a, pagination li a i {
- transition: background-color 0.2s ease, color 0.2s ease;
}
-.pagination .active {
- background-color: var(--primary-color) !important;
+table td {
+ max-width: 150px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
}
.sortable-header {
cursor: pointer;
transition: all 0.3s ease;
+ white-space: nowrap;
}
.sortable-header:hover {
@@ -132,6 +113,7 @@ table tr, table td {
.delete-button {
color: red;
transition: color 0.1s;
+ cursor: pointer;
}
.delete-button:hover {
diff --git a/static/js/ajaxtable.js b/static/js/ajaxtable.js
@@ -1,8 +1,9 @@
class AjaxTable {
- constructor(apiEndpoint, tableHeadersId, tableBodyId, searchBarId, pageSizeSelectorId, paginationContainerId) {
+ constructor(apiEndpoint, id_prefix, tableHeadersId, tableBodyId, searchBarId, pageSizeSelectorId, paginationContainerId) {
this.apiEndpoint = apiEndpoint;
this.tableHeadersId = tableHeadersId;
this.tableBodyId = tableBodyId;
+ this.id_prefix = id_prefix;
this.searchBarId = searchBarId;
this.pageSizeSelectorId = pageSizeSelectorId;
this.paginationContainerId = paginationContainerId;
@@ -18,7 +19,7 @@ class AjaxTable {
}
initEventListeners() {
- const debouncedSearchData = this.debounce(this.searchData.bind(this), 500);
+ const debouncedSearchData = this.debounce(this.searchData.bind(this), 300);
document.getElementById(this.searchBarId).addEventListener('keyup', debouncedSearchData);
document.getElementById(this.pageSizeSelectorId).addEventListener('change', () => {
@@ -42,16 +43,21 @@ class AjaxTable {
}
confirmDelete(apiEndpoint, itemId) {
- const deleteButton = document.getElementById('confirmDeleteButton');
- deleteButton.onclick = () => this.performDeletion(apiEndpoint, itemId);
+ var instance = M.Modal.getInstance(document.getElementById(this.id_prefix + 'deleteConfirmationModal'));
- // Open confirmation modal
- var instance = M.Modal.getInstance(document.getElementById('deleteConfirmationModal'));
+ // Set up the delete confirmation button's event listener
+ var confirmButton = document.getElementById(this.id_prefix + 'confirmDeleteButton');
+ confirmButton.onclick = () => {
+ this.performDeletion(apiEndpoint, itemId);
+ instance.close();
+ };
+
+ // Open the modal
instance.open();
}
performDeletion(apiEndpoint, itemId) {
- const deleteUrl = `${apiEndpoint}/${itemId}`;
+ const deleteUrl = `${apiEndpoint}${itemId}`;
fetch(deleteUrl, { method: 'DELETE' })
.then(response => {
@@ -184,15 +190,16 @@ class AjaxTable {
searchData() {
this.currentSearchQuery = document.getElementById(this.searchBarId).value;
+ this.currentPage = 1;
this.fetchData();
}
sortTableByHeader() {
document.querySelectorAll(`#${this.tableHeadersId} th`).forEach(header => {
header.addEventListener('click', () => {
- this.currentSortField = header.getAttribute('data-field');
- this.currentSortOrder = header.getAttribute('data-order') === 'asc' ? 'desc' : 'asc';
- header.setAttribute('data-order', this.currentSortOrder);
+ this.currentSortField = header.getAttribute(this.id_prefix + 'data-field');
+ this.currentSortOrder = header.getAttribute(this.id_prefix + 'data-order') === 'asc' ? 'desc' : 'asc';
+ header.setAttribute(this.id_prefix + 'data-order', this.currentSortOrder);
this.fetchData();
});
});
diff --git a/templates/component/ajaxtable.html b/templates/component/ajaxtable.html
@@ -1,53 +1,57 @@
-<div id="deleteConfirmationModal" class="modal">
+<div id="{{ context.id_prefix }}deleteConfirmationModal" class="modal">
<div class="modal-content">
- <h4>Confirm deletion</h4>
+ <h4>Delete Confirmation</h4>
<p>Are you sure you want to delete this item?</p>
</div>
<div class="modal-footer">
- <a href="#!" class="modal-close waves-effect waves-green btn-flat" id="confirmDeleteButton">Delete</a>
- <a href="#!" class="modal-close waves-effect waves-red btn-flat">Cancel</a>
+ <a href="#!" class="modal-close waves-effect waves-green btn-flat">Cancel</a>
+ <a href="#!" id="{{ context.id_prefix }}confirmDeleteButton" class="waves-effect waves-red btn-flat">Delete</a>
</div>
</div>
-<div class="row">
- <div class="input-field col s10">
- <input type="text" id="search-bar" placeholder="Search {{ api_endpoint }}...">
+<div class="{{ context.id_prefix }}table-container">
+ <!-- Search Bar -->
+ <div class="row">
+ <div class="input-field col s10">
+ <input type="text" id="{{ context.id_prefix }}search-bar" placeholder="Search...">
+ </div>
+ <div class="input-field col s2 tooltipped" data-position="right" data-tooltip="Select page size">
+ <select id="{{ context.id_prefix }}page-size">
+ <option value="5">5</option>
+ <option value="10" selected>10</option>
+ <option value="25">25</option>
+ <option value="50">50</option>
+ </select>
+ </div>
</div>
- <div class="input-field col s2">
- <select id="page-size">
- <option value="5">5</option>
- <option value="10" selected>10</option>
- <option value="25">25</option>
- <option value="50">50</option>
- </select>
- </div>
-</div>
-<table class="highlight table-instance">
- <thead id="table-headers">
- <tr>
- <th data-field="id" data-order="asc" class="sortable-header">ID <i class="material-icons tiny">unfold_more</i></th>
- <th data-field="relevance" data-order="asc" class="sortable-header">Relevance <i class="material-icons tiny">unfold_more</i></th>
- <th data-field="name" data-order="asc" class="sortable-header">Name <i class="material-icons tiny">unfold_more</i></th>
- <th data-field="content" data-order="asc" class="sortable-header">Content <i class="material-icons tiny">unfold_more</i></th>
- <th></th>
- </tr>
- </thead>
- <tbody id="table-body">
- <!-- Table data -->
- </tbody>
-</table>
+ <!-- Table -->
+ <table class="highlight {{ context.id_prefix }}table-instance">
+ <thead id="{{ context.id_prefix }}table-headers">
+ <tr>
+ {% for header, width in context.headers %}
+ <th {{context.id_prefix}}data-field="{{ header|lower }}" {{context.id_prefix}}data-order="asc"
+ class="sortable-header" style="width: {{ width }};">{{
+ header }} <i class="material-icons tiny">unfold_more</i></th>
+ {% endfor %}
+ <th></th> <!-- for the delete button column -->
+ </tr>
+ </thead>
+ <tbody id="{{ context.id_prefix }}table-body">
+ <!-- Table data -->
+ </tbody>
+ </table>
-<ul class="pagination" id="pagination-container">
<!-- Pagination -->
-</ul>
-
-<script>
- const API_ENDPOINT = '/api/{{ api_endpoint }}/';
+ <ul class="pagination" id="{{ context.id_prefix }}pagination-container">
+ <!-- Pagination content -->
+ </ul>
- document.addEventListener('DOMContentLoaded', function() {
- M.AutoInit();
- new AjaxTable(API_ENDPOINT, 'table-headers', 'table-body', 'search-bar', 'page-size', 'pagination-container');
- });
+ <script>
+ document.addEventListener('DOMContentLoaded', function() {
+ M.AutoInit();
+ new AjaxTable('/api/{{ context.api_endpoint }}/', '{{ context.id_prefix }}', '{{ context.id_prefix }}table-headers', '{{ context.id_prefix }}table-body', '{{ context.id_prefix }}search-bar', '{{ context.id_prefix }}page-size', '{{ context.id_prefix }}pagination-container');
+ });
-</script>
-\ No newline at end of file
+ </script>
+</div>
+\ No newline at end of file
diff --git a/templates/login.html b/templates/login.html
@@ -12,7 +12,6 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap" rel="stylesheet">
- <link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
<style>
body {
diff --git a/templates/page/home.html b/templates/page/home.html
@@ -1,5 +1,24 @@
{% extends 'base.html' %}
{% block content %}
- {% include 'component/ajaxtable.html' %}
-{% endblock %}
+ <br>
+ <div class="row">
+ <div class="col s12">
+ <ul class="tabs">
+ <li class="tab col s10"><a href="#inbox">Inbox</a></li>
+ <li class="tab col s2"><a href="#junk">Junk</a></li>
+ </ul>
+ </div>
+ <div id="inbox" class="col s12">
+ {% with context=messages_context %}
+ {% include 'component/ajaxtable.html' %}
+ {% endwith %}
+ </div>
+
+ <div id="junk" class="col s12">
+ {% with context=spam_context %}
+ {% include 'component/ajaxtable.html' %}
+ {% endwith %}
+ </div>
+ </div>
+{% endblock %}
+\ No newline at end of file