mirror of
https://github.com/coder/coder.git
synced 2026-09-21 12:44:32 +08:00
fix(site): stop redundant RBAC paywall error toast on Groups page (#28249)
> 🤖 This PR was written by Coder Agents on behalf of Jake Howell. Fixes coder/coder#23898 / coder/coder#23898. ## Problem On a deployment without a Premium license, opening **Admin → Deployment settings → Groups** shows the Premium paywall *and* a redundant error toast in the bottom-right reading "Template RBAC is a Premium feature. Contact sales!". ## Root cause `GroupsPage.tsx` fired the paginated `groupsByOrganization` query unconditionally. Groups are gated behind the `template_rbac` (Premium) entitlement, so the request returned `403` ("Template RBAC is a Premium feature"), which a `useEffect` surfaced via `toast.error`. Meanwhile `GroupsPageView` already renders `PaywallPremium` when `groupsEnabled` is false, hence the duplicate messaging. The AI Governance page doesn't fire an entitlement-gated request, so it only shows the paywall. There's a second subtlety that made the bug load-path dependent: `selectFeatureVisibility` returns `{}` when unlicensed, so `template_rbac` is `undefined`, not `false`. React Query treats `enabled: undefined` as enabled, so a naive `enabled: groupsEnabled && ...` gate still fired the request on a fresh full page load (where entitlements were briefly in flight). Client-side navigation happened to have entitlements cached as `false`, so it looked fixed there but reproduced on hard reload. ## Fix Gate the groups query with `enabled: Boolean(groupsEnabled && organization)`. The `Boolean()` coercion is load-bearing: it turns the `undefined` entitlement into a real `false` so the request is genuinely skipped rather than defaulting to enabled. When the entitlement is missing there is no request, no error, and the paywall remains the single source of truth. Legitimate load failures (when the feature *is* entitled) still toast as before. <details><summary>Investigation notes</summary> * `site/src/pages/GroupsPage/GroupsPage.tsx` — `groupsQuery` ran regardless of entitlement; the `groupsQuery.error` effect calls `toast.error`. * `site/src/pages/GroupsPage/GroupsPageView.tsx` — renders `PaywallPremium` when `!groupsEnabled`, independent of the query. * `site/src/modules/dashboard/entitlements.ts` — `getFeatureVisibility` returns `{}` when `!hasLicense`, so feature flags are `undefined` (not `false`) on unlicensed deployments. * `usePaginatedQuery` forwards `enabled` to the underlying `useQuery`, and its prefetch / invalid-page effects are no-ops while the query is disabled. * Backend source of the message: `enterprise/coderd/templates.go`. </details> ## Testing Verified end-to-end on a local unlicensed `scripts/develop.sh` deployment (the exact repro condition): * Confirmed `GET /api/v2/organizations/coder/paginated-groups` returns `403 "Template RBAC is a Premium feature. Contact sales!"` — the toast's text. * **Before fix:** hard reload of `/deployment/groups` shows the error toast bottom-right alongside the paywall. * **After fix:** 3 consecutive hard reloads, no toast at any point (including the \~3s mark where it previously fired); paywall still renders correctly. * `pnpm --dir site lint:types` passes. Before/after screenshots are attached in the PR thread / chat.
This commit is contained in:
@@ -30,9 +30,10 @@ const GroupsPage: FC = () => {
|
||||
const { organization, showOrganizations } = useGroupsSettings();
|
||||
const aibridgeVisible = Boolean(aibridge);
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const groupsQuery = usePaginatedQuery(
|
||||
paginatedGroupsByOrganization(organization?.name ?? "", searchParams),
|
||||
);
|
||||
const groupsQuery = usePaginatedQuery({
|
||||
...paginatedGroupsByOrganization(organization?.name ?? "", searchParams),
|
||||
enabled: Boolean(groupsEnabled && organization),
|
||||
});
|
||||
const filter = useFilter({
|
||||
searchParams,
|
||||
onSearchParamsChange: setSearchParams,
|
||||
|
||||
Reference in New Issue
Block a user