Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions finbot/apps/ctf/templates/pages/challenges.html
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,11 @@ <h3 class="text-lg font-semibold text-text-bright mb-2">No challenges found</h3>
status: ''
};

const initialStatusFromUrl = new URLSearchParams(window.location.search).get('status');
if (initialStatusFromUrl) {
currentFilters.status = initialStatusFromUrl;
}

// Category icons
const CATEGORY_ICONS = {
'prompt_injection': { icon: '💉', class: 'injection' },
Expand All @@ -379,6 +384,11 @@ <h3 class="text-lg font-semibold text-text-bright mb-2">No challenges found</h3>
document.addEventListener('DOMContentLoaded', function() {
loadChallenges();
setupFilters();

if (initialStatusFromUrl) {
const statusOption = document.querySelector(`.filter-option[data-filter="status"][data-value="${initialStatusFromUrl}"]`);
if (statusOption) statusOption.click();
}
});

async function loadChallenges() {
Expand Down
6 changes: 3 additions & 3 deletions finbot/apps/vendor/templates/components/ctf_sidecar.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ <h2 class="text-lg font-bold text-white">CTF Progress</h2>
<div class="flex items-center justify-between mb-3">
<h3 class="text-sm font-semibold text-gray-300 flex items-center space-x-2">
<span>🎖️</span>
<span>Badges</span>
<a href="/ctf/badges" class="hover:text-white transition-colors no-underline">Badges</a>
<span id="ctf-badges-count" class="text-xs bg-gray-700 px-2 py-0.5 rounded-full">0</span>
</h3>
</div>
Expand All @@ -73,7 +73,7 @@ <h3 class="text-sm font-semibold text-gray-300 flex items-center space-x-2">
<div class="ctf-section">
<h3 class="text-sm font-semibold text-gray-300 flex items-center space-x-2 mb-3">
<span>🎯</span>
<span>Active Challenges</span>
<a href="/ctf/challenges?status=in_progress" class="hover:text-white transition-colors no-underline">Active Challenges</a>
</h3>
<div id="ctf-active-challenges" class="space-y-2">
<!-- Active challenges will be populated here -->
Expand All @@ -91,7 +91,7 @@ <h3 class="text-sm font-semibold text-gray-300 flex items-center space-x-2">
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-2 w-2 bg-green-500"></span>
</span>
<span>Live Activity</span>
<a href="/ctf/activity" class="hover:text-white transition-colors no-underline">Live Activity</a>
</h3>
<span id="ctf-ws-status" class="text-xs text-gray-500">Connecting...</span>
</div>
Expand Down
25 changes: 25 additions & 0 deletions finbot/static/css/vendor/ctf_sidecar.css
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@
font-size: 1.5rem;
cursor: pointer;
transition: all 0.2s;
text-decoration: none;
color: inherit;
box-sizing: border-box;
}

a.ctf-badge-item:focus-visible {
outline: 2px solid #10b981;
outline-offset: 2px;
}

.ctf-badge-item:hover {
Expand Down Expand Up @@ -132,11 +140,19 @@

/* Active Challenge Card */
.ctf-challenge-card {
display: block;
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 0.5rem;
padding: 0.75rem;
transition: all 0.2s;
text-decoration: none;
color: inherit;
}

a.ctf-challenge-card:focus-visible {
outline: 2px solid #10b981;
outline-offset: 2px;
}

.ctf-challenge-card:hover {
Expand Down Expand Up @@ -199,12 +215,21 @@
border-radius: 0.5rem;
margin-bottom: 0.25rem;
animation: slideIn 0.3s ease-out;
text-decoration: none;
color: inherit;
cursor: pointer;
box-sizing: border-box;
}

.ctf-activity-item:hover {
background: rgba(255, 255, 255, 0.03);
}

.ctf-activity-item:focus-visible {
outline: 2px solid #10b981;
outline-offset: 2px;
}

@keyframes slideIn {
from {
opacity: 0;
Expand Down
3 changes: 2 additions & 1 deletion finbot/static/js/ctf/activity.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@
isLoading = true;

try {
const data = await CTF.getActivity({ page: nextPage, page_size: PAGE_SIZE });
const options = { page: nextPage, page_size: PAGE_SIZE };
const data = await CTF.getActivity(options);
const items = data.items || [];

if (append) {
Expand Down
22 changes: 13 additions & 9 deletions finbot/static/js/vendor/ctf_sidecar.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,10 @@ class CTFSidecar {
const rarityIcons = { common: '⭐', rare: '💎', epic: '🌟', legendary: '👑' };

grid.innerHTML = badges.map(badge => `
<div class="ctf-badge-item rarity-${badge.rarity}" title="${badge.title}">
<img src="/static/images/ctf/badges/${badge.icon_url}" alt="${badge.title}" class="w-6 h-6 object-contain"
<a href="/ctf/badges" class="ctf-badge-item rarity-${badge.rarity}" title="${this.escapeHtml(badge.title)}">
<img src="/static/images/ctf/badges/${badge.icon_url}" alt="${this.escapeHtml(badge.title)}" class="w-6 h-6 object-contain"
onerror="this.replaceWith(Object.assign(document.createElement('span'), { textContent: '${rarityIcons[badge.rarity] || '🏅'}', className: 'text-lg' }))">
</div>
</a>
`).join('');
}

Expand All @@ -202,15 +202,15 @@ class CTFSidecar {
}

container.innerHTML = challenges.map(c => `
<div class="ctf-challenge-card">
<a href="/ctf/challenges/${encodeURIComponent(String(c.id))}" class="ctf-challenge-card">
<div class="ctf-challenge-title">${this.escapeHtml(c.title)}</div>
<div class="ctf-challenge-meta">
<span class="ctf-challenge-points">${c.points} pts</span>
<span class="ctf-difficulty-badge ctf-difficulty-${c.difficulty}">${c.difficulty}</span>
<span>${c.category}</span>
<span>${this.escapeHtml(c.category)}</span>
${c.attempts > 0 ? `<span>• ${c.attempts} attempts</span>` : ''}
</div>
</div>
</a>
`).join('');
}

Expand All @@ -233,15 +233,19 @@ class CTFSidecar {
createActivityItem(activity) {
const icon = this.getActivityIcon(activity.category);
const timeAgo = this.formatTimeAgo(activity.timestamp);
const summaryText = activity.summary || activity.type || activity.event_type || '';

// For vendor portal sidecar, go to the activity stream.
const href = '/ctf/activity';

return `
<div class="ctf-activity-item">
<a href="${href}" class="ctf-activity-item ctf-activity-link" aria-label="Open activity">
<div class="ctf-activity-icon ${activity.category}">${icon}</div>
<div class="ctf-activity-content">
<div class="ctf-activity-summary">${this.escapeHtml(activity.summary || activity.type)}</div>
<div class="ctf-activity-summary">${this.escapeHtml(summaryText)}</div>
<div class="ctf-activity-time">${timeAgo}</div>
</div>
</div>
</a>
`;
}

Expand Down
Loading