Your IP : 216.73.217.78


Current Path : /home/seto/indexator.pm/templates/projects/
Upload File :
Current File : /home/seto/indexator.pm/templates/projects/index.php

<?php
$title = 'Projects — Indexator';
ob_start();
?>
<div class="d-flex justify-content-between align-items-center mb-4">
    <h1 class="h3 mb-0">Projects</h1>
    <div class="d-flex gap-2">
        <select id="project-sort" class="form-select" style="width:190px;">
            <option value="name_asc">Name A → Z</option>
            <option value="name_desc">Name Z → A</option>
            <option value="total_desc">Most URLs</option>
            <option value="rate_asc">Worst Index</option>
            <option value="submitted_desc">Recently Submitted</option>
            <option value="created_desc">Recently Added</option>
        </select>
        <input type="search" id="project-search" class="form-control"
               placeholder="Search by name or domain…" style="width:220px;" autocomplete="off">
        <?php $hasChecking = !empty(array_filter($projects, fn($p) => $p['status'] === 'checking')); ?>
        <?php $hasNotIndexed = !empty(array_filter($projects, fn($p) => (int)$p['not_indexed'] > 0)); ?>
        <?php if ($hasNotIndexed && !$hasChecking): ?>
        <button id="recheck-all-btn" class="btn btn-outline-primary"
                data-csrf="<?= htmlspecialchars(\App\Core\CsrfGuard::getToken()) ?>">
            <i class="bi bi-arrow-clockwise"></i> Recheck All
        </button>
        <?php endif; ?>
        <?php if ($hasChecking): ?>
        <button id="stop-all-btn" class="btn btn-danger"
                data-csrf="<?= htmlspecialchars(\App\Core\CsrfGuard::getToken()) ?>">
            ■ Stop All
        </button>
        <?php endif; ?>
        <a href="/export/all?filter=not_indexed" class="btn btn-outline-secondary">↓ Export Not Indexed</a>
        <a href="/projects/create" class="btn btn-dark">+ New Project</a>
    </div>
</div>

<?php if (!empty($projects)): ?>
<!-- ── Overall summary card ─────────────────────────────────────────────── -->
<div id="summary-card" class="card shadow-sm mb-4 border-0 bg-dark text-white">
    <div class="card-body">
        <div class="row g-3 align-items-center">
            <div class="col-sm-auto">
                <div class="fw-semibold opacity-75 small mb-1">All projects <span class="opacity-50">(<?= count($projects) ?>)</span></div>
                <div class="d-flex gap-3 flex-wrap">
                    <div>
                        <span class="opacity-75 small">Total URLs</span><br>
                        <span class="fs-5 fw-bold"><?= number_format($summary['total']) ?></span>
                    </div>
                    <div>
                        <span class="opacity-75 small">Checked</span><br>
                        <span class="fs-5 fw-bold"><?= number_format($summary['checked']) ?></span>
                    </div>
                    <div>
                        <span class="text-success small">Indexed</span><br>
                        <span class="fs-5 fw-bold text-success"><?= number_format($summary['indexed']) ?></span>
                        <?php if ($summary['delta_indexed'] !== null && $summary['delta_indexed'] !== 0): ?>
                        <?php $sd = $summary['delta_indexed']; ?>
                        <span class="small <?= $sd > 0 ? 'text-success' : 'text-danger' ?>">
                            <?= $sd > 0 ? '▲ +' : '▼ ' ?><?= $sd ?>
                        </span>
                        <?php endif; ?>
                    </div>
                    <div>
                        <span class="text-warning small">Not indexed</span><br>
                        <span class="fs-5 fw-bold text-warning"><?= number_format($summary['not_indexed']) ?></span>
                    </div>
                    <?php if ($summary['error'] > 0): ?>
                    <div>
                        <span class="text-danger small">Error</span><br>
                        <span class="fs-5 fw-bold text-danger"><?= number_format($summary['error']) ?></span>
                    </div>
                    <?php endif; ?>
                </div>
            </div>
            <div class="col">
                <div class="mb-2">
                    <div class="d-flex justify-content-between small opacity-75 mb-1">
                        <span>Check progress</span>
                        <span><?= $summary['check_pct'] ?>%</span>
                    </div>
                    <div class="progress" style="height:8px;">
                        <div class="progress-bar bg-light"
                             style="width:<?= $summary['check_pct'] ?>%"></div>
                    </div>
                </div>
                <div>
                    <div class="d-flex justify-content-between small opacity-75 mb-1">
                        <span>Indexation rate</span>
                        <span><?= $summary['indexation_rate'] ?>%</span>
                    </div>
                    <div class="progress" style="height:8px;">
                        <div class="progress-bar bg-success"
                             style="width:<?= $summary['indexation_rate'] ?>%"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<?php endif; ?>

<?php if (empty($projects)): ?>
    <div class="text-center text-muted py-5">
        <p class="mb-3">No projects yet.</p>
        <a href="/projects/create" class="btn btn-dark">Create your first project</a>
    </div>
<?php else: ?>
    <div class="row g-3" id="projects-list">
        <?php foreach ($projects as $p): ?>
        <?php
            $total   = (int)$p['total'];
            $checked = (int)$p['checked'];
            $indexed = (int)$p['indexed'];
        ?>
        <?php
            $borderColor = match($p['status']) {
                'checking' => '#ffc107',
                'done'     => '#198754',
                default    => '#adb5bd',
            };
            $badgeClass = match($p['status']) {
                'checking' => 'bg-warning text-dark',
                'done'     => 'bg-success',
                default    => 'bg-secondary',
            };
        ?>
        <div class="col-12 project-card"
             data-name="<?= htmlspecialchars(mb_strtolower($p['name'])) ?>"
             data-domain="<?= htmlspecialchars(mb_strtolower($p['domain'])) ?>"
             data-total="<?= (int)$p['total'] ?>"
             data-rate="<?= (int)$p['indexation_rate'] ?>"
             data-submitted="<?= $p['last_indexed_at'] ? strtotime($p['last_indexed_at']) : 0 ?>"
             data-created="<?= strtotime($p['created_at']) ?>"
             data-last-checked="<?= $p['updated_at'] ? strtotime($p['updated_at']) : 0 ?>">
            <div class="card project-card-inner" style="border-left: 4px solid <?= $borderColor ?>;">
                <div class="card-body py-3">

                    <!-- Header -->
                    <div class="d-flex justify-content-between align-items-center mb-2">
                        <div class="min-w-0">
                            <a href="/projects/<?= $p['id'] ?>" class="fw-semibold text-decoration-none text-dark project-title">
                                <?= htmlspecialchars($p['name']) ?>
                            </a>
                            <span class="text-muted small ms-2"><?= htmlspecialchars($p['domain']) ?></span>
                        </div>
                        <div class="d-flex align-items-center gap-2 ms-3 flex-shrink-0">
                            <span class="badge <?= $badgeClass ?>"><?= htmlspecialchars($p['status']) ?></span>
                            <?php if ($p['last_indexed_at']): ?>
                            <?php
                                $idxDiff  = round((time() - strtotime($p['last_indexed_at'])) / 86400);
                                $idxLabel = $idxDiff === 0 ? 'today' : $idxDiff . 'd ago';
                                $idxTip   = htmlspecialchars(
                                    number_format((int)$p['last_indexed_count']) . ' URLs · '
                                    . $idxLabel . ' · ' . strtoupper($p['last_indexed_engines'])
                                    . ' · ' . $p['last_indexed_status']
                                );
                            ?>
                            <span class="badge-indexed-dot" data-bs-toggle="tooltip"
                                  data-bs-placement="top" title="<?= $idxTip ?>"><i class="bi bi-lightning-charge-fill"></i></span>
                            <?php endif; ?>
                            <?php
                                $recentlyChecked   = $p['updated_at']      && (time() - strtotime($p['updated_at']))      < 6  * 3600;
                                $recentlySubmitted = $p['last_indexed_at'] && (time() - strtotime($p['last_indexed_at'])) < 72 * 3600;
                                $checkedAgo  = $p['updated_at']      ? round((time() - strtotime($p['updated_at']))      / 3600, 1) . 'h ago' : '';
                                $submittedAgo = $p['last_indexed_at'] ? round((time() - strtotime($p['last_indexed_at'])) / 3600, 1) . 'h ago' : '';
                            ?>
                            <?php if ((int)$p['not_indexed'] > 0 && $p['status'] !== 'checking'): ?>
                            <button class="btn-recheck-project btn-project-arrow<?= $recentlyChecked ? ' btn-recently-used' : '' ?>"
                                    data-project-id="<?= $p['id'] ?>"
                                    title="Recheck not indexed<?= $recentlyChecked ? ' · last checked ' . $checkedAgo : '' ?>"><i class="bi bi-arrow-clockwise"></i></button>
                            <?php endif; ?>
                            <button class="btn-index-project btn-project-arrow<?= $recentlySubmitted ? ' btn-recently-used' : '' ?>"
                                    data-project-id="<?= $p['id'] ?>"
                                    data-project-name="<?= htmlspecialchars($p['name']) ?>"
                                    data-not-indexed="<?= (int)$p['not_indexed'] ?>"
                                    title="Submit to indexing<?= $recentlySubmitted ? ' · submitted ' . $submittedAgo : '' ?>"><i class="bi bi-send"></i></button>
                            <a href="/projects/<?= $p['id'] ?>" class="btn-project-arrow" title="Open project"><i class="bi bi-chevron-right"></i></a>
                        </div>
                    </div>

                    <!-- Stats + indexation rate -->
                    <div class="d-flex align-items-center justify-content-between gap-3 mb-2 flex-wrap">
                        <div class="project-stats-row">
                            <span class="stat-item"><span class="stat-label">Total</span> <span class="stat-val"><?= number_format($total) ?></span></span>
                            <span class="stat-sep">·</span>
                            <span class="stat-item"><span class="stat-label">Checked</span> <span class="stat-val"><?= number_format($checked) ?></span></span>
                            <span class="stat-sep">·</span>
                            <span class="stat-item"><span class="stat-label">Indexed</span> <span class="stat-val text-success fw-semibold"><?= number_format($indexed) ?></span></span>
                            <span class="stat-sep">·</span>
                            <span class="stat-item"><span class="stat-label">Not indexed</span> <span class="stat-val text-warning-emphasis"><?= number_format((int)$p['not_indexed']) ?></span></span>
                            <?php if ((int)$p['error'] > 0): ?>
                            <span class="stat-sep">·</span>
                            <span class="stat-item"><span class="stat-label">Errors</span> <span class="stat-val text-danger"><?= (int)$p['error'] ?></span></span>
                            <?php endif; ?>
                        </div>
                        <div class="d-flex align-items-baseline gap-2 flex-shrink-0">
                            <span class="indexation-rate-big" style="color:<?= $borderColor ?>;"><?= $p['indexation_rate'] ?>%</span>
                            <?php if ($p['delta_indexed'] !== null && $p['delta_indexed'] !== 0): ?>
                            <?php $di = (int)$p['delta_indexed']; ?>
                            <span class="small <?= $di > 0 ? 'text-success' : 'text-danger' ?>">
                                <?= $di > 0 ? '▲ +' . $di : '▼ ' . $di ?>
                            </span>
                            <?php endif; ?>
                        </div>
                    </div>

                    <!-- Progress bars -->
                    <div class="d-flex gap-2 flex-column">
                        <div>
                            <div class="d-flex justify-content-between" style="font-size:0.7rem; color:#adb5bd; margin-bottom:3px;">
                                <span>Check progress</span><span><?= $p['check_pct'] ?>%</span>
                            </div>
                            <div class="progress" style="height:4px; border-radius:2px;">
                                <div class="progress-bar bg-secondary" style="width:<?= $p['check_pct'] ?>%"></div>
                            </div>
                        </div>
                        <div>
                            <div class="d-flex justify-content-between" style="font-size:0.7rem; color:#adb5bd; margin-bottom:3px;">
                                <span>Indexation</span><span><?= $indexed ?> / <?= $checked ?></span>
                            </div>
                            <div class="progress" style="height:4px; border-radius:2px;">
                                <div class="progress-bar" style="width:<?= $p['indexation_rate'] ?>%; background:<?= $borderColor ?>;"></div>
                            </div>
                        </div>
                    </div>

                </div>
            </div>
        </div>
        <?php endforeach; ?>
    </div>
    <div id="no-search-results" class="text-center text-muted py-5" style="display:none;">
        No projects match your search.
    </div>
<?php endif; ?>
<?php
$content = ob_get_clean();
require __DIR__ . '/../layout.php';