More dynamic menu handling. Did a lot of stuff using Flask-Nav & Flask_Menu, but removed all of it becauses it became overly complex or the extensions were no longer in active development.

This commit is contained in:
Josako
2024-04-28 22:15:47 +02:00
parent f782519c40
commit f4decbc0cd
7 changed files with 196 additions and 72 deletions

View File

@@ -5,13 +5,10 @@ from flask_security import Security
from flask_mailman import Mail
from flask_login import LoginManager
# Create extensions
db = SQLAlchemy()
migrate = Migrate()
bootstrap = Bootstrap()
security = Security()
mail = Mail()
login_manager = LoginManager()
login_manager = LoginManager()

View File

@@ -1,68 +1,22 @@
<!-- Navbar Light -->
{% from "navbar_macros.html" import nav_link, dropdown %}
<div class="navbar navbar-expand-lg navbar-light bg-white z-index-3 py-3">
<div class="container position-sticky z-index-sticky top-0">
<div class="row">
<div class="col-12">
<nav class="navbar navbar-expand-lg blur border-radius-xl top-0 z-index-fixed shadow position-absolute my-3 py-2 start-0 end-0 mx-4">
<div class="container-fluid px-0">
<a class="navbar-brand font-weight-bolder ms-sm-3 d-none d-md-block" href="https://www.flow-it.net" rel="tooltip" title="Idee Generated & Implemented by Flow IT" data-placement="bottom">
EveAI
</a>
</div>
<div class="collapse navbar-collapse w-100 pt-3 pb-2 py-lg-0" id="navigation">
<ul class="navbar-nav navbar-nav-hover mx-auto">
<li class="nav-item dropdown dropdown-hover mx-2">
<a role="button" class="nav-link ps-2 d-flex cursor-pointer align-items-center" id="dropdownMenuUser" data-bs-toggle="dropdown" aria-expanded="false">
<i class="material-icons opacity-6 me-2 text-md">contacts</i>
User Mgmt
<img src="{{url_for('static', filename='/assets/img/down-arrow-dark.svg')}}" alt="down-arrow" class="arrow ms-2 d-lg-block d-none">
<img src="{{url_for('static', filename='/assets/img/down-arrow-dark.svg')}}" alt="down-arrow" class="arrow ms-1 d-lg-none d-block ms-auto">
</a>
<div class="dropdown-menu dropdown-menu-animation ms-n3 dropdown-md p-3 border-radius-xl mt-0 mt-lg-3" aria-labelledby="dropdownMenuPages">
<div class="d-none d-lg-flex">
<ul class="list-group w-100">
<li class="nav-item dropdown dropdown-hover dropdown-subitem list-group-item border-0 p-0">
<a class="dropdown-item ps-3 border-radius-md mb-1" href="/user/tenant">
<span>Tenant Registration</span>
</a>
<a class="dropdown-item ps-3 border-radius-md mb-1" href="/user/user">
<span>User Registration</span>
</a>
</li>
</ul>
</div>
</div>
</li>
<li class="nav-item dropdown dropdown-hover mx-2">
<a role="button" class="nav-link ps-2 d-flex cursor-pointer align-items-center" id="dropdownMenuUser" data-bs-toggle="dropdown" aria-expanded="false">
<i class="material-icons opacity-6 me-2 text-md">contacts</i>
Account
<img src="{{url_for('static', filename='/assets/img/down-arrow-dark.svg')}}" alt="down-arrow" class="arrow ms-2 d-lg-block d-none">
<img src="{{url_for('static', filename='/assets/img/down-arrow-dark.svg')}}" alt="down-arrow" class="arrow ms-1 d-lg-none d-block ms-auto">
</a>
<div class="dropdown-menu dropdown-menu-animation ms-n3 dropdown-md p-3 border-radius-xl mt-0 mt-lg-3" aria-labelledby="dropdownMenuPages">
<div class="d-none d-lg-flex">
<ul class="list-group w-100">
<li class="nav-item dropdown dropdown-hover dropdown-subitem list-group-item border-0 p-0">
<a class="dropdown-item ps-3 border-radius-md mb-1" href="/login">
<span>Login</span>
</a>
<a class="dropdown-item ps-3 border-radius-md mb-1" href="/logout">
<span>Logout</span>
</a>
</li>
</ul>
</div>
</div>
</li>
</ul>
</div>
</nav>
</div>
</div>
...
<div class="collapse navbar-collapse w-100 pt-3 pb-2 py-lg-0" id="navigation">
<ul class="navbar-nav navbar-nav-hover mx-auto">
{% if current_user.is_authenticated %}
{{ dropdown('User Mgmt', 'contacts', [
{'name': 'Select Tenant', 'url': '/user/select_tenant', 'roles': ['Super User']},
{'name': 'Tenant Registration', 'url': '/user/tenant', 'roles': ['Super User']},
{'name': 'User Registration', 'url': '/user/user', 'roles': ['admin', 'manager']},
{'name': 'User List', 'url': '/user/view_users', 'roles': ['Super User', 'Tenant Admin']}
]) }}
{% endif %}
{{ dropdown('Account', 'contacts', [
{'name': 'Login', 'url': '/login'},
{'name': 'Logout', 'url': '/logout'}
]) }}
</ul>
</div>
</div>
<!-- End Navbar -->
...
</div>

View File

@@ -0,0 +1,43 @@
{% macro nav_link(name, url, icon=None) %}
<li class="nav-item mx-2">
<a class="nav-link" href="{{ url }}">
{% if icon %}
<i class="material-icons">{{ icon }}</i>
{% endif %}
{{ name }}
</a>
</li>
{% endmacro %}
{% macro dropdown(title, icon, children) %}
<li class="nav-item dropdown dropdown-hover mx-2">
<a role="button" class="nav-link ps-2 d-flex cursor-pointer align-items-center" id="{{ title | replace(' ', '') }}" data-bs-toggle="dropdown" aria-expanded="false">
{% if icon %}
<i class="material-icons opacity-6 me-2 text-md">{{ icon }}</i>
{% endif %}
{{ title }}
<img src="{{ url_for('static', filename='assets/img/down-arrow-dark.svg') }}" alt="down-arrow" class="arrow ms-2">
</a>
<div class="dropdown-menu dropdown-menu-animation" aria-labelledby="{{ title | replace(' ', '') }}">
<ul class="list-group w-100">
{% for child in children %}
{% if child.roles %}
{% if current_user.has_roles(*child.roles) %}
<li class="nav-item dropdown-subitem list-group-item border-0 p-0">
<a class="dropdown-item ps-3 border-radius-md mb-1" href="{{ child.url }}">
<span>{{ child.name }}</span>
</a>
</li>
{% endif %}
{% else %}
<li class="nav-item dropdown-subitem list-group-item border-0 p-0">
<a class="dropdown-item ps-3 border-radius-md mb-1" href="{{ child.url }}">
<span>{{ child.name }}</span>
</a>
</li>
{% endif %}
{% endfor %}
</ul>
</div>
</li>
{% endmacro %}

View File

@@ -0,0 +1,33 @@
{% extends 'base.html' %}
{% from "macros.html" import render_field %}
{% block title %}Tenant Selection{% endblock %}
{% block content_title %}Select a Tenant{% endblock %}
{% block content_description %}Select the active tenant for the current session{% endblock %}
{% block content %}
<form method="POST" action="{{ url_for('user_bp.handle_tenant_selection') }}">
<table class="table">
<thead>
<tr>
<th>Select</th>
<th>Tenant Name</th>
<th>Tenant ID</th>
</tr>
</thead>
<tbody>
{% for tenant in tenants %}
<tr>
<td><input type="radio" name="tenant_id" value="{{ tenant.id }}" required></td>
<td>{{ tenant.name }}</td>
<td>{{ tenant.id }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="submit" name="action" value="view_users" class="btn btn-primary">View Users</button>
<button type="submit" name="action" value="edit_tenant" class="btn btn-secondary">Edit Tenant</button>
<!-- Add more buttons as needed -->
</form>
{% endblock %}

View File

@@ -0,0 +1,55 @@
{% extends 'base.html' %}
{% from "macros.html" import render_field %}
{% block title %}View Users{% endblock %}
{% block content_title %}Select a user{% endblock %}
{% block content_description %}Select the user you'd like to action upon{% endblock %}
{% block content %}
<h3>Users for Selected Tenant</h3>
<form action="{{ url_for('user_bp.handle_user_action') }}" method="POST">
<table id="usersTable" class="display" style="width:100%">
<thead>
<tr>
<th>Select</th>
<th>User ID</th>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td><input type="radio" name="user_id" value="{{ user.id }}" required></td>
<td>{{ user.id }}</td>
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-group mt-3">
<button type="submit" name="action" value="edit_user" class="btn btn-primary">Edit Selected User</button>
<!-- Additional buttons can be added here for other actions -->
</div>
</form>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script src="https://cdn.datatables.net/1.10.21/js/jquery.dataTables.min.js"></script>
<script>
$(document).ready(function() {
$('#usersTable').DataTable({
'columnDefs': [{
'targets': 0,
'searchable': false,
'orderable': false,
'className': 'dt-body-center',
'render': function (data, type, full, meta){
return '<input type="radio" name="user_id" value="' + $('<div/>').text(data).html() + '">';
}
}],
'order': [[1, 'asc']]
});
});
</script>
{% endblock %}

View File

@@ -2,7 +2,7 @@
import uuid
from datetime import datetime as dt, timezone as tz
from flask import request, redirect, url_for, flash, render_template, Blueprint, session
from flask_security import hash_password
from flask_security import hash_password, current_user
from ..models.user import User, Tenant, Role, RolesUsers
from ..extensions import db
@@ -162,3 +162,44 @@ def edit_user(user_id):
form.roles.data = [role.id for role in user.roles]
return render_template('user/edit_user.html', form=form, user_id=user_id)
@user_bp.route('/select_tenant')
def select_tenant():
tenants = Tenant.query.all() # Fetch all tenants from the database
return render_template('user/select_tenant.html', tenants=tenants)
@user_bp.route('/handle_tenant_selection', methods=['POST'])
def handle_tenant_selection():
tenant_id = request.form['tenant_id']
session['tenant_id'] = request.form['tenant_id']
action = request.form['action']
if action == 'view_users':
return redirect(url_for('user_bp.view_users', tenant_id=tenant_id))
elif action == 'edit_tenant':
return redirect(url_for('user_bp.edit_tenant', tenant_id=tenant_id))
# Add more conditions for other actions
return redirect(url_for('select_tenant'))
@user_bp.route('/view_users/<tenant_id>')
def view_users(tenant_id):
print(tenant_id)
tenant_id = int(tenant_id)
users = User.query.filter_by(tenant_id=tenant_id).all()
# Render the users in a template
return render_template('user/view_users.html', users=users)
@user_bp.route('/handle_user_action', methods=['POST'])
def handle_user_action():
user_id = request.form['user_id']
action = request.form['action']
if action == 'edit_user':
return redirect(url_for('user_bp.edit_user', user_id=user_id))
# Add more conditions for other actions
return redirect(url_for('view_users'))

View File

@@ -1,4 +1,5 @@
Flask~=3.0.3
WTForms~=3.1.2
SQLAlchemy~=2.0.29
alembic~=1.13.1
alembic~=1.13.1
Werkzeug~=3.0.2