Major update to the scanning engine to support "Pause & Resume" workflows. The system can now halt execution to ask for user input (e.g. Weight) and resume processing seamlessly. Key Changes: - Backend (Global Actions): Added `OPEN_FORM` action type to pause pipeline and request manual input. - Backend (Routes): Updated `scan_lot` to handle `extra_data` payloads, allowing the pipeline to resume after user input. - Backend (Logic): Implemented `confirm_duplicate` gatekeeper to handle "Warn vs Block" logic dynamically. - Frontend (JS): Added `processSmartScan` to handle router signals (Open Modal, Warn Duplicate). - Frontend (JS): Added `saveSmartScanData` to send original barcode + new form data back to the engine. - UI: Fixed modal ID/Name conflicts (forcing use of `name` attribute for DB compatibility). - UI: Restored missing "Cancel" button to Details Modal. - Config: Added "User Input" rule type to the Rule Editor. Ver: 0.18.0
146 lines
6.5 KiB
HTML
146 lines
6.5 KiB
HTML
{% extends 'base.html' %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid p-4">
|
|
|
|
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h2>
|
|
<i class="fas fa-random me-2"></i>Routing Rules
|
|
<small class="text-muted fs-6 ms-2">IFTTT Logic Engine</small>
|
|
</h2>
|
|
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addRuleModal">
|
|
<i class="fas fa-plus"></i> Add New Rule
|
|
</button>
|
|
</div>
|
|
|
|
<div class="card shadow-sm">
|
|
<div class="card-header bg-light">
|
|
<h5 class="mb-0">Active Rules</h5>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
{% if rules %}
|
|
<table class="table table-hover mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th style="width: 80px;">Line</th>
|
|
<th>Rule Name</th>
|
|
<th>Match Pattern (Regex)</th>
|
|
<th>Actions</th>
|
|
<th>Status</th>
|
|
<th class="text-end">Options</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for rule in rules %}
|
|
<tr>
|
|
<td><span class="badge bg-secondary">{{ rule['line_number'] }}</span></td>
|
|
<td><strong>{{ rule['rule_name'] }}</strong></td>
|
|
<td><code>{{ rule['match_pattern'] }}</code></td>
|
|
<td>
|
|
<span class="badge bg-info text-dark">JSON Logic</span>
|
|
</td>
|
|
<td>
|
|
{% if rule['is_active'] %}
|
|
<span class="badge bg-success">Active</span>
|
|
{% else %}
|
|
<span class="badge bg-secondary">Archived</span>
|
|
{% endif %}
|
|
</td>
|
|
<td class="text-end">
|
|
<a href="{{ url_for('conssheets.edit_router_rule', process_id=process['id'], rule_id=rule['id']) }}" class="btn btn-sm btn-outline-secondary">Edit</a>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
{% else %}
|
|
<div class="text-center py-5">
|
|
<i class="fas fa-code-branch fa-3x text-muted mb-3"></i>
|
|
<p class="lead text-muted">No routing rules defined yet.</p>
|
|
<p class="small text-muted">Rules allow you to auto-parse barcodes into multiple fields.</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal fade" id="addRuleModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Add Routing Rule</h5>
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<form action="{{ url_for('conssheets.add_router_rule', process_id=process['id']) }}" method="POST">
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label">Line Number</label>
|
|
<input type="number" class="form-control" name="line_number" placeholder="e.g. 10, 20, 30" required>
|
|
<div class="form-text">Rules run in order. Leave gaps (10, 20) for future inserts.</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Rule Name</label>
|
|
<input type="text" class="form-control" name="rule_name" placeholder="e.g. Parse Data Matrix" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Match Pattern (Regex)</label>
|
|
<input type="text" class="form-control" name="match_pattern" placeholder="e.g. ^\d{8}-.*" required>
|
|
<div class="form-text">
|
|
Use <code>.*</code> to match everything (default/catch-all).
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Create Rule</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Elements
|
|
const modal = document.getElementById('addRuleModal');
|
|
const openBtn = document.querySelector('[data-target="#addRuleModal"]');
|
|
const closeBtns = modal.querySelectorAll('[data-dismiss="modal"]');
|
|
|
|
// Function to open modal
|
|
openBtn.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
modal.style.display = 'block';
|
|
setTimeout(() => modal.classList.add('show'), 10); // Small delay for transition
|
|
document.body.classList.add('modal-open');
|
|
|
|
// Add dark backdrop
|
|
const backdrop = document.createElement('div');
|
|
backdrop.className = 'modal-backdrop fade show';
|
|
backdrop.id = 'custom-backdrop';
|
|
document.body.appendChild(backdrop);
|
|
});
|
|
|
|
// Function to close modal
|
|
function closeModal() {
|
|
modal.classList.remove('show');
|
|
setTimeout(() => {
|
|
modal.style.display = 'none';
|
|
document.body.classList.remove('modal-open');
|
|
const backdrop = document.getElementById('custom-backdrop');
|
|
if (backdrop) backdrop.remove();
|
|
}, 150); // Wait for transition
|
|
}
|
|
|
|
// Attach close event to all close buttons (X and Cancel)
|
|
closeBtns.forEach(btn => btn.addEventListener('click', closeModal));
|
|
|
|
// Close if clicking outside the modal content
|
|
window.addEventListener('click', function(event) {
|
|
if (event.target === modal) {
|
|
closeModal();
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %} |