Artur Mukhamadiev 7d6429aca9 frontend: queue-aware submit flow and queued loading view
Submit joins the admission queue first and sends the PAT only once the
reservation is held. Queued state shows the shaping orb, ordinal position
with estimate, and an exit button whose label changes with the wait;
running switches the orb to solving. Rejoin once on a lost reservation or
ticket, best-effort leave on pagehide. Mock server gains the queue
endpoints and five scenarios; contract, unit and e2e tests cover them.
2026-09-15 13:38:59 +03:00

169 lines
8.2 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Confluence Research</title>
<link rel="icon" type="image/svg+xml" href="assets/book.svg">
<link rel="stylesheet" href="css/style.css">
<script src="vendor/marked.min.js"></script>
<script src="vendor/purify.min.js"></script>
<script type="module" src="js/app.js"></script>
</head>
<body>
<!-- Top Navigation Header -->
<header class="app-header">
<div id="app-brand" class="app-brand">
<span id="brand-logo" class="book" aria-hidden="true">
<span class="book-page"></span>
<span class="book-edge"></span>
<span class="book-cover"><span class="book-label"></span></span>
</span>
<span>Confluence Research</span>
</div>
<button id="key-btn" class="key-btn" type="button" aria-label="Configure Confluence Credentials" title="Configure Confluence Credentials">
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="M 6.5625 5.0136719 C 2.4595703 5.2668613 -0.68726562 9.0536406 0.13085938 13.369141 C 0.65285938 16.124141 2.8748594 18.347141 5.6308594 18.869141 C 9.378008 19.579519 12.720128 17.298793 13.703125 14 L 18 14 L 18 15 C 18 16.105 18.895 17 20 17 C 21.105 17 22 16.105 22 15 L 22 14 C 23.105 14 24 13.105 24 12 C 24 10.895 23.105 10 22 10 L 13.699219 10 C 12.979424 7.5432523 10.909496 5.6120152 8.3691406 5.1308594 C 7.7527656 5.0139844 7.1486328 4.977502 6.5625 5.0136719 z M 7 9 C 8.657 9 10 10.343 10 12 C 10 13.657 8.657 15 7 15 C 5.343 15 4 13.657 4 12 C 4 10.343 5.343 9 7 9 z"></path>
</svg>
<span id="cred-indicator" class="cred-indicator" aria-hidden="true"></span>
<span id="cred-status-sr" class="sr-only">Credentials not set</span>
</button>
</header>
<!-- Main View Container -->
<main class="app-main">
<!-- State 1: Prompt View -->
<section id="view-prompt" class="view-prompt" aria-label="Research prompt view">
<div class="prompt-wrapper">
<h1 class="prompt-title">What would you like to research?</h1>
<div id="prompt-error" class="alert-box error-box hidden" role="alert"></div>
<div class="prompt-box">
<textarea
id="prompt-input"
class="prompt-input"
placeholder="Search or ask about Confluence documentation..."
rows="3"
aria-label="Research prompt"
></textarea>
<div class="prompt-footer">
<span class="prompt-helper">Press Enter ↵ to send · Shift + Enter for new line</span>
<button id="submit-btn" class="submit-btn" type="button" aria-label="Send query">
<span>Send</span>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<line x1="22" y1="2" x2="11" y2="13"></line>
<polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
</svg>
</button>
</div>
</div>
</div>
</section>
<!-- State 3: Loading View -->
<section id="view-loading" class="view-loading hidden" aria-label="Loading execution view">
<div class="spinner-wrapper">
<canvas id="thinking-orb" class="thinking-orb" width="64" height="64" aria-hidden="true"></canvas>
</div>
<p id="loading-status" class="loading-status" aria-live="polite">Agent researching Confluence...</p>
<button id="cancel-btn" class="cancel-btn" type="button">Cancel</button>
<button id="exit-queue-btn" class="cancel-btn exit-queue-btn hidden" type="button" aria-label="Leave the queue">I will try next time</button>
</section>
<!-- State 4: Result View -->
<section id="view-result" class="view-result hidden" aria-label="Research result view">
<div class="action-bar">
<button id="back-btn" class="action-btn back-btn" type="button">← Back to prompt</button>
<button id="export-btn" class="action-btn export-btn" type="button">Export to MD</button>
</div>
<div id="result-warnings" class="warnings-container hidden" role="region" aria-label="Result warnings"></div>
<div id="section-nav" class="section-nav hidden"></div>
<div id="output-content" class="output-content"></div>
<!-- Artifacts Section -->
<div id="artifacts-section" class="artifacts-section hidden" role="region" aria-label="Generated artifacts">
<h2 class="artifacts-heading">Generated Artifacts</h2>
<div id="artifacts-error" class="alert-box error-box hidden" role="alert"></div>
<ul id="artifacts-list" class="artifacts-list"></ul>
</div>
<!-- Sources & Request History Section -->
<div id="history-section" class="history-section" role="region" aria-label="Sources and request history">
<button id="history-toggle-btn" class="history-toggle-btn" type="button" aria-expanded="false" aria-controls="history-content">
<span id="history-toggle-title">Sources &amp; Request History (0 pages accessed)</span>
<span class="toggle-icon"></span>
</button>
<div id="history-content" class="history-content hidden">
<h3 class="history-subheading">Pages Read</h3>
<div id="pages-accessed-list" class="pages-list"></div>
<h3 class="history-subheading">Tool Operations</h3>
<div id="tool-history-list" class="tool-list"></div>
</div>
</div>
</section>
</main>
<!-- State 2: Credentials Configuration Modal -->
<div id="modal-backdrop" class="modal-backdrop hidden" tabindex="-1">
<div id="modal-dialog" class="modal-dialog" role="dialog" aria-modal="true" aria-labelledby="modal-title">
<div class="modal-header">
<h2 id="modal-title" class="modal-title">Confluence Credentials</h2>
<button id="modal-close-btn" class="modal-close-btn" type="button" aria-label="Close credentials dialog">&times;</button>
</div>
<form id="credentials-form" novalidate>
<div class="form-group">
<label for="cred-url" class="form-label">Confluence Base URL</label>
<input
type="url"
id="cred-url"
class="modal-input"
placeholder="https://confluence.example.com"
autocomplete="off"
spellcheck="false"
required
>
<span class="field-hint">Must be a valid HTTP or HTTPS URL (max 8 KiB)</span>
</div>
<div class="form-group">
<label for="cred-pat" class="form-label">Personal Access Token (PAT)</label>
<div class="password-input-wrapper">
<input
type="password"
id="cred-pat"
class="modal-input"
placeholder="Personal Access Token"
autocomplete="off"
spellcheck="false"
required
>
<button type="button" id="toggle-pat-btn" class="toggle-password-btn" aria-label="Show token">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
<circle cx="12" cy="12" r="3"></circle>
</svg>
</button>
</div>
<span class="field-hint">Token is kept strictly in browser memory (max 8 KiB)</span>
</div>
<div id="modal-feedback" class="modal-feedback hidden" role="status" aria-live="polite"></div>
<div class="modal-actions">
<div class="modal-actions-left">
<button type="button" id="btn-clear-cred" class="btn-secondary danger">Clear credentials</button>
</div>
<div class="modal-actions-right">
<button type="button" id="btn-test-cred" class="btn-secondary">Test Connection</button>
<button type="button" id="btn-cancel-cred" class="btn-secondary">Cancel</button>
<button type="submit" id="btn-save-cred" class="btn-primary">Save &amp; Close</button>
</div>
</div>
</form>
</div>
</div>
</body>
</html>