Implement boxes management module with auto-numbered box creation
- Add boxes_crates database table with BIGINT IDs and 8-digit auto-numbered box_numbers - Implement boxes CRUD operations (add, edit, update, delete, delete_multiple) - Create boxes route handlers with POST actions for all operations - Add boxes.html template with 3-panel layout matching warehouse locations module - Implement barcode generation and printing with JsBarcode and QZ Tray integration - Add browser print fallback for when QZ Tray is not available - Simplify create box form to single button with auto-generation - Fix JavaScript null reference errors with proper element validation - Convert tuple data to dictionaries for Jinja2 template compatibility - Register boxes blueprint in Flask app initialization
This commit is contained in:
@@ -31,6 +31,9 @@
|
||||
<a href="{{ url_for('settings.database_settings') }}" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-database"></i> Database Info
|
||||
</a>
|
||||
<a href="{{ url_for('settings.logs_explorer') }}" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-file-alt"></i> Logs Explorer
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
<a href="{{ url_for('settings.database_settings') }}" class="list-group-item list-group-item-action active">
|
||||
<i class="fas fa-database"></i> Database Info
|
||||
</a>
|
||||
<a href="{{ url_for('settings.logs_explorer') }}" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-file-alt"></i> Logs Explorer
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
<a href="{{ url_for('settings.database_settings') }}" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-database"></i> Database Info
|
||||
</a>
|
||||
<a href="{{ url_for('settings.logs_explorer') }}" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-file-alt"></i> Logs Explorer
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
<a href="{{ url_for('settings.database_settings') }}" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-database"></i> Database Info
|
||||
</a>
|
||||
<a href="{{ url_for('settings.logs_explorer') }}" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-file-alt"></i> Logs Explorer
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
|
||||
@@ -13,6 +13,96 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- App Overview Section -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<h4 class="mb-3"><i class="fas fa-chart-pie"></i> Application Overview</h4>
|
||||
<div class="row">
|
||||
<!-- Users Card -->
|
||||
<div class="col-md-3 col-sm-6 mb-3">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-6 text-primary mb-2">{{ stats.user_count }}</div>
|
||||
<p class="card-text mb-0">Active Users</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Database Size Card -->
|
||||
<div class="col-md-3 col-sm-6 mb-3">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-6 text-info mb-2">{{ stats.database_size_mb }} MB</div>
|
||||
<p class="card-text mb-0">Database Size</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Logs Size Card -->
|
||||
<div class="col-md-3 col-sm-6 mb-3">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-6 text-warning mb-2">{{ stats.logs_size_mb }} MB</div>
|
||||
<p class="card-text mb-0">Logs Size</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Database Count Card -->
|
||||
<div class="col-md-3 col-sm-6 mb-3">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-6 text-secondary mb-2">{{ stats.database_count }}</div>
|
||||
<p class="card-text mb-0">Databases</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Backups Card -->
|
||||
<div class="col-md-3 col-sm-6 mb-3">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-6 text-success mb-2">{{ stats.backup_count }}</div>
|
||||
<p class="card-text mb-0">Scheduled Backups</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Printer Keys Card -->
|
||||
<div class="col-md-3 col-sm-6 mb-3">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-6 text-danger mb-2">{{ stats.printer_keys_count }}</div>
|
||||
<p class="card-text mb-0">Printer Keys</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- App Keys Availability Card -->
|
||||
<div class="col-md-6 col-sm-6 mb-3">
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<p class="card-text mb-0">App Key Availability</p>
|
||||
<h5 class="mb-0 mt-2">
|
||||
{% if stats.app_key_availability.available %}
|
||||
<span class="badge bg-success"><i class="fas fa-check-circle"></i> {{ stats.app_key_availability.status }}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-danger"><i class="fas fa-times-circle"></i> {{ stats.app_key_availability.status }}</span>
|
||||
{% endif %}
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="list-group">
|
||||
@@ -31,6 +121,9 @@
|
||||
<a href="{{ url_for('settings.database_settings') }}" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-database"></i> Database Info
|
||||
</a>
|
||||
<a href="{{ url_for('settings.logs_explorer') }}" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-file-alt"></i> Logs Explorer
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
|
||||
159
app/templates/modules/settings/logs_explorer.html
Normal file
159
app/templates/modules/settings/logs_explorer.html
Normal file
@@ -0,0 +1,159 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Logs Explorer - Settings{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid py-4">
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<h1 class="mb-2">
|
||||
<i class="fas fa-file-alt"></i> Logs Explorer
|
||||
</h1>
|
||||
<p class="text-muted">View and manage application log files</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Log Statistics -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-6 text-primary mb-2">{{ log_stats.total_files }}</div>
|
||||
<p class="card-text mb-0">Log Files</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-6 text-info mb-2">{{ log_stats.total_size_mb }} MB</div>
|
||||
<p class="card-text mb-0">Total Size</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<p class="card-text mb-1"><small><strong>Newest:</strong> {{ log_stats.newest_log or 'N/A' }}</small></p>
|
||||
<p class="card-text mb-0"><small><strong>Oldest:</strong> {{ log_stats.oldest_log or 'N/A' }}</small></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Search Section -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0"><i class="fas fa-search"></i> Search Logs</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="GET" action="{{ url_for('settings.search_logs') }}" class="form-inline">
|
||||
<input type="text" name="q" class="form-control mr-2" placeholder="Search term..." style="flex: 1; margin-right: 10px;">
|
||||
<select name="file" class="form-control mr-2" style="width: auto;">
|
||||
<option value="">All Files</option>
|
||||
{% for log_file in log_files %}
|
||||
<option value="{{ log_file.name }}">{{ log_file.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-search"></i> Search
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Log Files Table -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0"><i class="fas fa-list"></i> Log Files</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if log_files %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>File Name</th>
|
||||
<th>Size</th>
|
||||
<th>Last Modified</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for log_file in log_files %}
|
||||
<tr>
|
||||
<td>
|
||||
<i class="fas fa-file-lines text-primary"></i>
|
||||
{{ log_file.name }}
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-info">{{ log_file.size_mb }} MB</span>
|
||||
</td>
|
||||
<td>
|
||||
<small class="text-muted">{{ log_file.modified_at }}</small>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('settings.view_log', filename=log_file.name) }}"
|
||||
class="btn btn-sm btn-outline-primary" title="View">
|
||||
<i class="fas fa-eye"></i> View
|
||||
</a>
|
||||
<a href="{{ url_for('settings.download_log', filename=log_file.name) }}"
|
||||
class="btn btn-sm btn-outline-success" title="Download">
|
||||
<i class="fas fa-download"></i> Download
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-info mb-0">
|
||||
<i class="fas fa-info-circle"></i> No log files found
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.form-inline {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.form-inline input,
|
||||
.form-inline select,
|
||||
.form-inline button {
|
||||
flex: 1;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.form-inline {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.form-inline input,
|
||||
.form-inline select,
|
||||
.form-inline button {
|
||||
flex: 1;
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.btn.btn-outline-primary,
|
||||
.btn.btn-outline-success {
|
||||
margin-right: 5px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
142
app/templates/modules/settings/search_logs.html
Normal file
142
app/templates/modules/settings/search_logs.html
Normal file
@@ -0,0 +1,142 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Search Logs - Settings{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid py-4">
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h1 class="mb-0">
|
||||
<i class="fas fa-search"></i> Search Logs
|
||||
</h1>
|
||||
<p class="text-muted mb-0">Find entries in log files</p>
|
||||
</div>
|
||||
<a href="{{ url_for('settings.logs_explorer') }}" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Back
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Search Form -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0"><i class="fas fa-filter"></i> Search Options</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="GET" action="{{ url_for('settings.search_logs') }}">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="form-group">
|
||||
<label for="search_term">Search Term:</label>
|
||||
<input type="text" id="search_term" name="q" class="form-control"
|
||||
value="{{ search_term }}" placeholder="Enter search term..." required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<label for="log_file">Log File:</label>
|
||||
<select id="log_file" name="file" class="form-control">
|
||||
<option value="">All Files</option>
|
||||
{% for log_file in log_files %}
|
||||
<option value="{{ log_file.name }}" {% if log_file.name == selected_file %}selected{% endif %}>
|
||||
{{ log_file.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-search"></i> Search
|
||||
</button>
|
||||
{% if search_term %}
|
||||
<a href="{{ url_for('settings.search_logs') }}" class="btn btn-secondary">
|
||||
<i class="fas fa-times"></i> Clear
|
||||
</a>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Search Results -->
|
||||
{% if search_term %}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">
|
||||
<i class="fas fa-list"></i> Results
|
||||
{% if results %}
|
||||
<span class="badge bg-primary">{{ results|length }} found</span>
|
||||
{% endif %}
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if results %}
|
||||
<div class="list-group">
|
||||
{% for result in results %}
|
||||
<div class="list-group-item">
|
||||
<div class="d-flex w-100 justify-content-between align-items-start">
|
||||
<div>
|
||||
<h6 class="mb-1">
|
||||
<i class="fas fa-file-lines text-primary"></i>
|
||||
{{ result.file }}
|
||||
<span class="badge bg-secondary">Line {{ result.line_num }}</span>
|
||||
</h6>
|
||||
<p class="mb-0" style="font-family: 'Courier New', monospace; font-size: 12px; word-break: break-all;">
|
||||
{{ result.line }}
|
||||
</p>
|
||||
</div>
|
||||
<a href="{{ url_for('settings.view_log', filename=result.file) }}#line-{{ result.line_num }}"
|
||||
class="btn btn-sm btn-outline-primary">
|
||||
<i class="fas fa-eye"></i> View
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-info mb-0">
|
||||
<i class="fas fa-info-circle"></i> No results found for "{{ search_term }}"
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info">
|
||||
<i class="fas fa-search"></i> Enter a search term to find entries in your logs
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.list-group-item {
|
||||
border-left: 3px solid #007bff;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.list-group-item:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
@@ -30,6 +30,9 @@
|
||||
<a href="{{ url_for('settings.database_settings') }}" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-database"></i> Database Info
|
||||
</a>
|
||||
<a href="{{ url_for('settings.logs_explorer') }}" class="list-group-item list-group-item-action">
|
||||
<i class="fas fa-file-alt"></i> Logs Explorer
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
|
||||
87
app/templates/modules/settings/view_log.html
Normal file
87
app/templates/modules/settings/view_log.html
Normal file
@@ -0,0 +1,87 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}View Log - Settings{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid py-4">
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h1 class="mb-0">
|
||||
<i class="fas fa-file-alt"></i> {{ log_data.filename }}
|
||||
</h1>
|
||||
<p class="text-muted mb-0"><small>Size: {{ log_data.size_mb }} MB | Modified: {{ log_data.modified_at }}</small></p>
|
||||
</div>
|
||||
<div>
|
||||
<a href="{{ url_for('settings.logs_explorer') }}" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> Back
|
||||
</a>
|
||||
<a href="{{ url_for('settings.download_log', filename=log_data.filename) }}" class="btn btn-success">
|
||||
<i class="fas fa-download"></i> Download
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- File Info -->
|
||||
<div class="row mb-3">
|
||||
<div class="col-12">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<p class="mb-0"><strong>File Size:</strong></p>
|
||||
<p class="text-muted">{{ log_data.size_mb }} MB</p>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<p class="mb-0"><strong>Total Lines:</strong></p>
|
||||
<p class="text-muted">{{ log_data.total_lines|default(0) }}</p>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<p class="mb-0"><strong>Displayed Lines:</strong></p>
|
||||
<p class="text-muted">{{ log_data.displayed_lines|default(0) }}</p>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<p class="mb-0"><strong>Last Modified:</strong></p>
|
||||
<p class="text-muted">{{ log_data.modified_at }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% if log_data.truncated %}
|
||||
<div class="alert alert-info mb-0">
|
||||
<i class="fas fa-info-circle"></i> Showing last {{ log_data.displayed_lines }} lines of {{ log_data.total_lines }} total lines.
|
||||
<a href="{{ url_for('settings.view_log', filename=log_data.filename, lines='') }}">View all lines</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Log Content -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0"><i class="fas fa-align-left"></i> Log Content</h5>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<pre class="mb-0" style="background-color: #f8f9fa; padding: 15px; border-radius: 0 0 4px 4px; max-height: 600px; overflow-y: auto;">{{ log_data.content }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
pre {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
color: #333;
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user