Repository navigation
Commit 5275d1f
feat(app-shell): search on the Studio landing, the palette lists packages, objects and flows (objectui#11863, Q2) (#12044)
Fixes #11863
Clause-②: yes
## What this does
Q2 of objectui#11863, search on the Studio landing, as ruled in retriage
`6054672824` ("Q2 → A, with C as the fallback if no read lists flows
across packages"). A read that lists flows across packages exists, so
this builds A with flows. Q1 (PR #12004) and Q3 (PR #11996) have landed;
Q2 is the card's last ruled item.
- `StudioLanding` (`apps/console/src/components/StudioRoute.tsx`) mounts
`CommandPaletteProvider` and `CommandPalette scope="studio"`. Under the
provider, the `studio` header draws its Search trigger through
objectui#11912's existing rule, and `Ctrl+K` / `⌘K` opens the palette.
`AppHeader`'s rule is unchanged; only its comment now names the
`/studio` mount.
- `CommandPalette` gets a declared second scope. `scope="studio"` takes
no other prop: there is no active app, so the scope has no app
navigation group, no record search, no app switching, and no full-search
command (its link is `/apps/APP/search`). It lists three Studio groups
instead:
- **Packages**: `fetchPackages`, the list the landing and its switcher
read (kernel packages already left out). Each opens `/studio/PKG/data`,
as a landing card does.
- **Objects**: `useMetadata().objects`, each under the package it
declares (`_packageId`), opened at
`/studio/PKG/data?surface=object:NAME`. An object whose package is not
in the list, or that has no package, has no Studio page and is left out.
- **Flows**: the metadata cache's `flow` list, opened at
`/studio/PKG/automations?surface=flow:NAME`. A flow that belongs to no
package opens in the package-less scope,
`/studio/~org/automations?surface=flow:NAME` (`studioOrgScopePath`,
objectui#11553).
- Entries match on label or machine name through `matchesPaletteQuery`,
the rule the palette's other entries use (objectui#11812). An object or
packaged flow shows its package's name on the right. Nothing is read
until the palette opens. The theme commands and the recently viewed
records stay.
- Two pack rows in all ten packs: `console.commandPalette.packages` and
`console.commandPalette.flows`. The objects group reuses
`console.commandPalette.objects`.
- Docs: `packages/app-shell/README.md` (the palette section) and
`content/docs/guide/console.md` (a "Search in Studio" row). Changeset
`.changeset/11863-studio-search.md`. The pending Q1 changeset
`.changeset/11863-studio-header.md` gains one append-only dated note
(patch round 1, see Acceptance notes).
## Contract face (Clause-② yes, widening)
- `@object-ui/app-shell`, `CommandPalette` props: a second form,
`scope="studio"`, which takes no other prop. The in-app form (`apps`,
`activeApp`, `objects`, `onAppChange`, optional `dataSource`) is
unchanged and still required; it leaves `scope` out. The props type is
not exported by name. No export is added or removed. The scope is
declared, not inferred from a missing `activeApp`. A type pin in the new
test holds both directions: `CommandPalette scope="studio"
activeApp=...` and a bare `CommandPalette` are compile errors. The pins
are two `@ts-expect-error` lines that the package's `type-check` (`tsc
-p tsconfig.test.json`) compiles.
- `@object-ui/i18n`: the exported `en` pack and `TranslationKeys` gain
`console.commandPalette.packages` and `console.commandPalette.flows`.
Nothing is removed.
- Changeset: `@object-ui/app-shell` minor, `@object-ui/i18n` patch,
`@object-ui/console` patch. That follows the Q3 changeset's precedent
for added pack rows. No major.
## The PM hypotheses, measured
- **H1, held** on `049012b`. `CommandPaletteProvider` was mounted only
in `ConsoleLayout`. `AppHeader` asks
`useCommandPaletteProviderMounted()`. In the reverse leg below, base
`StudioRoute.tsx` gives "Unable to find an element by:
[data-testid="action:command-palette:open"]" on `/studio`. So this card
mounts the palette itself.
- **H2, held.** The clean shape mounts in `StudioLanding` only, not
above Home, Organizations or AI. In a real browser, `/home` still draws
0 desktop and 0 compact triggers on this branch. Nothing was widened or
narrowed silently.
- **H3, held** on `049012b`. A scratch probe (deleted, never committed)
put the base `CommandPalette` (blob `77b85897`) at `/studio` with `apps`
empty and `activeApp` null. The query `search` rendered the full-search
item, and picking it went to `/apps/undefined/search`: 1 passed. This
branch drops that command and every app-scoped group in the `studio`
scope, by declaration.
- **H4: a cross-package flow read exists, so A, not C.** The metadata
cache's `getItemsByType('flow')` is the unscoped `GET
/api/v1/meta/flow`. It is the same unscoped list that
`loadPackageLessSurfaces` narrows, and that function's doc says "The
unscoped list also carries every PACKAGED item". On the server,
`getMetaItems({ type })` with no package returns every package's items.
The URL shapes come from `StudioDesignSurface`'s routing on `main`:
`PILLAR_FOR_SURFACE_TYPE` (object to `data`, flow to `automations`), the
`?surface=TYPE:NAME` deep link (`DESIGNER_SURFACE_PARAM`,
`formatSurfaceParam`) and `studioOrgScopePath`. These were checked
against a mocked API in the browser. I did not check them against a live
objectstack server, because the sibling checkout is not installed or
built in this container.
- **H5, fits.** Eager closure under the lock: base `049012b` is
3,238,404 B ("3162.5 KB gzipped across 289 of 2474 chunks (budget:
3204.6 KB, headroom: 42.1 KB)"). Branch `dbca37f` is 3,239,095 B
("3163.2 KB gzipped across 289 of 2474 chunks (budget: 3204.6 KB,
headroom: 41.4 KB)"). The delta is +691 B, under the 3,281,467 ceiling,
which was not touched. The bytes land in the `index` chunk (+770 B).
`packages-io` was already in the eager `PackagesPage` chunk on base, so
`fetchPackages` adds no module. `i18n-locale-en` grows 45,231 to 45,241
B, under its own ceiling. `b6a003e` changes one test docstring after
`dbca37f`, with no source change.
- **H6.** `console.commandPalette.objects` fits the objects heading and
is reused. No row in `packages/i18n` fits "Packages" or "Flows" as a
group heading: `common.package` and `packagedAutomation.colFlow` are
singular, and `console.studio.title` is the product name. The designer
table (`metadata-admin/i18n.ts`) has `engine.packages.title`, but the
palette reads only `packages/i18n` through `useObjectTranslation`. So
the PR adds two rows in all ten packs.
## Verification (head `b6a003e`)
- **Union**, every test file that imports or names `CommandPalette`,
`CommandPaletteProvider`, `AppHeader`, `StudioRoute` or `commandPalette`
(`git grep -l`, 59 files), under `os-verify-lock`: "Test Files 59 passed
(59)", "Tests 515 passed (515)".
- `packages/i18n/`: "Test Files 82 passed (82)", "Tests 1316 passed | 13
skipped (1329)".
- `scripts/__tests__/`: "Test Files 179 passed | 2 skipped (181)",
"Tests 5452 passed | 2 skipped (5454)".
- **Type-check**: `pnpm --filter @object-ui/i18n --filter
@object-ui/app-shell --filter @object-ui/console run type-check`, all
three script names echoed, exit 0. This ran after `turbo run build
--filter='@object-ui/console^...'`.
- **New tests:** `CommandPalette.studioScope-11863.test.tsx` has 10
cases: groups and exclusions, each target URL, matching, no app-scoped
entry plus an app-scope CONTROL, nothing read while closed plus a
CONTROL. `StudioRoute.searchPalette-11863.test.tsx` has 4 cases through
the real `studioRoutes`: both triggers, click, `Ctrl+K`, and picking a
package opens its builder. The 11912 pin's CONTROL now includes `studio`
under a provider.
- **Reverse verification**, from committed `dbca37f`.
`CommandPalette.tsx` and `StudioRoute.tsx` were swapped to their base
blobs (`77b85897`, `9e2098ca`; anchors `useStudioPaletteEntries` 1 to 0
and `scope="studio"` 1 to 0). The run gave "Tests 13 failed | 8 passed
(21)". Red: the 9 studio-scope cases (the base palette throws "Cannot
read properties of undefined (reading 'filter')" with no app props) and
the 4 route cases (no trigger). Green: the app-scope CONTROL and the 7
cases of the 11912 pin. The trap restored both files from `HEAD`: blobs
`05643164`, `b314334d` equal `HEAD`, and `git diff HEAD` is empty.
- **Gates**, exit 0 each: `check:i18n-keys` ("Every in-scope call-site
key resolves against the en pack (3313 keys)"), `check:i18n-drift`,
`check:i18n-dead-keys` (report-only; neither new key listed),
`check:eager-locale-catalogues`, `check:new-line-citations` ("0 new
citation(s)"), `check:control-bytes`, `check:vi-mock-specifiers`,
`check:vi-mock-inherit`, `check:vi-mock-override-shape` and
`check:test-path-roots`. Also exit 0: `check:changeset-claims`
(report-only; `11806-login-server-unreachable.md` names
`packages/app-shell/README.md` for its sign-up table, which this PR
leaves alone), `check:pending-changeset-literals`, `check:doc-fences`,
`check:icon-record-names`, `check:shell-escape-residue`,
`check:unreferenced-sources`, `check:readme-exports`,
`check:doc-snippets`, `check-changeset-presence` ("17 source file(s) of
3 released package(s) changed, and this change declares 1 changeset(s)")
and `check-changeset-no-major`. `check-governed-queue-guard --test` over
the 20 paths says NOT GOVERNED.
- **eslint**: `--no-inline-config --format json` over the 17 changed
ts/tsx files gives 0 errors. Each of the 5 edited files has the same
warning count as its base blob through `--stdin`: 2, 13, 22, 11 and 13.
The two new test files have 0. The population is the config's
`**/*.{ts,tsx}` and the file count comes from the JSON output. The
config is not type-aware (no `parserOptions.project` /
`projectService`), so this diff cannot move any untouched file's
verdict. The repo-wide `pnpm lint` is CI's.
- **Patch round 1, head `12f3f09`.** One commit, changeset text only:
`.changeset/11863-studio-header.md`, 2 lines added and 0 removed. At
that head, exit 0 each: `check-changeset-presence` ("17 source file(s)
of 3 released package(s) changed, and this change declares 1
changeset(s)"), `check-changeset-no-major`, `check:changeset-claims`
(report-only, the same 11806 reading as above),
`check:pending-changeset-literals`, `check:control-bytes` and
`check:new-line-citations` ("0 new citation(s)"). The union, type-check,
eslint, bundle and browser readings in this section are from `b6a003e`
and `dbca37f` and were not re-run: no source or test file changed. The
two bot comments on this PR were read: the changeset-claim re-read
(6077690455) names `.changeset/11806-login-server-unreachable.md` for
`packages/app-shell/README.md`, and its paragraph is about the sign-up
table, which this PR leaves alone, so it still holds; the CI Console
Performance Budget on `b6a003e` (6077731629) reads PASS, 3163.4 KB
against 3204.6 KB.
### Real browser (Chromium `/opt/pw-browsers/chromium`, 1440x900, `vite
preview` of the `dbca37f` build on a private port, API mocked with
`page.route`; `pageErrors` empty)
| Where | What was read |
|---|---|
| `/studio` | desktop trigger 1, compact 1; click gives
`/studio?palette=1` |
| palette, empty query | headings Packages, Objects, Flows, Preferences;
Acme CRM, People; Account (Acme CRM), Employee (People); Onboard Account
(Acme CRM), Nightly Cleanup; three theme commands. Kernel package,
`sys_user` and the kernel flow absent |
| query `search` | 0 items: no full-search command, nothing under
`/apps/` |
| query `employee`, picked |
`/studio/com.acme.hr/data?surface=object%3Ahr_employee` |
| `Ctrl+K` on `/studio`, package-less flow picked | `/studio?palette=1`,
then `/studio/~org/automations?surface=flow%3Aorg_cleanup` |
| CONTROL `/apps/crm_app` | triggers 1 and 1; headings Objects,
Preferences, Actions; `search` gives the full-search command |
| `/home` (untouched frame) | triggers 0 and 0 |
## Acceptance notes
- The pending `.changeset/11863-studio-header.md` (Q1) ends its first
paragraph with "No command palette is mounted on `/studio`, so the
header shows no search trigger there." This PR makes that sentence
false. Patch round 1 leaves the sentence as written and appends one
dated note after its paragraph, in the objectui#6152 round-12 shape:
from objectui#11863 Q2 (this PR) the landing mounts the command palette
in its `studio` scope, so the header draws the search trigger and `⌘K`
opens it. This PR's own changeset also states the reversal in its first
paragraph.
- Bounds, by design and stated in the code: objects and flows are the
published items from the metadata cache, so an item that exists only as
a draft is not listed. If the package read fails, the packaged entries
are left out, and the landing under the palette shows that read's error.
- The pillar builder (`/studio/PKG/TAB`) mounts no palette. It is
`StudioDesignSurface`'s full-screen frame, which this claim does not
hold.
Session: `https://claude.ai/code/session_01CijGnfWLxTLUFcJkY2ouUw`
---
_Generated by [Claude
Code](https://claude.ai/code/session_01CijGnfWLxTLUFcJkY2ouUw)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent d328698 commit 5275d1f
21 files changed
Lines changed: 844 additions & 29 deletions
File tree
- .changeset
- apps/console/src/components
- content/docs/guide
- packages
- app-shell
- src
- chrome
- layout
- __tests__
- i18n/src/locales
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
| 10 | + | |
9 | 11 | | |
10 | 12 | | |
11 | 13 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| 41 | + | |
| 42 | + | |
41 | 43 | | |
42 | 44 | | |
43 | 45 | | |
| |||
151 | 153 | | |
152 | 154 | | |
153 | 155 | | |
154 | | - | |
155 | | - | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
156 | 163 | | |
157 | 164 | | |
158 | 165 | | |
159 | | - | |
160 | | - | |
161 | | - | |
162 | | - | |
163 | | - | |
164 | | - | |
165 | | - | |
166 | | - | |
167 | | - | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
168 | 178 | | |
169 | | - | |
| 179 | + | |
170 | 180 | | |
171 | 181 | | |
172 | 182 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| 31 | + | |
31 | 32 | | |
32 | 33 | | |
33 | 34 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1037 | 1037 | | |
1038 | 1038 | | |
1039 | 1039 | | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
| 1044 | + | |
| 1045 | + | |
| 1046 | + | |
| 1047 | + | |
| 1048 | + | |
| 1049 | + | |
1040 | 1050 | | |
1041 | 1051 | | |
1042 | 1052 | | |
| |||
0 commit comments