Skip to content

feat(app-shell): offer Disable / Enable on a suite's module rows from the served disableable verdict - #28903

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-hip8m4
Nov 3, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/project-thread-hip8m4

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steedos · project thread

Fixes #28118

Clause-②: no
Metadata-protocol: none

维护者速读

What changes

  • Disable reads the served verdict. PackageDetailSheet gates its Disable / Enable button on the row's disableable (the disable door's own verdict, package-api-assembled.zod.ts SERVED_ROW_VERDICTS, served by GET /api/v1/packages and GET /api/v1/packages/:id), not on writable. It is read the way the sheet reads writable: anything but true offers no Disable. ⛔ Nothing is re-derived from manifest.type, scope or writable. Enable is still offered on any disabled package, as before (the enable door has no writability gate).
  • Every other write stays on writable. Edit, Publish, Revert, Duplicate, Adopt loose items and Delete are unchanged, so a module row (writable: false, disableable: true) offers only Disable / Enable beside the reads.
  • The read-only note. A read-only row that is disableable no longer says it "cannot be edited, disabled or deleted": two studio keys, engine.packages.detail.readOnlyDisableable and engine.packages.detail.codeReadOnlyDisableable (en, zh), say it cannot be edited or deleted but can be disabled and enabled again. The confirm dialog's consequence sentence (disableDescription) already reads right for a module and is unchanged.
  • Type. InstalledPackageRow gains disableable?: InstalledPackageAtEitherStage['disableable'], taken from the spec's served row. It is optional on the row type so that a row without the key types and renders as "not disableable".
  • Docs (doc rider 6540426908). content/docs/deployment/marketplace-handbook.mdx: step 7 says each package of a suite is its own row in Installed Apps and the sheet offers Disable where the runtime allows it; "Disabling a module" names the Console path and the disableable key.

Where module rows appear, measured before coding (reported on the card): install-local registers every package of the artifact with source: 'marketplace', so a marketplace suite's modules are their own rows in Setup → Installed Apps (?source=marketplace). A suite booted from code has source: 'code'; its modules are on the unfiltered Setup → Packages page, with the same button.

Tests

  • New PackagesPage.moduleDisable-28118.test.tsx (10 cases, real PackageDetailSheet and real PackagesPage):
    • (1) a module row with disableable: true shows Disable; it opens the confirm with the consequence copy, sends nothing until confirmed, then sends the one PATCH /api/v1/packages/:id/disable;
    • (2) every other write action is hidden on it; its read-only note is the disableable one, scope-less and project-scoped;
    • (3) disableable: false and a row with no key offer no Disable and keep the plain read-only note;
    • (4) a disabled module row shows Enable, which runs at once with no dialog;
    • (5) a non-module row served disableable: true offers Disable: the verdict decides, not manifest.type;
    • the Installed Apps view lists a marketplace module as its own row and its sheet offers Disable; control: the suite's app row (disableable: false) offers none.
  • Existing fixtures in readOnlyActions-13157, readOnlyReasonAndDisableConfirm-27521, adoptLooseItems-13339 and confirmFlows-11784 now carry disableable as the server serves it for a non-module package (equal to writable).
  • Ablation, once, on commit 2d45950f: node scripts/ablation-replace.mjs put the gate back to writable || !enabled (anchor 1 → 0, blob 93d7556c → 7ebf253c). The new file went red, 3 failed / 7 passed: (1), (5) and the Installed Apps case. Restored blob 93d7556c equals HEAD and git diff HEAD is empty. Case (4) and the controls stay green both ways, as expected: Enable does not change.

Acceptance notes

Verification

Local runs
  • pnpm --dir ui exec vitest run on the 5 touched test files: 5 files, 55 tests green.
  • The 25 Packages page, package source and metadata-admin i18n test files plus MarketplaceRowActions.installedAppsPins: 25 files, 292 tests green.
  • pnpm --dir ui exec vitest run packages/i18n/: 94 files, 1438 passed, 13 skipped.
  • check:i18n-keys, check:i18n-drift, check:i18n-dead-keys: exit 0.
  • ESLint on the 8 changed ts/tsx files: exit 0, 0 errors, 15 warnings, none on a changed line.
  • turbo run type-check --filter=@object-ui/app-shell --filter=@object-ui/i18n (each runs tsc --noEmit and tsc -p tsconfig.test.json, so the tests are compiled): 66 tasks, exit 0.
  • pnpm --dir ui exec vitest run scripts/: 169 files passed, 2 skipped; 4900 tests passed. check:new-line-citations: 0 new. node scripts/check-sdui-manifest.mjs: exit 0 (in the derived set).
  • dispatch-gates --commands at 2d45950f: 66 derived, 66 run, all exit 0; --ran reconciles 66 of 66 with 0 NOT-MEASURED. check:skill-examples first refused with exit 3 (@objectstack/client-react declarations not built); after pnpm --filter @objectstack/client-react build it ran: 280 prose examples type-check, exit 0.
  • Main merged at 4775dfce (4 commits; two touch app-shell and the studio en / zh catalogues, no conflict). Re-run on that head: the app-shell + i18n type-check (66 tasks, exit 0), the 25 Packages page files plus packages/i18n/ (119 files, 1730 passed, 13 skipped), the three i18n checks and check-sdui-manifest (exit 0). The derived-gate sweep above is from 2d45950f, before the merge; the merge adds no file to this diff.
  • Dogfood battery: n/a, no ! in the title and no (narrowing) arm.
  • NOT MEASURED: a live Console against a marketplace-installed suite. The measurement is from source and the landed server tests (packages-disable-app-module.test.ts pins the module row's source per install path; packages-disableable-verdict.test.ts pins the served verdict).

Generated by Claude Code

… the served disableable verdict

The package detail sheet gates Disable on the row's served `disableable`
(the disable door's own verdict) instead of `writable`, so a module of an
installed app, read-only for authoring, can be switched off and on from the
Packages page and the Installed Apps view. Every other write action stays
gated on `writable`. The read-only note on such a row says it can be
disabled (two studio keys, en and zh), and the marketplace handbook names
the button and the key.

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

Copy link
Copy Markdown
Contributor Author

triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

Path: none

Triage: stale PR · domain:ui#1 · 2026-11-03T03:08Z

⛔ Not a claim. The maintainer asked triage to sweep open PRs with no update for 3 h and push the owning lane.

Answer here: the next act, with an ETA, or the blocker, parked under landing-operations.md §C with its Blocked-by: / Resume-from: line.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

席位注记 · parked (landing-operations.md §C) · 2026-11-03T03:09Z

Answer to triage 6594440097: this PR is parked as a draft on purpose. It is not idle work.

Blocked-by: objectstack-ai/hotcrm#2383
Resume-from: hotcrm#2383 lands, on a HotCRM release that carries #28877. The seat then brings the branch up to main through the relay (pr_update_branch), reads CI on the new head, and posts the ACCEPT. That ACCEPT takes pr_ready then automerge_enable.

  • The hold is the one recorded in claim amendment 6568088585 and seat note 6568176097. Once this lands, a suite's module rows offer Disable. HotCRM must tolerate a disabled module first, or a customer sees broken HotCRM reads.
  • Head 4775dfce is green and clean today; no expected-red list is owed.
  • Contract review: none is owed. The PR declares Clause-②: no (two new studio strings in en and zh only, no published key or export), so there is no Clause-② record to write on this head.
  • ETA: none from this lane. It follows the HotCRM release; the seat's hourly patrol re-checks hotcrm#2383 and acts the same hour it closes.

@os-zhuang

Copy link
Copy Markdown
Contributor

平台的开发先行,hotcrm随后

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

席位核对 · ACCEPT · 2026-11-03T06:12Z

Head-sha: 263a3dd201f4af7085cf35badf6f8515ffb655d9

  • Hold released: the park note 6594457160 held this PR on app: the HotCRM app's UI-side reads of a disabled module (lookups, add-to-campaign / quote actions, the revenue dashboard tile) meet 404 OBJECT_PACKAGE_DISABLED instead of hiding (objectstack#28117 ruling A) hotcrm#2383, which is still open. os-zhuang, a governed approver, ruled on this PR at 05:50Z (comment 6596506876): 「平台的开发先行,hotcrm随后」. The platform lands first and HotCRM follows. That lifts the sequencing hold the seat set on itself in amendment 6568088585. The body's line "stays draft until hotcrm#2383" is superseded by that ruling. The seat brought the branch up to main through the relay (pr_update_branch, from 4775dfce to 263a3dd2) and read CI on the new head.
  • Shape:
    • The PR is a draft against main, with Fixes #28118 as its first card line, under claim 6568047039 and amendment 6568088585.
    • 10 files, +286 / −15:
      • PackagesPage.tsx (+24 / −10)
      • the new PackagesPage.moduleDisable-28118.test.tsx (+222)
      • four existing PackagesPage suites, each gaining a disableable fixture key (+2 or +3)
      • two studio strings in en and zh
      • marketplace-handbook.mdx, the doc rider
      • a changeset
    • That is the claimed surface. check-governed-merges --pr 28903: 0 of 10 paths hit the register, so it is not governed. 301 changed lines, under the human-merge threshold.
    • Clause-②: no and Metadata-protocol: none. The two keys are in the lazy studio namespace (en and zh only), not the published @object-ui/i18n packs. InstalledPackageRow.disableable? is an internal row type taken from the spec's served row. No contract-review record is owed.
  • Read in the diff: Disable/Enable is now gated on the served disableable === true, not writable. Anything else offers no Disable (fail closed). Enable is still offered on any disabled package. Edit, Publish, Revert, Duplicate, Adopt and Delete stay on writable, so a module row offers only Disable/Enable beside the reads. A read-only row that is disableable gets the new note: "cannot be edited or deleted, but can be disabled and enabled again". Nothing is re-derived from manifest.type, scope or writable.
  • Pins changed: four suites gain disableable on their fixture rows, so that writable rows still offer Disable under the new gate. No assertion changed.
  • Gates (check-runs on this head): 51 success, 8 skipped, 0 failed or pending. Lint & Repo Gates and TypeScript Type Check are both green. mergeable_state is clean.
  • Tests (dev): the new suite (10 cases, real PackageDetailSheet and PackagesPage) is red on main for every module-row case, and the CONTROLs stay green. It was measured at the original head. The merge from main brings in no change to these files, and CI is green on the merged head.
  • NOT MEASURED: no live suite install. Where the module rows appear was measured by code read: Installed Apps for a marketplace suite, Packages for a code-booted one.
  • Findings: the risk named at park still stands. Once this lands, an admin can disable a suite module, and HotCRM's UI-side reads of a disabled module meet 404 OBJECT_PACKAGE_DISABLED instead of hiding, until app: the HotCRM app's UI-side reads of a disabled module (lookups, add-to-campaign / quote actions, the revenue dashboard tile) meet 404 OBJECT_PACKAGE_DISABLED instead of hiding (objectstack#28117 ruling A) hotcrm#2383 ships. Per the ruling, HotCRM follows. hotcrm#2383 is already filed and open, so no new card is owed.
  • Serial: none open.
  • Landing: ordinary queue landing, pr_ready then automerge_enable. Fixes #28118 closes the card on merge.

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 tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Packages page: offer Enable / Disable on a suite's type:module rows once the server allows disabling them

2 participants