quantum-ai-v3/workflows/templates/workflows/data-analyzer.html
Claude c2cdaa4918 Enhance agent template with modern UX patterns and data analyzer improvements
AGENT TEMPLATE ENHANCEMENTS:
• Add enhanced file upload with preview, progress, and drag-and-drop
• Implement real-time validation with colored feedback messages
• Create class-based JavaScript architecture following data-analyzer pattern
• Consolidate CSS framework with all modern styling patterns
• Add comprehensive documentation and setup instructions

DATA ANALYZER UX IMPROVEMENTS:
• Enhanced file upload experience with preview card
• Real-time validation with detailed error messages
• Progress indicators and visual state management
• Replace/remove file functionality
• Improved drag-and-drop with visual feedback

TEMPLATE FEATURES:
• Complete class-based processor pattern in agent-template-starter.js
• Advanced file validation with size and type checking
• Mobile-responsive design with accessibility improvements
• Integration with workflows-core.js and existing components
• Step-by-step setup guide for new agent development

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 11:51:07 +05:30

468 lines
15 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends 'base.html' %}
{% load static %}
{% block title %}Data Analyzer - Quantum Tasks AI{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{% static 'css/agent-base.css' %}?v={{ timestamp }}">
<style>
/* Data Analyzer Specific Styles */
.file-upload-area {
border: 2px dashed var(--outline-variant);
border-radius: var(--radius-md);
padding: var(--spacing-xl);
text-align: center;
background: var(--surface);
transition: all 0.2s ease;
cursor: pointer;
position: relative;
}
.file-upload-area:hover,
.file-upload-area.dragover {
border-color: var(--primary);
background: var(--surface-variant);
transform: translateY(-1px);
box-shadow: var(--shadow-sm);
}
.file-upload-area.file-selected {
border-color: var(--success);
background: #f0fdf4;
color: #16a34a;
cursor: default;
}
.file-upload-area.upload-error {
border-color: var(--error);
background: #fef2f2;
color: #dc2626;
}
.file-upload-area.uploading {
border-color: var(--primary);
background: var(--surface-variant);
pointer-events: none;
}
/* File Preview Section */
.file-preview {
display: none;
background: var(--surface-variant);
border: 1px solid var(--outline-variant);
border-radius: var(--radius-md);
padding: var(--spacing-md);
margin-top: var(--spacing-md);
position: relative;
}
.file-preview.show {
display: block;
}
.file-preview-content {
display: flex;
align-items: flex-start;
gap: var(--spacing-md);
}
.file-icon {
font-size: 32px;
flex-shrink: 0;
opacity: 0.8;
}
.file-details {
flex: 1;
min-width: 0;
}
.file-name {
font-weight: 600;
color: var(--on-surface);
margin-bottom: var(--spacing-xs);
word-break: break-all;
}
.file-meta {
font-size: 12px;
color: var(--on-surface-variant);
display: flex;
gap: var(--spacing-md);
flex-wrap: wrap;
}
.file-actions {
display: flex;
gap: var(--spacing-sm);
flex-shrink: 0;
}
.file-action-btn {
background: none;
border: 1px solid var(--outline);
border-radius: var(--radius-sm);
padding: var(--spacing-xs) var(--spacing-sm);
font-size: 12px;
cursor: pointer;
transition: all 0.2s ease;
color: var(--on-surface-variant);
}
.file-action-btn:hover {
background: var(--surface);
border-color: var(--primary);
color: var(--primary);
}
.file-action-btn.remove {
color: var(--error);
border-color: var(--error);
}
.file-action-btn.remove:hover {
background: #fef2f2;
}
/* Upload Progress */
.upload-progress {
display: none;
margin-top: var(--spacing-sm);
}
.upload-progress.show {
display: block;
}
.progress-bar {
width: 100%;
height: 4px;
background: var(--outline-variant);
border-radius: 2px;
overflow: hidden;
margin-bottom: var(--spacing-xs);
}
.progress-fill {
height: 100%;
background: var(--primary);
transition: width 0.3s ease;
width: 0%;
}
.progress-text {
font-size: 12px;
color: var(--on-surface-variant);
text-align: center;
}
/* Validation Messages */
.validation-message {
display: none;
margin-top: var(--spacing-sm);
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--radius-sm);
font-size: 13px;
font-weight: 500;
}
.validation-message.show {
display: block;
}
.validation-message.error {
background: #fef2f2;
color: #dc2626;
border: 1px solid #fecaca;
}
.validation-message.success {
background: #f0fdf4;
color: #16a34a;
border: 1px solid #bbf7d0;
}
.validation-message.warning {
background: #fffbeb;
color: #d97706;
border: 1px solid #fed7aa;
}
.upload-icon {
font-size: 48px;
margin-bottom: var(--spacing-sm);
opacity: 0.7;
}
.upload-text {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--spacing-sm);
color: var(--on-surface-variant);
}
.upload-text > div:first-child {
font-weight: 500;
color: var(--on-surface);
}
.radio-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: var(--spacing-md);
margin-top: var(--spacing-sm);
}
.radio-card {
display: flex;
align-items: center;
gap: var(--spacing-sm);
padding: var(--spacing-md);
border: 2px solid var(--outline-variant);
border-radius: var(--radius-md);
cursor: pointer;
transition: all 0.2s ease;
background: var(--surface);
position: relative;
}
.radio-card:hover {
border-color: var(--primary);
background: var(--surface-variant);
transform: translateY(-1px);
box-shadow: var(--shadow-sm);
}
.radio-card.selected {
border-color: var(--primary);
background: rgba(0, 0, 0, 0.02);
}
.radio-card input[type="radio"] {
position: absolute;
opacity: 0;
pointer-events: none;
}
.radio-button {
width: 20px;
height: 20px;
border: 2px solid var(--outline);
border-radius: 50%;
position: relative;
transition: all 0.2s ease;
flex-shrink: 0;
}
.radio-card.selected .radio-button {
border-color: var(--primary);
}
.radio-card.selected .radio-button::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 8px;
height: 8px;
background: var(--primary);
border-radius: 50%;
transform: translate(-50%, -50%);
}
.radio-label {
font-size: 14px;
font-weight: 500;
color: var(--on-surface);
cursor: pointer;
display: flex;
align-items: center;
gap: var(--spacing-xs);
}
/* Responsive Design */
@media (max-width: 768px) {
.radio-grid {
grid-template-columns: 1fr;
}
.file-upload-area {
padding: var(--spacing-lg);
}
}
</style>
{% endblock %}
{% block content %}
<script>
// Set data attributes for JavaScript access
document.body.setAttribute('data-user-authenticated', '{{ user.is_authenticated|yesno:"true,false" }}');
document.body.setAttribute('data-agent-price', '{{ agent_config.price }}');
</script>
<div class="agent-container">
<!-- Agent Header Component -->
{% include "workflows/components/agent_header.html" with agent_title="Data Analyzer" agent_subtitle="AI-powered analysis of your data files with comprehensive insights" %}
<!-- Quick Agent Access Panel Component -->
{% include "workflows/components/quick_agents_panel.html" %}
<!-- Main Agent Grid -->
<div class="agent-grid">
<!-- Data Analysis Form Widget -->
<div class="agent-widget widget-large" style="flex: 1; margin-right: clamp(0px, var(--spacing-lg), 2vw);">
<div class="widget-header">
<h3 class="widget-title">
<span class="widget-icon">📊</span>
Data Analysis Configuration
</h3>
</div>
<div class="widget-content">
<form id="agentForm" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<!-- File Upload Section -->
<div class="form-group">
<label class="form-label">📁 Upload Data File *</label>
<div class="file-upload-area" id="fileUploadArea" onclick="triggerFileSelect()"
role="button" tabindex="0" aria-label="Click to upload data file or drag and drop"
onkeydown="if(event.key==='Enter'||event.key===' '){triggerFileSelect()}">
<div class="upload-text" id="uploadText">
<div class="upload-icon">📁</div>
<div><strong>Click to upload</strong> or drag and drop</div>
<div>PDF files only</div>
</div>
</div>
<input type="file" id="dataFile" name="file" accept=".pdf" style="display: none;" required>
<!-- Upload Progress -->
<div class="upload-progress" id="uploadProgress">
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<div class="progress-text" id="progressText">Preparing upload...</div>
</div>
<!-- File Preview -->
<div class="file-preview" id="filePreview">
<div class="file-preview-content">
<div class="file-icon">📄</div>
<div class="file-details">
<div class="file-name" id="previewFileName"></div>
<div class="file-meta">
<span id="previewFileSize"></span>
<span id="previewFileType">PDF Document</span>
<span id="previewTimestamp"></span>
</div>
</div>
<div class="file-actions">
<button type="button" class="file-action-btn" onclick="replaceFile()" title="Replace file">
🔄 Replace
</button>
<button type="button" class="file-action-btn remove" onclick="removeFile()" title="Remove file">
🗑️ Remove
</button>
</div>
</div>
</div>
<!-- Validation Messages -->
<div class="validation-message" id="validationMessage"></div>
<div class="form-help">Supported format: PDF files only. Max size: 10MB</div>
<div id="dataFile-error" class="form-error" style="display: none;"></div>
</div>
<!-- Analysis Type Selection -->
<div class="form-group">
<label class="form-label">📈 Analysis Type *</label>
<div class="radio-grid">
<div class="radio-card selected" onclick="selectRadio('summary')">
<input type="radio" id="summary" name="analysisType" value="summary" checked>
<div class="radio-button"></div>
<label for="summary" class="radio-label">📋 Summary</label>
</div>
<div class="radio-card" onclick="selectRadio('detailed')">
<input type="radio" id="detailed" name="analysisType" value="detailed">
<div class="radio-button"></div>
<label for="detailed" class="radio-label">📈 Detailed</label>
</div>
<div class="radio-card" onclick="selectRadio('statistical')">
<input type="radio" id="statistical" name="analysisType" value="statistical">
<div class="radio-button"></div>
<label for="statistical" class="radio-label">🔢 Statistical</label>
</div>
</div>
<div class="form-help">Choose the type of analysis for your data file</div>
<div id="analysisType-error" class="form-error" style="display: none;"></div>
</div>
<!-- Submit Button -->
<div style="margin-top: var(--spacing-lg);">
{% if user.is_authenticated %}
{% if user.wallet_balance >= agent_config.price %}
<button type="submit" class="btn btn-primary btn-full" id="generateBtn">
🚀 Analyze Data ({{ agent_config.price }} AED)
</button>
{% else %}
<div style="background: #fef2f2; color: #dc2626; padding: var(--spacing-md); border-radius: var(--radius-md); margin-bottom: var(--spacing-md); font-size: 14px; font-weight: 500; text-align: center;">
Insufficient balance! You need {{ agent_config.price }} AED.
</div>
<a href="{% url 'wallet:wallet' %}" class="btn btn-primary btn-full" style="text-decoration: none;">
💰 Top Up Wallet
</a>
{% endif %}
{% else %}
<a href="{% url 'authentication:login' %}" class="btn btn-primary btn-full">
🔐 Login to Continue
</a>
{% endif %}
</div>
</form>
</div>
</div>
<!-- How It Works Widget -->
<div class="agent-widget widget-small" style="min-width: min(280px, 100%); max-width: min(280px, 100%); margin-left: auto;">
<div class="widget-header">
<h3 class="widget-title">
<span class="widget-icon"></span>
How It Works
</h3>
</div>
<div class="widget-content">
<ol class="info-list">
<li>Upload your PDF file</li>
<li>Choose analysis type and preferences</li>
<li>Our AI analyzes your data</li>
<li>Get comprehensive insights and reports</li>
</ol>
<!-- Other Agents Button -->
<button class="quick-agent-toggle btn btn-secondary btn-full" onclick="toggleQuickAgents()"
title="Quick access to other agents"
aria-label="Open quick access panel for other AI agents"
aria-expanded="false"
aria-controls="quickAgentsPanel"
style="margin-top: var(--spacing-md);">
<span class="toggle-icon" aria-hidden="true">🚀</span>
<span class="toggle-text">Explore Other Agents</span>
</button>
</div>
</div>
</div>
<!-- Processing Status Component -->
{% include "workflows/components/processing_status.html" with status_title="Analyzing Your Data..." status_text="Please wait while our AI processes your file..." %}
<!-- Results Component -->
{% include "workflows/components/results_container.html" with results_title="Analysis Results" %}
</div>
{% endblock %}
{% block extra_js %}
<script src="{% static 'js/workflows-core.js' %}?v={{ timestamp }}"></script>
<script src="{% static 'js/data-analyzer.js' %}?v={{ timestamp }}"></script>
{% endblock %}