Move settings endpoints to separate blueprint

This commit is contained in:
Peter Stockings
2026-02-08 18:48:03 +11:00
parent 31078b181a
commit 8c08140ad0
6 changed files with 80 additions and 69 deletions

57
app.py
View File

@@ -23,6 +23,7 @@ from routes.export import export_bp # Import the new export blueprint
from routes.tags import tags_bp # Import the new tags blueprint
from routes.programs import programs_bp # Import the new programs blueprint
from routes.exercises import exercises_bp # Import the new exercises blueprint
from routes.settings import settings_bp # Import the new settings blueprint
from extensions import db
from utils import convert_str_to_date
from flask_htmx import HTMX
@@ -73,6 +74,7 @@ app.register_blueprint(export_bp) # Register the export blueprint (prefix define
app.register_blueprint(tags_bp) # Register the tags blueprint (prefix defined in blueprint file)
app.register_blueprint(programs_bp) # Register the programs blueprint (prefix defined in blueprint file)
app.register_blueprint(exercises_bp) # Register the exercises blueprint
app.register_blueprint(settings_bp) # Register the settings blueprint
@app.after_request
def response_minify(response):
@@ -224,62 +226,7 @@ def get_person_name(person_id):
@ app.route("/settings")
@ login_required
def settings():
if htmx:
return render_block(app.jinja_env, 'settings.html', 'content')
return render_template('settings.html')
@ app.route("/settings/tab/people")
@ login_required
def settings_people():
people = db.get_people()
return render_template('partials/settings/people.html', people=people)
@ app.route("/settings/tab/exercises")
@ login_required
def settings_exercises():
exercises = db.get_all_exercises()
all_attributes = db.exercises.get_attributes_by_category()
categories_list = db.exercises.get_all_attribute_categories()
# Format options for custom_select
formatted_options = {}
for cat, attrs in all_attributes.items():
formatted_options[cat] = [{"id": a['attribute_id'], "attribute_id": a['attribute_id'], "name": a['name'], "category_id": a['category_id']} for a in attrs]
return render_template('partials/settings/exercises.html',
exercises=exercises,
all_attributes=formatted_options,
categories_list=categories_list)
@ app.route("/settings/tab/export")
@ login_required
def settings_export():
return render_template('partials/settings/export.html')
@ app.route("/settings/tab/activity")
@ login_required
def settings_activity():
return render_template('partials/settings/activity.html')
@app.route("/settings/activity_logs")
@login_required
def settings_activity_logs():
limit = 50
offset = request.args.get('offset', 0, type=int)
logs = db.activityRequest.get_recent_logs(limit=limit, offset=offset)
# Check if there are more logs to load
has_more = len(logs) == limit
return render_template('partials/activity_logs.html',
logs=logs,
offset=offset,
limit=limit,
has_more=has_more)
# Routes moved to routes/tags.py blueprint

64
routes/settings.py Normal file
View File

@@ -0,0 +1,64 @@
from flask import Blueprint, render_template, request
from flask_login import login_required
from jinja2_fragments import render_block
from extensions import db
from flask import current_app
settings_bp = Blueprint('settings', __name__)
@settings_bp.route("/settings")
@login_required
def settings():
# Detect HTMX via header since we don't have the global htmx object here
is_htmx = request.headers.get('HX-Request') == 'true'
if is_htmx:
return render_block(current_app.jinja_env, 'settings.html', 'content')
return render_template('settings.html')
@settings_bp.route("/settings/tab/people")
@login_required
def settings_people():
people = db.get_people()
return render_template('partials/settings/people.html', people=people)
@settings_bp.route("/settings/tab/exercises")
@login_required
def settings_exercises():
exercises = db.get_all_exercises()
all_attributes = db.exercises.get_attributes_by_category()
categories_list = db.exercises.get_all_attribute_categories()
# Format options for custom_select
formatted_options = {}
for cat, attrs in all_attributes.items():
formatted_options[cat] = [{"id": a['attribute_id'], "attribute_id": a['attribute_id'], "name": a['name'], "category_id": a['category_id']} for a in attrs]
return render_template('partials/settings/exercises.html',
exercises=exercises,
all_attributes=formatted_options,
categories_list=categories_list)
@settings_bp.route("/settings/tab/export")
@login_required
def settings_export():
return render_template('partials/settings/export.html')
@settings_bp.route("/settings/tab/activity")
@login_required
def settings_activity():
return render_template('partials/settings/activity.html')
@settings_bp.route("/settings/activity_logs")
@login_required
def settings_activity_logs():
limit = 50
offset = request.args.get('offset', 0, type=int)
logs = db.activityRequest.get_recent_logs(limit=limit, offset=offset)
# Check if there are more logs to load
has_more = len(logs) == limit
return render_template('partials/activity_logs.html',
logs=logs,
offset=offset,
has_more=has_more)

View File

@@ -192,8 +192,8 @@
</svg>
<span class="ml-3">Endpoints</span>
</a>
<a hx-get="{{ url_for('settings') }}" hx-push-url="true" hx-target="#container"
class="text-base text-gray-900 font-normal rounded-lg hover:bg-gray-100 group transition duration-75 flex items-center p-2 cursor-pointer {{ is_selected_page(url_for('settings')) }} page-link"
<a hx-get="{{ url_for('settings.settings') }}" hx-push-url="true" hx-target="#container"
class="text-base text-gray-900 font-normal rounded-lg hover:bg-gray-100 group transition duration-75 flex items-center p-2 cursor-pointer {{ is_selected_page(url_for('settings.settings')) }} page-link"
_="on click add .hidden to #sidebar then remove .ml-64 from #main
on htmx:afterRequest go to the top of the body">
<svg class="w-6 h-6 text-gray-500 group-hover:text-gray-900 transition duration-75"

View File

@@ -50,7 +50,7 @@
{% if has_more %}
<tr id="load-more-row">
<td colspan="5" class="p-4 text-center">
<button hx-get="/settings/activity_logs?offset={{ offset + limit }}"
<button hx-get="{{ url_for('settings.settings_activity_logs', offset=offset + limit) }}"
hx-target="#load-more-row" hx-swap="outerHTML"
class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-cyan-700 bg-cyan-100 hover:bg-cyan-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-cyan-500 transition-colors">
Load More...

View File

@@ -3,7 +3,7 @@
<h3 class="text-xl font-bold text-gray-900">Activity Logs</h3>
<p class="text-sm text-gray-500">Review recent actions and administrative changes.</p>
</div>
<div id="activity-logs-container" hx-get="/settings/activity_logs" hx-trigger="load">
<div id="activity-logs-container" hx-get="{{ url_for('settings.settings_activity_logs') }}" hx-trigger="load">
<div class="flex justify-center p-12">
<div class="flex flex-col items-center">
<div class="animate-spin rounded-full h-10 w-10 border-b-2 border-cyan-600 mb-4"></div>

View File

@@ -13,8 +13,8 @@
<div class="border-b border-gray-200 mb-6 bg-gray-50 z-10">
<ul class="flex flex-wrap -mb-px text-sm font-medium text-center text-gray-500">
<li class="mr-2">
<label for="radio-users" hx-get="/settings/tab/people" hx-target="#people-tab-content"
hx-trigger="click"
<label for="radio-users" hx-get="{{ url_for('settings.settings_people') }}"
hx-target="#people-tab-content" hx-trigger="click"
class="inline-flex items-center justify-center p-4 border-b-2 rounded-t-lg group cursor-pointer transition-colors
peer-checked/users:border-cyan-600 peer-checked/users:text-cyan-600 border-transparent hover:text-gray-700 hover:border-gray-300">
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20"
@@ -26,8 +26,8 @@
</label>
</li>
<li class="mr-2">
<label for="radio-exercises" hx-get="/settings/tab/exercises" hx-target="#exercises-tab-content"
hx-trigger="click"
<label for="radio-exercises" hx-get="{{ url_for('settings.settings_exercises') }}"
hx-target="#exercises-tab-content" hx-trigger="click"
class="inline-flex items-center justify-center p-4 border-b-2 rounded-t-lg group cursor-pointer transition-colors
peer-checked/exercises:border-cyan-600 peer-checked/exercises:text-cyan-600 border-transparent hover:text-gray-700 hover:border-gray-300">
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20"
@@ -41,8 +41,8 @@
</label>
</li>
<li class="mr-2">
<label for="radio-export" hx-get="/settings/tab/export" hx-target="#export-tab-content"
hx-trigger="click"
<label for="radio-export" hx-get="{{ url_for('settings.settings_export') }}"
hx-target="#export-tab-content" hx-trigger="click"
class="inline-flex items-center justify-center p-4 border-b-2 rounded-t-lg group cursor-pointer transition-colors
peer-checked/export:border-cyan-600 peer-checked/export:text-cyan-600 border-transparent hover:text-gray-700 hover:border-gray-300">
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20"
@@ -55,8 +55,8 @@
</label>
</li>
<li class="mr-2">
<label for="radio-activity" hx-get="/settings/tab/activity" hx-target="#activity-tab-content"
hx-trigger="click"
<label for="radio-activity" hx-get="{{ url_for('settings.settings_activity') }}"
hx-target="#activity-tab-content" hx-trigger="click"
class="inline-flex items-center justify-center p-4 border-b-2 rounded-t-lg group cursor-pointer transition-colors
peer-checked/activity:border-cyan-600 peer-checked/activity:text-cyan-600 border-transparent hover:text-gray-700 hover:border-gray-300">
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20"
@@ -72,8 +72,8 @@
</div>
<!-- Users Tab Content -->
<div class="hidden peer-checked/users:block" id="people-tab-content" hx-get="/settings/tab/people"
hx-trigger="load">
<div class="hidden peer-checked/users:block" id="people-tab-content"
hx-get="{{ url_for('settings.settings_people') }}" hx-trigger="load">
<div class="flex justify-center p-12">
<div class="flex flex-col items-center">
<div class="animate-spin rounded-full h-10 w-10 border-b-2 border-cyan-600 mb-4"></div>