refactor(base): drop SpaceCaslSubject.Base, route base permissions through Page

Bases are pages (isBase=true) and the casl rules already granted the
exact same Manage/Read level on the Base subject as on Page for every
space role (admin, writer, reader). The `Base` subject was therefore
pure duplication: any caller that needed to check base access either
went through pageAccessService (which uses Page internally) or did a
direct Page-equivalent ability.cannot(..., Base) check that produced
the same outcome as Page would have.

Drop SpaceCaslSubject.Base entirely — server enum, server union,
server factory rules, client enum, client union — and switch the two
remaining direct callers to Page:

  - base.controller.ts `create` and list checks now use Page (matching
    page.controller.ts's create/list).
  - base-table.tsx's `canSave` now reads Page edit ability.

Net effect: one source of truth for "can this user view/edit/manage
content in this space," whether the content is a regular page or a
base. Existing role assignments behave identically; no migration
needed because permissions are computed per-request from the role,
not stored.
This commit is contained in:
Philipinho
2026-04-28 19:21:46 +01:00
parent 0ec30ba804
commit 936c0de7fe
5 changed files with 20 additions and 12 deletions
@@ -109,9 +109,11 @@ export function BaseTable({ pageId, embedded }: BaseTableProps) {
// use-history-restore.tsx for the same pattern.
const { data: space } = useSpaceQuery(base?.spaceId ?? "");
const spaceAbility = useSpaceAbility(space?.membership?.permissions);
// Bases are pages — gate save on the same Page subject the rest of
// the app uses; the dedicated Base subject was redundant.
const canSave = spaceAbility.can(
SpaceCaslAction.Edit,
SpaceCaslSubject.Base,
SpaceCaslSubject.Page,
);
// Hold the rows query until `base` has loaded. Otherwise the query
@@ -9,11 +9,12 @@ export enum SpaceCaslSubject {
Settings = "settings",
Member = "member",
Page = "page",
Base = "base",
}
// Bases are pages and inherit Page permissions — a separate Base
// subject was redundant and has been dropped from the server's casl
// rules too. Anything that used to check Base now checks Page.
export type SpaceAbility =
| [SpaceCaslAction, SpaceCaslSubject.Settings]
| [SpaceCaslAction, SpaceCaslSubject.Member]
| [SpaceCaslAction, SpaceCaslSubject.Page]
| [SpaceCaslAction, SpaceCaslSubject.Base];
| [SpaceCaslAction, SpaceCaslSubject.Page];