Skip to content

Fixes and improvements#583

Merged
ussaama merged 3 commits into
mainfrom
fixes-and-improvements
May 21, 2026
Merged

Fixes and improvements#583
ussaama merged 3 commits into
mainfrom
fixes-and-improvements

Conversation

@ussaama
Copy link
Copy Markdown
Contributor

@ussaama ussaama commented May 21, 2026

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fixed "New organisation workspace" button appearing for users without organization membership.
    • Improved column visibility menu interactions in admin settings.
    • Avatar display now shows a maximum of 3 members with overflow count.
  • Changes

    • Free-tier workspaces are no longer discoverable or requestable.
    • Project defaults settings section is now hidden for external-only users.
    • Workspace request notifications now process asynchronously for improved performance.

Review Change Stack

ussaama added 3 commits May 21, 2026 16:08
  - Hide "Recently approved" badge on free workspaces (auto-created, not approved)
  - Cap workspace card avatars at 3 + overflow bubble so busy workspaces don't overflow the card
  - Exclude free-tier workspaces from non-admin discovery and reject access requests against them
  - Hide "New organisation workspace" button and "Project Defaults" settings for users with no org membership
  The Columns dropdown and period selector on /admin/usage-and-billing
  appeared inert — checkbox toggles and "Last month" clicks fired and
  even refetched, but the table never reflected them.

  Two bugs stacked:
  1. Menu.Item's onClick called preventDefault(), which swallowed the
     bubbled checkbox click and stopped the toggle (same root cause as
     the org-usage fix in 0ba5830).
  2. React Compiler memoized BillingTable's JSX on [footerTotals, table].
     TanStack's useReactTable returns a stable reference and mutates the
     table in place, so the cache always hit and state changes never
     reached the DOM. SimpleDataTable had the same latent issue affecting
     Partners / Upgrades sort + search.
…request path

  Submit and approve/deny were doing N sequential Directus notification
  writes plus a synchronous SendGrid send inline, adding 5–7s of click
  latency. Schedule them via FastAPI BackgroundTasks so the response
  returns immediately. Also drop the redundant workspace re-fetch in
  _notify_requester_approved by threading the name through from the
  caller (_upgrade_workspace_for_request now returns (id, name)).

  Same test surface; affected suite runtime drops from ~71s to ~1.4s,
  mirroring the production speedup.

  Five files changed:
  - server/dembrane/api/v2/workspace_requests.py — extract staff fan-out into _notify_staff_workspace_request_submitted, schedule via BackgroundTasks.
  - server/dembrane/api/v2/admin.py — BackgroundTasks on decide_workspace_request; background-schedule both notify helpers; drop redundant get_item("workspace", …); _upgrade_workspace_for_request returns (id,
  name).
  - server/tests/test_workspace_requests.py, server/tests/test_approve_deny_action.py, server/tests/test_request_notifications.py — pass BackgroundTasks(), drain queue where assertions check side-effects,
  adjust the tuple-return assertion + drop now-unused workspace mocks.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5cd7d74a-7bd5-4339-b6d2-fa73f0cbe97d

📥 Commits

Reviewing files that changed from the base of the PR and between f0f355a and 75d67d8.

📒 Files selected for processing (10)
  • echo/frontend/src/components/settings/MyAccessCard.tsx
  • echo/frontend/src/routes/admin/AdminSettingsRoute.tsx
  • echo/frontend/src/routes/settings/UserSettingsRoute.tsx
  • echo/frontend/src/routes/workspaces/WorkspaceSelectorRoute.tsx
  • echo/server/dembrane/api/v2/access_requests.py
  • echo/server/dembrane/api/v2/admin.py
  • echo/server/dembrane/api/v2/workspace_requests.py
  • echo/server/tests/test_approve_deny_action.py
  • echo/server/tests/test_request_notifications.py
  • echo/server/tests/test_workspace_requests.py

Walkthrough

This PR implements free-tier workspace restrictions and refactors notification handling to async BackgroundTasks. Backend endpoints now filter free-tier workspaces from discovery and block direct access requests. Notifications for both staff submissions and requester approvals are scheduled asynchronously. Frontend UI is gated by user access level and workspace tier, preventing low-access users from accessing certain features.

Changes

Workspace Access Control and Async Notifications

Layer / File(s) Summary
Backend: Free-Tier Workspace Restrictions
echo/server/dembrane/api/v2/access_requests.py
request_workspace_access and list_discoverable_workspaces now exclude or block free-tier workspaces: direct requests raise 404, and discovery queries filter tier != "free" for non-admins.
Admin Endpoint: Background Task Scheduling and Workspace Name Passing
echo/server/dembrane/api/v2/admin.py
decide_workspace_request now accepts BackgroundTasks, threads workspace_name through approval paths, and enqueues notifications instead of awaiting them inline. _upgrade_workspace_for_request returns tuple (workspace_id, workspace_name); _notify_requester_approved accepts optional workspace_name parameter.
Submit Request: Background Task Scheduling and Staff Notifications
echo/server/dembrane/api/v2/workspace_requests.py
submit_workspace_request accepts BackgroundTasks and introduces _notify_staff_workspace_request_submitted helper to emit staff audience events, resolve email addresses, apply throttling, and queue digest items as best-effort background work.
Frontend: Access and Tier-Based UI Gating
echo/frontend/src/components/settings/MyAccessCard.tsx, echo/frontend/src/routes/settings/UserSettingsRoute.tsx, echo/frontend/src/routes/workspaces/WorkspaceSelectorRoute.tsx
MyAccessCard gates "New organisation workspace" button by organisation membership count. UserSettingsRoute hides "project-defaults" section for external-only users via useQuery and useMemo. WorkspaceSelectorRoute caps avatar display to 3 members and excludes free-tier workspaces from recently-approved badge.
Admin Route: Memoization Pragmas and Checkbox Interaction
echo/frontend/src/routes/admin/AdminSettingsRoute.tsx
Adds React-compiler "use no memo" pragmas to BillingTable and SimpleDataTable to prevent cache issues; refactors column visibility checkbox to toggle state via functional updates and suppress click propagation.
Tests: Admin Endpoint Background Tasks and Tuple Return
echo/server/tests/test_approve_deny_action.py
All decide_workspace_request test calls now pass BackgroundTasks() instances. _upgrade_workspace_for_request assertions updated to handle tuple returns; tier-upgrade test mocks tuple value.
Tests: Submit Request Background Tasks and Notification Draining
echo/server/tests/test_request_notifications.py
Submit and approve tests now construct BackgroundTasks, pass them to endpoints, and drain via await bg() before asserting notifications. Directus mocking simplified; approval assertions now include workspace_name kwarg verification.
Tests: Workspace Request Call Sites
echo/server/tests/test_workspace_requests.py
All submit_workspace_request invocations updated to pass BackgroundTasks() as third argument across validation, permission, billing, and payload tests.

🎯 3 (Moderate) | ⏱️ ~25 minutes


Possibly related PRs

  • Dembrane/echo#581: Modifies WorkspaceSelectorRoute's "Recently approved" badge logic; this PR further refines it to exclude free-tier workspaces.

Suggested labels

improvement

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Fixes and improvements' is vague and generic, using non-descriptive terms that don't convey meaningful information about the actual changeset. Use a more descriptive title that reflects the primary change, such as 'Add workspace tier restrictions and background task notifications' or 'Gate project-defaults and restrict free-tier workspace access'.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fixes-and-improvements

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.

@ussaama ussaama added this pull request to the merge queue May 21, 2026
Merged via the queue into main with commit 8a021db May 21, 2026
11 checks passed
github-merge-queue Bot pushed a commit that referenced this pull request May 25, 2026
fix: repair regressions from sidebar PR (#585)

The sidebar PR overlapped with #577, #581, #582, and #583 and introduced
  a few cross-cutting issues this commit addresses:

- Restore the "hide Project defaults for external-only users" gate in
the
new sidebar's UserSettingsView. PR #582/#583 added this filter to the
    old UserSettingsRoute; when the sidebar moved navigation into a new
view component, the NavItem rendered unconditionally and external-only
    users could click through to an empty pane.
- Drop schema-step tests that imported the deleted
scripts/create_schema.py
    one-shot seeding script. The committed snapshot under
directus/sync/snapshot/ is the source of truth now, so those structural
    guards were checking a script that no longer exists.
- Update AGENTS.md to remove the create_schema.py reference and point at
    the snapshot directory.
- Populate ref_workspace_id on PROJECT_SHARE_ROLE_CHANGED
(project_sharing.py),
    REPORT_READY, and REPORT_FAILED (tasks.py). The new useNotifications
    href builder requires both ref_workspace_id and ref_project_id to
    produce /w/{ws}/projects/... links; without it those notifications
    rendered as dead clicks.
- Strip the per-request org_membership lookup in get_workspace_context.
    PR #582 enforces role='external' ⟺ no org_membership at every write
path, and on_organisation_member_removed cascades workspace_membership
    soft-deletes correctly, so the read-side normalisation was redundant
    per-request DB overhead.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* User settings view now fetches and displays workspace access
information, conditionally showing relevant configuration options based
on access level.
* Notifications for project sharing and report status now include
workspace context information for better organization.

* **Documentation**
* Updated deployment guide with clarified schema snapshot and migration
script procedures.

* **Tests**
  * Removed legacy schema step validation tests from test suite.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/Dembrane/echo/pull/586?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants