feat(admin): redesign organizations table with entitlements/usage tabs#3602
feat(admin): redesign organizations table with entitlements/usage tabs#3602alexkgold wants to merge 6 commits into
Conversation
Split admin organizations table into Entitlements and Usage tabs surfacing SSO, provider/model controls, data privacy, GitHub/GitLab/Slack integrations, and auto top-up status alongside existing usage and billing fields. Adds backing fields to the admin list query, dedicated trials page header and create button copy, and seed coverage for every new column.
- Critical: countQuery now joins latestSubscriptions, so the new Stripe Status filter no longer throws (regression test added). - Null subscription_amount_usd for non-billable statuses so the Subscription column doesn't display the dollar amount of churned plans as if it were MRR. - Tighten .gitignore .env* rule to preserve .env.example/.env.test/.envrc. - Propagate showStripeStatus through the Entitlements column so the trials page hides Stripe Status whether the user is on the Usage or Entitlements tab. - Centralize the Stripe subscription status registry under lib/admin/stripe-subscription-statuses so the filter dropdown, badge, and router input share one source of truth, and tighten the router input from free-form string to the canonical enum. - Extract hasPlatformIntegrationSql helper so the active/pending status set for github/gitlab/slack EXISTS subqueries lives in one place. - Replace showCreateButton + createButtonLabel with a single create config object so the create-button label can never be rendered without a wired click target.
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryAll previously flagged issues are resolved: the accidentally committed local ESLint cache file ( Changes Since Last ReviewResolved (1):
Files Reviewed (16 files)
Reviewed by claude-sonnet-4.6 · 167,181 tokens Review guidance: REVIEW.md from base branch |
Co-authored-by: kilo-code-bot[bot] <240665456+kilo-code-bot[bot]@users.noreply.github.com>
The kilo-app/.expo/cache/eslint/.cache_15fcvgc file contained absolute developer paths and was committed by accident. Add a repo-wide `**/.expo/` ignore rule (matching the apps/mobile precedent) so any Expo app's cache anywhere in the tree is excluded going forward.
| [sharedParams, updateUrl] | ||
| ); | ||
|
|
||
| const buttons = create ? ( |
There was a problem hiding this comment.
Problem: OrganizationsTable now only renders the create button when a create prop is passed, but /admin/organizations/page.tsx still calls without that prop, so the main page loses the “Create Organization” action.
Solution: preserve the old default by either:
- passing create={{ label: 'Create Organization' }} from /admin/organizations/page.tsx, or
- defaulting create inside OrganizationsTable to { label: 'Create Organization' }.
| // Get total count using the same filtering logic. Must mirror baseQuery's | ||
| // joins so finalWhereCondition references (e.g. latestSubscriptions for the | ||
| // stripe_status filter) resolve. | ||
| const countQuery = db |
There was a problem hiding this comment.
Problem: the pagination count query always joins the latestSubscriptions windowed subquery, even though it only needs that join when stripe_status is filtering by latest subscription status. This adds avoidable historical subscription-table work to normal list requests.
Solution: build the count query without latestSubscriptions by default, and add that join only when stripe_status is present.
Brings a lot more data into admin organizations table and splits out trial organizations from others.
Summary
/admin/organizationsinto Entitlements and Usage tabs and reuses the same component for/admin/organizations/trials, with a renamed header, a Trial-specific create button label, and Usage as the default tab. The Organizations page no longer shows a Create button at all.listquery with derived booleans and JSONB checks; the row-level Stripe link, Pylon link, and View Org link now live together in a Links cell.lib/admin/stripe-subscription-statusesso the filter dropdown, badge, and TRPC input enum share one source of truth, extracts ahasPlatformIntegrationSqlhelper for the github/gitlab/slack EXISTS subqueries, fixes a count-query bug that broke the new Stripe Status filter, and nullssubscription_amount_usdfor non-billable subscription statuses so the Subscription column doesn't display the price of a churned plan as if it were current MRR.Verification
pnpm dev:seed app:org-dashboardand walked/admin/organizations(Entitlements + Usage tabs) and/admin/organizations/trials(Trial Organizations header, Usage tab default, Create Org Trial button)./admin/organizationswithout crashing the count query (regression test added:list — stripe_status filterinorganization-admin-router.test.ts).git check-ignorestill ignores arbitrary.env.foowhile preserving committed.env.local.example,.envrc, andapps/web/.env.test.Visual Changes
Reviewer Notes
latestSubscriptionsderived table no longer filters onsubscription_status = 'active'so the new `latest_stripe_status` can populate; `subscription_amount_usd` is masked to `NULL` when the latest status is not in `('active','trialing','past_due')` to preserve the previous "current paying value" semantics.