Repository navigation
Commit 0c8c27e
feat(console): Setup → Integrations → Connector Credentials, and a credential step after a marketplace install (#28200)
<!-- claude-projects-attribution: {"github_login":"os-tesla"} -->
_Requested by **Tesla** · [project
thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6Jao2zgfxhwFdVq6dfqdLqxCuS)_
Fixes #27238
Clause-②: yes (widening: `@objectstack/service-automation` exports
`CONNECTOR_CREDENTIALS_UI_BUNDLE`, `CONNECTOR_CREDENTIALS_COMPONENT_REF`
and `CONNECTOR_CREDENTIALS_NAV_CAPABILITY`, and registers a new Setup
navigation entry `nav_connector_credentials` resolving component ref
`automation:connector-credentials`; no existing key, route or shape
changes)
Metadata-protocol: none
Skills-docs: updated here (`content/docs/automation/connectors.mdx`, a
Console paragraph pair in the existing "Setting a credential" section
rather than a new page, which would have duplicated that section)
## 维护者速读
- 改了什么:管理员现在可以在 Setup → Integrations → Connector Credentials
页面里查看、设置、替换和清除已安装应用的连接器凭据;从市场安装应用后,安装结果里会直接列出这个应用还缺的凭据,可以当场填,也可以「暂时跳过」,跳过的会给出去设置页的链接。
- 为什么改:按 #27230 裁决 A,托管环境的管理员碰不到服务器环境变量,以前只能调 API 才能填凭据;服务端接口(#27237)已在
main 上,这次补上 Console 这一半。
-
风险与回滚:值永远不回显,输入框始终为空,留空即「不改」,空值不会发出请求;拒绝(多组织隔离形态、无权限、旧服务端没有这些路由)显示为服务器原话的配置说明,不当作红色错误。回滚即
revert 本 PR,服务端行为不变。
-
先看:`ui/packages/app-shell/src/views/setup/connectorCredentials.ts`(读写规则与安装步骤的过滤),然后是
`ConnectorCredentialsPage.tsx` 和
`console/marketplace/ConnectorCredentialsStep.tsx`。
- 两分钟验证:`pnpm --dir ui exec vitest run
packages/app-shell/src/views/setup/connectorCredentials.test.ts
packages/app-shell/src/views/setup/ConnectorCredentialsPage
packages/app-shell/src/console/marketplace/__tests__/ConnectorCredentialsStep-27238.test.tsx
packages/app-shell/src/console/marketplace/__tests__/MarketplacePackagePage.credentialStep-27238.test.tsx`,预期
5 个文件 44 passed。
- 需要你做的:无,席位落地。
## What changes
**Setup → Integrations → Connector Credentials**
(`ui/packages/app-shell/src/views/setup/ConnectorCredentialsPage.tsx`)
- One row per reference from `GET
/api/v1/automation/connectors/credential-refs`: the reference, the
connectors naming it (with their package), its status badge (`set` /
`missing` / `rejected`, with the upstream's reason for `rejected`), its
source (`env`, `vault`) and when and by whom it last changed, plus when
it was last seen working.
- A masked input (`CredentialValueForm.tsx`, shared with the install
step) for each writable, declared reference. It starts empty whatever is
stored, Save stays disabled while it is empty, and a save sends exactly
`{ value }` with `PUT`. The row then shows the entry the door answered
after its reconcile, and the typed value is dropped from state.
- **Clear**, behind a confirmation dialog, for a value stored here
(`source: 'object'`). It sends `DELETE` with no body.
- A reference an environment variable supplies is read-only: no input
and no Clear, with a sentence saying the variable wins.
- Honesty: `404` / `405` reads "This server does not manage connector
credentials"; `403` (missing capability, or the `group` / `isolated`
posture), `501` and `503` show the server's own sentence as an
informational notice. Only anything else is a red failure, with Try
again.
**The entry ships with the door** (triage `6469948452`, cloud ADR-0009
shape)
- `packages/services/service-automation/src/connector-credentials-ui.ts`
declares `CONNECTOR_CREDENTIALS_UI_BUNDLE`: one
`navigationContributions` row into Setup's `group_integrations`, a
`component` item `nav_connector_credentials` naming
`automation:connector-credentials`, gated on `manage_metadata` (the
capability every verb of the door asks).
- `AutomationServicePlugin` registers it through the `manifest` service
at `kernel:ready`, after the inert-mode return. A one-shot tool
registers nothing, and a kernel with no manifest service boots with no
entry.
- App-shell registers the component for that ref in
`builtinComponents.tsx`, eagerly like `automation:packaged`. The nav
label is translated in the four platform locales, and
`check-app-nav-i18n.mjs` gains the bundle as a contributor row.
**The credential step after a marketplace install**
(`ui/packages/app-shell/src/console/marketplace/ConnectorCredentialsStep.tsx`)
- It reads the same listing, filtered to the package by
`connectors[].packageId`, and offers each reference that is not `set`,
still declared and writable (so `rejected` is offered and `env` never
is). Each has the masked input and **Skip for now**. A value the door
answers `set` closes its row; any other answer keeps the row open with
its new status. Skipped references stay listed with a link to the Setup
page.
- It is mounted in three install results: the package page's
install-local banner when the running kernel loaded the package
(`hotLoaded: true`), the org-package install on the marketplace page in
the same case, and the cloud install dialog / org deploy strip once the
app is served in this runtime.
- Where the listing cannot be read (a walled posture), it shows the
install answer's `credentialNote` instead.
**Docs and i18n**
- `content/docs/automation/connectors.mdx`: what the Console page shows,
the read-only env rows, the walled conclusion, and the install step with
skip.
- A `connectorCredentials` namespace (43 keys) in all ten Console packs.
- `ui/packages/i18n/src/locales/index.ts`: `builtInLocales` gets an
explicit type. The 43 keys tipped the inferred type of that map past
what `tsc` will serialize into the declaration file (`TS7056` on the
`@object-ui/i18n` build). Each property is `typeof <pack>`, so the type
is unchanged and is emitted as a reference.
## Tests
- `views/setup/connectorCredentials.test.ts` (18): read rules per
status, a malformed row dropped, a `200` without `data.credentialRefs`
read as a failure and never as an empty list, a network error read as a
failure, `PUT` body exactly `{ value }` at the encoded ref, an empty
value not sent, `DELETE` with no body, the install-step filter.
- `views/setup/ConnectorCredentialsPage.test.tsx` (13): rows, env
read-only, inputs masked and empty, an undeclared stored ref, empty
state, Save disabled when empty, save round-trip with the typed value
absent from the DOM afterwards, a refusal under the input, clear confirm
and cancel, `403` / `404` as notices with no `role="alert"`, `500` with
Try again. The posture sentence is transcribed from
`connectorCredentialWalledMessage('group')`.
- `views/setup/ConnectorCredentialsPage.navContribution.test.tsx` (3):
the production registration, the URL the ref builds, and the page
mounting through `ComponentNavView`.
-
`console/marketplace/__tests__/ConnectorCredentialsStep-27238.test.tsx`
(7) and `MarketplacePackagePage.credentialStep-27238.test.tsx` (3): the
package filter, set / rejected / skip, the `credentialNote` fallback,
and a real install-local round trip through `marketplaceApi` with
`hotLoaded: true`, walled, and `hotLoaded: false` (no step, no listing
read).
-
`packages/services/service-automation/src/connector-credentials-ui.test.ts`
(5): the bundle parses under `ManifestSchema`; its contribution exactly;
a `LiteKernel` boot registers it once at `kernel:ready`; an inert boot
and a boot without a manifest service register none.
## Acceptance notes
- **The step is after the install, not before it** (the card says
"prompts for the missing refs of the package being installed").
Measured: the door answers `404` for a reference no installed package
declares, so a value typed before the install could not be stored. The
step opens in the install result, where the package's connectors already
exist degraded and materialize as soon as a credential is set, with no
restart.
- **Cloud ask `6473504855`: adopted.** The step reads the same `GET
…/credential-refs` route the page uses, filtered by package, after any
install landing in this runtime: install-local, and a cloud install once
its app is served here (the same condition the suggested-bindings panel
already uses). It needs no cloud change and no new route. The hosted
install path itself stays objectstack-ai/cloud#3352's (triage
`6522868103`).
- `Clause-②` measured `yes (widening)` from the diff: three new exports
on the published `@objectstack/service-automation` entry and a new Setup
nav entry. The seat's claim said `no`.
- Not changed: the dogfood roster
`packages/qa/dogfood/test/platform-app-object-entry-views.test.ts`
judges object entries only, and this entry is a component, so it needs
no row.
- jsdom covers every acceptance bullet above. Only a live stack can show
three things: the entry appearing in a real Setup sidebar for an admin
and not for a member, a real install-local flipping a degraded connector
to ready through the step, and the walled posture's sentence on a
`group` deployment. None of the three was run here.
## Verification
Head `e7b058e5`, merged with `origin/main` `139bc181`.
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`: 97 derived, all exit 0. `--ran`
reconciliation: 97 run, 0 NOT-MEASURED, 0 UNRUN. Two of them
(`check:skill-examples`, `check:dual-build-cjs-loads`) first exited 3 on
missing dists and passed after a full workspace build.
- Builds: `env -u OS_SKIP_DTS pnpm turbo run build` for the console
closure plus service-automation, platform-objects and cli, then a full
workspace build and `pnpm --filter @object-ui/console build`.
- Outside the derivation, all exit 0:
```
pnpm --filter @objectstack/service-automation run typecheck :: exit 0
pnpm --filter @objectstack/service-automation run check:test-typecheck :: exit 0
pnpm --filter @objectstack/platform-objects run typecheck :: exit 0
pnpm --filter @objectstack/cli run typecheck :: exit 0
pnpm --filter @object-ui/i18n run type-check :: exit 0
pnpm --filter @object-ui/app-shell run type-check :: exit 0
pnpm check:app-nav-i18n :: exit 0 (13 contributors, setup: 58 merged nav ids, every id labelled in every locale)
cd ui && node scripts/check-eager-closure-budget.mjs :: exit 0 (2006.9 KB of 2431.6 KB)
cd ui && node scripts/check-i18n-call-site-keys.mjs :: exit 0
cd ui && node scripts/check-i18n-en-drift.mjs :: exit 0
pnpm --dir ui run check:new-line-citations :: exit 0 (0 new)
pnpm --dir ui exec vitest run packages/app-shell/src/views/setup packages/app-shell/src/console/marketplace :: exit 0 (50 files, 487 tests)
pnpm --dir ui exec vitest run packages/i18n :: exit 0
packages/services/service-automation: vitest run connector-credentials-ui, activation-ledger-registration, connector-credential-door :: exit 0 (33 tests)
eslint on the new and changed source files :: exit 0 (no warnings in the new files)
```
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L9qibvG8uA9GWnnZkscgFF)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 35ffb77 commit 0c8c27e
36 files changed
Lines changed: 2493 additions & 13 deletions
File tree
- .changeset
- content/docs
- automation
- deployment
- packages
- cli/scripts
- platform-objects/src/apps/translations
- services/service-automation/src
- ui/packages
- app-shell/src
- console/marketplace
- __tests__
- services
- views/setup
- i18n/src/locales
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
313 | 313 | | |
314 | 314 | | |
315 | 315 | | |
316 | | - | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
317 | 334 | | |
318 | 335 | | |
319 | 336 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
107 | 107 | | |
108 | 108 | | |
109 | 109 | | |
110 | | - | |
111 | | - | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | | - | |
116 | | - | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
117 | 116 | | |
118 | 117 | | |
119 | 118 | | |
| |||
203 | 202 | | |
204 | 203 | | |
205 | 204 | | |
206 | | - | |
207 | | - | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
208 | 211 | | |
209 | 212 | | |
210 | 213 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
416 | 416 | | |
417 | 417 | | |
418 | 418 | | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
419 | 431 | | |
420 | 432 | | |
421 | 433 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
155 | 155 | | |
156 | 156 | | |
157 | 157 | | |
| 158 | + | |
158 | 159 | | |
159 | 160 | | |
160 | 161 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
106 | 106 | | |
107 | 107 | | |
108 | 108 | | |
| 109 | + | |
109 | 110 | | |
110 | 111 | | |
111 | 112 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
106 | 106 | | |
107 | 107 | | |
108 | 108 | | |
| 109 | + | |
109 | 110 | | |
110 | 111 | | |
111 | 112 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
116 | 116 | | |
117 | 117 | | |
118 | 118 | | |
| 119 | + | |
119 | 120 | | |
120 | 121 | | |
121 | 122 | | |
| |||
| 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 | + | |
| 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 | + | |
0 commit comments