Skip to content

feat(studio): New Package asks only for a name; the package ID, namespace, version and type sit behind Advanced - #27883

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-1n23sn
Oct 30, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-1n23sn

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Bill · project thread

维护者速读

  • 改了什么:Studio「新建软件包」对话框第一步只剩「显示名称」和可选的「描述」;软件包 ID、对象命名空间、版本、类型收进默认折叠的「高级」区,名称下方一行写明自动生成的 ID 和命名空间。
  • 为什么改:原来一打开就是反向域名 ID、命名空间、SemVer 版本和类型,面向开发者;其实 ID/命名空间/版本早就能从名称自动生成,缺的是一个普通人能直接回答的第一步。
  • 风险与回滚:只改 ui 的这个对话框和 studio 中英文案;「高级」里的字段任何一个挡住「创建」时会自动展开(例如纯中文名称生成不了 ID),不会出现按钮灰着却看不到原因。编辑已有软件包不变。回滚 = revert 本 PR。
  • 先看:PackageFormDialog.tsx 的 advancedNeeded / showAdvanced 两行和 Collapsible 一段;PackageFormDialog.nameOnlyFirstStep-27833.test.tsx。
  • 两分钟验证:Studio → 首页「新建」→「新建软件包」,只输入 Field Service 点「创建软件包」,应直接建成,名称下方先显示自动生成的 ID(有当前组织时形如 com.ORG.field-service)和命名空间 field_service;改输 工单中心,「高级」应自动展开并提示需要手填 ID。
  • 需要你做的:无,席位落地。

Fixes #27833
Clause-②: no
Metadata-protocol: none

What changes

Create mode of PackageFormDialog (Home → New → New Package, Packages → New Package, the Studio switcher's New package):

  • The Basics card holds only the display name and the optional description. Under the name, once the id and namespace it derived are valid, one line says what they are: "Its ID will be ID, and its object names will start with NAMESPACE_. You can change both under Advanced." (engine.packages.create.derivedSummary).
  • The package ID (PackageIdInput), object namespace, version and type move into one Advanced disclosure, collapsed by default, with a hint line ("Package ID, namespace, version and type, filled in from the name."). The spec form's own Advanced rows (defaultDatasource) and the dependencies editor join the same disclosure, so the dialog no longer shows two sections both called Advanced.
  • The disclosure's content stays mounted while closed (forceMount plus hidden), so the id input keeps its own state across a collapse and the rows leave the accessibility tree while hidden.
  • The disclosure opens by itself whenever, with a name typed, the id, namespace or version is what keeps Create package disabled (advancedNeeded). A name with no Latin letters (no id derived), an id the spec refuses, or an emptied namespace never leaves the author at a disabled button with the reason folded away; while that holds, the disclosure cannot be closed.
  • The dialog description drops the reverse-domain explanation and says what a package is, in plain words (en + zh changed together, as check:i18n-drift requires for the studio catalogue).

Unchanged: the derivation rules (objectui#11792 id from the name, framework#2694 namespace from the id, objectui#12512 marks and select-on-focus), the spec validation, the POST body, and edit / view mode.

Tests

  • New PackageFormDialog.nameOnlyFirstStep-27833.test.tsx (7 cases): the first step's textboxes are exactly name + description and the technical rows are out of the accessibility tree; a name alone creates the package with the derived id / namespace / version / type in the POST; Advanced shows the derived id and namespace and both are editable; an edited id does not move on relabel; a hand-typed id the spec refuses is refused in words (idRule.formatHint), Create waits, and the disclosure cannot be folded; a CJK-only name opens Advanced by itself at the idRule.notDerived line; edit mode has no disclosure and keeps the locked id and the version row.
  • Pins moved with the layout, each with its reason in a comment: derivedFields-12512 (id / namespace / version now ordered under Advanced, the name still first in Basics), createCopy-13126 (positive control is the description's own sentence, since the example id left the copy), dependenciesEditor-13278 (e) (opens Advanced first), and the live spec ui/e2e/live/studio-object-designer.spec.ts F1 (clicks Advanced before filling the id; Playwright's fill waits for a visible input).

Acceptance notes

  • A name alone creates the package: case 2 posts { id: 'com.field-service', namespace: 'field_service', name: 'Field Service', version: '0.1.0', type: 'app' } after typing only the name. With an active organization the id is com.ORG.field-service, as before (the card's com.default.field-service is that rule with the org slug default).
  • Derived id / namespace shown and editable under Advanced: case 3.
  • An edited id never moves on relabel: case 4.
  • An invalid hand-typed id is refused in words: case 5 (the spec-rule sentence under the input, Create disabled).
  • Editing an existing package keeps today's fields: case 7, plus the unchanged edit / view suites (idDerive-11792, editDependencies-13121, createScope-12869, EditPackageDialog).
  • Not changed, on purpose: the landing copy "writable base" / "environment overlay" pinned by BuilderLanding.environmentOverlayCopy-12171; this card's step does not need it. The English help lines under the id and version rows are still ManifestSchema's .describe() text ("Unique package identifier — must match reverse-domain notation …", "Package version (SemVer 2.0.0 …)"); they now sit under Advanced, where that developer wording fits, and helpTextI18n keeps the spec as their one English producer. Rewording them at the source is a packages/spec change, named as a seam in the report, not taken here.
  • Not measured in a browser: the layout was checked through jsdom (roles, hidden, aria-expanded); the live spec F1 (ui/e2e/live/studio-object-designer.spec.ts) drives the dialog in Chromium wherever the live e2e suite runs.

Verification

Tests (head 05d9ba6)
  • pnpm --dir ui exec vitest run over 37 named files (every test that renders PackageFormDialog, CreatePackageDialog, EditPackageDialog, PackagesPage or BuilderLanding) plus packages/i18n/src/__tests__/, under the verify lock: first run Test Files 1 failed | 126 passed (127) · Tests 1 failed | 1666 passed | 13 skipped; the one red was dependenciesEditor-13278 (e), which now opens Advanced first, then Tests 5 passed (5) on that file.
  • The new file plus the two moved pins: Test Files 3 passed (3) · Tests 23 passed (23).
  • Not run locally: the whole app-shell suite and the live e2e; CI runs both.
Ablations (scripts/ablation-replace.mjs, mutation proven on disk, restored to the HEAD blob)

app-shell tests import src, so no dist build is involved.

  • A: const advancedNeeded = createMode → const advancedNeeded = false && !'ABLATED_27833_A' && createMode (the disclosure no longer opens by itself): Tests 2 failed | 5 passed (7), red on "a hand-typed id the spec refuses … Advanced cannot fold it away" and "a name that derives no id opens Advanced by itself". Restored: blob 1cc49767f808 == HEAD, git diff HEAD empty.
  • B: hidden={!showAdvanced} → hidden={false && !'ABLATED_27833_B'} (the closed disclosure stays visible): Tests 1 failed | 6 passed (7), red on "opens with the name and the description in reach, the technical rows folded away". Restored the same way.
Gates (head 05d9ba6)

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 34 commands; each run and its exit code recorded before any pipe; --ran reconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Four more run because the diff changes studio copy, app-shell / i18n sources and an e2e spec (outside the derivation):

node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-sdui-manifest.mjs :: exit 0
node scripts/check-sdui-manifest.mjs --self-test :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --dir ui exec vitest run scripts/ :: exit 0
pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:dispatcher-error-vocabulary :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:engine-double-contract :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:pm-changeset-deadline-census :: exit 0
pnpm check:published-files :: exit 0
pnpm check:query-options-erasure :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:tier-file-adoption :: exit 0
pnpm check:type-check-coverage :: exit 0
pnpm check:type-check-debt :: exit 0
pnpm check:undeclared-dep-imports :: exit 0
pnpm check:watch-hint-literal :: exit 0
pnpm check:where-matcher :: exit 0
pnpm --dir ui run check:i18n-drift :: exit 0
pnpm --filter @object-ui/app-shell run type-check :: exit 0
pnpm --filter @object-ui/i18n run type-check :: exit 0
pnpm --dir ui run type-check:e2e :: exit 0

Everything CI runs beyond this subset: the PR's check-runs.


Generated by Claude Code

…nd Advanced

The create dialog's Basics card now holds the display name and the
description. The derived package ID and namespace are summarised under
the name; the ID, namespace, version and type move into one collapsed
Advanced disclosure (mounted while closed, `hidden`), which opens by
itself whenever one of its rows keeps Create disabled. The spec form's
own Advanced rows join that disclosure instead of rendering a second
one. The dialog description drops the reverse-domain explanation.

Claude-Session: https://claude.ai/code/session_01Utp6CZHUokxLoPS381KzP6
Co-Authored-By: Claude <noreply@anthropic.com>
…s the id or dependencies

The dependencies editor control and the live switcher spec reach rows that
now sit in the collapsed Advanced section on create.

Claude-Session: https://claude.ai/code/session_01Utp6CZHUokxLoPS381KzP6
Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Oct 30, 2026
…cription pin

The positive control reads the description through `t`; in zh the first
render starts the on-demand catalogue fetch, so the control could read
the zh sentence while the dialog had rendered the en fallback (red in CI
Test UI 4/16). Loading the catalogue first makes both read zh.

Claude-Session: https://claude.ai/code/session_01Utp6CZHUokxLoPS381KzP6
Co-Authored-By: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe

席位核对

ACCEPT · head 1558d9bbaf6a88b754bc99f48148797866b74641 · 2026-10-30T03:08Z

  • Shape: draft → main, Fixes #27833 on its own line, no other card number beside a closing keyword. Clause-②: no and Metadata-protocol: none match the claim; @object-ui/app-shell (private: true) plus studio keys (two added, one sentence changed, en and zh). No contract review owed.
  • Premise, measured: in create mode, the New Package dialog's Basics now asks only for a display name (and an optional description), and the line under the name states the derived ID and namespace. ID, namespace, version and type, with the spec form's own Advanced rows and the dependencies editor, sit in one Advanced section that is collapsed by default (forceMount + hidden). The section opens and stays open whenever a filled name still leaves Create blocked (a name with no Latin letters, or an invalid hand-typed id). The derivation already existed (fix(driver-sql): name the declarations behind MySQL's row-size refusal #11792 / test(auth): pin the human-user predicate agreement across the plugin-security boundary #12512); this card is layout and copy. The id is still judged by ManifestSchema, not loosened. Edit mode is unchanged.
  • Gates (check-runs on the head): 44 success, 11 skipped, 0 failure; mergeable_state clean. check-governed-merges --pr 27883: NOT governed (0 of 9 paths), 454 changed lines.
  • History on this PR: Test UI shard 4/16 was red on 05d9ba6b. The createCopy-13126 zh case read the English fallback before the studio zh catalogue loaded. Fixed on 1558d9bb by awaiting loadStudioCatalogue('zh') in that test file, as helpTextI18n already does.
  • Accepted deviations: ui/e2e/live/studio-object-designer.spec.ts is outside the claimed surface. Two lines open Advanced before F1 fills the id; without them this change turns F1 red. Approved by the seat.
  • Out of scope: two notes, not filed. The spec's developer wording for id / version describe() is a seam, and it now sits under Advanced. The landing's "writable base" copy is untouched.
  • Landing: non-governed, all checks green, mergeable_state clean ⇒ the seat lands it (pr_ready + automerge_enable).

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 30, 2026 03:10
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 30, 2026 03:10
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit 88d6020 Oct 30, 2026
56 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-1n23sn branch October 30, 2026 03:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Studio New Package: a name-only first step with plain help, instead of reverse-domain id, namespace and SemVer up front (#27521 row 24)

1 participant