Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Multi Agent Research</title> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script> | |
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> | |
<style> | |
html, body { | |
height: 100%; | |
margin: 0; | |
padding: 0; | |
overflow: hidden; | |
font-family: 'Roboto', sans-serif; | |
} | |
#app { | |
height: 100%; | |
display: flex; | |
flex-direction: column; | |
} | |
.content-wrapper { | |
flex-grow: 1; | |
position: relative; | |
overflow: hidden; | |
} | |
iframe { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
border: none; | |
} | |
.sidebar { | |
position: fixed; | |
left: 0; | |
top: 0; | |
bottom: 0; | |
width: 250px; | |
background-color: #2c3e50; | |
color: white; | |
display: flex; | |
flex-direction: column; | |
transition: transform 0.3s ease-in-out; | |
transform: translateX(-100%); | |
overflow-y: auto; | |
padding-top: 60px; | |
z-index: 1000; | |
} | |
.sidebar.open { | |
transform: translateX(0); | |
} | |
.sidebar button { | |
width: 80%; | |
margin: 10px auto; | |
padding: 15px; | |
background-color: #3498db; | |
color: white; | |
border: none; | |
border-radius: 10px; | |
font-size: 14px; | |
cursor: pointer; | |
text-align: center; | |
transition: all 0.3s ease; | |
display: block; | |
} | |
.sidebar button:hover { | |
background-color: #2980b9; | |
transform: translateY(-2px); | |
box-shadow: 0 4px 8px rgba(0,0,0,0.2); | |
} | |
.toggle-btn { | |
position: fixed; | |
left: 10px; | |
top: 10px; | |
background-color: #3498db; | |
color: white; | |
border: none; | |
border-radius: 10px; | |
font-size: 16px; | |
cursor: pointer; | |
padding: 7px 15px; | |
z-index: 1001; | |
transition: background-color 0.3s ease; | |
} | |
.toggle-btn:hover { | |
background-color: #2980b9; | |
} | |
.category { | |
width: 100%; | |
margin-bottom: 20px; | |
} | |
.category-title { | |
width: 80%; | |
margin: 10px auto; | |
padding: 10px; | |
background-color: #34495e; | |
color: white; | |
border-radius: 10px; | |
font-size: 16px; | |
text-align: center; | |
cursor: pointer; | |
} | |
.category-content { | |
display: none; | |
width: 100%; | |
} | |
.category-content.show { | |
display: block; | |
} | |
.user-info { | |
width: 80%; | |
margin: 20px auto; | |
text-align: center; | |
} | |
.user-name { | |
margin-bottom: 10px; | |
font-weight: bold; | |
} | |
.logout-btn { | |
background-color: #e74c3c; | |
} | |
.logout-btn:hover { | |
background-color: #c0392b; | |
} | |
@media (max-width: 768px) { | |
.sidebar { | |
width: 100%; | |
} | |
.sidebar button, .category-title, .user-info { | |
width: 90%; | |
} | |
} | |
@media (max-width: 480px) { | |
.sidebar button, .category-title, .user-info { | |
width: 95%; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<div id="app"> | |
<div v-if="loading">Loading...</div> | |
<div v-else-if="error">{{ error }}</div> | |
<div v-else class="content-wrapper"> | |
<div class="sidebar" :class="{ 'open': sidebarOpen }" id="sidebar"> | |
<div v-for="(apps, category) in appData" :key="category" class="category"> | |
<div class="category-title" @click="toggleCategory">{{ category }}</div> | |
<div class="category-content"> | |
<button v-for="app in apps" :key="app.name" @click="switchToApp(app.url)">{{ app.name }}</button> | |
</div> | |
</div> | |
<div class="user-info"> | |
<div class="user-name">{{ userName }}</div> | |
<button class="logout-btn" @click="handleLogout">Logout</button> | |
</div> | |
</div> | |
<button class="toggle-btn" @click="toggleSidebar">☰</button> | |
<iframe :src="currentPage" id="iframe" allowfullscreen allow="clipboard-read; clipboard-write" sandbox="allow-scripts allow-same-origin allow-popups allow-forms allow-downloads"></iframe> | |
</div> | |
</div> | |
<script> | |
const { createApp } = Vue; | |
const client = new Appwrite.Client(); | |
client.setEndpoint('https://cloud.appwrite.io/v1') | |
.setProject('66c2f6c7000abed7f1f9'); | |
const account = new Appwrite.Account(client); | |
const app = createApp({ | |
data() { | |
return { | |
appData: {}, | |
currentPage: '', | |
loading: true, | |
error: null, | |
sidebarOpen: false, | |
userName: '' | |
} | |
}, | |
methods: { | |
async checkAuth() { | |
try { | |
console.log("Checking authentication"); | |
const session = await account.getSession('current'); | |
console.log("Session:", session); | |
return session; | |
} catch (error) { | |
console.error("Not authenticated", error); | |
return null; | |
} | |
}, | |
redirectToLogin() { | |
console.log("Redirecting to login"); | |
window.location.href = '/'; | |
}, | |
async checkAllowlist(email) { | |
try { | |
console.log("Checking allowlist for email:", email); | |
const response = await axios.post('http://127.0.0.1:8000/check-allowlist', { email }); | |
console.log("Received response:", response.data); | |
if (response.data.allowed) { | |
console.log("Access allowed, setting app data"); | |
this.appData = response.data.app_data; | |
this.currentPage = this.appData["Updated Tools"][0].url; | |
} else { | |
console.log("Access denied"); | |
this.error = 'Access Denied: Your email is not on the allowlist.'; | |
} | |
} catch (error) { | |
console.error("Error checking allowlist:", error); | |
this.error = 'An error occurred while checking access.'; | |
} finally { | |
console.log("Setting loading to false"); | |
this.loading = false; | |
} | |
}, | |
toggleSidebar() { | |
this.sidebarOpen = !this.sidebarOpen; | |
}, | |
toggleCategory(event) { | |
const content = event.target.nextElementSibling; | |
content.classList.toggle('show'); | |
}, | |
switchToApp(url) { | |
this.currentPage = url; | |
localStorage.setItem('currentPage', url); | |
this.toggleSidebar(); | |
}, | |
async handleLogout() { | |
const loadingElement = document.createElement('div'); | |
loadingElement.textContent = 'Logging out...'; | |
document.body.appendChild(loadingElement); | |
try { | |
const logoutPromise = account.deleteSession('current'); | |
const timeoutPromise = new Promise((_, reject) => | |
setTimeout(() => reject(new Error('Logout timed out')), 5000) | |
); | |
await Promise.race([logoutPromise, timeoutPromise]); | |
localStorage.clear(); | |
this.redirectToLogin(); | |
} catch (error) { | |
console.error("Logout failed:", error); | |
alert("Logout failed. Please try again."); | |
} finally { | |
document.body.removeChild(loadingElement); | |
} | |
}, | |
async fetchProfileInfo() { | |
try { | |
const user = await account.get(); | |
this.userName = user.name || 'User'; | |
await this.checkAllowlist(user.email); | |
} catch (error) { | |
console.error("Error fetching profile info:", error); | |
this.error = 'Error loading profile information.'; | |
} | |
} | |
}, | |
async mounted() { | |
console.log("Component mounted"); | |
const session = await this.checkAuth(); | |
if (!session) { | |
this.redirectToLogin(); | |
} else { | |
await this.fetchProfileInfo(); | |
} | |
} | |
}); | |
app.mount('#app'); | |
</script> | |
</body> | |
</html> |