Skip to content

fix: desk assets support in workplace and concierge - #656

Merged
stakach merged 28 commits into
developfrom
fix/desk-assets
Nov 2, 2026
Merged

stakach merged 28 commits into
developfrom
fix/desk-assets

Conversation

@stakach

@stakach stakach commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

Desks have moved from desks zone metadata to _DESKS_ assets. The move is done by init migrate:desk_assets (PlaceOS/init) and covered on the driver side by PlaceOS/drivers#646. This PR fixes workplace and concierge where they assumed metadata desk ids, or where they lost desk data in assets mode.

Desk assets

  • Map status: API bookings carry the asset id, so the map now matches them on asset id or map id. Booked desks showed as free.
  • other_data: tags, homebase and custom keys (e.g. floorsense_id) are read from other_data and merged back on save. Extra security groups are kept.
  • Old desk ids: the migration keeps each desk's original id as its map_id, so these all fall back to map_id:
    • favourites, rewritten to asset ids
    • desk links (/book/desk?asset_id=), which no longer read stale metadata
    • check-in codes
    • booking rule resource_ids
    • concierge booking names
    • CSV import (matches existing desk assets instead of creating duplicates)
    • map manager protected ids
  • Concierge:
    • The duplicate check compares map ids.
    • "New desk" opens the form instead of saving a nameless asset.
    • Imported rows use their own level.
  • Desk search and "book near colleague" use the map id.

Zones and queries

  • Zone path on save: parking spaces, locker banks and lockers now save the full zone path (org, region, building, level), like desks, via a shared assetZones. init backfills existing assets.
  • One query per building or region: desk lists, the assigned desk lookup, search, links, check-in and concierge reports query zones=<building|region> instead of once per level.
  • Pagination: desk, parking and locker queries follow it past 500 assets. A failed desk type lookup is no longer cached for the session.
  • CSV export: includes every row's columns, not just the first row's.

Other

  • bun: pinned to 1.4.3, matching CI and the lockfile (1.3.11 couldn't read bun.lock).
  • enrolment, map-studio, signage tests: fixed for Node 25+, where Node's own localStorage hid the test storage. signage reads stored API keys through the Storage interface.

Node 26

  • CI (build.yml, mobile.yml, pull-request.yml) and .nvmrc use Node 26, the active LTS. Angular 22, Capacitor, Vite and Vitest all support it.
  • Every project now loads libs/common/src/test-storage.ts as its first test setup file.
  • Manual step: the self-hosted e2e runner (placeos-e2e-mac) installs Node by hand. Run brew install node@26 && brew link --overwrite --force node@26 on that machine. Its docs are updated. The e2e job is advisory and doesn't block this PR.

Review

  • On Node 26:
    • tests pass for all 30 projects
    • lint passes for 31 projects
    • all 19 apps build
  • Each fix has a test, and I checked that the new tests fail without the fix.
  • Deploy after init migrate:desk_assets has run. That task writes desks.use_assets, hides the _DESKS_ category and backfills asset zones.

🤖 Generated with Claude Code

stakach and others added 27 commits November 2, 2026 09:51
API bookings reference the desk asset id while AreaManagement uses the map id,
so booked desk assets showed as free.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Desk tags, homebase and third party ids (floorsense_id) are stored in
other_data by the desk migration. Expose them on the desk model and merge
them back on save, and keep additional security groups.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Favourites saved with old metadata desk ids are rewritten to the matching
desk asset (by map id) when desk assets load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Desk assets have an asset id that differs from their map id, so search results
failed to locate on the map and showed the asset id as the description.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Colleague desk bookings reference the desk asset id, the map lookup needs the
desk's map id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assets were queried with the building or region as `zone_id`, which only
matches the asset's level, so reports found no levels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Imported rows use their own `zone_id` level and update the desk asset with the
same id or map id (the original desk id) instead of creating duplicates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ames

Desk assets are identified by their map id (the asset id is generated), so the
duplicate check compares map ids, and bookings with the original desk id find
the desk's name by map id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rules saved before desks moved to assets list the original desk ids, which desk
assets keep as their map id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ookup

Desk queries stopped at 500 assets per level, and a failed desk type lookup was
cached for the session, leaving desk lists empty until a reload.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Links with the original desk id match the desk asset's map id, and in assets
mode the building search reads desk assets instead of the stale desks metadata.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…desk id

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New desks are saved straight away, so in assets mode open the desk modal rather
than creating a nameless desk asset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Parking spaces, locker banks and lockers now store the org, region, building and
level in `zones` like desk assets (shared `assetZones`), so they can be queried
by building. Parking updates refresh the zones without moving the space.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Desk assets list their building in `zones`, so one paginated query replaces a
query per level.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Assets list their building in `zones` (backfilled by init migrate:desk_assets),
so one paginated query per asset type replaces a query per level.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Desk lists, the assigned desk lookup, desk search, desk links and code check-in
query desk assets by building or region `zones` instead of once per level.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Columns came from the first row only, so later rows' fields (e.g. custom desk
fields) were dropped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On Node 25+ globalThis.localStorage is a getter returning undefined, so
vitest skips jsdom's storage and ts-client captures undefined at import.
Run the storage setup file first so it is in place before any import.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Object.keys only lists keys on storage that exposes them as properties,
so iterate with length/key() which every Storage implementation supports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Node 25+ shadows jsdom's localStorage with a getter returning undefined,
so install the shared in-memory storage as a setup file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
frontend-templates Ignored Ignored Preview Nov 2, 2026 12:46am UTC

Node 26 is the active LTS and supported by Angular 22. Every project loads the
in-memory test storage first, as Node 25+ defines an empty `localStorage`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@stakach
stakach merged commit fbc80ef into develop Nov 2, 2026
52 checks passed
camreeves added a commit that referenced this pull request Nov 3, 2026
Brings in #654 (PPT-2872), #655 (PPT-2871) and the desk asset changes
from #656, which the settings specs are updated for next.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015VtrxAzu8XnqXeQG3QbRXt
camreeves added a commit that referenced this pull request Nov 3, 2026
…asset fixes

- desks and events bookable_hours: the last start now leaves room for the
  shortest duration (PPT-2872, #654). The closing-time case asserts no start
  is offered at closing time, and the specs pin min_duration so the expected
  last start doesn't depend on the stack's settings.
- parking use_building_timezone: drop test.fail now that an explicit parking
  false overrides bookings (PPT-2871, #655).
- desks.use_assets: the assets fixture also answers the building-wide
  `zones=<building>` query the desk list sends since #656.
- QA status doc updated to match.

Full settings and settings-browser run with develop merged in: 443 passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015VtrxAzu8XnqXeQG3QbRXt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant