Skip to content

Conversation

@devin-ai-integration
Copy link

@devin-ai-integration devin-ai-integration bot commented Jan 17, 2026

Summary

This PR adds a new "Training Days" page to the contest server for training programs, along with enhancements to display score information in both the contest server and admin interface.

New Training Days page (/training_days):

  • Shows "Ongoing and Upcoming Trainings" section with countdown timers and entry buttons
  • Shows "Past Trainings" section with training score and home score per archived training day
  • Includes sortable columns for date, training score, and home score
  • Visual status indicators: green "LIVE" pill for active trainings, red "ENDED" pill for completed trainings, blue countdown for upcoming

Task Archive table enhancements (training program overview):

  • Added "Assigned" date column with sorting
  • Added "Source" column showing which training day the task came from (or "Manual" for manual assignments)

Admin interface enhancements (student tasks page):

  • Added "Training Score" and "Home Score" columns to the assigned tasks table

Navigation enhancement:

  • Inside training day contests, the "Logout" button is replaced with a "Back to Training Program" button that returns users to the training program overview

Updates since last revision

  • Removed "Total" column from past trainings table (was redundant with home score)
  • Fixed "LIVE" indicator to not appear on ended trainings - now shows red "ENDED" pill when actual_phase >= 1
  • Changed LIVE pill color from red to green for better visual distinction
  • Fixed aria-valuenow clamping in progress bar (now properly clamped to 0-100 range)
  • Removed unused data-total-score attribute from past trainings table rows
  • Optimized N+1 queries in both TrainingDaysHandler and StudentTasksHandler by batch-fetching ArchivedStudentRanking records
  • Added "Back to Training Program" button in training day contests (replaces logout button since login is via training program)

Review & Testing Checklist for Human

  • Verify "Back to Training Program" button: Inside a training day contest, confirm the button appears instead of logout and correctly navigates to the training program overview
  • Verify "ended" logic: Trainings show "ENDED" when actual_phase >= 1. Confirm this threshold correctly identifies trainings that have finished.
  • Verify score calculation logic: Training score comes from ArchivedStudentRanking.task_scores, home score from participation.task_scores cache. Confirm this matches expected behavior.
  • Test with archived training days: The past trainings section only shows training days where contest is None. Verify this correctly identifies archived trainings.
  • Test sorting functionality: Click each sortable column header in both the task archive table and past trainings table to verify sorting works correctly.

Recommended test plan:

  1. Access a training program as a student
  2. Navigate to Training Days page and verify ongoing/upcoming trainings display correctly
  3. Verify active trainings show green "LIVE" pill, ended trainings show red "ENDED" pill
  4. Enter a training day contest and verify "Back to Training Program" button appears (not logout)
  5. Click the button and verify it returns to the training program overview
  6. Verify past trainings show with correct scores
  7. Test all sorting columns
  8. In admin, view a student's tasks and verify training/home scores display

Notes

  • The training_days.html template reuses styling patterns from training_program_overview.html for consistency
  • JavaScript countdown logic is duplicated from the overview page - could be refactored to shared code in future
  • CSS is currently inline in templates - could be moved to cws_style.css for better caching in future

Link to Devin run: https://app.devin.ai/sessions/331e76ca9c504acca396b205c653afda
Requested by: @ronryv

- Add 'Training Days' menu item to contest server training programs
- Create new TrainingDaysHandler and training_days.html template
- Show ongoing/upcoming trainings section with countdown timers
- Show past trainings with training score, home score, and total score
- Add training score and home score columns to admin archive table
- Add assigned date and training source columns to task archive table
- Add sorting capability for assigned date and source columns

Co-Authored-By: Ron Ryvchin <[email protected]>
@devin-ai-integration
Copy link
Author

devin-ai-integration bot commented Jan 17, 2026

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@coderabbitai
Copy link

coderabbitai bot commented Jan 17, 2026

Warning

Rate limit exceeded

@ronryv has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 10 minutes and 43 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 1c5fb37 and e17c4bd.

📒 Files selected for processing (8)
  • cms/server/admin/handlers/trainingprogram.py
  • cms/server/admin/templates/student_tasks.html
  • cms/server/contest/handlers/__init__.py
  • cms/server/contest/handlers/trainingprogram.py
  • cms/server/contest/static/cws_style.css
  • cms/server/contest/templates/contest.html
  • cms/server/contest/templates/training_days.html
  • cms/server/contest/templates/training_program_overview.html
📝 Walkthrough

Walkthrough

This PR enhances the training program feature by introducing a dedicated training days page with score tracking and improved user interface. It adds home and training score calculations to admin handlers and templates, implements a new TrainingDaysHandler for displaying ongoing/upcoming and past trainings with eligibility checks and timing computations, refactors the training overview page with sortable columns and improved progress bar styling, and includes client-side functionality for countdowns and sorting.

Changes

Cohort / File(s) Summary
Admin Score Enrichment
cms/server/admin/handlers/trainingprogram.py, cms/server/admin/templates/student_tasks.html
Reconstructs home_scores and training_scores from cached participation task_scores and ArchivedStudentRanking data; adds Training Score and Home Score columns to the Assigned Tasks table, displaying numeric scores or hyphens when unavailable.
Contest Handler Routing
cms/server/contest/handlers/__init__.py
Imports TrainingDaysHandler from trainingprogram module and registers it with the /training_days route.
Training Days Handler
cms/server/contest/handlers/trainingprogram.py
Introduces TrainingDaysHandler with get() method that computes ongoing/upcoming and past trainings using eligibility checks, timing computations, and ArchivedStudentRanking data; includes _build_past_training_info() helper for assembling past training metadata with per-task scores.
Progress Bar Styling
cms/server/contest/static/cws_style.css
Adds .progress-track and .progress-fill CSS components with color variants (high/med/low) for visual progress indicators.
Contest Navigation
cms/server/contest/templates/contest.html
Adds conditional Training Days navigation item shown when training_program exists, with active state highlighting.
Training Days Template
cms/server/contest/templates/training_days.html
New template rendering ongoing/upcoming trainings with countdowns and action controls, plus a sortable past trainings table with date, description, task details, and score columns; includes modals for delay requests and real-time countdown updates via client-side JavaScript.
Training Overview Refactor
cms/server/contest/templates/training_program_overview.html
Replaces inline progress bar with semantic progress-track element; adds sortable Assigned and Source columns to task archive table with data attributes for client-side sorting; updates task row styling and sorting logic.

Sequence Diagram

sequenceDiagram
    participant Client
    participant TrainingDaysHandler
    participant Participation
    participant ArchivedStudentRanking
    participant Template

    Client->>TrainingDaysHandler: GET /training_days
    activate TrainingDaysHandler
    
    alt Ongoing/Upcoming Trainings
        TrainingDaysHandler->>TrainingDaysHandler: check_training_day_eligibility
        TrainingDaysHandler->>TrainingDaysHandler: compute_effective_times
        TrainingDaysHandler->>Template: render ongoing_upcoming_trainings
    end
    
    alt Past Trainings (Archived)
        TrainingDaysHandler->>Participation: get cached task_scores
        TrainingDaysHandler->>ArchivedStudentRanking: fetch archived task_scores
        TrainingDaysHandler->>TrainingDaysHandler: _build_past_training_info
        TrainingDaysHandler->>Template: render past_trainings with scores
    end
    
    deactivate TrainingDaysHandler
    Template->>Client: Return training_days.html
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Daniel-Aga

Poem

🐰 A training days page hops into view,
With scores and past trainings, shiny and new!
Progress bars dance in colors so bright,
And countdowns tick down through the night.
Sorting and scoring, oh what a sight! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main feature being added: a Training Days page with scores and sorting functionality. It reflects the primary changes across multiple files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

ronryv and others added 2 commits January 17, 2026 16:09
- Remove Total column from past trainings table (same as home score)
- Add has_ended flag to handler for trainings with actual_phase >= 1
- Show red stripe and 'ENDED' label for ended trainings
- Change LIVE pill to green color for active trainings

Co-Authored-By: Ron Ryvchin <[email protected]>
@ronryv
Copy link
Collaborator

ronryv commented Jan 17, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 17, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@cms/server/contest/templates/training_days.html`:
- Around line 131-140: The current template uses contest_url("tasks", task.name,
"description") for every task but archived training days (pt where contest_id is
None) only have data in archived_tasks_data and will 404 when
TaskDescriptionHandler calls get_task; update the template logic around pt.tasks
(or where pt is iterated) to detect archived trainings (pt.contest_id is None)
and render task.name as plain text (no anchor) for those entries, preserving the
existing score span, so links are only generated for non-archived trainings that
have live contest tasks and continue to use contest_url for those.

In `@cms/server/contest/templates/training_program_overview.html`:
- Around line 111-119: The aria-valuenow on the .progress-track should be
clamped to 0–100 like the fill width; change the template to compute a clamped
value from the existing percentage (e.g. clamped = min(max(percentage, 0), 100))
and use that clamped value for aria-valuenow and for the progress-fill width
instead of the raw {{ percentage }} so both the accessibility attribute and
visual width stay consistent; update the progress-track div and progress-fill
usage of {{ percentage }} to reference the clamped variable.
🧹 Nitpick comments (5)
cms/server/contest/handlers/trainingprogram.py (2)

174-281: Consider extracting shared logic with TrainingProgramOverviewHandler.

The get() method duplicates significant logic from TrainingProgramOverviewHandler (student lookup, eligibility checks, timing computations, sorting). While the PR notes mention this for future refactor, extracting common helpers (e.g., _get_student_for_program, _compute_training_day_timing) would reduce maintenance burden.


298-303: Potential N+1 query for ArchivedStudentRanking.

This query runs once per past training day inside the loop (line 208). For students with many past trainings, this could cause performance issues. Consider fetching all ArchivedStudentRanking records for the student in a single query before the loop and indexing by training_day_id.

♻️ Suggested optimization
# Before the loop in get(), fetch all rankings at once:
if student is not None:
    all_rankings = {
        r.training_day_id: r
        for r in self.sql_session.query(ArchivedStudentRanking)
        .filter(ArchivedStudentRanking.student_id == student.id)
        .all()
    }
else:
    all_rankings = {}

# Then pass to _build_past_training_info and use:
archived_ranking = all_rankings.get(training_day.id)
cms/server/contest/templates/training_days.html (2)

121-121: Unused data-total-score attribute.

The data-total-score attribute is included but the "Total" column was removed per PR objectives. This is harmless but could be cleaned up for clarity.

♻️ Suggested cleanup
-        <tr data-training-score="{{ pt.training_score }}" data-home-score="{{ pt.home_score }}" data-total-score="{{ pt.max_score }}" data-date="{{ pt.start_time.timestamp() if pt.start_time else 0 }}">
+        <tr data-training-score="{{ pt.training_score }}" data-home-score="{{ pt.home_score }}" data-date="{{ pt.start_time.timestamp() if pt.start_time else 0 }}">

160-262: Consider moving styles to cws_style.css.

This is a substantial block of CSS (~100 lines) that would be better maintained in the shared stylesheet. This also enables caching and reduces template size.

cms/server/admin/handlers/trainingprogram.py (1)

1792-1811: Batch archived ranking lookups to avoid N+1 queries.

The per-task ArchivedStudentRanking query inside the loop can trigger many DB hits (and repeat work for the same training day). Prefetch by distinct source_training_day_id and map the results once.

♻️ Proposed refactor (batch ranking lookup)
         # Build training scores from archived student rankings
         training_scores = {}
-        for st in student.student_tasks:
-            if st.source_training_day_id is not None:
-                archived_ranking = (
-                    self.sql_session.query(ArchivedStudentRanking)
-                    .filter(ArchivedStudentRanking.training_day_id == st.source_training_day_id)
-                    .filter(ArchivedStudentRanking.student_id == student.id)
-                    .first()
-                )
-                if archived_ranking and archived_ranking.task_scores:
-                    task_id_str = str(st.task_id)
-                    if task_id_str in archived_ranking.task_scores:
-                        training_scores[st.task_id] = archived_ranking.task_scores[task_id_str]
+        source_training_day_ids = {
+            st.source_training_day_id
+            for st in student.student_tasks
+            if st.source_training_day_id is not None
+        }
+        archived_rankings = {}
+        if source_training_day_ids:
+            archived_rankings = {
+                r.training_day_id: r
+                for r in (
+                    self.sql_session.query(ArchivedStudentRanking)
+                    .filter(ArchivedStudentRanking.training_day_id.in_(source_training_day_ids))
+                    .filter(ArchivedStudentRanking.student_id == student.id)
+                    .all()
+                )
+            }
+
+        for st in student.student_tasks:
+            if st.source_training_day_id is None:
+                continue
+            archived_ranking = archived_rankings.get(st.source_training_day_id)
+            if archived_ranking and archived_ranking.task_scores:
+                task_id_str = str(st.task_id)
+                if task_id_str in archived_ranking.task_scores:
+                    training_scores[st.task_id] = archived_ranking.task_scores[task_id_str]

devin-ai-integration bot and others added 3 commits January 17, 2026 14:57
Changed task links from contest_url (managing contest) to use the
training program's URL pattern: /<training_program>/tasks/<task>/description

Co-Authored-By: Ron Ryvchin <[email protected]>
…1 queries

- Revert task link change (contest_url was correct)
- Fix aria-valuenow clamping in progress bar (0-100 range)
- Remove unused data-total-score attribute from training_days.html
- Optimize N+1 query in TrainingDaysHandler (batch ArchivedStudentRanking)
- Optimize N+1 query in StudentTasksHandler (batch ArchivedStudentRanking)

Co-Authored-By: Ron Ryvchin <[email protected]>
… pages

When inside a training day contest, show a 'Back to Training Program' button
instead of the logout button, since login is now via the training program.

Co-Authored-By: Ron Ryvchin <[email protected]>
@ronryv
Copy link
Collaborator

ronryv commented Jan 17, 2026

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Jan 17, 2026

✅ Actions performed

Full review triggered.

@ronryv ronryv merged commit 9413fb2 into training_program Jan 17, 2026
5 checks passed
ronryv added a commit that referenced this pull request Jan 22, 2026
* Add Training Days page to contest server with scores and sorting

- Add 'Training Days' menu item to contest server training programs
- Create new TrainingDaysHandler and training_days.html template
- Show ongoing/upcoming trainings section with countdown timers
- Show past trainings with training score, home score, and total score
- Add training score and home score columns to admin archive table
- Add assigned date and training source columns to task archive table
- Add sorting capability for assigned date and source columns

Co-Authored-By: Ron Ryvchin <[email protected]>

* styling

* Remove Total column and fix ended trainings display

- Remove Total column from past trainings table (same as home score)
- Add has_ended flag to handler for trainings with actual_phase >= 1
- Show red stripe and 'ENDED' label for ended trainings
- Change LIVE pill to green color for active trainings

Co-Authored-By: Ron Ryvchin <[email protected]>

* Fix task links in past trainings to use training program URL

Changed task links from contest_url (managing contest) to use the
training program's URL pattern: /<training_program>/tasks/<task>/description

Co-Authored-By: Ron Ryvchin <[email protected]>

* Address PR feedback: revert task link, fix aria-valuenow, optimize N+1 queries

- Revert task link change (contest_url was correct)
- Fix aria-valuenow clamping in progress bar (0-100 range)
- Remove unused data-total-score attribute from training_days.html
- Optimize N+1 query in TrainingDaysHandler (batch ArchivedStudentRanking)
- Optimize N+1 query in StudentTasksHandler (batch ArchivedStudentRanking)

Co-Authored-By: Ron Ryvchin <[email protected]>

* Replace logout button with 'Back to Training Program' in training day pages

When inside a training day contest, show a 'Back to Training Program' button
instead of the logout button, since login is now via the training program.

Co-Authored-By: Ron Ryvchin <[email protected]>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Ron Ryvchin <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants