The space sidebar tree loaded children one level at a time, so there was
no way to expand the whole tree at once - doing it client-side would mean
recursively paging /pages/sidebar-pages hundreds of times. Add a server
endpoint that returns the whole space tree in one permission-filtered
request, and two menu items in the Space menu that drive it.
Server:
- POST /pages/tree (reuses SidebarPageDto, CASL Read gate) returns
{ items: [...] } - a flat list in the same shape as /pages/sidebar-pages
(id, slugId, title, icon, position, parentPageId, spaceId, hasChildren,
canEdit), sorted by position (collate 'C') then id.
- pageRepo.getSpaceDescendants(spaceId, opts): recursive CTE seeded from
space roots (parentPageId IS NULL). getSpaceDescendantsExcludingRestricted
is also added (space-rooted variant of getPageAnd*ExcludingRestricted)
but not used by the read endpoint - see below.
- pageService.getSidebarPagesTree: fetches the whole space tree WITHOUT
SQL restricted-pruning and lets filterAccessibleTreePages drop
inaccessible pages + their subtrees. This mirrors the stepwise
/pages/sidebar-pages behavior, so a restricted page the user HAS
access to stays visible in expand-all (an earlier draft pruned in SQL
and hid them - a behavioural regression). canEdit is per-page in
restricted spaces (filterAccessiblePageIdsWithPermissions) and
space-wide in open spaces. filterAccessibleTreePages is now public
and accepts rootPageId=null to treat every top-level page as a root.
- hasChildren is derived in JS (a page hasChildren iff some returned row
has it as parentPageId) - O(n), no N subqueries.
Client:
- SpaceTree is now a forwardRef exposing { expandAll, collapseAll,
isExpanding } via useImperativeHandle. expandAll fires one
getSpaceTree request, merges the full nested tree into treeDataAtom
(replace-and-merge so the authoritative server tree wins over stale
partially-loaded roots), opens every branch id of the current space,
and guards against space switches via spaceIdRef. Errors are logged
AND surfaced in a notification with the real reason - never a generic
string. collapseAll clears ONLY current-space ids from the shared
open-map (does not disturb other spaces).
- isExpanding is lifted to reactive state in SpaceSidebar and passed as
a prop to SpaceMenu so the Expand item's disabled state actually
updates (a ref mutation alone would not re-render).
- Two Menu.Items inside SpaceMenu (Expand all / Collapse all), gated
only by read access (not canManage) - these are view operations.
A progressive Node.js framework for building efficient and scalable server-side applications.
Description
Nest framework TypeScript starter repository.
Installation
$ npm install
Running the app
# development
$ npm run start
# watch mode
$ npm run start:dev
# production mode
$ npm run start:prod
Migrations
# This creates a new empty migration file named 'init'
$ npm run migration:create --name=init
# Generates 'init' migration file from existing entities to update the database schema
$ npm run migration:generate --name=init
# Runs all pending migrations to update the database schema
$ npm run migration:run
# Reverts the last executed migration
$ npm run migration:revert
# Reverts all migrations
$ npm run migration:revert
# Shows the list of executed and pending migrations
$ npm run migration:show
## Test
```bash
# unit tests
$ npm run test
# e2e tests
$ npm run test:e2e
# test coverage
$ npm run test:cov
Support
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please read more here.
Stay in touch
- Author - Kamil Myśliwiec
- Website - https://nestjs.com
- Twitter - @nestframework
License
Nest is MIT licensed.