mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-25 14:53:34 +00:00
feat(web): improve WASM channel setup flow (#380)
* feat(web): improve WASM channel setup flow with stepper UI and auto-configure Streamline the WASM channel setup experience in the web gateway: - Auto-open configure modal after installing a WASM channel - Add progress stepper (Installed → Configured → Active) on channel cards - Replace generic Activate button with state-specific actions (Setup, Reconfigure, Restart) - Show "Awaiting Pairing" status for Telegram until first user is paired - Add SSE extension_status events for real-time status updates - Add gateway restart endpoint (POST /api/gateway/restart) with idempotency guard - Always mount webhook routes at startup so hot-added channels work without restart - Add pairing request polling (10s interval) on extensions tab - Track activation errors per channel with inline error display Includes review fixes: activation_error priority over active status, stepper failed state rendering, restart poll timeout, configure modal double-submit guard, and SSE sender ordering constraint documentation. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * refactor: address PR review comments - Move PairingStore construction outside .map() loop - Extract createReconfigureButton() helper to reduce duplication Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> --------- Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
abda94d44f
commit
996c6a8cc9
@@ -2156,6 +2156,159 @@ body {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* WASM channel setup stepper */
|
||||
.ext-stepper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
margin: 8px 0 4px;
|
||||
}
|
||||
|
||||
.stepper-step {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.stepper-circle {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.stepper-label {
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.stepper-step.completed .stepper-circle {
|
||||
background: var(--success);
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.stepper-step.completed .stepper-label {
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.stepper-step.failed .stepper-circle {
|
||||
background: var(--danger);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.stepper-step.failed .stepper-label {
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.stepper-step.in-progress .stepper-circle {
|
||||
background: var(--warning);
|
||||
color: #000;
|
||||
animation: pulse-glow 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.stepper-step.in-progress .stepper-label {
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
@keyframes pulse-glow {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.6; }
|
||||
}
|
||||
|
||||
.stepper-step.pending .stepper-circle {
|
||||
background: var(--bg-tertiary);
|
||||
border: 1px solid var(--border);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.stepper-step.pending .stepper-label {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.ext-pairing-label {
|
||||
font-size: 12px;
|
||||
color: var(--warning);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.stepper-connector {
|
||||
width: 20px;
|
||||
height: 2px;
|
||||
background: var(--border);
|
||||
margin: 0 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.stepper-connector.completed {
|
||||
background: var(--success);
|
||||
}
|
||||
|
||||
.ext-error {
|
||||
font-size: 11px;
|
||||
color: var(--danger);
|
||||
background: rgba(230, 76, 76, 0.1);
|
||||
border: 1px solid rgba(230, 76, 76, 0.2);
|
||||
border-radius: var(--radius);
|
||||
padding: 6px 8px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.ext-note {
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
padding: 6px 8px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
/* Restart overlay */
|
||||
.restart-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
z-index: 2000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.restart-message {
|
||||
text-align: center;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.restart-message h2 {
|
||||
margin: 16px 0 8px;
|
||||
}
|
||||
|
||||
.restart-message p {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.restart-spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 3px solid var(--border);
|
||||
border-top-color: var(--accent);
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.btn-ext {
|
||||
padding: 4px 10px;
|
||||
border-radius: var(--radius);
|
||||
|
||||
Reference in New Issue
Block a user