From 950533d8dbc06186cba48816dda2a549ea2fefbb Mon Sep 17 00:00:00 2001 From: Seth Bernstein Date: Sun, 31 May 2026 08:53:51 -0400 Subject: [PATCH 1/4] add ab button --- .../templates/assignment/instructor/peer_dashboard.html | 8 +++++--- components/rsptx/templates/staticAssets/js/peer.js | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/components/rsptx/templates/assignment/instructor/peer_dashboard.html b/components/rsptx/templates/assignment/instructor/peer_dashboard.html index d868c1c00..b3ebc3f03 100644 --- a/components/rsptx/templates/assignment/instructor/peer_dashboard.html +++ b/components/rsptx/templates/assignment/instructor/peer_dashboard.html @@ -333,11 +333,13 @@

Question {{ current_qnum }} of {{ num_questions }}

or - {% if enable_ab %} - or + + {% if enable_ab %} +
+ After verbal: - {% endif %}
+ {% endif %}
diff --git a/components/rsptx/templates/staticAssets/js/peer.js b/components/rsptx/templates/staticAssets/js/peer.js index 1a7e4e28d..335a9ab09 100644 --- a/components/rsptx/templates/staticAssets/js/peer.js +++ b/components/rsptx/templates/staticAssets/js/peer.js @@ -1,7 +1,7 @@ // Configuration for the PI steps and helper functions to handle step progression in the instructor's interface const STEP_CONFIG = { vote1: { - next: ['makep', 'facechat', 'makeabgroups'], + next: ['makep', 'facechat'], status: 'Vote 1 Stopped' }, makep: { @@ -9,7 +9,7 @@ const STEP_CONFIG = { status: 'Text Chat in Progress…' }, facechat: { - next: ['vote2'], + next: ['vote2', 'makeabgroups'], status: 'In-person Chat in Progress…' }, makeabgroups: { From 707becf84cdc3dcadb558e553972aa1435a7dcb9 Mon Sep 17 00:00:00 2001 From: Seth Bernstein Date: Sun, 31 May 2026 09:23:28 -0400 Subject: [PATCH 2/4] persist ab group assignments to user_experiment table --- bases/rsptx/assignment_server_api/routers/peer.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bases/rsptx/assignment_server_api/routers/peer.py b/bases/rsptx/assignment_server_api/routers/peer.py index 957f8fd72..f75f89c14 100644 --- a/bases/rsptx/assignment_server_api/routers/peer.py +++ b/bases/rsptx/assignment_server_api/routers/peer.py @@ -38,6 +38,7 @@ fetch_course_students, fetch_api_token, fetch_question, + create_user_experiment_entry, ) from rsptx.db.models import UseinfoValidation, Useinfo from rsptx.db.async_session import async_session @@ -750,6 +751,12 @@ def process_peep( rslogger.debug(f"FINAL PEEPS IN CHAT = {peeps}") rslogger.debug(f"FINAL PEEPS IN PERSON = {peeps_in_person}") + experiment_id = f"{div_id}_ab" + for sid in peeps_in_person: + await create_user_experiment_entry(sid=sid, ab=experiment_id, group=0) + for sid in peeps_in_chat: + await create_user_experiment_entry(sid=sid, ab=experiment_id, group=1) + # Chat pairing for the remaining students in `peeps` done = len(peeps) == 0 while not done: From 011b39475c048d065c3d9039130cbd7e5ee067c3 Mon Sep 17 00:00:00 2001 From: Seth Bernstein Date: Wed, 3 Jun 2026 14:07:00 -0400 Subject: [PATCH 3/4] make A/B button available after any chat mode --- .../rsptx/templates/assignment/instructor/peer_dashboard.html | 1 - components/rsptx/templates/staticAssets/js/peer.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/components/rsptx/templates/assignment/instructor/peer_dashboard.html b/components/rsptx/templates/assignment/instructor/peer_dashboard.html index b3ebc3f03..9a5c90e61 100644 --- a/components/rsptx/templates/assignment/instructor/peer_dashboard.html +++ b/components/rsptx/templates/assignment/instructor/peer_dashboard.html @@ -336,7 +336,6 @@

Question {{ current_qnum }} of {{ num_questions }}

{% if enable_ab %}
- After verbal:
{% endif %} diff --git a/components/rsptx/templates/staticAssets/js/peer.js b/components/rsptx/templates/staticAssets/js/peer.js index 335a9ab09..6365889c7 100644 --- a/components/rsptx/templates/staticAssets/js/peer.js +++ b/components/rsptx/templates/staticAssets/js/peer.js @@ -5,7 +5,7 @@ const STEP_CONFIG = { status: 'Vote 1 Stopped' }, makep: { - next: ['vote2'], + next: ['vote2', 'makeabgroups'], status: 'Text Chat in Progress…' }, facechat: { From 3fa39077213154b2a8a29c87bcc2fd3ee5849d47 Mon Sep 17 00:00:00 2001 From: Seth Bernstein Date: Thu, 4 Jun 2026 11:24:47 -0400 Subject: [PATCH 4/4] sync pi fixes from feedback --- .../assignment_server_api/routers/peer.py | 1 - .../assignment/instructor/peer_dashboard.html | 23 +++++++++++++++- .../assignment/student/peer_question.html | 26 ++++++++++++++++++- .../rsptx/templates/staticAssets/js/peer.js | 19 +++----------- 4 files changed, 50 insertions(+), 19 deletions(-) diff --git a/bases/rsptx/assignment_server_api/routers/peer.py b/bases/rsptx/assignment_server_api/routers/peer.py index f75f89c14..3dcfb30e8 100644 --- a/bases/rsptx/assignment_server_api/routers/peer.py +++ b/bases/rsptx/assignment_server_api/routers/peer.py @@ -1229,7 +1229,6 @@ async def clear_pairs( @router.get("/course_students") -@instructor_role_required() @with_course() async def get_course_students( request: Request, diff --git a/components/rsptx/templates/assignment/instructor/peer_dashboard.html b/components/rsptx/templates/assignment/instructor/peer_dashboard.html index 9a5c90e61..4ad426016 100644 --- a/components/rsptx/templates/assignment/instructor/peer_dashboard.html +++ b/components/rsptx/templates/assignment/instructor/peer_dashboard.html @@ -240,6 +240,17 @@ #vote1details[open] summary::before { transform: rotate(90deg); } #vote1details summary:hover { color: var(--pi-teal-dark); } #vote1details > div { padding: 4px 16px 12px; font-size: 13px; color: var(--af-ink-2); } + + .pi-lineno { + display: inline-block; + min-width: 2em; + color: #999; + text-align: right; + border-right: 1px solid #ddd; + padding-right: 0.5em; + margin-right: 0.8em; + user-select: none; + } {% endblock %} @@ -271,7 +282,6 @@

Question {{ current_qnum }} of {{ num_questions }}

-
Vote 1 in Progress
{% if not is_last %} @@ -578,5 +588,16 @@

Question {{ current_qnum }} of {{ num_questions }}

}); syncActivityFlow(); } + + setTimeout(function addLineNumbers() { + document.querySelectorAll(".oneq pre").forEach(function (pre) { + var lines = pre.innerHTML.split("\n"); + if (lines.length <= 1) return; + if (lines[lines.length - 1].trim() === "") lines.pop(); + pre.innerHTML = lines.map(function (line, i) { + return '' + (i + 1) + "" + line; + }).join("\n"); + }); + }, 1000); {% endblock %} diff --git a/components/rsptx/templates/assignment/student/peer_question.html b/components/rsptx/templates/assignment/student/peer_question.html index 0fc0585c4..bdbba9d2d 100644 --- a/components/rsptx/templates/assignment/student/peer_question.html +++ b/components/rsptx/templates/assignment/student/peer_question.html @@ -30,6 +30,17 @@ .hidden-content { display: none; } + + .pi-lineno { + display: inline-block; + min-width: 2em; + color: #999; + text-align: right; + border-right: 1px solid #ddd; + padding-right: 0.5em; + margin-right: 0.8em; + user-select: none; + } {% endblock %} @@ -104,9 +115,11 @@

Peer Instruction: {{ assignment_name }}

@@ -201,5 +214,16 @@

Peer Instruction: {{ assignment_name }}

await setupPeerGroup(); } doIt(); + + setTimeout(function addLineNumbers() { + document.querySelectorAll(".oneq pre").forEach(function (pre) { + var lines = pre.innerHTML.split("\n"); + if (lines.length <= 1) return; + if (lines[lines.length - 1].trim() === "") lines.pop(); + pre.innerHTML = lines.map(function (line, i) { + return '' + (i + 1) + "" + line; + }).join("\n"); + }); + }, 1000); {% endblock %} diff --git a/components/rsptx/templates/staticAssets/js/peer.js b/components/rsptx/templates/staticAssets/js/peer.js index 6365889c7..4308401a9 100644 --- a/components/rsptx/templates/staticAssets/js/peer.js +++ b/components/rsptx/templates/staticAssets/js/peer.js @@ -236,7 +236,7 @@ function connect(event) { } } else { if (getVoteNum() < 2) { - messarea.innerHTML = `

Please give an explanation for your answer.

Then, discuss your answer with your group members.

`; + messarea.innerHTML = `

Wait for your instructor to start the discussion.

`; } else { messarea.innerHTML = `

Voting for this question is complete.

`; let feedbackDiv = document.getElementById(`${currentQuestion}_feedback`); @@ -354,20 +354,7 @@ function connect(event) { } } - if (displayPeers.length > 0) { - messarea.innerHTML = `

Current Verbal Discussion Group

Please have a verbal discussion with your selected partners:

`; - } else { - // fallback to server-provided group list - messarea.innerHTML = `

Current Verbal Discussion Group

Please have a verbal discussion with the following group:

`; - } + messarea.innerHTML = `

Current Verbal Discussion Group

Please have a verbal discussion with your group, then select who you talked to below.

`; let facechat = document.getElementById("group_select_panel"); if (facechat) { @@ -805,7 +792,7 @@ async function setupPeerGroup() { } // Make the select element searchable with multiple selections $('.assignment_partner_select').select2({ - placeholder: "Select up to 4 team members", + placeholder: "Click to search or select by name", allowClear: true, maximumSelectionLength: 4, });