ContactBridge

Log | Files | Refs | README

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:
MWebInterface/routes.py | 14+++++++++++++-
Mdatabase/database.db | 0
Mstatic/css/main.css | 36+++++++++---------------------------
Mstatic/js/ajaxtable.js | 27+++++++++++++++++----------
Mtemplates/component/ajaxtable.html | 86+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mtemplates/login.html | 1-
Mtemplates/page/home.html | 24++++++++++++++++++++++--
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