Spaces:
Running
Running
| <html> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> | |
| <script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio,line-clamp"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"> | |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/flowbite/2.2.1/flowbite.min.css" rel="stylesheet" /> | |
| <script> | |
| function fetchAndDisplaySubmissionInfo() { | |
| const articleLoadingSpinner = document.getElementById('articleLoadingSpinner'); | |
| articleLoadingSpinner.classList.remove('hidden'); | |
| fetch('/submission_info') | |
| .then(response => { | |
| if (!response.ok) { | |
| throw new Error('Network response was not ok'); | |
| } | |
| return response.json(); // Parse the JSON response | |
| }) | |
| .then(data => { | |
| // Populate the 'content' div with the HTML from the response | |
| const contentDiv = document.getElementById('content'); | |
| contentDiv.innerHTML = marked.parse(data.response); | |
| addTargetBlankToLinks(); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| }) | |
| .catch(error => { | |
| console.error('There has been a problem with your fetch operation:', error); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| }); | |
| } | |
| function fetchAndDisplaySubmissions() { | |
| const apiEndpoint = '/my_submissions'; | |
| const articleLoadingSpinner = document.getElementById('articleLoadingSpinner'); | |
| articleLoadingSpinner.classList.remove('hidden'); | |
| const requestOptions = { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| } | |
| }; | |
| fetch(apiEndpoint, requestOptions) | |
| .then(response => { | |
| if (!response.ok) { | |
| throw new Error('Network response was not ok'); | |
| } | |
| return response.json(); | |
| }) | |
| .then(data => { | |
| const contentDiv = document.getElementById('content'); | |
| const teamNameDiv = `<h2>${data.response.team_name}</h2>` | |
| // console.log(data.response.submissions); | |
| // contentDiv.innerHTML = marked.parse(data.response.submission_text) + data.response.submissions; | |
| if (data.response.submissions && data.response.submissions.length > 0 && data.response.error.length == 0) { | |
| // Start building the table HTML | |
| let tableHTML = teamNameDiv; | |
| tableHTML += '<table border="1"><tr><th width: 17%;>Datetime</th><th style="width: 40%;">Submission ID</th><th style="width: 20%;">Score</th><th style="width: 8%;">Status</th><th style="width: 15%;">Error</th></tr>'; | |
| // Iterate over each submission and add it to the table | |
| data.response.submissions.forEach(submission => { | |
| tableHTML += `<tr> | |
| <td>${submission.datetime}</td> | |
| <td>${submission.submission_id}</td> | |
| <td>${submission.score}</td> | |
| <td>${submission.status}</td> | |
| <td>${submission.error_message}</td> | |
| </tr>`; | |
| }); | |
| // Close the table HTML and set it as the content | |
| tableHTML += '</table>'; | |
| // add a text field which displays team name and a button to update team name | |
| contentDiv.innerHTML = marked.parse(data.response.submission_text) + tableHTML; | |
| document.getElementById('updateSelectedSubmissionsButton').addEventListener('click', function () { | |
| updateSelectedSubmissions(); | |
| }); | |
| } else { | |
| // Display message if there are no submissions | |
| contentDiv.innerHTML = teamNameDiv + marked.parse(data.response.submission_text) + marked.parse(data.response.error); | |
| } | |
| document.getElementById('updateTeamNameButton').addEventListener('click', function () { | |
| updateTeamName(); | |
| }); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| }) | |
| .catch(error => { | |
| console.error('There was a problem with the fetch operation:', error); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| }); | |
| } | |
| function showSubmissionModal() { | |
| const modal = document.getElementById('submission-modal'); | |
| modal.classList.add('flex'); | |
| modal.classList.remove('hidden'); | |
| } | |
| document.addEventListener('DOMContentLoaded', function () { | |
| function hideSubmissionModal() { | |
| const modal = document.getElementById('submission-modal'); | |
| modal.classList.remove('flex'); | |
| modal.classList.add('hidden'); | |
| } | |
| function addTargetBlankToLinks() { | |
| const content = document.getElementById('content'); | |
| const links = content.getElementsByTagName('a'); | |
| for (let i = 0; i < links.length; i++) { | |
| if (!links[i].hasAttribute('target')) { | |
| links[i].setAttribute('target', '_blank'); | |
| } | |
| } | |
| } | |
| function fetchAndDisplayCompetitionInfo() { | |
| const articleLoadingSpinner = document.getElementById('articleLoadingSpinner'); | |
| articleLoadingSpinner.classList.remove('hidden'); | |
| fetch('/competition_info') | |
| .then(response => { | |
| if (!response.ok) { | |
| throw new Error('Network response was not ok'); | |
| } | |
| return response.json(); // Parse the JSON response | |
| }) | |
| .then(data => { | |
| // Populate the 'content' div with the HTML from the response | |
| const contentDiv = document.getElementById('content'); | |
| contentDiv.style.display = 'block'; | |
| contentDiv.innerHTML = marked.parse(data.response); | |
| addTargetBlankToLinks(); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| }) | |
| .catch(error => { | |
| console.error('There has been a problem with your fetch operation:', error); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| }); | |
| } | |
| function fetchAndDisplayDatasetInfo() { | |
| const articleLoadingSpinner = document.getElementById('articleLoadingSpinner'); | |
| articleLoadingSpinner.classList.remove('hidden'); | |
| fetch('/dataset_info') | |
| .then(response => { | |
| if (!response.ok) { | |
| throw new Error('Network response was not ok'); | |
| } | |
| return response.json(); // Parse the JSON response | |
| }) | |
| .then(data => { | |
| // Populate the 'content' div with the HTML from the response | |
| const contentDiv = document.getElementById('content'); | |
| contentDiv.innerHTML = marked.parse(data.response); | |
| addTargetBlankToLinks(); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| }) | |
| .catch(error => { | |
| console.error('There has been a problem with your fetch operation:', error); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| }); | |
| } | |
| // function fetchAndDisplayLeaderboard(leaderboardType) { | |
| // const articleLoadingSpinner = document.getElementById('articleLoadingSpinner'); | |
| // articleLoadingSpinner.classList.remove('hidden'); | |
| // const payload = { | |
| // lb: leaderboardType, | |
| // }; | |
| // fetch('/leaderboard', { | |
| // method: 'POST', | |
| // headers: { | |
| // 'Content-Type': 'application/json' | |
| // }, | |
| // body: JSON.stringify(payload) | |
| // }) | |
| // .then(response => { | |
| // if (!response.ok) { | |
| // throw new Error('Network response was not ok'); | |
| // } | |
| // return response.json(); | |
| // }) | |
| // .then(data => { | |
| // const contentDiv = document.getElementById('content'); | |
| // contentDiv.innerHTML = marked.parse(data.response); | |
| // articleLoadingSpinner.classList.add('hidden'); | |
| // }) | |
| // .catch(error => { | |
| // console.error('There has been a problem with your fetch operation:', error); | |
| // articleLoadingSpinner.classList.add('hidden'); | |
| // }); | |
| // } | |
| // function fetchAndDisplayPublicLeaderboard() { | |
| // fetchAndDisplayLeaderboard('public'); | |
| // } | |
| // function fetchAndDisplayPrivateLeaderboard() { | |
| // fetchAndDisplayLeaderboard('private'); | |
| // } | |
| function fetchAndDisplayTeamInfo() { | |
| const apiEndpoint = '/team_info'; | |
| const articleLoadingSpinner = document.getElementById('articleLoadingSpinner'); | |
| articleLoadingSpinner.classList.remove('hidden'); | |
| const requestOptions = { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| } | |
| }; | |
| fetch(apiEndpoint, requestOptions) | |
| .then(response => { | |
| if (!response.ok) { | |
| throw new Error('Network response was not ok'); | |
| } | |
| return response.json(); // Parse the JSON response | |
| }) | |
| .then(data => { | |
| // Populate the 'content' div with the HTML from the response | |
| const contentDiv = document.getElementById('content'); | |
| if (data.team_exists) { | |
| contentHTML = "<h2>Team</h2>"; | |
| contentHTML += "<p>" + data.team_name + "</p>"; | |
| contentDiv.innerHTML = marked.parse(contentHTML); | |
| } else { | |
| contentDiv.innerHTML = marked.parse(data.response); | |
| } | |
| contentDiv.innerHTML = marked.parse(data.response); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| }) | |
| .catch(error => { | |
| console.error('There has been a problem with your fetch operation:', error); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| }); | |
| } | |
| function fetchAndDisplayRules() { | |
| const articleLoadingSpinner = document.getElementById('articleLoadingSpinner'); | |
| articleLoadingSpinner.classList.remove('hidden'); | |
| fetch('/rules') | |
| .then(response => { | |
| if (!response.ok) { | |
| throw new Error('Network response was not ok'); | |
| } | |
| return response.json(); // Parse the JSON response | |
| }) | |
| .then(data => { | |
| // Populate the 'content' div with the HTML from the response | |
| const contentDiv = document.getElementById('content'); | |
| contentDiv.innerHTML = marked.parse(data.response); | |
| addTargetBlankToLinks(); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| }) | |
| .catch(error => { | |
| console.error('There has been a problem with your fetch operation:', error); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| }); | |
| } | |
| function fetchAndDisplayLeaderboard() { | |
| const articleLoadingSpinner = document.getElementById('articleLoadingSpinner'); | |
| articleLoadingSpinner.classList.remove('hidden'); | |
| fetch('/leaderboard', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| }, | |
| }).then(response => { | |
| if (!response.ok) { | |
| throw new Error('Network response was not ok'); | |
| } | |
| return response.json(); | |
| }).then(data => { | |
| const contentDiv = document.getElementById('content'); | |
| contentDiv.innerHTML = marked.parse(data.response); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| }).catch(error => { | |
| console.error('There has been a problem with your fetch operation:', error); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| }); | |
| } | |
| const homeLink = document.getElementById('home'); | |
| const datasetLink = document.getElementById('dataset'); | |
| // const publicLBLink = document.getElementById('public_lb'); | |
| // const privateLBLink = document.getElementById('private_lb'); | |
| const rulesLink = document.getElementById('rules'); | |
| const leaderBoardLink = document.getElementById('leaderboard'); | |
| leaderBoardLink.addEventListener('click', function (event) { | |
| event.preventDefault(); // Prevent the default link behavior | |
| fetchAndDisplayLeaderboard(); // Fetch and display info on click | |
| }); | |
| // Add a click event listener to the 'Home' link | |
| homeLink.addEventListener('click', function (event) { | |
| event.preventDefault(); // Prevent the default link behavior | |
| fetchAndDisplayCompetitionInfo(); // Fetch and display info on click | |
| }); | |
| datasetLink.addEventListener('click', function (event) { | |
| event.preventDefault(); // Prevent the default link behavior | |
| fetchAndDisplayDatasetInfo(); // Fetch and display info on click | |
| }); | |
| // publicLBLink.addEventListener('click', function (event) { | |
| // event.preventDefault(); // Prevent the default link behavior | |
| // fetchAndDisplayPublicLeaderboard(); // Fetch and display info on click | |
| // }); | |
| // privateLBLink.addEventListener('click', function (event) { | |
| // event.preventDefault(); // Prevent the default link behavior | |
| // fetchAndDisplayPrivateLeaderboard(); // Fetch and display info on click | |
| // }); | |
| rulesLink.addEventListener('click', function (event) { | |
| event.preventDefault(); // Prevent the default link behavior | |
| fetchAndDisplayRules(); // Fetch and display info on click | |
| }); | |
| // Fetch and display info when the page loads | |
| fetchAndDisplayCompetitionInfo(); | |
| document.querySelector('#submission-modal .cancel').addEventListener('click', function () { | |
| hideSubmissionModal(); | |
| }); | |
| }); | |
| </script> | |
| <script> | |
| function makeApiRequest(url, callback) { | |
| var xhr = new XMLHttpRequest(); | |
| xhr.open("GET", url, true); | |
| xhr.onreadystatechange = function () { | |
| if (xhr.readyState === 4 && xhr.status === 200) { | |
| var response = JSON.parse(xhr.responseText); | |
| callback(response.response); | |
| } | |
| }; | |
| xhr.send(); | |
| } | |
| function checkOAuth() { | |
| var url = "/login_status"; | |
| const submissionInfo = document.getElementById('submission_info'); | |
| const mySubmissions = document.getElementById('my_submissions'); | |
| const newSubmission = document.getElementById('new_submission'); | |
| makeApiRequest(url, function ({is_login, is_admin, is_registered, is_white_team}) { | |
| const registerRemoveStyle = ["pointer-events-none", "text-gray-400", "cursor-not-allowed"]; | |
| const registerNewStyle = ["ext-gray-900", "hover:bg-gray-100"] | |
| if (is_login) { | |
| document.getElementById("loginButton").style.display = "none"; | |
| document.getElementById("logoutButton").style.display = "block"; | |
| } else { | |
| document.getElementById("loginButton").style.display = "block"; | |
| document.getElementById("logoutButton").style.display = "none"; | |
| } | |
| if (is_admin) { | |
| document.getElementById("admin").classList.remove("hidden"); | |
| } | |
| if (is_registered) { | |
| document.getElementById("updateTeamInfo").style.display = "block"; | |
| } | |
| submissionInfo.addEventListener('click', function (event) { | |
| event.preventDefault(); // Prevent the default link behavior | |
| if (is_registered) { | |
| fetchAndDisplaySubmissionInfo(); // Fetch and display info on click | |
| } else { | |
| alert(`You need to register to access the "Submission Information."`) | |
| } | |
| }); | |
| mySubmissions.addEventListener('click', function (event) { | |
| event.preventDefault(); // Prevent the default link behavior | |
| if (is_white_team) { | |
| fetchAndDisplaySubmissions(); // Fetch and display info on click | |
| } else { | |
| alert(`Access to "SUBMIT" will be granted after we manually review your registration. This process usually takes up to 24 hours.`) | |
| } | |
| }); | |
| newSubmission.addEventListener('click', function (event) { | |
| event.preventDefault(); // Prevent the default link behavior | |
| if (is_white_team) { | |
| showSubmissionModal(); // Show the submission modal | |
| } else { | |
| alert(`Access to "SUBMIT" will be granted after we manually review your registration. This process usually takes up to 24 hours.`) | |
| } | |
| }); | |
| if (is_login && !is_registered) { | |
| document.getElementById("registerButton").style.display = "block"; | |
| } | |
| }); | |
| } | |
| window.onload = checkOAuth; | |
| </script> | |
| </head> | |
| <body class="flex h-screen"> | |
| <!-- Sidebar --> | |
| <aside id="sidebar-multi-level-sidebar" | |
| class="fixed top-0 left-0 z-40 w-64 h-screen transition-transform -translate-x-full sm:translate-x-0" | |
| aria-label="Sidebar"> | |
| <div class="h-full px-3 py-4 overflow-y-auto"> | |
| <ul class="space-y-2 font-medium"> | |
| <li> | |
| <a href="#" id="home" | |
| class="flex items-center p-2 text-gray-900 rounded-lg hover:bg-gray-100 group"> | |
| <svg class="w-5 h-5 text-gray-500 transition duration-75 group-hover:text-gray-900" | |
| viewBox="0 0 22 21" xmlns="http://www.w3.org/2000/svg" fill="currentColor"> | |
| <path d="M1,10 L11,1 L21,10 L21,20 L1,20 Z" /> <!-- House structure --> | |
| <path d="M6,20 L6,14 L16,14 L16,20" /> <!-- Door --> | |
| </svg> | |
| <span class="ms-3">Home</span> | |
| </a> | |
| </li> | |
| <li> | |
| <a href="#" id="dataset" | |
| class="flex items-center p-2 text-gray-900 rounded-lg hover:bg-gray-100 group"> | |
| <svg class="flex-shrink-0 w-5 h-5 text-gray-500 transition duration-75 group-hover:text-gray-900" | |
| aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" | |
| viewBox="0 0 18 18"> | |
| <path | |
| d="M6.143 0H1.857A1.857 1.857 0 0 0 0 1.857v4.286C0 7.169.831 8 1.857 8h4.286A1.857 1.857 0 0 0 8 6.143V1.857A1.857 1.857 0 0 0 6.143 0Zm10 0h-4.286A1.857 1.857 0 0 0 10 1.857v4.286C10 7.169 10.831 8 11.857 8h4.286A1.857 1.857 0 0 0 18 6.143V1.857A1.857 1.857 0 0 0 16.143 0Zm-10 10H1.857A1.857 1.857 0 0 0 0 11.857v4.286C0 17.169.831 18 1.857 18h4.286A1.857 1.857 0 0 0 8 16.143v-4.286A1.857 1.857 0 0 0 6.143 10Zm10 0h-4.286A1.857 1.857 0 0 0 10 11.857v4.286c0 1.026.831 1.857 1.857 1.857h4.286A1.857 1.857 0 0 0 18 16.143v-4.286A1.857 1.857 0 0 0 16.143 10Z" /> | |
| </svg> | |
| <span class="flex-1 ms-3 whitespace-nowrap">Dataset</span> | |
| </a> | |
| </li> | |
| <!-- {% if rules_available %} | |
| <li> | |
| <a href="#" id="rules" | |
| class="flex items-center p-2 text-gray-900 rounded-lg hover:bg-gray-100 group"> | |
| <svg class="flex-shrink-0 w-5 h-5 text-gray-500 transition duration-75 group-hover:text-gray-900" | |
| aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" | |
| viewBox="0 0 24 24"> | |
| <path | |
| d="M3 0h18v2H3V0zm0 4h18v2H3V4zm0 4h18v2H3V8zm0 4h18v2H3v-2zm0 4h18v2H3v-2zm0 4h18v2H3v-2z" /> | |
| </svg> | |
| <span class="flex-1 ms-3 whitespace-nowrap">Rules</span> | |
| </a> | |
| </li> | |
| {% else %} | |
| <span id="rules"></span> | |
| {% endif %} --> | |
| <span id="rules"></span> | |
| <li> | |
| <a href="#" id="leaderboard" | |
| class="flex items-center p-2 text-gray-900 rounded-lg hover:bg-gray-100 group"> | |
| <svg class="flex-shrink-0 w-5 h-5 text-gray-500 transition duration-75 group-hover:text-gray-900" | |
| aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" | |
| viewBox="0 0 18 21"> | |
| <path d="M2,4 L20,4 L20,16 L2,16 Z" /> | |
| <path d="M6,17 L16,17 L16,18 L6,18 Z" /> | |
| </svg> | |
| <span class="flex-1 ms-3 text-left rtl:text-right whitespace-nowrap">Leaderboard</span> | |
| </a> | |
| </li> | |
| <li> | |
| <button type="button" | |
| class="flex items-center w-full p-2 text-base text-gray-900 transition duration-75 rounded-lg group hover:bg-gray-100" | |
| aria-controls="submissions-dropdown" data-collapse-toggle="submissions-dropdown"> | |
| <svg class="flex-shrink-0 w-5 h-5 text-gray-500 transition duration-75 group-hover:text-gray-900" | |
| aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" | |
| viewBox="0 0 20 20"> | |
| <path d="M5 5V.13a2.96 2.96 0 0 0-1.293.749L.879 3.707A2.96 2.96 0 0 0 .13 5H5Z" /> | |
| <path | |
| d="M6.737 11.061a2.961 2.961 0 0 1 .81-1.515l6.117-6.116A4.839 4.839 0 0 1 16 2.141V2a1.97 1.97 0 0 0-1.933-2H7v5a2 2 0 0 1-2 2H0v11a1.969 1.969 0 0 0 1.933 2h12.134A1.97 1.97 0 0 0 16 18v-3.093l-1.546 1.546c-.413.413-.94.695-1.513.81l-3.4.679a2.947 2.947 0 0 1-1.85-.227 2.96 2.96 0 0 1-1.635-3.257l.681-3.397Z" /> | |
| <path | |
| d="M8.961 16a.93.93 0 0 0 .189-.019l3.4-.679a.961.961 0 0 0 .49-.263l6.118-6.117a2.884 2.884 0 0 0-4.079-4.078l-6.117 6.117a.96.96 0 0 0-.263.491l-.679 3.4A.961.961 0 0 0 8.961 16Zm7.477-9.8a.958.958 0 0 1 .68-.281.961.961 0 0 1 .682 1.644l-.315.315-1.36-1.36.313-.318Zm-5.911 5.911 4.236-4.236 1.359 1.359-4.236 4.237-1.7.339.341-1.699Z" /> | |
| </svg> | |
| <span class="flex-1 ms-3 text-left rtl:text-right whitespace-nowrap">Submissions</span> | |
| <svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" | |
| viewBox="0 0 10 6"> | |
| <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" | |
| d="m1 1 4 4 4-4" /> | |
| </svg> | |
| </button> | |
| <ul id="submissions-dropdown" class="py-2 space-y-2"> | |
| <li> | |
| <a href="#" id="submission_info" | |
| class="flex items-center w-full p-2 transition duration-75 rounded-lg pl-11 group ext-gray-900 hover:bg-gray-100">Submission | |
| information</a> | |
| </li> | |
| <li> | |
| <a href="#" id="my_submissions" | |
| class="flex items-center w-full p-2 transition duration-75 rounded-lg pl-11 group ext-gray-900 hover:bg-gray-100">My | |
| submissions</a> | |
| </li> | |
| <li> | |
| <a href="#" id="new_submission" | |
| class="flex items-center w-full p-2 transition duration-75 rounded-lg pl-11 group ext-gray-900 hover:bg-gray-100">New | |
| submission</a> | |
| </li> | |
| </ul> | |
| </li> | |
| <li> | |
| <a href="#" id="admin" | |
| class="flex items-center p-2 text-gray-900 rounded-lg hover:bg-gray-100 group hidden"> | |
| <svg class="flex-shrink-0 w-5 h-5 text-gray-500 transition duration-75 group-hover:text-gray-900" | |
| aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" | |
| viewBox="0 0 24 24"> | |
| <path | |
| d="M12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5zm7.43-3.5c.04-.33.07-.66.07-1s-.03-.67-.07-1l2.11-1.65c.19-.15.23-.42.12-.63l-2-3.46c-.11-.21-.35-.3-.57-.24l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.57 2.18 14.3 2 14 2h-4c-.3 0-.57.18-.64.45L8.98 5.1c-.61.25-1.17.58-1.69.98l-2.49-1c-.22-.06-.46.03-.57.24l-2 3.46c-.11.21-.07.48.12.63l2.11 1.65c-.04.33-.07.66-.07 1s.03.67.07 1L2.46 14.1c-.19.15-.23.42-.12.63l2 3.46c.11.21.35.3.57.24l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.07.27.34.45.64.45h4c.3 0 .57-.18.64-.45l.38-2.65c.61-.25 1.17-.58 1.69-.98l2.49 1c.22.06.46-.03.57-.24l2-3.46c.11-.21.07-.48-.12-.63l-2.11-1.65zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5z" /> | |
| </svg> | |
| <span class="flex-1 ms-3 whitespace-nowrap">Admin</span> | |
| </a> | |
| </li> | |
| <li id="registerButton" style="display: none;"> | |
| <a href="#" | |
| class="flex justify-center items-center bg-blue-400 hover:bg-blue-600 text-white text-center font-bold py-2 px-4 rounded transition duration-200 ease-in-out"> | |
| Register | |
| </a> | |
| </li> | |
| <li id="loginButton" style="display: none;"> | |
| <a href="/login/huggingface" | |
| class="flex justify-center items-center bg-blue-400 hover:bg-blue-600 text-white text-center font-bold py-2 px-4 rounded transition duration-200 ease-in-out"> | |
| Login with Hugging Face | |
| </a> | |
| </li> | |
| <li id="updateTeamInfo" style="display: none;"> | |
| <a href="/update_team_info_page" | |
| class="flex justify-center items-center bg-green-600 hover:bg-green-800 text-white text-center font-bold py-2 px-4 rounded transition duration-200 ease-in-out"> | |
| Update Team Info | |
| </a> | |
| </li> | |
| <li id="logoutButton" style="display: none;"> | |
| <a href="/logout" | |
| class="flex justify-center items-center bg-red-400 hover:bg-red-600 text-white text-center font-bold py-2 px-4 rounded transition duration-200 ease-in-out"> | |
| Logout | |
| </a> | |
| </li> | |
| </ul> | |
| <footer> | |
| <div class="w-full mx-auto max-w-screen-xl p-4 md:flex md:items-center md:justify-between"> | |
| <span class="text-sm text-gray-500 sm:text-center">Powered by <a | |
| href="https://github.com/huggingface/competitions" target="_blank" | |
| class="hover:underline">Hugging Face | |
| Competitions</a> | |
| </span> | |
| </div> | |
| <div class="text-center"> | |
| <span class="text-xs text-gray-400">{{version}} | |
| </span> | |
| </div> | |
| </footer> | |
| </div> | |
| </aside> | |
| <div class="p-1 sm:ml-64 overflow-x-hidden"> | |
| <img src={{logo}} alt="Competition logo"> | |
| <hr class="mt-3 mb-2"> | |
| <div id="articleLoadingSpinner" role="status" | |
| class="hidden absolute -translate-x-1/2 -translate-y-1/2 top-2/4 left-1/2"> | |
| <div class="animate-spin rounded-full h-32 w-32 border-b-2 border-gray-900"></div> | |
| <span class="sr-only">Loading...</span> | |
| </div> | |
| <article class="prose w-full mx-auto max-w-screen-xl p-4 md:flex md:items-center md:justify-between" | |
| id="content"> | |
| </article> | |
| </div> | |
| <div id="submission-modal" tabindex="-1" | |
| class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full"> | |
| <div id="loadingSpinner" role="status" | |
| class="hidden absolute -translate-x-1/2 -translate-y-1/2 top-2/4 left-1/2"> | |
| <div class="animate-spin rounded-full h-32 w-32 border-b-2 border-gray-900"></div> | |
| <span class="sr-only">Loading...</span> | |
| </div> | |
| <div class="form-container max-w-5xl mx-auto mt-3 p-6 shadow-2xl bg-white"> | |
| <p class="text-lg font-medium text-gray-900">New Submission</p> | |
| <form action="#" method="post" class="gap-2" enctype="multipart/form-data"> | |
| {% if competition_type == 'generic' %} | |
| <div class="form-group"> | |
| <label class="block mb-2 text-sm font-medium text-gray-900" for="submission_file">Upload | |
| file</label> | |
| <input | |
| class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 focus:outline-none " | |
| id="submission_file" type="file" name="submission_file"> | |
| </div> | |
| {% endif %} | |
| {% if competition_type == 'script' %} | |
| <div class="form-group"> | |
| <label for="hub_model" class="text-sm font-medium text-gray-700">Hub Dataset | |
| </label> | |
| <input type="text" name="hub_model" id="hub_model" | |
| class="mt-1 block w-full border border-gray-300 px-3 py-1.5 bg-white rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500" | |
| placeholder="username/my-model"> | |
| </div> | |
| {% endif %} | |
| <div class="form-group mt-2"> | |
| <label for="submission_comment" class="text-sm font-medium text-gray-700">Submission description | |
| (optional) | |
| </label> | |
| <textarea id="submission_comment" name="submission_comment" rows="5" | |
| class="p-2.5 w-full text-sm text-gray-900" placeholder=" "></textarea> | |
| </div> | |
| <div class="form-actions mt-6"> | |
| <button data-modal-hide="submission-modal" type="button" | |
| class="confirm text-white bg-green-600 hover:bg-green-800 focus:ring-4 focus:outline-none focus:ring-green-300font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center me-2"> | |
| Submit | |
| </button> | |
| <button data-modal-hide="submission-modal" type="button" | |
| class="cancel text-white bg-red-600 hover:bg-red-100 focus:ring-4 focus:outline-none focus:ring-red-200 rounded-lg border border-red-200 text-sm font-medium px-5 py-2.5 hover:text-red-900 focus:z-10">Cancel</button> | |
| </div> | |
| </form> | |
| <hr class="mt-3"> | |
| <div id="error-message" style="color: red;"></div> | |
| <div id="success-message" style="color: green;"></div> | |
| </div> | |
| </div> | |
| <div id="admin-modal" tabindex="-1" | |
| class="hidden fixed inset-0 z-40 flex items-center justify-center w-full h-full bg-black bg-opacity-50"> | |
| <div id="adminLoadingSpinner" role="status" | |
| class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50"> | |
| <div class="animate-spin rounded-full h-32 w-32 border-b-2 border-gray-900"></div> | |
| <span class="sr-only">Loading...</span> | |
| </div> | |
| <div class="relative w-full max-w-5xl p-4"> | |
| <div class="relative bg-white rounded-lg shadow-2xl"> | |
| <button type="button" | |
| class="absolute top-3 right-3 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 inline-flex justify-center items-center" | |
| data-modal-hide="admin-modal"> | |
| <svg class="w-4 h-4" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" | |
| viewBox="0 0 14 14"> | |
| <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" | |
| d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" /> | |
| </svg> | |
| <span class="sr-only">Close</span> | |
| </button> | |
| <div class="p-6 md:p-8 text-center"> | |
| <h3 class="mb-5 text-lg font-medium text-gray-900">Admin</h3> | |
| <div class="tabs"> | |
| <ul class="flex border-b"> | |
| <li class="mr-1"> | |
| <a class="tab bg-white inline-block py-2 px-4 text-blue-500 hover:text-blue-800 font-semibold" | |
| href="#config">Config</a> | |
| </li> | |
| <li class="mr-1"> | |
| <a class="tab bg-white inline-block py-2 px-4 text-blue-500 hover:text-blue-800 font-semibold" | |
| href="#competition-desc">Competition Desc</a> | |
| </li> | |
| <li class="mr-1"> | |
| <a class="tab bg-white inline-block py-2 px-4 text-blue-500 hover:text-blue-800 font-semibold" | |
| href="#dataset-desc">Dataset Desc</a> | |
| </li> | |
| <li class="mr-1"> | |
| <a class="tab bg-white inline-block py-2 px-4 text-blue-500 hover:text-blue-800 font-semibold" | |
| href="#submission-desc">Submission Desc</a> | |
| </li> | |
| <li class="mr-1"> | |
| <a class="tab bg-white inline-block py-2 px-4 text-blue-500 hover:text-blue-800 font-semibold" | |
| href="#rules-desc">Rules</a> | |
| </li> | |
| </ul> | |
| </div> | |
| <div id="tab-contents" | |
| class="text-xs font-normal text-left overflow-y-auto max-h-[calc(100vh-400px)] border-t border-gray-200 pt-4"> | |
| <div id="config"> | |
| <textarea id="config-textarea" class="w-full h-64 p-2 border rounded">Loading..</textarea> | |
| <p class="text-xs text-gray-500">Note: The config should be a valid JSON object. To learn | |
| details about entries, click <a | |
| href="https://huggingface.co/docs/competitions/competition_repo#confjson" | |
| target="_blank">here</a>. | |
| </p> | |
| </div> | |
| <div id="competition-desc" class="hidden"> | |
| <textarea id="competition-desc-textarea" | |
| class="w-full h-64 p-2 border rounded">Loading..</textarea> | |
| </div> | |
| <div id="dataset-desc" class="hidden"> | |
| <textarea id="dataset-desc-textarea" | |
| class="w-full h-64 p-2 border rounded">Loading..</textarea> | |
| </div> | |
| <div id="submission-desc" class="hidden"> | |
| <textarea id="submission-desc-textarea" | |
| class="w-full h-64 p-2 border rounded">Loading..</textarea> | |
| </div> | |
| <div id="rules-desc" class="hidden"> | |
| <textarea id="rules-desc-textarea" | |
| class="w-full h-64 p-2 border rounded">Loading..</textarea> | |
| </div> | |
| </div> | |
| <button id="save-button" class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-700"> | |
| Save | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/2.2.1/flowbite.min.js"></script> | |
| <script> | |
| document.addEventListener("DOMContentLoaded", function () { | |
| const content = document.getElementById('content'); | |
| const links = content.getElementsByTagName('a'); | |
| for (let i = 0; i < links.length; i++) { | |
| if (!links[i].hasAttribute('target')) { | |
| links[i].setAttribute('target', '_blank'); | |
| } | |
| } | |
| }); | |
| </script> | |
| </body> | |
| <script> | |
| document.addEventListener("DOMContentLoaded", function () { | |
| document.querySelectorAll('.tabs a').forEach(tab => { | |
| tab.addEventListener('click', event => { | |
| event.preventDefault(); | |
| document.querySelectorAll('.tabs a').forEach(t => t.classList.remove('active')); | |
| tab.classList.add('active'); | |
| document.querySelectorAll('#tab-contents > div').forEach(content => content.classList.add('hidden')); | |
| const selectedTab = document.querySelector(tab.getAttribute('href')); | |
| selectedTab.classList.remove('hidden'); | |
| }); | |
| }); | |
| async function fetchAdminCompInfo() { | |
| const adminLoadingSpinner = document.getElementById('adminLoadingSpinner'); | |
| adminLoadingSpinner.classList.remove('hidden'); | |
| try { | |
| const response = await fetch("/admin/comp_info", { | |
| method: "POST", | |
| headers: { | |
| "Content-Type": "application/json" | |
| } | |
| }); | |
| const data = await response.json(); | |
| if (response.ok) { | |
| populateAdminModal(data.response); | |
| } else { | |
| alert(data.response || "Failed to fetch competition info"); | |
| } | |
| } catch (error) { | |
| console.error("Error fetching admin competition info:", error); | |
| alert("An error occurred while fetching competition info."); | |
| } finally { | |
| adminLoadingSpinner.classList.add('hidden'); | |
| } | |
| } | |
| function populateAdminModal(data) { | |
| document.getElementById("config-textarea").value = JSON.stringify(data.config, null, 2); | |
| document.getElementById("competition-desc-textarea").value = data.markdowns["competition_desc"] || ""; | |
| document.getElementById("dataset-desc-textarea").value = data.markdowns["dataset_desc"] || ""; | |
| document.getElementById("submission-desc-textarea").value = data.markdowns["submission_desc"] || ""; | |
| document.getElementById("rules-desc-textarea").value = data.markdowns["rules"] || "No rules available."; | |
| } | |
| document.querySelectorAll(".tab").forEach(tab => { | |
| tab.addEventListener("click", function (event) { | |
| event.preventDefault(); | |
| const targetId = this.getAttribute("href").substring(1); | |
| document.querySelectorAll("#tab-contents > div").forEach(content => { | |
| content.classList.add("hidden"); | |
| }); | |
| document.getElementById(targetId).classList.remove("hidden"); | |
| document.querySelectorAll(".tab").forEach(t => { | |
| t.classList.remove("text-blue-800"); | |
| t.classList.add("text-blue-500"); | |
| }); | |
| this.classList.remove("text-blue-500"); | |
| this.classList.add("text-blue-800"); | |
| }); | |
| }); | |
| document.getElementById("admin").addEventListener("click", function () { | |
| document.getElementById("admin-modal").classList.remove("hidden"); | |
| fetchAdminCompInfo(); | |
| }); | |
| document.querySelector("[data-modal-hide='admin-modal']").addEventListener("click", function () { | |
| document.getElementById("admin-modal").classList.add("hidden"); | |
| }); | |
| document.getElementById("save-button").addEventListener("click", async function () { | |
| const adminLoadingSpinner = document.getElementById('adminLoadingSpinner'); | |
| adminLoadingSpinner.classList.remove('hidden'); | |
| const config = document.getElementById("config-textarea").value; | |
| const competitionDesc = document.getElementById("competition-desc-textarea").value; | |
| const datasetDesc = document.getElementById("dataset-desc-textarea").value; | |
| const submissionDesc = document.getElementById("submission-desc-textarea").value; | |
| const rulesDesc = document.getElementById("rules-desc-textarea").value; | |
| const data = { | |
| config: JSON.parse(config), | |
| markdowns: { | |
| competition_desc: competitionDesc, | |
| dataset_desc: datasetDesc, | |
| submission_desc: submissionDesc, | |
| rules: rulesDesc | |
| } | |
| }; | |
| try { | |
| const response = await fetch("/admin/update_comp_info", { | |
| method: "POST", | |
| headers: { | |
| "Content-Type": "application/json" | |
| }, | |
| body: JSON.stringify(data) | |
| }); | |
| const result = await response.json(); | |
| if (response.ok) { | |
| alert(result.response || "Successfully updated competition info"); | |
| } else { | |
| alert(result.response || "Failed to update competition info"); | |
| } | |
| } catch (error) { | |
| console.error("Error updating competition info:", error); | |
| alert("An error occurred while updating competition info."); | |
| } finally { | |
| adminLoadingSpinner.classList.add('hidden'); | |
| } | |
| }); | |
| }); | |
| </script> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function () { | |
| document.querySelector('.confirm').addEventListener('click', function (event) { | |
| event.preventDefault(); | |
| document.getElementById('error-message').textContent = ''; | |
| document.getElementById('success-message').textContent = ''; | |
| const loadingSpinner = document.getElementById('loadingSpinner'); | |
| loadingSpinner.classList.remove('hidden'); | |
| var formData = new FormData(); | |
| var competitionType = '{{ competition_type }}'; | |
| if (competitionType === 'generic') { | |
| var submissionFile = document.getElementById('submission_file').files[0]; | |
| formData.append('submission_file', submissionFile); | |
| formData.append('hub_model', 'None'); | |
| } else if (competitionType === 'script') { | |
| var hubModel = document.getElementById('hub_model').value; | |
| if (!hubModel) { | |
| alert('Hub Dataset is required.'); | |
| return; | |
| } | |
| formData.append('hub_model', hubModel); | |
| } else { | |
| alert('Invalid competition type.'); | |
| return; | |
| } | |
| var submissionComment = document.getElementById('submission_comment').value; | |
| formData.append('submission_comment', submissionComment); | |
| fetch('/new_submission', { | |
| method: 'POST', | |
| body: formData | |
| }) | |
| .then(response => response.json()) | |
| .then(data => { | |
| loadingSpinner.classList.add('hidden'); | |
| document.getElementById('success-message').textContent = data.response; | |
| }) | |
| .catch((error) => { | |
| console.error('Error:', error); | |
| loadingSpinner.classList.add('hidden'); | |
| document.getElementById('error-message').textContent = error; | |
| }); | |
| }); | |
| }); | |
| </script> | |
| <script> | |
| function updateSelectedSubmissions() { | |
| const selectedSubmissions = document.querySelectorAll('input[name="selectedSubmissions"]:checked'); | |
| const articleLoadingSpinner = document.getElementById('articleLoadingSpinner'); | |
| articleLoadingSpinner.classList.remove('hidden'); | |
| let selectedSubmissionIds = []; | |
| selectedSubmissions.forEach((submission) => { | |
| selectedSubmissionIds.push(submission.value); | |
| }); | |
| const updateEndpoint = '/update_selected_submissions'; | |
| const requestOptions = { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ | |
| "submission_ids": selectedSubmissionIds.join(',') | |
| }) | |
| }; | |
| fetch(updateEndpoint, requestOptions) | |
| .then(response => { | |
| if (!response.ok) { | |
| throw new Error('Network response was not ok'); | |
| } | |
| return response.json(); | |
| }) | |
| .then(data => { | |
| if (data.success) { | |
| // Optionally, display a success message or handle accordingly | |
| console.log('Update successful'); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| } else { | |
| // Handle failure case | |
| console.log('Update failed'); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| alert(data.error); | |
| } | |
| // Refresh submissions display | |
| fetchAndDisplaySubmissions(); | |
| }) | |
| .catch(error => { | |
| console.error('There was a problem with the fetch operation for updating:', error); | |
| }); | |
| } | |
| </script> | |
| <script> | |
| function updateTeamName() { | |
| const teamName = document.getElementById('team_name').value; | |
| const articleLoadingSpinner = document.getElementById('articleLoadingSpinner'); | |
| articleLoadingSpinner.classList.remove('hidden'); | |
| const updateEndpoint = '/update_team_name'; | |
| const requestOptions = { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ | |
| "new_team_name": teamName | |
| }) | |
| }; | |
| fetch(updateEndpoint, requestOptions) | |
| .then(response => { | |
| if (!response.ok) { | |
| throw new Error('Network response was not ok'); | |
| } | |
| return response.json(); | |
| }) | |
| .then(data => { | |
| if (data.success) { | |
| // Optionally, display a success message or handle accordingly | |
| console.log('Update successful'); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| } else { | |
| // Handle failure case | |
| console.log('Update failed'); | |
| articleLoadingSpinner.classList.add('hidden'); | |
| alert(data.error); | |
| } | |
| // Refresh submissions display | |
| fetchAndDisplaySubmissions(); | |
| }) | |
| .catch(error => { | |
| console.error('There was a problem with the fetch operation for updating:', error); | |
| }); | |
| } | |
| </script> | |
| <script> | |
| function showAdminModal() { | |
| const modal = document.getElementById('admin-modal'); | |
| modal.classList.add('flex'); | |
| modal.classList.remove('hidden'); | |
| } | |
| function hideAdminModal() { | |
| const modal = document.getElementById('admin-modal'); | |
| modal.classList.remove('flex'); | |
| modal.classList.add('hidden'); | |
| } | |
| document.querySelector('#admin').addEventListener('click', function () { | |
| showAdminModal(); | |
| }); | |
| document.querySelector('[data-modal-hide="admin-modal"]').addEventListener('click', function () { | |
| hideAdminModal(); | |
| }); | |
| </script> | |
| <script> | |
| document.getElementById("registerButton").addEventListener("click", function () { | |
| window.location.href = "/register_page"; | |
| }); | |
| </script> | |
| </html> |