314 lines
14 KiB
HTML
314 lines
14 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Brightwheel Exporter Dashboard</title>
|
|
<link rel="stylesheet" href="dashboard.css">
|
|
<script src="../lib/jszip.min.js"></script>
|
|
</head>
|
|
<body>
|
|
<div class="app-layout">
|
|
<!-- Navigation Bar -->
|
|
<header class="top-nav">
|
|
<div class="nav-brand">
|
|
<div class="brand-icon">
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
|
<polyline points="7 10 12 15 17 10"></polyline>
|
|
<line x1="12" y1="15" x2="12" y2="3"></line>
|
|
</svg>
|
|
</div>
|
|
<div class="brand-text">
|
|
<h1>Brightwheel Exporter</h1>
|
|
<span>Memories & Reports Archiver</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="session-badge" id="sessionBadge">
|
|
<span class="session-dot" id="sessionDot"></span>
|
|
<span id="sessionStatusText">Detecting Brightwheel Session...</span>
|
|
<button id="refreshSessionBtn" class="icon-btn" title="Refresh Session">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<polyline points="23 4 23 10 17 10"></polyline>
|
|
<polyline points="1 20 1 14 7 14"></polyline>
|
|
<path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Main Content Grid -->
|
|
<main class="main-container">
|
|
<div class="dashboard-grid">
|
|
<!-- Left Panel: Configuration -->
|
|
<div class="config-column">
|
|
<!-- Card 1: Student Selection -->
|
|
<section class="card">
|
|
<div class="card-header">
|
|
<div class="card-title-group">
|
|
<span class="step-num">1</span>
|
|
<h2>Select Child / Student</h2>
|
|
</div>
|
|
</div>
|
|
<div class="card-content">
|
|
<div class="students-list" id="studentsList">
|
|
<div class="loading-placeholder">
|
|
<div class="spinner"></div>
|
|
<span>Scanning Brightwheel profile...</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Manual ID Fallback Accordion -->
|
|
<details class="manual-id-details" id="manualDetails">
|
|
<summary>Enter Student UUID Manually</summary>
|
|
<div class="manual-input-row">
|
|
<input type="text" id="manualStudentId" placeholder="e.g. edda433b-2a24-4da7-bbd5-9f131b4b2565" value="edda433b-2a24-4da7-bbd5-9f131b4b2565">
|
|
<button id="setManualIdBtn" class="secondary-btn">Use ID</button>
|
|
</div>
|
|
</details>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Card 2: Date Range -->
|
|
<section class="card">
|
|
<div class="card-header">
|
|
<div class="card-title-group">
|
|
<span class="step-num">2</span>
|
|
<h2>Date Range Filter</h2>
|
|
</div>
|
|
</div>
|
|
<div class="card-content">
|
|
<div class="quick-dates-pills" id="quickDatePills">
|
|
<button class="pill-btn active" data-range="all">All Time</button>
|
|
<button class="pill-btn" data-range="this-year">This Year</button>
|
|
<button class="pill-btn" data-range="last-year">Last Year</button>
|
|
<button class="pill-btn" data-range="last-90">Last 90 Days</button>
|
|
<button class="pill-btn" data-range="custom">Custom</button>
|
|
</div>
|
|
|
|
<div class="date-inputs-row" id="customDateRow">
|
|
<div class="date-field">
|
|
<label for="startDate">From</label>
|
|
<input type="date" id="startDate">
|
|
</div>
|
|
<div class="date-field">
|
|
<label for="endDate">To</label>
|
|
<input type="date" id="endDate">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Card 3: Export Categories -->
|
|
<section class="card">
|
|
<div class="card-header">
|
|
<div class="card-title-group">
|
|
<span class="step-num">3</span>
|
|
<h2>Export Categories</h2>
|
|
</div>
|
|
</div>
|
|
<div class="card-content">
|
|
<div class="checkbox-group">
|
|
<label class="custom-checkbox">
|
|
<input type="checkbox" id="catPhotos" checked>
|
|
<span class="checkmark"></span>
|
|
<div class="checkbox-label">
|
|
<strong>Photos & Videos</strong>
|
|
<small>High resolution original media files & captions</small>
|
|
</div>
|
|
</label>
|
|
|
|
<label class="custom-checkbox">
|
|
<input type="checkbox" id="catCare" checked>
|
|
<span class="checkmark"></span>
|
|
<div class="checkbox-label">
|
|
<strong>Daily Care Logs</strong>
|
|
<small>Meals, nap duration, potty checks, medications</small>
|
|
</div>
|
|
</label>
|
|
|
|
<label class="custom-checkbox">
|
|
<input type="checkbox" id="catMilestones" checked>
|
|
<span class="checkmark"></span>
|
|
<div class="checkbox-label">
|
|
<strong>Learning Milestones & Observations</strong>
|
|
<small>Curriculum tags, developmental notes, kudos</small>
|
|
</div>
|
|
</label>
|
|
|
|
<label class="custom-checkbox">
|
|
<input type="checkbox" id="catAttendance" checked>
|
|
<span class="checkmark"></span>
|
|
<div class="checkbox-label">
|
|
<strong>Attendance & Health Screening</strong>
|
|
<small>Check-in/out timestamps, temperature readings</small>
|
|
</div>
|
|
</label>
|
|
|
|
<label class="custom-checkbox">
|
|
<input type="checkbox" id="catMessages" checked>
|
|
<span class="checkmark"></span>
|
|
<div class="checkbox-label">
|
|
<strong>Staff Messages & Announcements</strong>
|
|
<small>Communication history between school & family</small>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Card 4: Destination & Output -->
|
|
<section class="card">
|
|
<div class="card-header">
|
|
<div class="card-title-group">
|
|
<span class="step-num">4</span>
|
|
<h2>Destination & Output</h2>
|
|
</div>
|
|
</div>
|
|
<div class="card-content">
|
|
<!-- Direct Folder Destination Picker (Recommended) -->
|
|
<div class="folder-destination-box" style="background: rgba(255, 107, 53, 0.05); border: 1.5px dashed var(--primary); border-radius: var(--radius-md); padding: 14px 16px; margin-bottom: 18px;">
|
|
<div style="display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px;">
|
|
<div style="display: flex; align-items: center; gap: 8px;">
|
|
<span style="font-size: 20px;">📁</span>
|
|
<div>
|
|
<strong style="font-size: 13.5px; color: var(--text);">Direct Local Folder Save</strong>
|
|
<span class="badge" style="background: var(--primary); color: #fff; font-size: 10px; padding: 2px 6px; border-radius: 4px; margin-left: 6px;">Fastest & Zero Lag</span>
|
|
</div>
|
|
</div>
|
|
<button type="button" id="chooseFolderBtn" class="secondary-btn" style="padding: 6px 12px; font-size: 12px; white-space: nowrap; border-color: var(--primary); color: var(--primary); font-weight: 600;">
|
|
Choose Folder...
|
|
</button>
|
|
</div>
|
|
<div id="folderStatusBox" style="font-size: 12px; color: var(--text-muted);">
|
|
<span id="folderPathText">No folder selected (will download as instant ZIP)</span>
|
|
<button type="button" id="clearFolderBtn" style="display: none; background: none; border: none; color: var(--error); font-size: 11px; text-decoration: underline; cursor: pointer; margin-left: 8px;">Reset</button>
|
|
</div>
|
|
<small style="display: block; margin-top: 6px; color: var(--text-muted); font-size: 11px;">
|
|
⚡ Streams photos & videos directly to your hard drive in real-time as they download. No zip compression delay!
|
|
</small>
|
|
</div>
|
|
|
|
<div class="checkbox-group">
|
|
<label class="custom-checkbox">
|
|
<input type="checkbox" id="fmtJson" checked>
|
|
<span class="checkmark"></span>
|
|
<div class="checkbox-label">
|
|
<strong>Unified JSON Archive (<code>activities.json</code>)</strong>
|
|
<small>Single source of truth containing all structured & raw data</small>
|
|
</div>
|
|
</label>
|
|
|
|
<label class="custom-checkbox">
|
|
<input type="checkbox" id="fmtCsv" checked>
|
|
<span class="checkmark"></span>
|
|
<div class="checkbox-label">
|
|
<strong>Spreadsheet CSV (<code>activities.csv</code>)</strong>
|
|
<small>Open in Excel, Numbers, or Google Sheets</small>
|
|
</div>
|
|
</label>
|
|
|
|
<label class="custom-checkbox">
|
|
<input type="checkbox" id="fmtViewer" checked>
|
|
<span class="checkmark"></span>
|
|
<div class="checkbox-label">
|
|
<strong>Offline Memories Web Viewer (<code>index.html</code>)</strong>
|
|
<small>Standalone interactive browser app with gallery & timeline</small>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<!-- Right Panel: Export Controller & Live Monitor -->
|
|
<div class="action-column">
|
|
<!-- Primary Action Box -->
|
|
<section class="card hero-action-card">
|
|
<div class="action-header">
|
|
<h3>Export Controller</h3>
|
|
<div class="speed-setting">
|
|
<label for="concurrencySelect">Pacing / Delay:</label>
|
|
<select id="concurrencySelect">
|
|
<option value="400">Gentle (400ms delay - Safest)</option>
|
|
<option value="200" selected>Standard (200ms delay)</option>
|
|
<option value="50">Fast (50ms delay)</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="primary-controls">
|
|
<button id="startExportBtn" class="primary-action-btn">
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
|
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
|
<polyline points="7 10 12 15 17 10"></polyline>
|
|
<line x1="12" y1="15" x2="12" y2="3"></line>
|
|
</svg>
|
|
<span>Start Complete Export</span>
|
|
</button>
|
|
|
|
<div class="secondary-controls-row" id="inProgressControls" style="display: none;">
|
|
<button id="pauseExportBtn" class="secondary-btn">Pause</button>
|
|
<button id="cancelExportBtn" class="danger-btn">Cancel</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Progress Bar Section -->
|
|
<div class="progress-section" id="progressSection">
|
|
<div class="progress-labels">
|
|
<span class="progress-status" id="progressStatusText">Ready to start</span>
|
|
<span class="progress-percentage" id="progressPercent">0%</span>
|
|
</div>
|
|
<div class="progress-bar-track">
|
|
<div class="progress-bar-fill" id="progressBarFill" style="width: 0%;"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Live Metrics Grid -->
|
|
<div class="metrics-grid">
|
|
<div class="metric-card">
|
|
<span class="metric-value" id="metricActivitiesCount">0</span>
|
|
<span class="metric-label">Activities Found</span>
|
|
</div>
|
|
<div class="metric-card">
|
|
<span class="metric-value" id="metricMediaCount">0 / 0</span>
|
|
<span class="metric-label">Media Files</span>
|
|
</div>
|
|
<div class="metric-card">
|
|
<span class="metric-value" id="metricSize">0.0 MB</span>
|
|
<span class="metric-label">Downloaded Data</span>
|
|
</div>
|
|
<div class="metric-card">
|
|
<span class="metric-value" id="metricRateLimit">0</span>
|
|
<span class="metric-label">Retries / Backoffs</span>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Live Activity Log Card -->
|
|
<section class="card log-card">
|
|
<div class="card-header log-header">
|
|
<h3>Live Activity Log</h3>
|
|
<div class="log-actions">
|
|
<button id="clearLogBtn" class="link-btn">Clear</button>
|
|
</div>
|
|
</div>
|
|
<div class="terminal-log-body" id="terminalLog">
|
|
<div class="log-line info">[System] Exporter dashboard initialized. Waiting to begin...</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<footer class="dashboard-footer" style="text-align: center; padding: 24px 16px; color: var(--text-muted); font-size: 12px; border-top: 1px solid var(--border); margin-top: 40px;">
|
|
<p><strong>Disclaimer:</strong> This open-source extension is an independent, community-built tool and is not affiliated with, endorsed by, or sponsored by Brightwheel or its parent companies.</p>
|
|
<p style="margin-top: 4px; font-size: 11px; opacity: 0.85;">Runs 100% locally on your computer • No personal data is ever collected, transmitted, or stored remotely.</p>
|
|
</footer>
|
|
</div>
|
|
|
|
<script src="dashboard.js"></script>
|
|
</body>
|
|
</html>
|