feat(tasks): Add quick intent input with Create & Run at top
- Add prominent input box at top of tasks page - Gradient header with clean design - HTMX integration for /api/autotask/create - Show progress indicator during processing - Display result with app link when done - Enter key triggers submit - Auto-refresh task list after creation
This commit is contained in:
parent
410f799fb2
commit
d96c546c6a
3 changed files with 260 additions and 10 deletions
|
|
@ -3,6 +3,173 @@
|
|||
Automated Intelligent Task Management Interface
|
||||
============================================================================= */
|
||||
|
||||
/* =============================================================================
|
||||
INTENT INPUT SECTION
|
||||
============================================================================= */
|
||||
|
||||
.intent-input-section {
|
||||
padding: 24px;
|
||||
background: linear-gradient(135deg, var(--primary) 0%, #764ba2 100%);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.intent-input-container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.intent-input-wrapper {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.quick-intent-input {
|
||||
flex: 1;
|
||||
padding: 16px 20px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
color: #333;
|
||||
outline: none;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
||||
transition: box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.quick-intent-input::placeholder {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.quick-intent-input:focus {
|
||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.btn-create-run {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 16px 28px;
|
||||
background: #fff;
|
||||
color: var(--primary);
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.btn-create-run:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 30px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.btn-create-run:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.btn-create-run .spinner {
|
||||
display: none;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 2px solid var(--primary);
|
||||
border-top-color: transparent;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
.btn-create-run.htmx-request .btn-text {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.btn-create-run.htmx-request .spinner {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.intent-result {
|
||||
margin-top: 16px;
|
||||
padding: 0;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.intent-result:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.intent-result .result-card {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.intent-result .result-success {
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
.intent-result .result-error {
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
.intent-result .result-message {
|
||||
font-size: 15px;
|
||||
margin-bottom: 12px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.intent-result .result-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 20px;
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
border-radius: 8px;
|
||||
font-weight: 500;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.intent-result .result-link:hover {
|
||||
background: #5b21b6;
|
||||
}
|
||||
|
||||
.intent-result .result-progress {
|
||||
margin-top: 12px;
|
||||
height: 6px;
|
||||
background: #e5e7eb;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.intent-result .result-progress-bar {
|
||||
height: 100%;
|
||||
background: var(--primary);
|
||||
border-radius: 3px;
|
||||
transition: width 0.3s ease;
|
||||
animation: progress-pulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes progress-pulse {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
/* =============================================================================
|
||||
LAYOUT STRUCTURE
|
||||
============================================================================= */
|
||||
|
|
|
|||
|
|
@ -4,9 +4,35 @@
|
|||
============================================================================= -->
|
||||
|
||||
<div class="tasks-app">
|
||||
<!-- Main Content Area -->
|
||||
<section class="intent-input-section">
|
||||
<div class="intent-input-container">
|
||||
<div class="intent-input-wrapper">
|
||||
<input
|
||||
type="text"
|
||||
id="quick-intent-input"
|
||||
name="intent"
|
||||
class="quick-intent-input"
|
||||
placeholder="What would you like to do? e.g., 'create a CRM app' or 'remind me to call John tomorrow'"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<button
|
||||
id="quick-intent-btn"
|
||||
class="btn-create-run"
|
||||
hx-post="/api/autotask/create"
|
||||
hx-include="#quick-intent-input"
|
||||
hx-target="#intent-result"
|
||||
hx-swap="innerHTML"
|
||||
hx-indicator="#intent-spinner"
|
||||
>
|
||||
<span class="btn-text">Create & Run</span>
|
||||
<span class="spinner" id="intent-spinner"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="intent-result" class="intent-result"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<main class="tasks-main">
|
||||
<!-- Task List Panel (Left) -->
|
||||
<section class="tasks-list-panel">
|
||||
<div class="tasks-list-header">
|
||||
<div class="tasks-list-title">
|
||||
|
|
|
|||
|
|
@ -28,21 +28,78 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||
});
|
||||
|
||||
function initTasksApp() {
|
||||
// Initialize WebSocket for real-time updates
|
||||
initWebSocket();
|
||||
|
||||
// Setup event listeners
|
||||
setupEventListeners();
|
||||
|
||||
// Setup keyboard shortcuts
|
||||
setupKeyboardShortcuts();
|
||||
|
||||
// Auto-scroll agent log to bottom
|
||||
setupIntentInputHandlers();
|
||||
scrollAgentLogToBottom();
|
||||
|
||||
console.log("[Tasks] Initialized");
|
||||
}
|
||||
|
||||
function setupIntentInputHandlers() {
|
||||
const input = document.getElementById("quick-intent-input");
|
||||
const btn = document.getElementById("quick-intent-btn");
|
||||
|
||||
if (input) {
|
||||
input.addEventListener("keypress", function (e) {
|
||||
if (e.key === "Enter" && input.value.trim()) {
|
||||
btn.click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.body.addEventListener("htmx:beforeRequest", function (e) {
|
||||
if (e.detail.elt.id === "quick-intent-btn") {
|
||||
const resultDiv = document.getElementById("intent-result");
|
||||
resultDiv.innerHTML = `
|
||||
<div class="result-card">
|
||||
<div class="result-message">Processing your request...</div>
|
||||
<div class="result-progress">
|
||||
<div class="result-progress-bar" style="width: 30%"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
});
|
||||
|
||||
document.body.addEventListener("htmx:afterRequest", function (e) {
|
||||
if (e.detail.elt.id === "quick-intent-btn") {
|
||||
const resultDiv = document.getElementById("intent-result");
|
||||
try {
|
||||
const response = JSON.parse(e.detail.xhr.responseText);
|
||||
if (response.success) {
|
||||
let html = `<div class="result-card">
|
||||
<div class="result-message result-success">✓ ${response.message || "Done!"}</div>`;
|
||||
|
||||
if (response.app_url) {
|
||||
html += `<a href="${response.app_url}" class="result-link" target="_blank">
|
||||
Open App →
|
||||
</a>`;
|
||||
}
|
||||
|
||||
if (response.task_id) {
|
||||
html += `<div style="margin-top:8px;color:#666;font-size:13px;">Task ID: ${response.task_id}</div>`;
|
||||
}
|
||||
|
||||
html += `</div>`;
|
||||
resultDiv.innerHTML = html;
|
||||
|
||||
document.getElementById("quick-intent-input").value = "";
|
||||
htmx.trigger(document.body, "taskCreated");
|
||||
} else {
|
||||
resultDiv.innerHTML = `<div class="result-card">
|
||||
<div class="result-message result-error">✗ ${response.error || response.message || "Something went wrong"}</div>
|
||||
</div>`;
|
||||
}
|
||||
} catch (err) {
|
||||
resultDiv.innerHTML = `<div class="result-card">
|
||||
<div class="result-message result-error">✗ Failed to process response</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// WEBSOCKET CONNECTION
|
||||
// =============================================================================
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue