Spaces:
Sleeping
Sleeping
Upload 17 files
Browse files- dashboardlogic.js +98 -57
dashboardlogic.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
|
| 2 |
|
| 3 |
// Read/write tokens from sessionStorage
|
| 4 |
function getReadToken() {
|
|
@@ -8,7 +8,7 @@ function getWriteToken() {
|
|
| 8 |
return sessionStorage.getItem('hf_write_token') || '';
|
| 9 |
}
|
| 10 |
|
| 11 |
-
// Helper to add tokens to every API call
|
| 12 |
function withTokens(obj = {}) {
|
| 13 |
return {
|
| 14 |
...obj,
|
|
@@ -17,17 +17,6 @@ function withTokens(obj = {}) {
|
|
| 17 |
};
|
| 18 |
}
|
| 19 |
|
| 20 |
-
// Helper to call secure server-side proxy
|
| 21 |
-
async function callSecureApi(fn, args) {
|
| 22 |
-
const resp = await fetch('/api/proxy', {
|
| 23 |
-
method: 'POST',
|
| 24 |
-
headers: { 'Content-Type': 'application/json' },
|
| 25 |
-
body: JSON.stringify({ fn, args })
|
| 26 |
-
});
|
| 27 |
-
if (!resp.ok) throw new Error('Proxy error: ' + resp.status);
|
| 28 |
-
return await resp.json();
|
| 29 |
-
}
|
| 30 |
-
|
| 31 |
let client;
|
| 32 |
let currentUser = null;
|
| 33 |
let currentPassword = null;
|
|
@@ -63,13 +52,18 @@ async function initDashboard() {
|
|
| 63 |
}
|
| 64 |
|
| 65 |
try {
|
|
|
|
|
|
|
|
|
|
| 66 |
// Update account info
|
| 67 |
const initials = currentUser.substring(0, 2).toUpperCase();
|
| 68 |
document.querySelector('.avatar').textContent = initials;
|
| 69 |
document.querySelector('.account-name').textContent = currentUser;
|
|
|
|
| 70 |
// Load data
|
| 71 |
await loadUserData();
|
| 72 |
await loadFiles();
|
|
|
|
| 73 |
} catch (err) {
|
| 74 |
console.error('Init error:', err);
|
| 75 |
showToast('Connection failed');
|
|
@@ -81,29 +75,38 @@ async function initDashboard() {
|
|
| 81 |
async function loadUserData() {
|
| 82 |
try {
|
| 83 |
console.log('Loading user data...');
|
| 84 |
-
const result = await
|
| 85 |
const [log, isDev, isPro, isTester, capacityUsed, usedTotal] = result.data;
|
| 86 |
-
|
|
|
|
| 87 |
let role = 'free';
|
| 88 |
if (isDev) role = 'dev';
|
| 89 |
else if (isPro) role = 'pro';
|
| 90 |
else if (isTester) role = 'tester';
|
|
|
|
| 91 |
const tag = document.getElementById('role-tag');
|
| 92 |
tag.className = 'role-tag ' + role;
|
| 93 |
tag.textContent = role.charAt(0).toUpperCase() + role.slice(1);
|
| 94 |
document.getElementById('tier-val').textContent = tag.textContent;
|
|
|
|
|
|
|
| 95 |
const capacityPercent = Math.round(capacityUsed);
|
| 96 |
let usedDisplay = usedTotal || '0 / 5 GB';
|
| 97 |
let usedParts = usedDisplay.split('/');
|
| 98 |
let usedAmount = usedParts[0].trim();
|
| 99 |
let maxAmount = usedParts[1] ? usedParts[1].trim() : '5 GB';
|
|
|
|
|
|
|
| 100 |
document.querySelector('.card-bar-fill').style.width = capacityPercent + '%';
|
| 101 |
document.querySelector('.stor-label span:last-child').textContent = usedDisplay;
|
| 102 |
document.querySelector('.sbar-fill').style.width = capacityPercent + '%';
|
|
|
|
| 103 |
const storageCard = document.querySelectorAll('.card')[0];
|
| 104 |
-
storageCard.querySelector('.card-val').innerHTML = usedAmount + ' <span style="font-size:.38em;font-weight:400;color:rgba(0,0,0,.38)">(
|
| 105 |
storageCard.querySelector('.card-sub').textContent = usedDisplay + ' used';
|
|
|
|
| 106 |
document.querySelectorAll('.card')[3].querySelector('.card-sub').textContent = maxAmount + ' max capacity';
|
|
|
|
| 107 |
console.log('✓ User data loaded');
|
| 108 |
} catch (err) {
|
| 109 |
console.error('User data error:', err);
|
|
@@ -119,21 +122,26 @@ async function loadFiles() {
|
|
| 119 |
try {
|
| 120 |
console.log('Loading files...');
|
| 121 |
loading(true);
|
| 122 |
-
const result = await
|
| 123 |
user_id: currentUser,
|
| 124 |
password: currentPassword,
|
| 125 |
}));
|
| 126 |
// API returns [dropdown, status]
|
| 127 |
const dropdownData = result.data[0];
|
|
|
|
| 128 |
let fileNames = [];
|
| 129 |
if (dropdownData && typeof dropdownData === 'object' && dropdownData.choices) {
|
|
|
|
| 130 |
fileNames = dropdownData.choices.flat ? dropdownData.choices.flat() : [].concat(...dropdownData.choices);
|
| 131 |
} else if (Array.isArray(dropdownData)) {
|
| 132 |
fileNames = dropdownData;
|
| 133 |
} else if (typeof dropdownData === 'string') {
|
| 134 |
fileNames = [dropdownData];
|
| 135 |
}
|
|
|
|
| 136 |
fileNames = fileNames.map(f => String(f).trim()).filter(Boolean);
|
|
|
|
|
|
|
| 137 |
const seen = new Set();
|
| 138 |
const deduped = [];
|
| 139 |
for (const name of fileNames) {
|
|
@@ -151,13 +159,15 @@ async function loadFiles() {
|
|
| 151 |
size: '—',
|
| 152 |
date: 'Recently',
|
| 153 |
type: ext ? ext.toUpperCase() : '',
|
| 154 |
-
preview: null
|
| 155 |
};
|
| 156 |
});
|
|
|
|
| 157 |
selected.clear();
|
| 158 |
updateStatsCards();
|
| 159 |
render(files);
|
| 160 |
loading(false);
|
|
|
|
| 161 |
} catch (err) {
|
| 162 |
console.error('Files load error:', err);
|
| 163 |
loading(false);
|
|
@@ -331,9 +341,9 @@ async function loadPreviewContent(file) {
|
|
| 331 |
function escapeHtml(str) {
|
| 332 |
return String(str)
|
| 333 |
.replace(/&/g, '&')
|
| 334 |
-
.replace(/</g, '
|
| 335 |
-
.replace(/>/g, '
|
| 336 |
-
.replace(/"/g, '
|
| 337 |
.replace(/'/g, ''');
|
| 338 |
}
|
| 339 |
|
|
@@ -344,18 +354,25 @@ async function deleteFile(id) {
|
|
| 344 |
|
| 345 |
try {
|
| 346 |
loading(true);
|
| 347 |
-
const result = await
|
| 348 |
user_id: currentUser,
|
| 349 |
password: currentPassword,
|
| 350 |
filename: file.name,
|
| 351 |
}));
|
|
|
|
|
|
|
|
|
|
|
|
|
| 352 |
const [status, capacityUsed, usedTotal] = result.data;
|
| 353 |
const percent = Math.round(capacityUsed);
|
| 354 |
document.querySelector('.card-bar-fill').style.width = percent + '%';
|
| 355 |
document.querySelector('.sbar-fill').style.width = percent + '%';
|
| 356 |
document.querySelector('.stor-label span:last-child').textContent = usedTotal;
|
|
|
|
|
|
|
| 357 |
files.splice(id, 1);
|
| 358 |
selected.delete(id);
|
|
|
|
| 359 |
updateStatsCards();
|
| 360 |
render(files);
|
| 361 |
loading(false);
|
|
@@ -395,17 +412,43 @@ async function downloadFile(id) {
|
|
| 395 |
const file = files[id];
|
| 396 |
try {
|
| 397 |
loading(true);
|
| 398 |
-
// Use /
|
| 399 |
-
const
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 409 |
loading(false);
|
| 410 |
} catch (err) {
|
| 411 |
console.error('Download error:', err);
|
|
@@ -426,33 +469,31 @@ async function downloadPreviewFile() {
|
|
| 426 |
async function handleUpload(input) {
|
| 427 |
if (!input.files || !input.files[0]) return;
|
| 428 |
const file = input.files[0];
|
| 429 |
-
loading(true);
|
| 430 |
-
const formData = new FormData();
|
| 431 |
-
formData.append('file', file);
|
| 432 |
-
formData.append('user_id', currentUser);
|
| 433 |
-
formData.append('password', currentPassword);
|
| 434 |
-
// custom_name optional - use file.name
|
| 435 |
-
formData.append('custom_name', file.name);
|
| 436 |
try {
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 449 |
await loadFiles();
|
| 450 |
-
|
|
|
|
| 451 |
} catch (err) {
|
| 452 |
-
|
| 453 |
-
console.error(err);
|
| 454 |
-
} finally {
|
| 455 |
loading(false);
|
|
|
|
| 456 |
}
|
| 457 |
}
|
| 458 |
|
|
@@ -587,4 +628,4 @@ window.logoutUser = logoutUser;
|
|
| 587 |
window.openModal = openModal;
|
| 588 |
window.closeModal = closeModal;
|
| 589 |
window.loading = loading;
|
| 590 |
-
window.showToast = showToast;
|
|
|
|
| 1 |
+
import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client@1.9.0/dist/index.min.js";
|
| 2 |
|
| 3 |
// Read/write tokens from sessionStorage
|
| 4 |
function getReadToken() {
|
|
|
|
| 8 |
return sessionStorage.getItem('hf_write_token') || '';
|
| 9 |
}
|
| 10 |
|
| 11 |
+
// Helper to add tokens to every API call
|
| 12 |
function withTokens(obj = {}) {
|
| 13 |
return {
|
| 14 |
...obj,
|
|
|
|
| 17 |
};
|
| 18 |
}
|
| 19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
let client;
|
| 21 |
let currentUser = null;
|
| 22 |
let currentPassword = null;
|
|
|
|
| 52 |
}
|
| 53 |
|
| 54 |
try {
|
| 55 |
+
client = await Client.connect("pockit-cloud/main");
|
| 56 |
+
console.log('✓ Connected to API');
|
| 57 |
+
|
| 58 |
// Update account info
|
| 59 |
const initials = currentUser.substring(0, 2).toUpperCase();
|
| 60 |
document.querySelector('.avatar').textContent = initials;
|
| 61 |
document.querySelector('.account-name').textContent = currentUser;
|
| 62 |
+
|
| 63 |
// Load data
|
| 64 |
await loadUserData();
|
| 65 |
await loadFiles();
|
| 66 |
+
|
| 67 |
} catch (err) {
|
| 68 |
console.error('Init error:', err);
|
| 69 |
showToast('Connection failed');
|
|
|
|
| 75 |
async function loadUserData() {
|
| 76 |
try {
|
| 77 |
console.log('Loading user data...');
|
| 78 |
+
const result = await client.predict("/search_user", withTokens({ user_id: currentUser }));
|
| 79 |
const [log, isDev, isPro, isTester, capacityUsed, usedTotal] = result.data;
|
| 80 |
+
|
| 81 |
+
// Determine role
|
| 82 |
let role = 'free';
|
| 83 |
if (isDev) role = 'dev';
|
| 84 |
else if (isPro) role = 'pro';
|
| 85 |
else if (isTester) role = 'tester';
|
| 86 |
+
|
| 87 |
const tag = document.getElementById('role-tag');
|
| 88 |
tag.className = 'role-tag ' + role;
|
| 89 |
tag.textContent = role.charAt(0).toUpperCase() + role.slice(1);
|
| 90 |
document.getElementById('tier-val').textContent = tag.textContent;
|
| 91 |
+
|
| 92 |
+
// Parse capacity
|
| 93 |
const capacityPercent = Math.round(capacityUsed);
|
| 94 |
let usedDisplay = usedTotal || '0 / 5 GB';
|
| 95 |
let usedParts = usedDisplay.split('/');
|
| 96 |
let usedAmount = usedParts[0].trim();
|
| 97 |
let maxAmount = usedParts[1] ? usedParts[1].trim() : '5 GB';
|
| 98 |
+
|
| 99 |
+
// Update storage displays
|
| 100 |
document.querySelector('.card-bar-fill').style.width = capacityPercent + '%';
|
| 101 |
document.querySelector('.stor-label span:last-child').textContent = usedDisplay;
|
| 102 |
document.querySelector('.sbar-fill').style.width = capacityPercent + '%';
|
| 103 |
+
|
| 104 |
const storageCard = document.querySelectorAll('.card')[0];
|
| 105 |
+
storageCard.querySelector('.card-val').innerHTML = usedAmount + ' <span style="font-size:.38em;font-weight:400;color:rgba(0,0,0,.38)">(' + capacityPercent + '%)</span>';
|
| 106 |
storageCard.querySelector('.card-sub').textContent = usedDisplay + ' used';
|
| 107 |
+
|
| 108 |
document.querySelectorAll('.card')[3].querySelector('.card-sub').textContent = maxAmount + ' max capacity';
|
| 109 |
+
|
| 110 |
console.log('✓ User data loaded');
|
| 111 |
} catch (err) {
|
| 112 |
console.error('User data error:', err);
|
|
|
|
| 122 |
try {
|
| 123 |
console.log('Loading files...');
|
| 124 |
loading(true);
|
| 125 |
+
const result = await client.predict("/get_files_secure", withTokens({
|
| 126 |
user_id: currentUser,
|
| 127 |
password: currentPassword,
|
| 128 |
}));
|
| 129 |
// API returns [dropdown, status]
|
| 130 |
const dropdownData = result.data[0];
|
| 131 |
+
console.log('Raw dropdownData:', dropdownData);
|
| 132 |
let fileNames = [];
|
| 133 |
if (dropdownData && typeof dropdownData === 'object' && dropdownData.choices) {
|
| 134 |
+
// Flatten all sub-arrays in choices
|
| 135 |
fileNames = dropdownData.choices.flat ? dropdownData.choices.flat() : [].concat(...dropdownData.choices);
|
| 136 |
} else if (Array.isArray(dropdownData)) {
|
| 137 |
fileNames = dropdownData;
|
| 138 |
} else if (typeof dropdownData === 'string') {
|
| 139 |
fileNames = [dropdownData];
|
| 140 |
}
|
| 141 |
+
// Convert all to string, trim, and filter empty
|
| 142 |
fileNames = fileNames.map(f => String(f).trim()).filter(Boolean);
|
| 143 |
+
console.log('Extracted fileNames from dropdown:', fileNames);
|
| 144 |
+
// Deduplicate file names (case-insensitive, trim)
|
| 145 |
const seen = new Set();
|
| 146 |
const deduped = [];
|
| 147 |
for (const name of fileNames) {
|
|
|
|
| 159 |
size: '—',
|
| 160 |
date: 'Recently',
|
| 161 |
type: ext ? ext.toUpperCase() : '',
|
| 162 |
+
preview: null // for preview content
|
| 163 |
};
|
| 164 |
});
|
| 165 |
+
console.log('Final files array before render:', files);
|
| 166 |
selected.clear();
|
| 167 |
updateStatsCards();
|
| 168 |
render(files);
|
| 169 |
loading(false);
|
| 170 |
+
console.log('✓ Files loaded and rendered');
|
| 171 |
} catch (err) {
|
| 172 |
console.error('Files load error:', err);
|
| 173 |
loading(false);
|
|
|
|
| 341 |
function escapeHtml(str) {
|
| 342 |
return String(str)
|
| 343 |
.replace(/&/g, '&')
|
| 344 |
+
.replace(/</g, '<')
|
| 345 |
+
.replace(/>/g, '>')
|
| 346 |
+
.replace(/"/g, '"')
|
| 347 |
.replace(/'/g, ''');
|
| 348 |
}
|
| 349 |
|
|
|
|
| 354 |
|
| 355 |
try {
|
| 356 |
loading(true);
|
| 357 |
+
const result = await client.predict("/delete_file_secure", withTokens({
|
| 358 |
user_id: currentUser,
|
| 359 |
password: currentPassword,
|
| 360 |
filename: file.name,
|
| 361 |
}));
|
| 362 |
+
|
| 363 |
+
console.log('Deleted:', file.name);
|
| 364 |
+
|
| 365 |
+
// Update storage
|
| 366 |
const [status, capacityUsed, usedTotal] = result.data;
|
| 367 |
const percent = Math.round(capacityUsed);
|
| 368 |
document.querySelector('.card-bar-fill').style.width = percent + '%';
|
| 369 |
document.querySelector('.sbar-fill').style.width = percent + '%';
|
| 370 |
document.querySelector('.stor-label span:last-child').textContent = usedTotal;
|
| 371 |
+
|
| 372 |
+
// Remove from array
|
| 373 |
files.splice(id, 1);
|
| 374 |
selected.delete(id);
|
| 375 |
+
|
| 376 |
updateStatsCards();
|
| 377 |
render(files);
|
| 378 |
loading(false);
|
|
|
|
| 412 |
const file = files[id];
|
| 413 |
try {
|
| 414 |
loading(true);
|
| 415 |
+
// Use /get_download_link_action to get the raw download link
|
| 416 |
+
const result = await client.predict("/get_download_link_action", withTokens({
|
| 417 |
+
user_id: currentUser,
|
| 418 |
+
password: currentPassword,
|
| 419 |
+
filename: file.name,
|
| 420 |
+
}));
|
| 421 |
+
const fileUrl = result.data[0];
|
| 422 |
+
if (typeof fileUrl === 'string' && (fileUrl.startsWith('http') || fileUrl.startsWith('https'))) {
|
| 423 |
+
// Fetch as blob to force download, with optional Hugging Face token
|
| 424 |
+
const hfToken = sessionStorage.getItem('hf_read_token');
|
| 425 |
+
const fetchOptions = hfToken ? {
|
| 426 |
+
headers: { 'Authorization': 'Bearer ' + hfToken }
|
| 427 |
+
} : {};
|
| 428 |
+
const response = await fetch(fileUrl, fetchOptions);
|
| 429 |
+
if (!response.ok) {
|
| 430 |
+
console.error('Download fetch error:', {
|
| 431 |
+
url: fileUrl,
|
| 432 |
+
status: response.status,
|
| 433 |
+
statusText: response.statusText
|
| 434 |
+
});
|
| 435 |
+
throw new Error('Network response was not ok (status ' + response.status + '): ' + response.statusText);
|
| 436 |
+
}
|
| 437 |
+
const blob = await response.blob();
|
| 438 |
+
const url = window.URL.createObjectURL(blob);
|
| 439 |
+
const a = document.createElement('a');
|
| 440 |
+
a.href = url;
|
| 441 |
+
a.download = file.name;
|
| 442 |
+
document.body.appendChild(a);
|
| 443 |
+
a.click();
|
| 444 |
+
setTimeout(() => {
|
| 445 |
+
document.body.removeChild(a);
|
| 446 |
+
window.URL.revokeObjectURL(url);
|
| 447 |
+
}, 100);
|
| 448 |
+
showToast('Download started: ' + file.name);
|
| 449 |
+
} else {
|
| 450 |
+
showToast('Download link error');
|
| 451 |
+
}
|
| 452 |
loading(false);
|
| 453 |
} catch (err) {
|
| 454 |
console.error('Download error:', err);
|
|
|
|
| 469 |
async function handleUpload(input) {
|
| 470 |
if (!input.files || !input.files[0]) return;
|
| 471 |
const file = input.files[0];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 472 |
try {
|
| 473 |
+
loading(true);
|
| 474 |
+
// Use File object and pass custom_name for filename preservation
|
| 475 |
+
console.log('Uploading file:', file, 'type:', file.constructor.name);
|
| 476 |
+
const result = await client.predict("/upload_file_secure", withTokens({
|
| 477 |
+
user_id: currentUser,
|
| 478 |
+
password: currentPassword,
|
| 479 |
+
filepath: file,
|
| 480 |
+
custom_name: file.name,
|
| 481 |
+
}));
|
| 482 |
+
console.log('Uploaded:', file.name);
|
| 483 |
+
// Update storage
|
| 484 |
+
const [status, capacityUsed, usedTotal] = result.data;
|
| 485 |
+
const percent = Math.round(capacityUsed);
|
| 486 |
+
document.querySelector('.card-bar-fill').style.width = percent + '%';
|
| 487 |
+
document.querySelector('.sbar-fill').style.width = percent + '%';
|
| 488 |
+
document.querySelector('.stor-label span:last-child').textContent = usedTotal;
|
| 489 |
+
// Reload files
|
| 490 |
await loadFiles();
|
| 491 |
+
showToast(file.name + ' uploaded');
|
| 492 |
+
input.value = '';
|
| 493 |
} catch (err) {
|
| 494 |
+
console.error('Upload error:', err);
|
|
|
|
|
|
|
| 495 |
loading(false);
|
| 496 |
+
showToast('Upload failed');
|
| 497 |
}
|
| 498 |
}
|
| 499 |
|
|
|
|
| 628 |
window.openModal = openModal;
|
| 629 |
window.closeModal = closeModal;
|
| 630 |
window.loading = loading;
|
| 631 |
+
window.showToast = showToast;
|