Skip to content

Conversation

@rlorenzo
Copy link
Contributor

  • Add My Effort page for instructors to self-verify effort data
  • Implement verification reminder emails (individual and bulk)
  • Add VerificationController/Service with Razor email templates
  • Show verification status on instructor list with email buttons

- Add My Effort page for instructors to self-verify effort data
- Implement verification reminder emails (individual and bulk)
- Add VerificationController/Service with Razor email templates
- Show verification status on instructor list with email buttons
Copilot AI review requested due to automatic review settings January 24, 2026 07:06
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds instructor self-service effort verification and verification reminder emailing, including Razor-based email template rendering and UI updates to support verification workflows.

Changes:

  • Introduces Effort verification API (controller/service), settings, DTOs, and Razor email template(s) for verification reminders.
  • Adds shared Razor email templating infrastructure (layout + renderer) and migrates ClinicalScheduler “Primary Evaluator Removed” email to Razor templates.
  • Updates Vue Effort UI to add a “My Effort” page, show verification status, and provide single/bulk verification email actions.

Reviewed changes

Copilot reviewed 56 out of 56 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
web/appsettings.json Adds default Effort verification email settings.
web/appsettings.Test.json Adds EffortSettings BaseUrl for test environment links.
web/appsettings.Production.json Adds EffortSettings BaseUrl for production environment links.
web/Viper.csproj Adds Razor.Templating.Core dependency.
web/Program.cs Registers VerificationService, EffortSettings options, and Razor templating services.
web/EmailTemplates/Views/_ViewImports.cshtml Adds shared imports for email templates.
web/EmailTemplates/Views/Shared/_EmailLayout.cshtml Adds shared HTML email layout for UC Davis branding.
web/EmailTemplates/Services/IEmailTemplateRenderer.cs Defines abstraction for rendering Razor templates to HTML.
web/EmailTemplates/Services/EmailTemplateRenderer.cs Implements Razor template rendering via Razor.Templating.Core.
web/EmailTemplates/Models/EmailViewModelBase.cs Adds common email view-model base utilities (BaseUrl, absolute links).
web/Areas/Effort/Services/VerificationService.cs Implements “My Effort” retrieval, verification, and reminder email logic.
web/Areas/Effort/Services/IVerificationService.cs Defines verification service contract.
web/Areas/Effort/Services/IEffortPermissionService.cs Adds HasAnyViewAccessAsync API for permission checks.
web/Areas/Effort/Services/EffortRecordService.cs Auto-creates instructor record when creating an effort record (legacy parity).
web/Areas/Effort/Services/EffortPermissionService.cs Updates current person lookup via VIPER People and adds HasAnyViewAccessAsync.
web/Areas/Effort/Models/DTOs/Responses/VerificationDtos.cs Adds response DTOs for verification, emails, and “My Effort”.
web/Areas/Effort/Models/DTOs/Requests/VerificationRequests.cs Adds request DTOs for single/bulk verification email sends.
web/Areas/Effort/Models/AutoMapperProfileEffort.cs Adds mapping from EffortRecord → InstructorEffortRecordDto for display.
web/Areas/Effort/EmailTemplates/Views/VerificationReminder.cshtml Adds Razor template for verification reminder email body.
web/Areas/Effort/EmailTemplates/Models/VerificationReminderViewModel.cs Adds view model types for verification reminder email template.
web/Areas/Effort/EffortSettings.cs Adds configurable Effort verification settings.
web/Areas/Effort/Controllers/VerificationController.cs Adds verification API endpoints (self-service + admin email endpoints).
web/Areas/Effort/Controllers/TermsController.cs Expands terms endpoint access to VerifyEffort users for self-service.
web/Areas/Effort/Constants/EffortPermissions.cs Adds AnyViewAccess composed permission constant.
web/Areas/ClinicalScheduler/Services/ScheduleEditService.cs Switches primary-evaluator-removed email construction to Razor template rendering.
web/Areas/ClinicalScheduler/EmailTemplates/Views/PrimaryEvaluatorRemoved.cshtml Adds Razor template for primary evaluator removed notification email.
web/Areas/ClinicalScheduler/EmailTemplates/Models/PrimaryEvaluatorRemovedViewModel.cs Adds view model for primary evaluator removed email template.
test/EmailTemplates/EmailTemplateRendererIntegrationTests.cs Adds integration tests for Razor email rendering (currently has a compile issue).
test/Effort/VerificationServiceTests.cs Adds unit tests for verification service behavior (renderer mock setup needs adjustment).
test/Effort/VerificationControllerTests.cs Adds unit tests for verification controller endpoints.
test/Effort/Integration/EffortPermissionIntegrationTests.cs Updates integration tests for new EffortPermissionService constructor.
test/Effort/EffortRecordServiceTests.cs Updates tests for EffortRecordService constructor and new behavior.
test/Effort/EffortIntegrationTestBase.cs Adds VIPERContext to Effort integration test base and seeds needed person data.
test/ClinicalScheduler/TestableScheduleEditService.cs Updates testable service wrapper for new constructor dependency.
test/ClinicalScheduler/ScheduleEditServiceTest.cs Updates ScheduleEditService tests for new dependency (needs renderer mock setup).
test/ClinicalScheduler/Integration/ControllerServiceIntegrationTest.cs Updates integration wiring for new ScheduleEditService constructor dependency.
test/ClinicalScheduler/EmailNotificationTest.cs Updates notification tests for Razor rendering (generic mock setup needs adjustment).
scripts/verify-build.js Improves captured build error output when error.output is empty.
scripts/lib/build-cache.js Improves cached error messaging and expands error filtering patterns.
VueApp/src/Effort/types/verification-types.ts Adds TypeScript types for verification feature APIs.
VueApp/src/Effort/types/index.ts Re-exports verification types for consumers.
VueApp/src/Effort/services/verification-service.ts Adds Vue API client for verification endpoints.
VueApp/src/Effort/router/routes.ts Adds “My Effort” route and applies view-level permission meta to base routes.
VueApp/src/Effort/pages/MyEffort.vue Adds instructor “My Effort” verification page UI.
VueApp/src/Effort/pages/InstructorList.vue Shows verification status and adds single/bulk verification email actions.
VueApp/src/Effort/pages/InstructorDetail.vue Improves edit/add flows and warns about verification implications on record changes.
VueApp/src/Effort/pages/CourseList.vue Adds async load race-condition protection and improves accessibility labels.
VueApp/src/Effort/pages/CourseDetail.vue Adds accessibility labels for key actions.
VueApp/src/Effort/components/InstructorEditDialog.vue Adds accessibility label for close action.
VueApp/src/Effort/components/InstructorAddDialog.vue Adds accessibility label for close action.
VueApp/src/Effort/components/EffortRecordEditDialog.vue Adds verification warning banner and accessibility improvements.
VueApp/src/Effort/components/EffortRecordAddDialog.vue Adds verification warning banner, course preselect support, and accessibility improvements.
VueApp/src/Effort/components/EffortLeftNav.vue Adds “My Effort” nav entry and accessibility label for close action.
VueApp/src/Effort/components/CourseImportDialog.vue Emits imported courseId to enable follow-up “Add Effort” flow.
VueApp/src/Effort/components/CourseEditDialog.vue Adds accessibility label for close action.
VueApp/src/Effort/components/CourseAddDialog.vue Adds accessibility label for close action.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…ords

- Skip sending emails to instructors with no effort data; show N/A status
- Add CanSendVerificationEmail property for email eligibility checks
- Sanitize department code in bulk email logging (log injection fix)
- Add keyboard accessibility to email action icons
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 62 out of 62 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Filter bulk verification emails to only instructors with effort records
- Convert ChildCourseInfo to private sealed record for better encapsulation
- Fix test mock setup for instructor-not-found error path
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 62 out of 62 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Add audit entry for invalid email addresses in verification emails
- Use toLocaleString for date+time display on verification timestamps
@rlorenzo
Copy link
Contributor Author

@bsedwards Example of the new email template
effort-verification-email

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 62 out of 62 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Cache personId lookup in EffortPermissionService to avoid repeated DB queries
- Validate BaseUrl configuration before sending email to fail fast on misconfiguration
- Add proper URL format validation for BaseUrl setting
- Switch keyboard handlers from keyup to keydown.prevent to avoid double-firing
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 62 out of 62 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@rlorenzo
Copy link
Contributor Author

@bsedwards Improved the email templates:

No effort template. Added term dates under the term:

effort-verification-no-effort-email

Also, made the templates mobile responsive:

effort-verification-mobile

- Enable verification for instructors without effort records
- Add term dates and "no effort" messaging to verification emails
- Show "No Effort" badge and distinct verification icons in UI
- Make email layout responsive for mobile devices
- Fix Vite HMR config for secure WebSocket connections
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 63 out of 63 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…matting

- Replace VIPERContext MothraId lookup with direct AaudUserId from user context
- Remove VIPERContext dependency from EffortPermissionService and tests
- Trim SubjCode and SeqNumb in course code formatting (4 locations)
- Update RecordCount comment to reflect "no effort" verification support
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 80 out of 82 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • VueApp/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Pass credentials via curl stdin config instead of CLI args
- Validate tokens contain only safe alphanumeric characters
- Require HTTPS URLs and validate format before use
- Use set -a/source instead of brittle export/xargs parsing
- Use --ssl-revoke-best-effort for internal server CRL issues
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 80 out of 82 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • VueApp/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 80 out of 82 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • VueApp/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…ading

- Add LastEmailed/LastEmailedBy columns to Persons table with FK to avoid
  audit table scans; includes post-deployment migration with backfill
- Add read-only cross-schema entity for single-query sender name resolution
- Consolidate email and edit/delete into single Actions column in UI
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 87 out of 89 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • VueApp/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Automates merge workflow with safety checks: clean working dir,
  commits pushed, no divergence; auto-retries with rebase on conflict
- Fix hardcoded "7 days" in InstructorList to use config value
- Remove redundant HasColumnName mappings for ViperPerson entity
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 89 out of 91 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • VueApp/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Enable sending multiple verification emails simultaneously by using
  Sets instead of single-value state for tracking in-progress sends
- Block emails to already-verified instructors with 409 Conflict response
- Add Range validation to PersonId and TermCode request parameters
- Extend navigation guards to warn on any in-progress email operation
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 89 out of 91 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • VueApp/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Invert to fail-safe: require "0 Error(s)" or "Build succeeded." to pass
- Rename hasActualErrors() to isConfirmedWarningsOnly()
- Expand filterBuildErrors() to catch more error types
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 89 out of 91 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • VueApp/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@rlorenzo
Copy link
Contributor Author

rlorenzo commented Jan 29, 2026

@bsedwards Ready for review again.

Highlights of recent changes:

  1. Polished UI: Combined the Email and Action columns into just Action. Also using a pluralize library so the UI will automatically pluralize strings without having to do something like "Instructor(s)".
  2. Allowing concurrent bulk/individual email requests
  3. DX Improvements: If you set the Jenkins variables in .env.local (see .env.local.example), you can now easily merge feature branches to Development via npm run merge. It will also trigger the Jenkins build.
  4. Improved Instructor List page load speeds by no longer querying against the audit table for the last emailed by information

@bsedwards
Copy link
Collaborator

@rlorenzo Was trying to get to the effort entry for an instructor. On the instructor list, clicking their name should take you to their effort. Currently it opens the edit dialog like the edit button.

@rlorenzo
Copy link
Contributor Author

@bsedwards, I fixed it in the other branch: #102, since it was related to making the modal for Instructor editing a link.

But that brings up a UX issue. Right now, in the instructor listing, if you click on the Instructor's name, you go to a separate page to see the Instructor's effort. Then, if you click the edit icon, you'll see a modal where you can edit the instructor's details and the assignment percentage.

It isn't good UX to have both a separate page and a modal for similar actions to access a CRUD screen.

We can do the following options:

  1. Change everything to modal. More modern, but it does lead to modals inside modals. Not great.
  2. Change everything to a separate page. Follows the existing system, but you do lose your place, and it does seem odd to have the effort information and details in separate places.
  3. Have a consolidated instructor page that has tabs to view an instructor's Effort, Percent assignments, Details (or Details/Percent assignments). Then, if someone clicks the name, they go to the Effort tab; if they click edit, they go to the Details tab/Percent assignments tab. But they can quickly switch between the 2 tabs if needed.
  4. Have that consolidated instructor page as a modal instead of a separate page.
  5. Have focused quick edit modals on the Instructor listing:
  • Have a pencil icon next to the name, and clicking on it will bring up a small modal to edit just the instructor's info.
  • Have a pencil icon in the percent columns to add/edit/delete percentage to modify percentage information of that given type.
  • Display a summary of effort records, have a pencil icon to view/CRUD effort
  • Can still have a consolidated, tabbed page if the name is clicked on

Might be simpler to do 2, but option 3 is interesting. Thoughts?

@bsedwards
Copy link
Collaborator

If I had to guess, I would say 90% of department staff work is looking at the effort for an instructor.

The instructor edit page has info that is a) auto imported, like job code and department, and only updated if it's incorrect by Academic Programs or b) the percent assignment, again edited by Academic Programs and mostly via the other page.

So, I think the instructor effort page is where department staff and faculty (when verifying or now entering their own effort) interact the most.

Having instructor effort be a full page makes the most sense, though I understand the UX reason for a modal so the user doesn't lose their place. I thinking both of people's resistance to change, and also how it looks if their list is long.

Option three seems like it could work, but we should double check if department staff can use the edit button currently. If it's just AP that can edit the instructor then assess if it's worth it.

Thanks for the thoughtful approach.

@bsedwards, I fixed it in the other branch: #102, since it was related to making the modal for Instructor editing a link.

But that brings up a UX issue. Right now, in the instructor listing, if you click on the Instructor's name, you go to a separate page to see the Instructor's effort. Then, if you click the edit icon, you'll see a modal where you can edit the instructor's details and the assignment percentage.

It isn't good UX to have both a separate page and a modal for similar actions to access a CRUD screen.

We can do the following options:

  1. Change everything to modal. More modern, but it does lead to modals inside modals. Not great.
  2. Change everything to a separate page. Follows the existing system, but you do lose your place, and it does seem odd to have the effort information and details in separate places.
  3. Have a consolidated instructor page that has tabs to view an instructor's Effort, Percent assignments, Details (or Details/Percent assignments). Then, if someone clicks the name, they go to the Effort tab; if they click edit, they go to the Details tab/Percent assignments tab. But they can quickly switch between the 2 tabs if needed.
  4. Have that consolidated instructor page as a modal instead of a separate page.
  5. Have focused quick edit modals on the Instructor listing:
  • Have a pencil icon next to the name, and clicking on it will bring up a small modal to edit just the instructor's info.
  • Have a pencil icon in the percent columns to add/edit/delete percentage to modify percentage information of that given type.
  • Display a summary of effort records, have a pencil icon to view/CRUD effort
  • Can still have a consolidated, tabbed page if the name is clicked on

Might be simpler to do 2, but option 3 is interesting. Thoughts?

@rlorenzo
Copy link
Contributor Author

@bsedwards, For now, I will keep them both open on separate pages, for someone like BANNASCH, DANIKA, who has a long history of percent assignments dating back to 2002, using it in a modal is cumbersome.

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.

3 participants