Skip to content

Split Course Settings Into Multiple Pages - #453

Merged
cycomachead merged 28 commits into
mainfrom
cycomachead/145-basic-course-settings-refactor-the-sidebar-for-settings-to-be-a-links-under-a-collapsible-heading/1
Aug 6, 2026
Merged

Split Course Settings Into Multiple Pages#453
cycomachead merged 28 commits into
mainfrom
cycomachead/145-basic-course-settings-refactor-the-sidebar-for-settings-to-be-a-links-under-a-collapsible-heading/1

Conversation

@cycomachead

Copy link
Copy Markdown
Contributor

General Info

Changes

Refactors the course settings UI from a single tabbed page into focused, bookmarkable pages grouped under a collapsible "Course Settings" sidebar heading. Adds a new Course Details page for editing course name, code, and semester.

Approach: Course Details lives on courses#edit/update (it edits the Course record itself, so it belongs on the conventional resource route). Approvals and Email Templates share CourseSettingsController since they both edit CourseSettings — mirroring the existing FormSettingsController pattern. All settings URLs now live under /courses/:id/settings/.

Key changes:

  • Split the old tabbed settings page into two distinct pages: /settings/approvals and /settings/emails. Removes the ?tab= query param + JS history.pushState hack.
  • New Course Details page (courses#edit) exposes name, code, and semester. Semester uses season + year dropdowns (Winter/Spring/Summer/Fall, 2012–next year). If the stored value doesn't match the expected format, it's displayed as-is with the dropdowns left blank.
  • Sidebar "Settings" link replaced with a collapsible "Course Settings" group containing: Course Details, Approvals, Email Templates, Request Form. Auto-expands and highlights the active page.
  • Replaced scattered @side_nav = '...' ivar assignments with a single ApplicationHelper#sidebar_section helper that derives the active nav key from controller_name/action_name.
  • Replaced inline unless @role == 'instructor' checks with a before_action :require_course_instructor on CoursesController.
  • Adds a demo_course boolean column (default false) to Course to flag sandbox/demo courses for usage tracking. No behavioral effect.

Testing

  • RSpec: 446 examples, 0 failures
  • Cucumber (course_settings, form_settings features): 7 scenarios, 59 steps, all passing
  • Controller specs added for CoursesController#update (name/code/semester update, blank-dropdown preservation, non-instructor redirect, validation failure) and CourseSettingsController#approvals/#emails
  • Helper spec added covering all sidebar_section mappings
  • Model specs added for Course.semester_year_options and Course.parse_semester (valid input, unrecognized season, out-of-range year, malformed input)

Screenshots

Documentation

No documentation changes required.

Checklist

  • Name of branch corresponds to story

Superconductor Ticket Implementation | App Preview | Guided Review

cycomachead and others added 8 commits June 23, 2026 01:36
Replace the single tabbed Settings page (?tab=general|email) with two
distinct, bookmarkable pages served by CourseSettingsController:

- GET /courses/:id/course_settings/approvals
- GET /courses/:id/course_settings/emails
- PATCH /courses/:id/course_settings (update, redirects back via :page)

Distinct routes are more idiomatic than query-param tabs: each page has
its own URL and focused view, the brittle JS history/?tab= hack is gone,
and it mirrors the existing nested form_setting resource.

The old /courses/:id/edit now redirects to the Approvals page; its tabbed
view is removed and the unused Stimulus tab code is dropped. Sidebar and
in-page links are repointed at the new routes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Repurpose CoursesController#edit (and add #update) to edit the course
itself: name, code and semester. Editing the Course model belongs on the
courses resource, so this reuses the conventional edit/update routes
(GET /courses/:id/edit, PATCH /courses/:id).

Semester is entered as a season + year pair. Years run from 2012 through
next year (Course.semester_year_options); Course.parse_semester splits a
stored value into [season, year] when it is well formed, so the dropdowns
pre-select valid values and stay blank for anything in an unexpected
format, while the raw value is still shown beneath the picker. The stored
semester is only overwritten when both dropdowns are set, preserving a
malformed value the picker could not represent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the single Settings link (and the separate Form link) with a
collapsible "Settings" heading that expands to four pages: Course
Details, Approvals, Email Templates and Request Form. The group is
expanded and highlighted whenever the current page is one of them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the per-action @side_nav instance variable (set in four
controllers) with ApplicationHelper#sidebar_section, which maps the
current controller_name/action_name to a sidebar key. The view layer now
owns navigation-highlight logic instead of every controller action having
to remember to set an ivar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The collapsible group is now labelled "Course Settings". Only the
selected sub-page is highlighted — the parent header no longer gets the
active (yellow) treatment, so a single item reads as current. The header
keeps its collapse toggle and stays expanded on any settings page.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Route the settings pages under a clean /courses/:id/settings/ prefix
  (approvals, emails, form) and drop the redundant "course" from the URL;
  path helpers are unchanged.
- Move Course Details instructor check into a require_course_instructor
  before_action for consistent permissions.
- Order semester seasons Winter→Spring→Summer→Fall.
- Drop explanatory comments flagged in review.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Boolean column (default false) marking sandbox/demo courses, e.g. the
developer-login test course seeded in development. It only helps track
usage so these can be excluded from real metrics and has no effect on
behavior. Seed the DEV101 course with it enabled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-course-settings-refactor-the-sidebar-for-settings-to-be-a-links-under-a-collapsible-heading/1
@cycomachead cycomachead changed the title Basic Course Settings: * Refactor the Sidebar for 'Settings' to be a links under a collapsible heading: * Course Details * Approvals * Em... Split Course Settings Into Multiple Pages Jun 27, 2026
cycomachead and others added 2 commits July 1, 2026 19:12
…omachead/145-basic-course-settings-refactor-the-sidebar-for-settings-to-be-a-links-under-a-collapsible-heading/1

* 'main' of github.com:berkeley-cdss/flextensions:
  chore: autocorrect RSpec/MatchWithSimpleRegex offenses
  chore: use Rails.env.local? for developer provider gate
  refactor: simplify developer login gate and trim comments
  fix: prevent account takeover by splitting user lookup paths
  refactor: remove redundant TokenRefreshable from SessionController
  feat: update assignments table styling and sync functionality
  feat: extend user sessions via token refresh and persistent cookies
  tweak postion of the page size dropdown
  style(test): fix rubocop layout offenses in staging interceptor spec
  feat: implement email interceptor for staging environment
  Bump json from 2.19.5 to 2.20.0
  Bump rubocop-rspec from 3.9.0 to 3.10.2
  Bump sentry-rails from 6.5.0 to 6.6.2
  Bump axe-core-rspec from 4.11.3 to 4.12.0
  Bump brakeman from 8.0.4 to 8.0.5
  feat: update pagination and page size options for pending requests
  refactor: trust top-level base dates, drop all_dates parsing
  refactor: simplify Canvas base-date handling and document the API
  feat: group Canvas overrides by extension length
  fix: audit and resolve Canvas assignment override bugs
- Rename the "Approvals" page/link to "Automatic Approvals" and leave only
  the auto-approval rules on it.
- Move the extensions toggle, Gradescope, and notification (email + Slack)
  sections onto Course Details, along with the delete-course button.
  courses#update now saves the Course and its CourseSettings together and
  sends the Slack ping when the webhook is newly enabled; the Slack logic
  is removed from course_settings#update.
- Show "Unknown Semester" on Course Details when the course has no semester.
- Reduce the sidebar sub-item indentation so titles no longer wrap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@cycomachead

Copy link
Copy Markdown
Contributor Author

This is close, but will maybe wait until after I merge in the background job settings?

@cycomachead cycomachead added enhancement New feature or request UX labels Jul 2, 2026
@cycomachead

Copy link
Copy Markdown
Contributor Author
Screenshot 2026-07-01 at 7 18 19 PM

cycomachead and others added 3 commits July 2, 2026 02:57
- Consolidate the default email subject/template onto CourseSettings
  (heredoc) and reference it from the reset action, the Canvas import, and
  the Email Templates view; drop the duplicate controller constants.
- Set @course_settings via a single set_course_settings before_action.
- Redirect settings updates back to the originating page with
  redirect_back_or_to instead of a page-param helper; drop the page field.
- Authorize Course Details with course.course_staff? rather than a role
  string, and drop the leftover action comments.
- Add a "Demo course" checkbox to Course Details (permit demo_course).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Move slack_webhook_just_enabled? and slack_enabled_message onto
  CourseSettings, where the state they read lives; the controller just
  orchestrates the notify call.
- Rename ApplicationHelper#sidebar_section to current_nav_page.
- Replace the _sidebar_menu_item partial with a sidebar_nav_item helper
  that derives active state from current_nav_page and takes either a
  text: label or a block (used for the requests badge).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- "Reset to Default" is now a client-side action: a Stimulus controller
  fills the subject/body fields from defaults sent down in the HTML. The
  user must still Save to persist, so the reset click is non-destructive.
  Removed the reset_email_template server branch and its route flow.
- sidebar_nav_item sets aria-current="page" on the active link.
- Drop the redundant current_nav_page comment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@cycomachead cycomachead mentioned this pull request Jul 2, 2026
20 tasks
cycomachead and others added 11 commits July 4, 2026 01:37
…or-the-sidebar-for-settings-to-be-a-links-under-a-collapsible-heading/1
…-course-settings-refactor-the-sidebar-for-settings-to-be-a-links-under-a-collapsible-heading/1

# Conflicts:
#	app/controllers/course_settings_controller.rb
#	app/controllers/courses_controller.rb
#	app/controllers/requests_controller.rb
#	app/javascript/controllers/course_settings_controller.js
#	app/models/course.rb
#	app/models/course_settings.rb
#	app/views/courses/edit.html.erb
#	app/views/layouts/_sidebar.html.erb
#	db/schema.rb
#	spec/controllers/course_settings_controller_spec.rb
#	spec/features/accessibility_spec.rb
Post-merge fixes integrating main:
- Course Details update uses params.expect and staff_user?/require_course_staff!;
  drop the removed @role/determine_user_role path.
- Carry main's pending-notification fields onto the Course Details
  Notifications section and permit them in courses#update; keep the
  approvals/emails split trimmed to their own fields.
- Keep togglePendingNotificationEmail in the Stimulus controller; drop the
  obsolete tab logic.
- Move pending-notification controller specs onto CoursesController; fix
  Enrollment/lms_id usage in the settings specs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
oauth2 >= 2.0 raises when OAuth2::AccessToken is built with a blank
token, which the developer omniauth provider always has. Fall back to a
stub token so local developer login works again.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nges warning

- Rename the "Extensions" card to "Enable Extensions"; when student requests
  are off, highlight it with an info border + explanatory notice, and render
  the toggle as an enlarged .checkbox-xl switch.
- Delete Course button now reads exactly "Delete Course"; when extensions are
  enabled (delete not allowed) it is disabled and a Bootstrap tooltip (new
  tooltip Stimulus controller) explains why.
- Add an unsaved-changes Stimulus controller: any settings change shows a toast
  and arms a beforeunload prompt; saving clears both.
- Add Capybara feature specs (rack_test for the server-rendered states, a
  :js/:a11y example for the toast + save-clears-warning flow).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-course-settings-refactor-the-sidebar-for-settings-to-be-a-links-under-a-collapsible-heading/1

# Conflicts:
#	spec/Helpers/application_helper_spec.rb
- Add a Slack webhook instructions link + "individual Slack message" note
  below the webhook box on Course Details.
- Move the Enable email notifications toggle and Course Reply Email Address
  off Course Details onto the Email Templates page (below an hr), and permit
  those fields on course_settings#update instead of courses#update.
- Rename the Course Details "Notifications" card to "Staff Notifications".
- Update controller + feature specs for the new field placement.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Reorder the Email Templates card: the guidance note, Enable email
  notifications toggle, and Course Reply Email Address now sit above the
  subject/body template (separated by an hr).
- Add an info note at the top explaining what the notifications do, the
  recommendation to keep them enabled with a monitored reply-to, the
  upcoming approve/deny template split, and the noreply guidance.
- Extend the feature spec to assert the guidance text and the ordering.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-course-settings-refactor-the-sidebar-for-settings-to-be-a-links-under-a-collapsible-heading/1

# Conflicts:
#	app/views/courses/edit.html.erb
#	spec/Helpers/application_helper_spec.rb
…tings-refactor-the-sidebar-for-settings-to-be-a-links-under-a-collapsible-heading/1' into cycomachead/145-basic-course-settings-refactor-the-sidebar-for-settings-to-be-a-links-under-a-collapsible-heading/1
…bar-for-settings-to-be-a-links-under-a-collapsible-heading/1' of github.com:berkeley-cdss/flextensions into cycomachead/145-basic-course-settings-refactor-the-sidebar-for-settings-to-be-a-links-under-a-collapsible-heading/1

* 'cycomachead/145-basic-course-settings-refactor-the-sidebar-for-settings-to-be-a-links-under-a-collapsible-heading/1' of github.com:berkeley-cdss/flextensions: (236 commits)
  Show staff notes via a click popover on a button, not a hover tooltip
  Fix enrollments page tooltips/popovers not loading
  feat: refine instructor request review display
  Email Templates: move email settings above the template and add guidance
  Add text about shared notes status
  show notes on the enrollments page via tooltip
  db:migrate
  undo file rename (migrations were already run)
  feat: add student review context and history to instructor view
  Tidy the footer a bit
  Reorganize the sync buttons on the assignments page
  Update cron job times to 4:00PM
  feat: add instructor review context to request show page
  feat: add hourly email notifications and enable GoodJob cron
  Move email settings to Email Templates; add Slack webhook instructions
  refactor: left-align emails and add copy-to-clipboard functionality
  Course Details: enable-extensions emphasis, delete guard, unsaved-changes warning
  feat: add deployment timestamp and commit SHA to footer
  feat: add release date to assignments
  feat: implement Null Object Pattern for current_user
  ...
…or-the-sidebar-for-settings-to-be-a-links-under-a-collapsible-heading/1

* main:
  fix: restrict API write endpoints to test environment
  perf: preload and cache Canvas LMS entry at boot
…aved-changes

- Seed DEFAULT_EMAIL_SUBJECT/TEMPLATE on the course_settings row at
  creation (before_create) and drop the email_subject DB column default.
- Sidebar: rename 'Request for Student' to 'New Request' and pin the
  sidebar to a fixed 250px so opening/closing the submenu no longer shifts
  its width.
- Course Details: move the Enable Extensions card to the top of the page.
- Add the unsaved-changes toast + beforeunload warning to the Automatic
  Approvals, Email Templates, and Request Form pages via a shared partial.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@cycomachead
cycomachead merged commit e9e8cc8 into main Aug 6, 2026
13 checks passed
@cycomachead
cycomachead deleted the cycomachead/145-basic-course-settings-refactor-the-sidebar-for-settings-to-be-a-links-under-a-collapsible-heading/1 branch August 6, 2026 09:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request UX

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant