Skip to content

feat(gradebook): weighted view with per-tab weights and exclude flag (pr3 of 3)#8419

Draft
LWS49 wants to merge 26 commits into
lws49/feat-gradebook-weights-pr2-apifrom
lws49/feat-gradebook-weights-pr3-fe
Draft

feat(gradebook): weighted view with per-tab weights and exclude flag (pr3 of 3)#8419
LWS49 wants to merge 26 commits into
lws49/feat-gradebook-weights-pr2-apifrom
lws49/feat-gradebook-weights-pr3-fe

Conversation

@LWS49

@LWS49 LWS49 commented May 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Implements the gradebook weighted view feature end-to-end. Adds a new staff-only gradebook page with two views: a flat "All assessments" table showing every published assessment, and a "By weight" view showing per-tab weighted totals (Canvas-style: Σ(tab% × weight), bonus allowed). The backend adds a gradebook_weight column on assessment tabs, grade summary queries, max-grade aggregation, and ability checks for staff read access and manager-only weight editing. The frontend adds a configurable per-tab weights dialog with an exclude-from-weighted-total flag, a course-admin toggle to enable the weighted view, and a one-time dismissable hint that surfaces the setting to managers before they've turned it on.

Design decisions

  • Weighted view is off by default - most courses won't use per-tab weights, so the majority gets no extra tab; managers who want it opt in via Course Settings → Gradebook. Always-on would impose a permanent extra tab and an opt-out chore on the majority.
  • Discoverability via a one-time dismissable Alert - mirrors the existing CourseSuspendedAlert pattern (MUI Alert + Link into admin settings). Hint is manager-gated (canManageWeights) and only shows while the setting is off, so it disappears once it's done its job.
  • localStorage dismissal scoped to ${userId}:${key} - matches the pattern already used in useTanStackTableBuilder; per-device behaviour is an accepted limitation for an onboarding nudge. Backend-persisted dismissal is the upgrade path if ever needed, deliberately deferred.

Regression prevention

Automated tests cover: weighted total computation including excluded tabs (computeWeighted.test.ts), ConfigureWeightsPrompt rendering and exclude toggle, GradebookTable and GradebookWeightedTable cell rendering, GradebookColumnTree, GradebookIndex routing and role gating, WeightedViewHint visibility and dismissal, useDismissibleOnce hook, GradebookSettings admin toggle, backend controller specs for index and update_weights, and model specs for Tab#gradebook_weight, Assessment.max_grades, Submission.grade_summary, and ability checks.

Manual testing confirmed: manager sees hint when weighted view is off; hint absent when weighted view is on; TA/staff sees no hint; dismiss persists across page reload; dismissed state is per-user (second manager sees it fresh); settings link navigates correctly to Course Settings → Gradebook.

Backward compat preserved - weighted view is additive; existing gradebook pages and assessment flows are unchanged.

@LWS49 LWS49 changed the title Lws49/feat gradebook weights pr3 fe feat(gradebook): add weighted view with per-tab grade weights May 29, 2026
@LWS49 LWS49 changed the title feat(gradebook): add weighted view with per-tab grade weights feat(gradebook): add weighted view with per-tab grade weights (pr3 of 3) May 29, 2026
@LWS49 LWS49 changed the base branch from master to lws49/feat-gradebook-weights-pr2-api May 29, 2026 06:29
@LWS49 LWS49 force-pushed the lws49/feat-gradebook-weights-pr2-api branch 5 times, most recently from 333c45a to 8b79b30 Compare June 4, 2026 06:07
@LWS49 LWS49 force-pushed the lws49/feat-gradebook-weights-pr3-fe branch 4 times, most recently from b37937a to d4661f1 Compare June 8, 2026 11:35
@LWS49 LWS49 changed the title feat(gradebook): add weighted view with per-tab grade weights (pr3 of 3) feat(gradebook): weighted view with per-tab weights and exclude flag (pr3 of 3) Jun 8, 2026
@LWS49 LWS49 changed the title feat(gradebook): weighted view with per-tab weights and exclude flag (pr3 of 3) feat(gradebook): weighted view with per-tab weights and exclude flag Jun 9, 2026
@LWS49 LWS49 force-pushed the lws49/feat-gradebook-weights-pr3-fe branch from 5508fd2 to 2f958d0 Compare June 9, 2026 03:20
@LWS49 LWS49 force-pushed the lws49/feat-gradebook-weights-pr3-fe branch 3 times, most recently from 0e5d992 to 0155581 Compare June 9, 2026 10:59
LWS49 added 2 commits June 9, 2026 23:30
Introduces a course-wide gradebook showing per-student grades across all assessments. Instructors can toggle which assessment columns are visible via a hierarchical column picker (grouped by category/tab), then export the current view to CSV.

Backend adds GradebookController#index (JSON), ability guard, and model methods on Assessment and Submission for fetching grade data.

Table lib gains reusable ColumnPickerTemplate, MuiColumnPickerPrompt, ColumnPickerTreeGroup, and toolbar integration used by the gradebook.
- Add gradebook_weight (0-100 integer) column to course_assessment_tabs
- Add manage_gradebook_weights/settings abilities (manager/owner only)
- Add Course Admin -> Gradebook settings page to toggle the setting
@LWS49 LWS49 force-pushed the lws49/feat-gradebook-weights-pr2-api branch from 1025c75 to dd2063a Compare June 9, 2026 15:43
LWS49 added 2 commits June 9, 2026 23:44
…alog, toolbar buttons, visibility state, and tests

    - Add MuiColumnPickerDialog with Apply/Export actions, locked-column enforcement, and optional dataColumnIds hint when no data columns are selected
    - Update MuiTableToolbar to render a trigger button (opens dialog) and a direct export button alongside the existing CSV download icon
    - Extend useTanStackTableBuilder with column visibility state (localStorage persistence, dynamic reconciliation), onExportFromPicker, onDirectExport, and cross-page selection helpers (selectedCount, toggleAllFiltered, etc.)
    - Add ColumnPickerTemplate interface and Body.ts selection fields
    - Add full test coverage for dialog, toolbar, and hook behaviour
    - Add lib.components.table.* locale keys (en/ko/zh)
- add Tab.update_gradebook_weights: transactional bulk update scoped to
  course tabs, with pre-flight ID validation and single pre-fetch query
- extend GET /gradebook index JSON with weightedViewEnabled,
  canManageWeights, and per-tab gradebookWeight (gated by setting)
- add PATCH /gradebook/weights: manager-only, returns 422 on validation
  failure or foreign tab, transactionally rolls back on any error
@LWS49 LWS49 force-pushed the lws49/feat-gradebook-weights-pr2-api branch from dd2063a to 7158142 Compare June 9, 2026 15:44
LWS49 added 3 commits June 9, 2026 23:50
…alog, toolbar buttons, visibility state, and tests

    - Add MuiColumnPickerDialog with Apply/Export actions, locked-column enforcement, and optional dataColumnIds hint when no data columns are selected
    - Update MuiTableToolbar to render a trigger button (opens dialog) and a direct export button alongside the existing CSV download icon
    - Extend useTanStackTableBuilder with column visibility state (localStorage persistence, dynamic reconciliation), onExportFromPicker, onDirectExport, and cross-page selection helpers (selectedCount, toggleAllFiltered, etc.)
    - Add ColumnPickerTemplate interface and Body.ts selection fields
    - Add full test coverage for dialog, toolbar, and hook behaviour
    - Add lib.components.table.* locale keys (en/ko/zh)
- Add gradebook_weight (0-100 integer) column to course_assessment_tabs
- Add Course::Settings::GradebookComponent with weighted_view_enabled
- Add manage_gradebook_weights/settings abilities (manager/owner only)
- Add Course Admin -> Gradebook settings page to toggle the setting
- add Tab.update_gradebook_weights: transactional bulk update scoped to
  course tabs, with pre-flight ID validation and single pre-fetch query
- extend GET /gradebook index JSON with weightedViewEnabled,
  canManageWeights, and per-tab gradebookWeight (gated by setting)
- add PATCH /gradebook/weights: manager-only, returns 422 on validation
  failure or foreign tab, transactionally rolls back on any error
@LWS49 LWS49 force-pushed the lws49/feat-gradebook-weights-pr3-fe branch from 0155581 to 9d6cff0 Compare June 9, 2026 15:52
@LWS49 LWS49 changed the title feat(gradebook): weighted view with per-tab weights and exclude flag feat(gradebook): weighted view with per-tab weights and exclude flag (pr3 of 3) Jun 9, 2026
…picker

- add GradebookWeightedTable with 3-row sticky header showing per-tab
  additive weighted subtotals and per-student totals
- add ConfigureWeightsPrompt for managers to edit tab weights (0–100)
  with real-time sum-to-100 warning and integer validation
- add All vs By-weight view toggle in GradebookIndex (role-aware)
- add column picker (Student info, Gamification groups); External ID
  defaults visible when any student has one, hidden otherwise
- add computeWeighted helpers (computeTabSubtotal, computeStudentTotal,
  sumWeights) with full test coverage
- add useDismissibleOnce hook for one-time dismissible hint UI
@LWS49 LWS49 force-pushed the lws49/feat-gradebook-weights-pr3-fe branch from 9d6cff0 to dba6faa Compare June 9, 2026 16:17
LWS49 added 18 commits June 10, 2026 17:21
Expose tab weight_mode and assessment gradebook_weight as numeric JSON fields in the
gradebook API when weighted view is enabled. Fixes BigDecimal string serialization
by using &.to_f for safe float conversion.
@LWS49 LWS49 force-pushed the lws49/feat-gradebook-weights-pr2-api branch from 7158142 to 3316f5d Compare June 11, 2026 07:03
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.

1 participant