<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
    <title>SkyPilot Managed Jobs</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css"
        integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
    <style>
        :root {
            --secondary-color: #6c757d;
            --success-color: #198754;
            --warning-color: #ffc107;
            --info-color: #0dcaf0;
            --light-color: #f8f9fa;
        }

        body {
            margin-top: 0;
            font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            background-color: white;
        }

        .container {
            max-width: 100%;
            width: 100%;
            background-color: white;
            border-radius: 0;
            box-shadow: none;
            padding: 2rem;
            margin-bottom: 0;
        }

        header {
            position: sticky;
            top: 0;
            background: white;
            z-index: 1000;
            padding: 1.5rem 2rem;
            margin: -2rem -2rem 1.5rem -2rem;  /* Negative margins to match container padding */
            border-bottom: 1px solid #dee2e6;
        }

        /* Add shadow when header is sticky */
        header.sticky {
            box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
        }

        h1 {
            color: var(--primary-color);
            font-weight: 600;
            font-size: 2rem;
        }

        .table {
            width: 100%;       /* Ensure table takes full container width */
            border-radius: 8px;
            overflow: hidden;
            box-shadow: 0 0 8px rgba(0, 0, 0, 0.05);
            table-layout: auto;  /* Allow table to adjust column widths automatically */
        }

        .fixed-header-table thead th,
        .fixed-header-table thead td {  /* Added td selector */
            background-color: var(--light-color);
            padding: 1rem;
            font-weight: 600;
            border-bottom: 2px solid #dee2e6;
        }

        .table th:nth-child(2),  /* ID column */
        .table td:nth-child(2) {
            min-width: 30px;     /* Reduced from 100px */
            max-width: 60px;     /* Added max-width */
            overflow: hidden;     /* Handle overflow */
            text-overflow: ellipsis;  /* Show ellipsis for overflow */
            white-space: nowrap;  /* Keep text on one line */
        }

        .table th:nth-child(4),  /* Name column */
        .table td:nth-child(4) {
            min-width: 150px;
        }

        .table th:nth-child(10),  /* Status column */
        .table td:nth-child(10) {
            min-width: 120px;
        }

        .table th,
        .table td {
            padding: 0.8rem 1rem;
            white-space: nowrap;  /* Prevent text wrapping in cells */
        }

        /* Allow Details column to wrap */
        .table th:nth-child(12),  /* Details column */

        .table td:nth-child(12) {
            max-width: 250px;     /* Limit width */
            overflow: hidden;     /* Hide overflow */
            text-overflow: ellipsis; /* Show ellipsis for overflow */
            position: relative;   /* For tooltip positioning */
            cursor: pointer !important;  /* Force show pointer cursor */
            padding-right: 24px;  /* Make room for the arrow */
        }

        .table td:nth-child(12)::after {
            content: '▼';
            position: absolute;
            right: 8px;
            top: 12px;
            font-size: 0.6em;
            opacity: 0.5;
            display: none;  /* Hide by default */
        }

        .table td:nth-child(12).expandable::after {
            display: block;  /* Only show for expandable content */
        }

        .table td:nth-child(12).expanded::after {
            transform: rotate(180deg);
        }

        .table td:nth-child(12).expanded {
            max-width: none;
            white-space: normal;
            word-wrap: break-word;
        }

        .badge {
            padding: 0.5em 0.8em;
            font-weight: 500;
            border-radius: 6px;
        }

        .btn-outline-secondary {
            transition: all 0.2s;
        }

        .btn-outline-secondary:hover {
            background-color: var(--secondary-color);
            color: white;
            transform: translateY(-1px);
        }

        .filter-controls {
            background-color: var(--light-color);
            padding: 1rem;
            border-radius: 8px;
            margin: 1rem 0;
        }

        .form-select {
            border-radius: 6px;
            border: 1px solid #dee2e6;
            padding: 0.5rem 2rem 0.5rem 1rem;
            transition: all 0.2s;
        }

        .form-select:hover {
            border-color: var(--primary-color);
        }

        .form-check-input {
            cursor: pointer;
        }

        .clickable {
            transition: color 0.2s;
        }

        .clickable:hover {
            color: var(--primary-color);
        }

        /* Status badge animations */
        .badge {
            animation: fadeIn 0.3s ease-in;
        }

        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(-2px); }
            to { opacity: 1; transform: translateY(0); }
        }

        /* Loading indicator for auto-refresh */
        .refresh-indicator {
            display: inline-block;
            margin-left: 8px;
            font-size: 12px;
            color: var(--secondary-color);
        }

        .refresh-spinner {
            display: none;
            width: 12px;
            height: 12px;
            border: 2px solid #f3f3f3;
            border-top: 2px solid var(--primary-color);
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        .status-container {
            cursor: help;
            position: relative;
            display: inline-block;
        }

        .status-container:hover::after {
            content: attr(data-tooltip);
            position: absolute;
            left: 0;
            top: 100%;
            transform: translateY(8px);
            z-index: 1001;
            background-color: rgba(33, 37, 41, 0.9);
            color: white;
            padding: 0.75rem 1rem;
            border-radius: 6px;
            font-size: 0.875rem;
            white-space: pre;
            min-width: 500px;
            max-width: 800px;
            box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
            pointer-events: none;
            opacity: 0;
            animation: tooltipFadeIn 0.2s ease-in-out forwards;
        }

        /* Update the arrow position */
        .status-container:hover::before {
            content: '';
            position: absolute;
            left: 20px;
            top: 100%;          /* Changed from bottom: 100% */
            transform: none;
            border: 8px solid transparent;
            border-bottom-color: rgba(33, 37, 41, 0.9);  /* Changed from border-top-color */
            z-index: 1001;
            pointer-events: none;
            opacity: 0;
            animation: tooltipFadeIn 0.2s ease-in-out forwards;
        }

        @keyframes tooltipFadeIn {
            to {
                opacity: 1;
                transform: translateY(0);  /* Simplified animation */
            }
        }

        /* Ensure the table doesn't cut off tooltips */
        .table {
            overflow: visible !important;
        }

        .fixed-header-table {
            overflow: visible !important;
        }

        /* Add horizontal scroll for very small screens */
        @media (max-width: 1200px) {
            .table-responsive {
                overflow-x: auto;
            }
        }

        /* Update the timestamp hover styles */
        #last-updated {
            position: relative;
            text-decoration: none;
            border-bottom: 1px solid transparent;
            transition: border-bottom-color 0.2s;
            cursor: help;
        }

        #last-updated:hover {
            border-bottom-color: var(--secondary-color);
        }

        #last-updated:hover::after {
            content: attr(data-tooltip);
            position: absolute;
            top: 100%;           /* Changed from bottom: 100% to top: 100% */
            left: 50%;
            transform: translateX(-50%);
            padding: 0.5rem 1rem;
            background-color: rgba(33, 37, 41, 0.9);
            color: white;
            border-radius: 6px;
            font-size: 0.875rem;
            white-space: nowrap;
            z-index: 1000;
            margin-top: 8px;     /* Changed from margin-bottom to margin-top */
        }

        #last-updated:hover::before {
            content: '';
            position: absolute;
            top: 100%;           /* Changed from bottom: 100% to top: 100% */
            left: 50%;
            transform: translateX(-50%);
            border: 8px solid transparent;
            border-bottom-color: rgba(33, 37, 41, 0.9);  /* Changed from border-top-color to border-bottom-color */
            margin-top: -8px;    /* Changed from margin-bottom to margin-top */
            z-index: 1000;
        }

        .clickable-badge {
            cursor: pointer;
            transition: transform 0.2s, opacity 0.2s;
            opacity: 0.4;
        }

        .clickable-badge:hover {
            transform: scale(1.05);
            opacity: 1;
        }

        .clickable-badge.selected-filter {
            opacity: 1;
            box-shadow: 0 0 0 2px #fff, 0 0 0 4px currentColor;
        }

        /* Ensure tooltips appear above the sticky header */
        .status-container:hover::after,
        .status-container:hover::before,
        #last-updated:hover::after,
        #last-updated:hover::before {
            z-index: 1001;
        }

        /* Add tooltip styles for refresh label */
        .refresh-label {
            position: relative;
            cursor: help;
        }

        .refresh-label:hover::after {
            content: attr(data-tooltip);
            position: absolute;
            left: 50%;
            top: 100%;
            transform: translateX(-50%) translateY(8px);
            z-index: 1001;
            background-color: rgba(33, 37, 41, 0.9);
            color: white;
            padding: 0.5rem 1rem;
            border-radius: 6px;
            font-size: 0.875rem;
            white-space: nowrap;
            box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
        }

        .refresh-label:hover::before {
            content: '';
            position: absolute;
            left: 50%;
            top: 100%;
            transform: translateX(-50%);
            border: 8px solid transparent;
            border-bottom-color: rgba(33, 37, 41, 0.9);
            z-index: 1001;
        }
    </style>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
    <script
        src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.33/moment-timezone-with-data.min.js"></script>

</head>

<body>
    <div class="container">
        <header>
            <div class="d-flex justify-content-between align-items-center">
                <h1>SkyPilot Managed Jobs</h1>
                <div class="d-flex align-items-center">
                    <div class="form-check form-switch me-3">
                        <input class="form-check-input" type="checkbox" id="refresh-toggle" checked>
                        <label class="form-check-label refresh-label" for="refresh-toggle" data-tooltip="Refreshes every 30 seconds">
                            Auto-refresh
                            <span class="refresh-indicator">
                                <span class="refresh-spinner" id="refresh-spinner"></span>
                            </span>
                        </label>
                    </div>
                    <p class="text-muted mb-0" id="last-updated" data-tooltip="{{ utcTimestamp }}"></p>
                </div>
            </div>
        </header>

        <!-- Hidden status filter -->
        <select id="status-filter" style="display: none;">
            <option value="">All</option>
            {% for status in status_values %}
            <option value="{{ status }}">{{ status }}</option>
            {% endfor %}
        </select>

        {% if rows %}
        <p>Filter by status:
            <span class="badge bg-secondary clickable-badge selected-filter me-2" data-status="ALL">All</span>
            {% set status_dict = {} %}
            {% for row in rows %}
                {% set status = row[9].split()[0] %}
                {% if status not in status_dict %}
                    {% set _ = status_dict.update({status: 1}) %}
                {% else %}
                    {% set _ = status_dict.update({status: status_dict[status] + 1}) %}
                {% endif %}
            {% endfor %}
            {% for status, count in status_dict|dictsort %}
                <span class="me-2">
                    <span class="me-1">| {{ count }}</span>
                    {% if status.startswith('RUNNING') %}
                    <span class="badge bg-primary clickable-badge" data-status="{{ status }}">{{ status }}</span>
                    {% elif status.startswith('PENDING') or status.startswith('SUBMITTED') %}
                    <span class="badge bg-light clickable-badge" data-status="{{ status }}">{{ status }}</span>
                    {% elif status.startswith('RECOVERING') or status.startswith('CANCELLING') or status.startswith('STARTING') %}
                    <span class="badge bg-info clickable-badge" data-status="{{ status }}">{{ status }}</span>
                    {% elif status.startswith('SUCCEEDED') %}
                    <span class="badge bg-success clickable-badge" data-status="{{ status }}">{{ status }}</span>
                    {% elif status.startswith('CANCELLED') %}
                    <span class="badge bg-secondary clickable-badge" data-status="{{ status }}">{{ status }}</span>
                    {% elif status.startswith('FAILED') %}
                    <span class="badge bg-danger clickable-badge" data-status="{{ status }}">{{ status }}</span>
                    {% else %}
                    <span class="clickable-badge" data-status="{{ status }}">{{ status }}</span>
                    {% endif %}
                </span>
            {% endfor %}
        </p>
        {% else %}
        <p>No jobs found.</p>
        {% endif %}

        <table class="table table-hover table-hover-selected fixed-header-table" id="jobs-table">
            <thead>
                <tr>
                    <td></td>
                    <th>ID</th>
                    <th>Task</th>
                    <th>Name</th>
                    <th>Total Duration</th>
                    <th>Job Duration</th>
                    <th>Status</th>
                    <th>Resources</th>
                    <th>Cluster</th>
                    <th>Region</th>
                    <th>Recoveries</th>
                    <th>Details</th>
                    <th>Actions</th>
                </tr>
            </thead>
            <tbody>
                {% for row in rows %}
                <tr class="{% if row[2] == '' %}folder{% endif %}{% if row[1] == ' \u21B3' %}folded{% endif %}">
                    <td>{% if row[2] == '' %}<span class="clickable">▶</span>{% endif %}</td>
                    <td>{{ row[1]|string|replace(' \u21B3', '') }}</td>
                    <td>{{ row[2] }}</td>
                    <td>{{ row[3] }}</td>
                    <td>{{ row[6] }}</td>
                    <td>{{ row[7] }}</td>
                    <td>
                        <!-- Status column with tooltip -->
                        <div class="status-container" style="position: relative;" data-tooltip="{{ row[14] }}">
                            {% if row[9].startswith('RUNNING') %}
                            <span class="badge bg-primary">{{ row[9].split()[0] }}</span>{{ row[9][row[9].split()[0]|length:] }}
                            {% elif row[9].startswith('PENDING') or row[9].startswith('SUBMITTED') %}
                            <span class="badge bg-warning">{{ row[9].split()[0] }}</span>{{ row[9][row[9].split()[0]|length:] }}
                            {% elif row[9].startswith('RECOVERING') or row[9].startswith('CANCELLING') or row[9].startswith('STARTING') %}
                            <span class="badge bg-info">{{ row[9].split()[0] }}</span>{{ row[9][row[9].split()[0]|length:] }}
                            {% elif row[9].startswith('SUCCEEDED') %}
                            <span class="badge bg-success">{{ row[9].split()[0] }}</span>{{ row[9][row[9].split()[0]|length:] }}
                            {% elif row[9].startswith('CANCELLED') %}
                            <span class="badge bg-secondary">{{ row[9].split()[0] }}</span>{{ row[9][row[9].split()[0]|length:] }}
                            {% elif row[9].startswith('FAILED') %}
                            <span class="badge bg-danger">{{ row[9].split()[0] }}</span>{{ row[9][row[9].split()[0]|length:] }}
                            {% else %}
                            {{ row[9] }}
                            {% endif %}
                        </div>
                    </td>
                    <td>{{ row[4] }}</td>  {# Resources #}
                    <td>{{ row[11] }}</td>  {# Cluster #}
                    <td>{{ row[12] }}</td>  {# Region #}
                    <td>{{ row[8] }}</td>   {# Recoveries #}
                    <td data-full-text="{{ row[13] }}">{{ row[13] }}</td>  {# Details #}
                    <td>
                        {% if row[1]|string|replace(' \u21B3', '') and row[1]|string|replace(' \u21B3', '') != '-' %}
                        <a href="{{ url_for('download_log', job_id=row[1]|string|replace(' \u21B3', '')) }}"
                           class="btn btn-sm btn-outline-secondary">
                            controller log
                        </a>
                        {% endif %}
                    </td>
                </tr>
                {% endfor %}
            </tbody>
        </table>
    </div>
    <script>
        // Folder toggle for pipelines, this will fold/unfold the rows for
        // a pipeline and its tasks.
        document.querySelectorAll('.folder').forEach(function (folder) {
            folder.addEventListener('click', function () {
                let plusSign = folder.querySelector('.clickable');
                let folderIndex = Array.from(document.querySelectorAll('.folder')).indexOf(folder);

                if (!plusSign) {
                    plusSign = document.createElement('span');
                    plusSign.classList.add('clickable');
                    folder.children[0].prepend(plusSign); // Ensure the clickable span is the first child of the folder cell
                }

                let displayState = 'none';
                if (plusSign.textContent === '▶') {
                    plusSign.textContent = '▼'; // Change to downward-pointing triangle
                    displayState = '';
                    localStorage.setItem('folderState' + folderIndex, 'expanded');
                } else {
                    plusSign.textContent = '▶'; // Change back to right-pointing triangle
                    localStorage.setItem('folderState' + folderIndex, 'collapsed');
                }

                let next = folder.nextElementSibling;
                while (next && next.classList.contains('folded')) {
                    next.style.display = displayState;
                    next = next.nextElementSibling;
                }
            });
        });

        document.addEventListener("DOMContentLoaded", function () {
            // Setting initial fold state for each folder
            document.querySelectorAll('.folder').forEach(function (folder, index) {
                let storedState = localStorage.getItem('folderState' + index);
                let plusSign = folder.querySelector('.clickable');
                let next = folder.nextElementSibling;
                if (storedState === 'expanded') {
                    plusSign.textContent = '▼';
                    while (next && next.classList.contains('folded')) {
                        next.style.display = '';  // Show
                        next = next.nextElementSibling;
                    }
                } else {
                    plusSign.textContent = '▶';
                    while (next && next.classList.contains('folded')) {
                        next.style.display = 'none';  // Hide initially
                        next = next.nextElementSibling;
                    }
                }
            });
            document.querySelectorAll('.folded').forEach(function (folded) {
                if (!folded.previousElementSibling.querySelector('.clickable').textContent.includes('▼')) {
                    folded.style.display = 'none'; // Make sure these rows are initially hidden unless state is expanded
                }
            });
        });
    </script>
    <script>
        document.addEventListener("DOMContentLoaded", function () {
            var timestamp = "{{ last_updated_timestamp }}";  // Get the UTC timestamp from the template
            var localTimestamp = moment.utc(timestamp).tz(moment.tz.guess()).format('YYYY-MM-DD HH:mm:ss z');
            var utcTimestamp = moment.utc(timestamp).format('YYYY-MM-DD HH:mm:ss UTC');
            document.getElementById("last-updated").textContent = "Last updated: " + localTimestamp;
            document.getElementById("last-updated").setAttribute('data-tooltip', utcTimestamp);
        });
    </script>
    <script>
        // Function to handle toggle of auto-refresh
        // Retrieve the previous state from localStorage
        var storedRefreshState = localStorage.getItem("refreshState");
        var refreshToggle = document.getElementById("refresh-toggle");
        if (storedRefreshState === 'true' || storedRefreshState === null) {
            refreshToggle.checked = true;
        } else {
            refreshToggle.checked = false;
        }

        // Add event listener to the toggle switch
        function handleAutoRefresh() {
            localStorage.setItem("refreshState", refreshToggle.checked);
            // Check the state of the toggle switch
            if (refreshToggle.checked) {
                // Auto-refresh is enabled
                refreshInterval = setInterval(function () {
                    // Store current filter before reload
                    var currentFilter = document.getElementById("status-filter").value;
                    localStorage.setItem("statusFilter", currentFilter);
                    location.reload();
                }, 30000); // 30 seconds in milliseconds
            } else {
                // Auto-refresh is disabled
                clearInterval(refreshInterval);
            }
        }

        // Restore filter state after page load
        document.addEventListener("DOMContentLoaded", function() {
            var savedFilter = localStorage.getItem("statusFilter");
            if (savedFilter) {
                var statusFilter = document.getElementById("status-filter");
                statusFilter.value = savedFilter;
                filterStatus(savedFilter);
            }
        });

        refreshToggle.addEventListener("change", handleAutoRefresh);
        handleAutoRefresh();
    </script>
    <script>
        function filterStatus(status) {
            var rows = document.querySelectorAll("#jobs-table tbody tr");
            rows.forEach(function(row) {
                var statusCell = row.querySelector("td:nth-child(7)"); // Status is now in the 7th column
                if (statusCell) {
                    var statusText = statusCell.textContent.trim().split(' ')[0]; // Get first word of status

                    if (status === '' || statusText === status) {
                        row.style.display = "";
                    } else {
                        row.style.display = "none";
                    }
                }
            });
        }

        // Add event listener for the status filter
        document.addEventListener("DOMContentLoaded", function() {
            document.getElementById("status-filter").addEventListener("change", function() {
                filterStatus(this.value);
            });
        });
    </script>
    <script>
        // Show loading spinner during refresh
        window.addEventListener('beforeunload', function() {
            document.getElementById('refresh-spinner').style.display = 'inline-block';
        });
    </script>
    <script>
        // Update column indices for job table
        const JOB_TABLE_COLUMNS = [
            '', 'ID', 'Task', 'Name', 'Total Duration',
            'Job Duration', 'Status', 'Resources', 'Cluster', 'Region', 'Recoveries', 'Details',
            'Actions'
        ];
    </script>
    <script>
        // Replace the existing click handler for status badges with this updated version
        document.addEventListener("DOMContentLoaded", function() {
            const statusFilter = document.getElementById('status-filter');
            const badges = document.querySelectorAll('.clickable-badge');

            // Set initial state
            const savedFilter = localStorage.getItem("statusFilter") || '';
            updateSelectedBadge(savedFilter);

            badges.forEach(function(badge) {
                badge.addEventListener('click', function() {
                    const status = this.dataset.status;
                    const currentFilter = statusFilter.value;

                    // If clicking the already selected filter, clear it (show all)
                    const newStatus = (status === currentFilter || (status === 'ALL' && currentFilter === '')) ? '' :
                                    (status === 'ALL' ? '' : status);

                    // Update filter and UI
                    statusFilter.value = newStatus;
                    filterStatus(newStatus);
                    localStorage.setItem("statusFilter", newStatus);
                    updateSelectedBadge(newStatus);
                });
            });

            function updateSelectedBadge(selectedStatus) {
                badges.forEach(badge => {
                    badge.classList.remove('selected-filter');
                    if ((selectedStatus === '' && badge.dataset.status === 'ALL') ||
                        badge.dataset.status === selectedStatus) {
                        badge.classList.add('selected-filter');
                    }
                });
            }
        });
    </script>
    <script>
        // Add scroll event listener to handle sticky header shadow
        document.addEventListener("DOMContentLoaded", function() {
            const header = document.querySelector('header');
            const container = document.querySelector('.container');

            window.addEventListener('scroll', function() {
                if (container.getBoundingClientRect().top < 0) {
                    header.classList.add('sticky');
                } else {
                    header.classList.remove('sticky');
                }
            });
        });
    </script>
<script>
    // Add click handler for Details cells
    document.addEventListener('DOMContentLoaded', function() {
        const detailsCells = document.querySelectorAll('#jobs-table td:nth-child(12)');

        detailsCells.forEach(cell => {
            // Check if content is truncated
            if (cell.scrollWidth > cell.clientWidth) {
                cell.classList.add('expandable');
            }

            cell.addEventListener('click', function() {
                if (this.scrollWidth > this.clientWidth || this.classList.contains('expanded')) {
                    this.classList.toggle('expanded');
                }
            });
        });
    });
</script>
</body>

</html>
