ContactBridge

Log | Files | Refs | README

commit a6a036ba56805f8ad24fa295eb3f9114941b4550
parent 3757630acf1f0f1926deb0f3f2d39c2e0a5e0591
Author: William Lindholm <william_lindholm@outlook.com>
Date:   Sun,  5 Nov 2023 19:04:19 +0100

Refactoring of web interface.

Diffstat:
MWebInterface/routes.py | 23+++++++++++++++++++++++
AWebInterface/tableBuilder.py | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mstatic/css/main.css | 9+++++++++
Mtemplates/home.html | 2--
Atemplates/integrations.html | 6++++++
Mtemplates/login.html | 103++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Mtemplates/nav.html | 38++++++++++++++++++++++----------------
Atemplates/table.html | 50++++++++++++++++++++++++++++++++++++++++++++++++++
8 files changed, 245 insertions(+), 45 deletions(-)

diff --git a/WebInterface/routes.py b/WebInterface/routes.py @@ -4,6 +4,7 @@ from pathlib import Path from flask import Flask, request, redirect, url_for, render_template, session from dbrepository import DatabaseRepository from . import web_interface +from .tableBuilder import TableBuilder db = DatabaseRepository() @@ -32,6 +33,28 @@ def home(): return render_template('home.html', messages=formatted_messages, page_title="Messages") +@web_interface.route('/integrations') +def integrations(): + # Define headers and rows for the messages table + headers = ["ID", "Message", "Date"] + rows = [ + [1, "Hello World!", "2023-11-01"], + [2, "Another Message", "2023-11-02"], + # ... add more rows as needed + ] + + # Initialize TableBuilder and configure the table + table_builder = TableBuilder() + table_builder.set_headers(headers) + table_builder.add_rows(rows) + table_builder.set_pagination(enabled=True, page_size=5) + table_builder.set_sortable(["ID", "Date"]) + table_builder.add_callback_column("Delete", "deleteMessage") + + # Build the TableInstance + table_instance = table_builder.build() + return render_template('integrations.html', page_title="Integrations", table=table_instance) + @web_interface.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': diff --git a/WebInterface/tableBuilder.py b/WebInterface/tableBuilder.py @@ -0,0 +1,58 @@ +class TableInstance: + def __init__(self): + self.headers = [] + self.rows = [] + self.sortable_columns = [] + self.pagination_enabled = False + self.page_size = 10 + self.current_page = 1 + self.callback_column = None + self.row_click_url_template = "" + + def add_header(self, header): + self.headers.append(header) + + def add_row(self, row): + self.rows.append(row) + + def enable_pagination(self, page_size=10): + self.pagination_enabled = True + self.page_size = page_size + + def set_sortable_columns(self, columns): + self.sortable_columns = columns + + def set_callback_column(self, callback): + self.callback_column = callback + + def set_row_click_url_template(self, url_template): + self.row_click_url_template = url_template + + +class TableBuilder: + def __init__(self): + self.table_instance = TableInstance() + + def set_headers(self, headers): + for header in headers: + self.table_instance.add_header(header) + + def add_rows(self, rows): + for row in rows: + self.table_instance.add_row(row) + + def set_pagination(self, enabled=True, page_size=10): + if enabled: + self.table_instance.enable_pagination(page_size) + + def set_sortable(self, sortable_columns): + self.table_instance.set_sortable_columns(sortable_columns) + + def add_callback_column(self, name, callback): + self.table_instance.set_callback_column((name, callback)) + + def set_on_click(self, url_template): + self.table_instance.set_row_click_url_template(url_template) + + def build(self): + return self.table_instance +\ No newline at end of file diff --git a/static/css/main.css b/static/css/main.css @@ -47,7 +47,9 @@ h1 { } .content { + max-width: 100%; margin-left: var(--content-margin); + overflow: auto; } @media only screen and (max-width : 992px) { @@ -67,6 +69,13 @@ h1 { flex-shrink: 0; } +.sidenav-content { + display: flex; + flex-direction: column; + justify-content: space-between; + height: 100%; +} + h1.mobile { text-align: center; flex-grow: 1; diff --git a/templates/home.html b/templates/home.html @@ -1,7 +1,5 @@ {% extends 'base.html' %} -{% block title %}Child Page Title{% endblock %} - {% block content %} <br> <table class="highlight"> diff --git a/templates/integrations.html b/templates/integrations.html @@ -0,0 +1,5 @@ +{% extends 'base.html' %} + +{% block content %} +{% include 'table.html' %} +{% endblock %} +\ No newline at end of file diff --git a/templates/login.html b/templates/login.html @@ -1,38 +1,87 @@ -<!doctype html> -<html lang="en"> +<!DOCTYPE html> +<html> + <head> <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"> - <title>Login</title> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>CB | {{ page_title }}</title> + + <link rel="stylesheet" href="{{ url_for('static', filename='css/materialize.min.css') }}"> + <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> + <script src="{{ url_for('static', filename='js/materialize.min.js') }}"></script> + <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 { + background-color: #f4f4f4; + } + + .container .z-depth-1 { + background-color: #ffffff; + box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1); + } + + /* Existing styles for input fields */ + .input-field input:focus { + border-bottom: 1px solid #2c3e50; + box-shadow: 0 1px 0 0 #2c3e50; + } + + .input-field input:focus + label { + color: #2c3e50; + } + + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + input:-webkit-autofill:active { + -webkit-box-shadow: 0 0 0 30px #f4f4f4 inset !important; + } +</style> </head> -<body> -<div class='container' style="margin-top:10%;"> - <div class='row justify-content-center align-items-center'> - <div class='col-md-4'> - <div class='card'> - <div class='card-body'> - <form method='post'> - <div class='form-group'> - <label for='UserName'>Username</label> - <input type='text' class='form-control' id='UserName' name='username' placeholder='UserName' required> + +<body> + <main> + <center> + <div class="section"></div> + <div class="container"> + <div class="z-depth-1 grey lighten-4 card-panel" style="max-width:350px; padding: 40px 30px 30px 30px; border: 1px solid #EEE;"> + <form class="col s12" method="post"> + <h5 class="login-label">Login</h5> + <div class='row'> + <div class='input-field col s12'> + <input class='validate' type='text' name='username' id='username' /> + <label for='username'>Username</label> + </div> + </div> + <div class='row'> + <div class='input-field col s12'> + <input class='validate' type='password' name='password' id='password' /> + <label for='password'>Password</label> + </div> + </div> + <div class='row'> + <button type='submit' name='btn_login' class='col s12 btn btn-large waves-effect indigo'>Login</button> </div> - <div class='form-group'> - <label for='Password'>Password</label> - <input type='password' class='form-control' id='Password' name='password' placeholder='Password' required> + <div class='row'> + Server: + <span id="domain-label"></span> </div> - <button type='submit' class='btn btn-primary'>Login</button> </form> - <!-- If there is an error message, it will be displayed here --> - <!-- <div class='alert alert-danger mt-3' role='alert'>Error message here</div> --> </div> </div> - </div> - </div> -</div> - -<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script> - + </center> + </main> + <script> + document.addEventListener('DOMContentLoaded', function() { + var serverDomain = window.location.hostname; + document.getElementById('domain-label').textContent = serverDomain; + }); + </script> </body> + </html> \ No newline at end of file diff --git a/templates/nav.html b/templates/nav.html @@ -1,16 +1,22 @@ -<li> - <div class="user-view"> - <i class="material-icons medium" style="color: white;">account_circle</i> - <a href="#name"><span class="white-text name">John Doe</span></a> - <a href="#email"><span class="white-text email">jdandturk@gmail.com</span></a> +<div class="sidenav-content"> + <div> + <li> + <div class="user-view"> + <i class="material-icons medium" style="color: white;">account_circle</i> + <a href="#name"><span class="white-text name">John Doe</span></a> + <a href="#email"><span class="white-text email">jdandturk@gmail.com</span></a> + </div> + </li> + <li><a class="waves-effect" href="/home"><i class="material-icons">message</i>Messages</a></li> + <li><a class="waves-effect" href="/integrations"><i class="material-icons">settings_ethernet</i>Integrations</a></li> + <li><a class="waves-effect" href="#!"><i class="material-icons">group</i>Users</a></li> + <li> + <div class="divider"></div> + </li> + <li><a class="subheader">Settings</a></li> + <li><a class="waves-effect" href="#!"><i class="material-icons">account_box</i>Account</a></li> + <li><a class="waves-effect" href="#!"><i class="material-icons">admin_panel_settings</i>Admin</a></li> </div> -</li> -<li><a class="waves-effect" href="#!">Messages</a></li> -<li><a class="waves-effect" href="#!">Integrations</a></li> -<li><a class="waves-effect" href="#!">Users</a></li> -<li> - <div class="divider"></div> -</li> -<li><a class="subheader">Settings</a></li> -<li><a class="waves-effect" href="#!">Account</a></li> -<li><a class="waves-effect" href="#!">Admin</a></li> -\ No newline at end of file + + <li style="margin-top: auto;"><a class="waves-effect" href="/logout"><i class="material-icons">exit_to_app</i>Logout</a></li> +</div> +\ No newline at end of file diff --git a/templates/table.html b/templates/table.html @@ -0,0 +1,49 @@ +{% if table.pagination_enabled %} + <ul class="pagination"> + <!-- Add Pagination Logic Here --> + {% set total_pages = ((table.rows|length / table.page_size) | round(0, 'ceil')) | int %} + {% for i in range(1, total_pages + 1) %} + <li class="{% if table.current_page == i %}active{% else %}waves-effect{% endif %}"> + <a href="?page={{ i }}">{{ i }}</a> + </li> + {% endfor %} + </ul> +{% endif %} + +<table id="table-instance" class="highlight"> + <thead> + <tr> + <!-- Headers and sortable logic will be inserted here --> + {% for header in table.headers %} + <th> + {{ header }} + {% if header in table.sortable_columns %} + <!-- Add sorting logic/link here --> + <a href="?sort_by={{ header }}&order=asc">↑</a> + <a href="?sort_by={{ header }}&order=desc">↓</a> + {% endif %} + </th> + {% endfor %} + <!-- Additional header for callback actions if any --> + {% if table.callback_column %} + <th>{{ table.callback_column }}</th> + {% endif %} + </tr> + </thead> + <tbody> + <!-- Rows and Data will be inserted here --> + {% for row in table.rows %} + <tr onclick="window.location.href='{{ table.row_click_url_template.format(row[0]) }}';"> + {% for cell in row %} + <td>{{ cell }}</td> + {% endfor %} + <!-- Callback action buttons if any --> + {% if table.callback_column %} + <td> + <button onclick="{{ table.callback_column.function(row[0]) }}">{{ table.callback_column.name }}</button> + </td> + {% endif %} + </tr> + {% endfor %} + </tbody> +</table> +\ No newline at end of file