fix dashboard table layout

This commit is contained in:
nahakubuilde
2025-06-17 19:26:25 +01:00
parent f961e426e7
commit 45799593e0
5 changed files with 38 additions and 55 deletions

12
app.py
View File

@@ -330,9 +330,8 @@ def init_app():
settings.log_level = 'WARNING' settings.log_level = 'WARNING'
db.session.add(settings) db.session.add(settings)
# Create default admin if not exists # Create default admin only if no users exist in the database
admin = User.query.filter_by(email='superadmin@example.com').first() if User.query.first() is None:
if not admin:
hashed_password = bcrypt.generate_password_hash('adminsuper').decode('utf-8') hashed_password = bcrypt.generate_password_hash('adminsuper').decode('utf-8')
admin = User( admin = User(
username='superadmin', username='superadmin',
@@ -347,12 +346,11 @@ def init_app():
# Create initial API key for admin # Create initial API key for admin
api_key = ApiKey( api_key = ApiKey(
key=ApiKey.generate_key(), key=ApiKey.generate_key(),
description="Initial Admin API Key", description="Initial Admin API Key"
user_id=admin.id
) )
db.session.add(api_key) db.session.add(api_key)
db.session.commit()
db.session.commit() logger.info("Created initial admin account and API key")
# Initialize the application # Initialize the application
init_app() init_app()

View File

@@ -1,6 +1,6 @@
from flask import Blueprint, render_template, request, redirect, url_for, flash, current_app from flask import Blueprint, render_template, request, redirect, url_for, flash, current_app
from flask_login import login_required, current_user from flask_login import login_required, current_user
from auth.models import User, Company, UserCompany from auth.models import User, Company, UserCompany, ApiKey
from api.models import Log from api.models import Log
from extensions import db from extensions import db
from datetime import datetime, timedelta from datetime import datetime, timedelta
@@ -73,14 +73,21 @@ def dashboard():
end_date = datetime.now(app_tz) + timedelta(hours=1) # Include 1 hour in the future end_date = datetime.now(app_tz) + timedelta(hours=1) # Include 1 hour in the future
start_date = end_date - timedelta(hours=49) # Look back 48 hours from future end time start_date = end_date - timedelta(hours=49) # Look back 48 hours from future end time
# Get company filter if provided # Get companies for the dropdown filter based on user role, ordered by name
company_id = request.args.get('company_id', type=int) if current_user.is_global_admin():
# GlobalAdmin can see all companies
companies = Company.query.order_by(Company.name).all()
else:
# Get user's companies, ordered by name
user_company_ids = [uc.company_id for uc in current_user.companies]
companies = Company.query.filter(Company.id.in_(user_company_ids)).order_by(Company.name).all()
# Build base query with date range filter and eagerly load relationships # Get company filter if provided, otherwise use first available company
from auth.models import ApiKey, Company company_id = request.args.get('company_id', type=int)
if not company_id and companies:
company_id = companies[0].id # Default to first company
# Convert timezone-aware dates to naive for comparison with database timestamps # Convert timezone-aware dates to naive for comparison with database timestamps
# since the log timestamps are stored as naive datetime objects
start_date_naive = start_date.replace(tzinfo=None) start_date_naive = start_date.replace(tzinfo=None)
end_date_naive = end_date.replace(tzinfo=None) end_date_naive = end_date.replace(tzinfo=None)
@@ -90,39 +97,22 @@ def dashboard():
db.joinedload(Log.company) db.joinedload(Log.company)
).filter(Log.timestamp.between(start_date_naive, end_date_naive)) ).filter(Log.timestamp.between(start_date_naive, end_date_naive))
# Apply company-specific filtering based on user role # Apply company-specific filtering
if current_user.is_global_admin(): if current_user.is_global_admin():
# GlobalAdmin should be allowed to see all records, no matter what company/site # GlobalAdmin with specific company selected
if company_id: if company_id:
query = query.filter(Log.company_id == company_id) query = query.filter(Log.company_id == company_id)
# If no company_id specified, show all logs (no additional filtering)
else: else:
# CompanyAdmin and User should see only company log events and API Keys (sites) # Regular users always need company filtering
# for companies they are member of
user_company_ids = [uc.company_id for uc in current_user.companies] user_company_ids = [uc.company_id for uc in current_user.companies]
if company_id and company_id in user_company_ids:
if not user_company_ids: query = query.filter(Log.company_id == company_id)
# If user has no company associations, show no logs
query = query.filter(Log.id == -1) # Impossible condition = no results
else: else:
if company_id and company_id in user_company_ids: query = query.filter(Log.company_id.in_(user_company_ids))
# Filter by the specific company if requested and user has access
query = query.filter(Log.company_id == company_id)
else:
# Show logs from all companies the user has access to
query = query.filter(Log.company_id.in_(user_company_ids))
# Get the logs ordered by timestamp (newest first) # Get the logs ordered by timestamp (newest first)
logs = query.order_by(Log.timestamp.desc()).all() logs = query.order_by(Log.timestamp.desc()).all()
# Get companies for the dropdown filter based on user role
if current_user.is_global_admin():
# GlobalAdmin can see all companies
companies = Company.query.all()
else:
# CompanyAdmin and User should see only companies they are member of
companies = current_user.get_companies()
return render_template('frontend/dashboard.html', return render_template('frontend/dashboard.html',
title='Dashboard', title='Dashboard',
logs=logs, logs=logs,

View File

@@ -13,7 +13,8 @@ pillow
Flask-Migrate Flask-Migrate
# serving the application # serving the application
waitress # Production WSGI server for Windows (better than Gunicorn for Windows) #waitress # Production WSGI server for Windows (better than Gunicorn for Windows)
redis
gunicorn # Production WSGI server (Linux/Unix only - won't work on Windows) gunicorn # Production WSGI server (Linux/Unix only - won't work on Windows)
#psutil # System monitoring for health checks #psutil # System monitoring for health checks
#click # CLI tools (for database backups) #click # CLI tools (for database backups)

View File

@@ -181,11 +181,9 @@
<input type="text" id="daterange" name="daterange" class="form-control" <input type="text" id="daterange" name="daterange" class="form-control"
value="{{ start_date.strftime('%Y-%m-%d %H:%M') if start_date else '' }} - {{ end_date.strftime('%Y-%m-%d %H:%M') if end_date else '' }}"/> value="{{ start_date.strftime('%Y-%m-%d %H:%M') if start_date else '' }} - {{ end_date.strftime('%Y-%m-%d %H:%M') if end_date else '' }}"/>
</div> </div>
{% if companies %}
<div class="col-md-3"> <div class="col-md-3">
<label for="company_id" class="form-label">Company:</label> <label for="company_id" class="form-label">Company:</label>
<select class="form-select" id="company_id" name="company_id"> <select class="form-select" id="company_id" name="company_id" required>
<option value="">All Companies</option>
{% for company in companies %} {% for company in companies %}
<option value="{{ company.id }}" {% if selected_company_id == company.id %}selected{% endif %}> <option value="{{ company.id }}" {% if selected_company_id == company.id %}selected{% endif %}>
{{ company.name }} {{ company.name }}
@@ -193,7 +191,6 @@
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
{% endif %}
<div class="col-md-2"> <div class="col-md-2">
<button type="submit" class="btn btn-primary">Apply Filter</button> <button type="submit" class="btn btn-primary">Apply Filter</button>
</div> </div>
@@ -210,9 +207,7 @@
<th>Timestamp</th> <th>Timestamp</th>
<th>Event Type</th> <th>Event Type</th>
<th>User Name</th> <th>User Name</th>
{% if current_user.is_global_admin() and not selected_company_id %} <th>Company</th>
<th>Company</th>
{% endif %}
<th>Site</th> <th>Site</th>
<th>Computer Name</th> <th>Computer Name</th>
<th>Local IP</th> <th>Local IP</th>
@@ -227,9 +222,7 @@
</td> </td>
<td>{{ log.event_type }}</td> <td>{{ log.event_type }}</td>
<td>{{ log.user_name }}</td> <td>{{ log.user_name }}</td>
{% if current_user.is_global_admin() and not selected_company_id %} <td>{{ log.company.name if log.company else '' }}</td>
<td>{{ log.company.name if log.company else '' }}</td>
{% endif %}
<td>{{ log.api_key.description if log.api_key else '' }}</td> <td>{{ log.api_key.description if log.api_key else '' }}</td>
<td>{{ log.computer_name }}</td> <td>{{ log.computer_name }}</td>
<td>{{ log.local_ip or '' }}</td> <td>{{ log.local_ip or '' }}</td>
@@ -317,9 +310,14 @@
'<"row"<"col-sm-12 col-md-5"i><"col-sm-12 col-md-7"p>>', '<"row"<"col-sm-12 col-md-5"i><"col-sm-12 col-md-7"p>>',
columnDefs: [ columnDefs: [
{ {
targets: [5, 6, 7], // Computer Name, Local IP, and Public IP columns are now at indices 5, 6, and 7 targets: [5, 6, 7], // Computer Name, Local IP, and Public IP columns
visible: false, // Hide by default visible: false, // Hide by default
searchable: true // Still allow searching in these columns searchable: true // Still allow searching in these columns
},
{
targets: [3], // Company column
visible: {% if current_user.is_global_admin() %}true{% else %}false{% endif %},
searchable: {% if current_user.is_global_admin() %}true{% else %}false{% endif %}
} }
], ],
buttons: [ buttons: [
@@ -364,11 +362,7 @@
}); });
// Column names for the visibility controls // Column names for the visibility controls
var columnNames = ['Timestamp', 'Event Type', 'User Name']; var columnNames = ['Timestamp', 'Event Type', 'User Name', 'Company', 'Site', 'Computer Name', 'Local IP', 'Public IP'];
{% if current_user.is_global_admin() and not selected_company_id %}
columnNames.push('Company');
{% endif %}
columnNames.push('Site', 'Computer Name', 'Local IP', 'Public IP');
// Load saved column visibility from localStorage // Load saved column visibility from localStorage
function loadColumnVisibility() { function loadColumnVisibility() {

View File

@@ -129,7 +129,7 @@ class ConfigManager:
'logging': { 'logging': {
'DB_LOGGING_ENABLED': 'true', 'DB_LOGGING_ENABLED': 'true',
'DB_LOGGING_FILTERED_LOGGERS': 'watchfiles.main,watchfiles.watcher,watchdog,uvicorn.access,__mp_main__,__main__,app', 'DB_LOGGING_FILTERED_LOGGERS': 'watchfiles.main,watchfiles.watcher,watchdog,uvicorn.access,__mp_main__,__main__,app,werkzeug',
'DB_LOGGING_FILTERED_PATTERNS': 'database.db,instance/,file changed,reloading', 'DB_LOGGING_FILTERED_PATTERNS': 'database.db,instance/,file changed,reloading',
'FILTER_FILE_WATCHER_LOGS': 'true', 'FILTER_FILE_WATCHER_LOGS': 'true',
'DB_LOGGING_DEDUPE_INTERVAL': '1', 'DB_LOGGING_DEDUPE_INTERVAL': '1',