Skip to content

Commit ed893ae

Browse files
committed
Merge branch 'main' into async-toggle
2 parents f6e1af6 + 861470a commit ed893ae

71 files changed

Lines changed: 6620 additions & 789 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/test-crud.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: Tests
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- 'components/rsptx/db/**'
7+
- 'components/rsptx/configuration/**'
8+
- 'components/rsptx/validation/**'
9+
- 'components/rsptx/response_helpers/**'
10+
- 'components/rsptx/endpoint_validators/**'
11+
- 'bases/rsptx/book_server_api/**'
12+
- 'bases/rsptx/assignment_server_api/**'
13+
- 'test/**'
14+
- '.github/workflows/test-crud.yml'
15+
- 'pyproject.toml'
16+
17+
jobs:
18+
crud-tests:
19+
runs-on: ubuntu-latest
20+
21+
services:
22+
postgres:
23+
image: postgres:16
24+
env:
25+
POSTGRES_USER: runestone
26+
POSTGRES_PASSWORD: runestone
27+
POSTGRES_DB: runestone_test
28+
ports:
29+
- 5432:5432
30+
options: >-
31+
--health-cmd pg_isready
32+
--health-interval 10s
33+
--health-timeout 5s
34+
--health-retries 5
35+
36+
env:
37+
SERVER_CONFIG: test
38+
TEST_DBURL: postgresql://runestone:runestone@localhost:5432/runestone_test
39+
DROP_TABLES: "Yes"
40+
41+
steps:
42+
- name: Checkout code
43+
uses: actions/checkout@v4
44+
45+
- name: Set up Python
46+
uses: actions/setup-python@v5
47+
with:
48+
python-version: '3.10'
49+
50+
- name: Install Poetry
51+
uses: snok/install-poetry@v1
52+
with:
53+
virtualenvs-create: true
54+
virtualenvs-in-project: true
55+
56+
- name: Cache Poetry virtualenv
57+
uses: actions/cache@v4
58+
with:
59+
path: .venv
60+
key: venv-${{ runner.os }}-py3.10-${{ hashFiles('pyproject.toml', 'poetry.lock') }}
61+
restore-keys: |
62+
venv-${{ runner.os }}-py3.10-
63+
64+
- name: Install dependencies
65+
run: poetry install --with dev --no-interaction
66+
67+
- name: Run tests
68+
run: |
69+
poetry run pytest -v --tb=short

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ __pycache__
1212
.ssh
1313
.nova
1414
.env
15+
.env.backup*
1516
logfiles
1617
datashop
1718
build_info
@@ -33,3 +34,5 @@ _build
3334
**/test/_static
3435
bake.log
3536
WARP.md
37+
init_runestone.log
38+
.claude

CHANGELOG.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,43 @@
11
# ChangeLog
22

3+
## Updates since last changelog entry (2026-02-28 → 2026-03-13)
4+
5+
Coverage: changes merged/landed after the previous changelog update commit on **2026-02-28**, through **2026-03-13**.
6+
7+
### Highlights
8+
9+
- **Assignment visibility / date logic (issue-814):** enhanced visibility control logic and UI to support dual date display, including related plumbing (merge of the issue-814 workstream).
10+
- **Assignment list UX:** added sorting in `AssignmentList` with persistence via `localStorage`.
11+
- **Accessibility + theming:** WCAG AA fixes for assignment navigation links and dark-mode color adjustments.
12+
- **Peer Instruction grading correctness:** restored `studentVoteCount` increment for sync PI grading.
13+
- **Interactives fixes + polish:**
14+
- Matching: use `queuMathJax` instead of `typesetPromise`.
15+
- Multiple choice: ensure MathJax renders in feedback.
16+
- ShortAnswer: preserve event handlers when rebuilding.
17+
- ActiveCode: updated hotkeys/keybindings.
18+
- **Ops / tooling:** added pre-commit configuration, updated dependencies, and bumped releases (**7.11.18**, **7.11.19**) with assorted bugfixes; also updated `pgcli`.
19+
20+
### Commit notes (for reference)
21+
22+
- 7f2ec9c8 update - bugfixes
23+
- 7375c073 Release 7.11.18
24+
- e02df4fd update pgcli
25+
- 5cfa6569 ShortAnswer: preserve event handlers when building
26+
- 67e6d21e CSS: override bootstrap summary styling
27+
- 6c5fe9ea Fix: make sure to render mathjax in mchoice feedback
28+
- d78bebb1 Matching: use queuMathJax instead of typesetPromise
29+
- ffaf9192 fix activities required for new logic
30+
- b2e38cd9 issue-814 Enhance visibility control logic and UI to support dual date display
31+
- 70ff1e55 issue-1145 Implement sorting functionality in AssignmentList with localStorage persistence
32+
- 5815b226 issue-814 Rename created_date to updated_date in assignments and related components
33+
- f2581a22 Update activecode keybindings
34+
- 65e2bca3 Add pre-commit configuration and update dependencies in pyproject.toml
35+
- 27cb3b60 restore studentVoteCount increment for sync PI grading
36+
- cfa3ea2a WCAG AA fix for assignment nav links
37+
- 7ec65dae WCAG AA fix for darkmode grayToWhite
38+
39+
---
40+
341
## Updates since last changelog entry (2026-02-21 → 2026-02-27)
442

543
Coverage: commits from **2026-02-21** through **2026-02-27** (i.e., changes after the prior cutoff on 2026-02-20).

README.rst

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,45 @@ If you want to do development on Runestone, or run your own server, you will nee
1717

1818
.. image:: https://readthedocs.org/projects/runestone-monorepo/badge/?version=latest
1919
:target: https://runestone-monorepo.readthedocs.io/en/latest/?badge=latest
20-
:alt: Documentation Status
20+
:alt: Documentation Status
21+
22+
.. image:: https://github.com/RunestoneInteractive/rs/actions/workflows/test-crud.yml/badge.svg
23+
:target: https://github.com/RunestoneInteractive/rs/actions/workflows/test-crud.yml
24+
:alt: Tests
2125

2226
Chat with us on `Discord <https://discord.gg/f3Qmbk9P3U>`_
2327

28+
Quick Start: Run Your Own Runestone Server
29+
===========================================
30+
31+
Get a fully functional Runestone server running on your local machine with a single command:
32+
33+
.. code-block:: bash
34+
35+
bash <(curl -fsSL https://raw.githubusercontent.com/RunestoneInteractive/rs/main/init_runestone.sh)
36+
37+
The setup script will guide you through an interactive installation process.
38+
39+
**Prerequisites:**
40+
41+
* Docker Desktop with Docker Compose 2.20.2 or later
42+
* WSL2 (Windows users only - run the command from a WSL2 terminal)
43+
* Git (optional, but recommended for cloning book repositories)
44+
45+
**Before you start:**
46+
47+
Navigate to the directory where you want Runestone configuration files created:
48+
49+
.. code-block:: bash
50+
51+
mkdir ~/runestone && cd ~/runestone
52+
53+
**After installation:**
54+
55+
* Access your server at http://localhost
56+
* Log in with username: ``testuser1``, password: ``xxx``
57+
* See the `Running a Server guide <https://runestone-monorepo.readthedocs.io/en/latest/running.html>`_ for complete documentation
58+
2459
Runestone MonoRepo
2560
==================
2661

bases/rsptx/admin_server_api/routers/lti1p3.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import uuid
2323
import os
2424
import tldextract
25+
from zoneinfo import ZoneInfo
2526

2627
# Third-party imports
2728
# -------------------
@@ -42,6 +43,7 @@
4243
# -------------------
4344
from rsptx.db.models import (
4445
AuthUserValidator,
46+
Courses,
4547
CoursesValidator,
4648
Lti1p3Conf,
4749
Lti1p3User,
@@ -461,7 +463,7 @@ async def launch(request: Request):
461463
# make sure RS assignment is up to date (e.g. end date)
462464
course_attributes = await fetch_all_course_attributes(course.id)
463465
await update_rsassignment_from_lti(
464-
rs_assign, assign_lineitem, course_attributes
466+
rs_assign, assign_lineitem, course_attributes, course
465467
)
466468

467469
# start redirect to assignment
@@ -508,14 +510,34 @@ async def update_lti_assignment_record(
508510

509511

510512
async def update_rsassignment_from_lti(
511-
assign: AssignmentValidator, line_item: LineItem, course_attributes: dict
513+
assign: AssignmentValidator,
514+
line_item: LineItem,
515+
course_attributes: dict,
516+
course: Courses,
512517
) -> AssignmentValidator:
513518
"""
514519
Update a runestone assignment from LTI data.
515520
"""
516521
try:
517522
lms_due_string = line_item.get_end_date_time()
518-
lms_due = datetime.datetime.fromisoformat(lms_due_string)
523+
rslogger.info(
524+
f"LTI1p3 - Received {lms_due_string} for assignment {assign.name}"
525+
)
526+
527+
# Parse ISO datetime. Normalize trailing Z so fromisoformat can parse UTC.
528+
normalized_due_string = (
529+
lms_due_string.replace("Z", "+00:00")
530+
if lms_due_string.endswith("Z")
531+
else lms_due_string
532+
)
533+
lms_due = datetime.datetime.fromisoformat(normalized_due_string)
534+
535+
# If LMS provided timezone info and course has a timezone, convert to course local time.
536+
if lms_due.tzinfo is not None and course.timezone:
537+
lms_due = lms_due.astimezone(ZoneInfo(course.timezone))
538+
rslogger.info(
539+
f"LTI1p3 - Converted to {lms_due} in timezone {course.timezone}"
540+
)
519541
lms_due = lms_due.replace(tzinfo=None)
520542
if (
521543
lms_due is not None
@@ -1125,7 +1147,9 @@ async def assign_select(launch_id: str, request: Request, course=None):
11251147
)
11261148
await ags.update_lineitem(line_item)
11271149
# update RS due date
1128-
await update_rsassignment_from_lti(assign, line_item, course_attributes)
1150+
await update_rsassignment_from_lti(
1151+
assign, line_item, course_attributes, course
1152+
)
11291153
deep_link = message_launch.get_deep_link()
11301154
response_html = deep_link.output_response_form(response_list)
11311155
response = HTMLResponse(content=response_html, status_code=200)

bases/rsptx/assignment_server_api/assignment_builder/package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bases/rsptx/assignment_server_api/assignment_builder/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"@tiptap/suggestion": "^2.11.5",
4242
"better-react-mathjax": "^2.1.0",
4343
"classnames": "^2.5.1",
44+
"driver.js": "^1.4.0",
4445
"handsontable": "^14.2.0",
4546
"highlight.js": "^11.11.1",
4647
"html-react-parser": "^5.1.18",

bases/rsptx/assignment_server_api/assignment_builder/src/components/routes/AssignmentBuilder/components/exercises/AssignmentExercisesList/AssignmentExercisesContainer.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { EditView } from "./EditView";
1818
import { ErrorDisplay } from "./ErrorDisplay";
1919
import { ExerciseListView } from "./ExerciseListView";
2020
import { ExerciseSuccessDialog } from "./ExerciseSuccessDialog";
21-
import { AssignmentExercisesComponentProps, ViewMode } from "./types";
21+
import { AssignmentExercisesComponentProps } from "./types";
2222

2323
export const AssignmentExercisesContainer = ({
2424
startItemId,
@@ -100,7 +100,14 @@ export const AssignmentExercisesContainer = ({
100100

101101
{viewMode === "browse" && <ChooseExercises />}
102102

103-
{viewMode === "search" && <SmartSearchExercises />}
103+
{viewMode === "search" && (
104+
<SmartSearchExercises
105+
setCurrentEditExercise={setCurrentEditExercise}
106+
setViewMode={(mode: "list" | "browse" | "search" | "create" | "edit") =>
107+
updateExerciseViewMode(mode)
108+
}
109+
/>
110+
)}
104111

105112
{viewMode === "create" && (
106113
<CreateView

bases/rsptx/assignment_server_api/assignment_builder/src/components/routes/AssignmentBuilder/components/exercises/AssignmentExercisesList/AssignmentExercisesTable.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,6 @@ export const AssignmentExercisesTable = ({
395395
visible={copyModalVisible}
396396
onHide={handleCopyModalHide}
397397
exercise={selectedExerciseForCopy}
398-
copyToAssignment={true}
399398
setCurrentEditExercise={setCurrentEditExercise}
400399
setViewMode={setViewMode}
401400
/>

0 commit comments

Comments
 (0)