feat: pre-computed state store and async ACME issuance (fixes timeout mismatch)
- Add lib/state.py: in-memory state store with subsystem collectors (firewall, dnsmasq, nginx, acme, wireguard) - Refactor all handlers: read from state on GET, call refresh_state() after mutations instead of invoking subprocesses per request - daemon/server.py: add refresh_state(), /status/all, /status/refresh; populate state at startup - webui/api/certs.py: async step-by-step ACME issuance (validate, issue with request_id, poll status) replacing blocking endpoint - webui/server.py: render pages from state instead of direct lib calls - Update templates, JS for async cert issuance with polling UI - Update tests for state-based mocking; add test_state.py - Fix SIM105 lint issue (contextlib.suppress) - Add TODO.md with certificate issuance issue tracking Resolves: WebUI 30s timeout freeze during cert issuance (Problem 1)
This commit is contained in:
+28
-10
@@ -7,7 +7,7 @@
|
||||
<h1>Certificates</h1>
|
||||
<div class="subtitle">SSL/TLS certificate management</div>
|
||||
</div>
|
||||
<button class="btn btn-primary" onclick="openModal('issue-cert-modal')">+ Issue New Certificate</button>
|
||||
<button class="btn btn-primary" onclick="resetIssueWizard(); openModal('issue-cert-modal')">+ Issue New Certificate</button>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
@@ -53,24 +53,42 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Issue Certificate Modal -->
|
||||
<div class="modal-overlay" id="issue-cert-modal" onclick="if(event.target===this) closeModal('issue-cert-modal')">
|
||||
<div class="modal">
|
||||
<!-- Issue Certificate Modal — Phase 1: Validate -->
|
||||
<div class="modal-overlay" id="issue-cert-modal" onclick="if(event.target===this) closeIssueWizard()">
|
||||
<div class="modal" style="min-width:480px;">
|
||||
<h2>Issue New Certificate</h2>
|
||||
<form hx-post="/api/certs/issue" hx-encoding="json" hx-swap="none" hx-on::after-request="if(evt.detail.successful){ closeModal('issue-cert-modal'); refreshTable('/api/certs/list', document.getElementById('cert-rows'), renderCerts); showSuccessToast('Certificate issuance started'); }">
|
||||
|
||||
<!-- Phase 1: Input + Pre-flight Checks -->
|
||||
<div id="cert-wizard-input">
|
||||
<div class="form-group">
|
||||
<label for="cert-domain">Domain</label>
|
||||
<input type="text" id="cert-domain" name="domain" placeholder="example.com" required>
|
||||
<input type="text" id="cert-domain" placeholder="example.com" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="cert-email">Contact Email</label>
|
||||
<input type="email" id="cert-email" name="email" placeholder="admin@example.com" value="{{ (email or '') | e }}">
|
||||
<input type="email" id="cert-email" placeholder="admin@example.com" value="{{ (email or '') | e }}">
|
||||
</div>
|
||||
|
||||
<!-- Pre-flight validation results (shown after Check) -->
|
||||
<div id="cert-check-results" style="display:none;">
|
||||
<div class="section-title" style="margin-top:16px;">Pre-flight Checks</div>
|
||||
<div id="cert-checks-list"></div>
|
||||
</div>
|
||||
|
||||
<div class="modal-actions">
|
||||
<button type="button" class="btn btn-outline" onclick="closeModal('issue-cert-modal')">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">Issue</button>
|
||||
<button type="button" class="btn btn-outline" onclick="closeIssueWizard()">Cancel</button>
|
||||
<button type="button" id="cert-check-btn" class="btn btn-primary" onclick="validateCertIssue()">Check</button>
|
||||
<button type="button" id="cert-issue-btn" class="btn btn-primary" style="display:none;" onclick="startCertIssue()">Issue</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Phase 2: Step progress -->
|
||||
<div id="cert-wizard-progress" style="display:none;">
|
||||
<div id="cert-steps-list"></div>
|
||||
<div class="modal-actions">
|
||||
<button type="button" class="btn btn-outline" id="cert-close-progress" style="display:none;" onclick="closeIssueWizard(); refreshTable('/api/certs/list', document.getElementById('cert-rows'), renderCerts);">Done</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user