Skip to content

Validate project roster people#296

Merged
michaelmwu merged 6 commits into
mainfrom
michaelmwu/508-person-picker
May 20, 2026
Merged

Validate project roster people#296
michaelmwu merged 6 commits into
mainfrom
michaelmwu/508-person-picker

Conversation

@michaelmwu
Copy link
Copy Markdown
Member

@michaelmwu michaelmwu commented May 20, 2026

Summary

  • Require Add ERP user to choose a validated @508.dev person candidate from CRM/ERP lookup instead of accepting arbitrary text
  • Add dashboard removal actions with confirmation for ERP roster users and historical roster members
  • Add backend removal endpoints plus ERPNext/local roster helpers and coverage

Verification

  • uv run ruff check apps/api/src/five08/backend/api.py tests/unit/test_backend_api.py packages/shared/src/five08/projects.py packages/shared/src/five08/clients/erpnext.py tests/unit/test_erpnext_client.py
  • uv run pytest tests/unit/test_backend_api.py::test_dashboard_add_project_user_uses_erpnext_record_id tests/unit/test_backend_api.py::test_dashboard_add_project_user_requires_verified_candidate tests/unit/test_backend_api.py::test_dashboard_project_member_candidates_returns_verified_508_people tests/unit/test_backend_api.py::test_dashboard_add_project_historical_member_returns_person_not_found_detail tests/unit/test_backend_api.py::test_dashboard_remove_project_user_updates_erp_roster tests/unit/test_backend_api.py::test_dashboard_remove_project_historical_member_deletes_local_roster tests/unit/test_backend_api.py::test_project_roster_user_candidates_require_508_email tests/unit/test_erpnext_client.py::test_remove_project_user_updates_project_users
  • bun run lint in apps/admin_dashboard

Summary by CodeRabbit

Release Notes

  • New Features
    • Enhanced project roster management with improved candidate search and selection when adding team members
    • Added ability to remove individual users from project rosters with confirmation prompts
    • Improved roster interface with streamlined action controls and better table organization
    • Enhanced validation and error messaging for team member management operations

Review Change Stack

Copilot AI review requested due to automatic review settings May 20, 2026 02:28
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Warning

Rate limit exceeded

@michaelmwu has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 40 minutes and 24 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5c3b9c48-9f9d-43f9-8008-967ba2538777

📥 Commits

Reviewing files that changed from the base of the PR and between 10884ec and 5c36e32.

📒 Files selected for processing (10)
  • apps/admin_dashboard/src/main.tsx
  • apps/api/src/five08/backend/api.py
  • apps/api/src/five08/backend/static/dashboard/.vite/manifest.json
  • apps/api/src/five08/backend/static/dashboard/assets/index-CApCb86w.js
  • apps/api/src/five08/backend/static/dashboard/assets/index-DE3a-ZFE.css
  • apps/api/src/five08/backend/static/dashboard/index.html
  • packages/shared/src/five08/clients/erpnext.py
  • packages/shared/src/five08/projects.py
  • tests/unit/test_backend_api.py
  • tests/unit/test_erpnext_client.py
📝 Walkthrough

Walkthrough

This PR extends project roster management across the dashboard and backend to support validated @508.dev member selection, removal operations, and cached candidate resolution. It adds frontend helpers and UI flows for add/remove actions, backend endpoints with candidate filtering and caching, and removal handlers for both ERPNext and historical roster members.

Changes

Project Roster Member Management with Verified Candidate Selection

Layer / File(s) Summary
Foundation: imports, cache state, and request models
apps/admin_dashboard/src/main.tsx, apps/api/src/five08/backend/api.py
Icon import for remove action; in-memory candidate cache with TTL and size limits; updated DashboardProjectUserRequest with optional candidate_id, and new DashboardProjectHistoricalMemberRemoveRequest model.
Frontend roster add/remove helpers
apps/admin_dashboard/src/main.tsx
addProjectUser extended to accept and validate candidateId; new removeProjectUser and removeHistoricalProjectMember helpers that POST to dedicated endpoints and update local state with success/error toast feedback.
Frontend component contract updates
apps/admin_dashboard/src/main.tsx
ProjectsView and ProjectDetailPage props updated: onAddUser includes candidateId, new onRemoveUser and onRemoveHistoricalMember callbacks; callbacks wired through component hierarchy.
Roster candidate search and selection flow
apps/admin_dashboard/src/main.tsx
Debounced, abortable useEffect fetches HistoricalPersonCandidate records from /dashboard/api/project-member-candidates; adds person search input and verified result select UI to ProjectDetailPage.
Roster table with removal action column
apps/admin_dashboard/src/main.tsx
Roster table expanded with conditional "Actions" column when canWrite, containing remove button per row; button calls onRemoveHistoricalMember or onRemoveUser after confirmation depending on row type; table width and empty-state column span adjusted.
Backend candidate resolution pipeline
apps/api/src/five08/backend/api.py
New GET handler returns cached roster user candidates filtered to verified @508.dev emails; _project_roster_user_candidates implements caching with TTL/size limits; _project_roster_user_error_payload translates resolution errors; updated add_project_user flow resolves candidate by ID.
Backend removal endpoints and handlers
apps/api/src/five08/backend/api.py
dashboard_remove_project_user_handler removes ERPNext project user with CSRF/origin validation and audit logging; dashboard_remove_project_historical_member_handler removes local roster member, maps missing rows to HTTP 404, and logs audit events.
API route registration
apps/api/src/five08/backend/api.py
Registers GET /dashboard/api/project-member-candidates for candidate search, POST /dashboard/api/projects/{project_id}/users/remove, and POST /dashboard/api/projects/{project_id}/historical-members/remove.
Shared removal implementations
packages/shared/src/five08/clients/erpnext.py, packages/shared/src/five08/projects.py
ERPNextClient.remove_project_user() filters and updates Project.users child rows by case-insensitive user/email match; remove_project_roster_member() deletes roster member rows by project ID, source, and user ID.
Test coverage
tests/unit/test_backend_api.py, tests/unit/test_erpnext_client.py
Backend tests for candidate-based add/remove, roster candidate filtering and caching, and audit event generation; ERPNext client tests verify user removal updates Project.users and handles non-matching rows; all tests validate expected downstream calls.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 A roster grows with trusted hands,

Five-oh-eight hearts in every clan,

Search and select, remove with care,

Cached and tested, beyond compare! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Validate project roster people' directly reflects the main change: enforcing validated @508.dev person selection in the project roster add flow.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch michaelmwu/508-person-picker

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

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

This PR tightens project roster writes by requiring dashboard users to select a validated @508.dev person candidate (from CRM/ERPNext lookups) when adding ERP roster users, and adds dashboard + backend support for removing ERP roster users and local historical roster members.

Changes:

  • Require candidate_id when adding ERP project users; add a new dashboard endpoint to fetch validated roster candidates.
  • Add backend endpoints and shared helpers for removing ERP roster users (via ERPNext Project.users updates) and deleting local historical roster members.
  • Update admin dashboard UI to use verified-candidate selection for adds and to provide “Remove” actions with confirmation; expand unit tests for new behaviors.

Reviewed changes

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

Show a summary per file
File Description
tests/unit/test_erpnext_client.py Adds unit coverage for ERPNext Project.users removal behavior.
tests/unit/test_backend_api.py Updates/adds API tests for candidate validation and new remove endpoints.
packages/shared/src/five08/projects.py Adds remove_project_roster_member() helper for deleting local roster rows.
packages/shared/src/five08/clients/erpnext.py Adds remove_project_user() to update ERPNext Project.users by removing a user.
apps/api/src/five08/backend/api.py Adds candidate lookup endpoint, enforces candidate validation for adds, and introduces removal endpoints.
apps/admin_dashboard/src/main.tsx Updates UI flow to require verified-candidate selection and adds removal actions.

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

Comment thread apps/api/src/five08/backend/api.py
Comment thread apps/admin_dashboard/src/main.tsx
Comment thread packages/shared/src/five08/clients/erpnext.py Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
apps/admin_dashboard/src/main.tsx (1)

1010-1011: ⚡ Quick win

Use showError for remove failures to preserve diagnostic context.

Line 1010 and Line 1076 bypass the shared API error path (showError), so DEV diagnostics (DashboardDevErrors) won’t capture these failures consistently.

Suggested patch
-    } catch (error) {
-      showToast(error instanceof Error ? error.message : "Unable to remove project user", "error")
+    } catch (error) {
+      showError(error, "Unable to remove project user")
       return false
     } finally {
       setBusy(`project:${projectId}:user`, false)
     }
@@
-    } catch (error) {
-      showToast(
-        error instanceof Error ? error.message : "Unable to remove historical member",
-        "error",
-      )
+    } catch (error) {
+      showError(error, "Unable to remove historical member")
       return false
     } finally {
       setBusy(`project:${projectId}:historical`, false)
     }

Also applies to: 1076-1079

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/admin_dashboard/src/main.tsx` around lines 1010 - 1011, Replace the
direct showToast calls used for the remove-project-user failure path with the
shared showError helper so the failure is routed through the DashboardDevErrors
diagnostics path; specifically, where showToast(error instanceof Error ?
error.message : "Unable to remove project user", "error") is used (in the
remove-user handler in main.tsx), call showError with the Error object or with
both a message and the Error (e.g., showError(error) or showError("Unable to
remove project user", error)) and keep the existing return false; do the same
for the other occurrence around the 1076–1079 remove flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/shared/src/five08/clients/erpnext.py`:
- Around line 286-315: remove_project_user currently returns the original
project when no user matched, making callers unable to distinguish "not found"
from a successful removal; modify remove_project_user to raise an explicit
ERPNextAPIError (e.g., ERPNextAPIError(f"Project user not found: {user} for
project {project_id}")) when removed is False after iterating, while keeping the
existing behavior of calling update_project(project_id, {"users": next_users})
when a removal did occur; keep get_project and update_project calls unchanged
and include the normalized_user and project_id in the error text for clear
diagnostics.

In `@packages/shared/src/five08/projects.py`:
- Around line 819-822: The DELETE currently interpolates Python into SQL via the
f-string using the variable where_clause; replace this with a static
parameterized SQL string and pass values via the DB parameter API instead of
formatting into the query. Locate the code that constructs the DELETE for
project_roster_members (the usage of where_clause in
packages.shared.src.five08.projects.py) and rewrite it to build a fixed SQL
statement (e.g., "DELETE FROM project_roster_members WHERE <column>=%s" or
similar) and supply the corresponding parameters in the execute call rather than
injecting where_clause via f-string.

---

Nitpick comments:
In `@apps/admin_dashboard/src/main.tsx`:
- Around line 1010-1011: Replace the direct showToast calls used for the
remove-project-user failure path with the shared showError helper so the failure
is routed through the DashboardDevErrors diagnostics path; specifically, where
showToast(error instanceof Error ? error.message : "Unable to remove project
user", "error") is used (in the remove-user handler in main.tsx), call showError
with the Error object or with both a message and the Error (e.g.,
showError(error) or showError("Unable to remove project user", error)) and keep
the existing return false; do the same for the other occurrence around the
1076–1079 remove flow.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 161679fd-e7aa-488a-8b2e-542ef40a02ce

📥 Commits

Reviewing files that changed from the base of the PR and between d1055d3 and 10884ec.

📒 Files selected for processing (11)
  • apps/admin_dashboard/src/main.tsx
  • apps/api/src/five08/backend/api.py
  • apps/api/src/five08/backend/static/dashboard/.vite/manifest.json
  • apps/api/src/five08/backend/static/dashboard/assets/index--kTKJbUI.js
  • apps/api/src/five08/backend/static/dashboard/assets/index-E1H3CuXy.css
  • apps/api/src/five08/backend/static/dashboard/assets/index-WxptdPpM.js
  • apps/api/src/five08/backend/static/dashboard/index.html
  • packages/shared/src/five08/clients/erpnext.py
  • packages/shared/src/five08/projects.py
  • tests/unit/test_backend_api.py
  • tests/unit/test_erpnext_client.py

Comment thread packages/shared/src/five08/clients/erpnext.py
Comment thread packages/shared/src/five08/projects.py Outdated
Copy link
Copy Markdown

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 9 out of 11 changed files in this pull request and generated no new comments.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 10884ecf9f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/api/src/five08/backend/api.py Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3a075577b7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/admin_dashboard/src/main.tsx Outdated
Copilot AI review requested due to automatic review settings May 20, 2026 03:06
@michaelmwu michaelmwu merged commit f96d76d into main May 20, 2026
9 checks passed
@michaelmwu michaelmwu deleted the michaelmwu/508-person-picker branch May 20, 2026 03:10
Copy link
Copy Markdown

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 9 out of 11 changed files in this pull request and generated 2 comments.

)
elif exc.code == "person_not_found":
detail = (
f'No active CRM person or ERPNext user with a @508.dev email matched "{user}". '
Comment on lines +3796 to +3797
return JSONResponse(
{"error": "erpnext_project_user_remove_failed", "detail": str(exc)},
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.

2 participants