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:
@@ -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()
|
||||
|
||||
@@ -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>
|
||||
43
eveai_app/templates/navbar_macros.html
Normal file
43
eveai_app/templates/navbar_macros.html
Normal 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 %}
|
||||
33
eveai_app/templates/user/select_tenant.html
Normal file
33
eveai_app/templates/user/select_tenant.html
Normal 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 %}
|
||||
55
eveai_app/templates/user/view_users.html
Normal file
55
eveai_app/templates/user/view_users.html
Normal 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 %}
|
||||
@@ -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'))
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user