diff --git a/apps/client/__tests__/config-schema-form.spec.tsx b/apps/client/__tests__/config-schema-form.spec.tsx index 6749b0cc..c885293e 100644 --- a/apps/client/__tests__/config-schema-form.spec.tsx +++ b/apps/client/__tests__/config-schema-form.spec.tsx @@ -246,6 +246,85 @@ describe('config schema form', () => { expect(html).not.toContain('config.detail.inheritedReadonly') }) + it('opens a runtime adapter account when its config schema is unavailable', () => { + const onChange = vi.fn() + const uiSection: ConfigUiSection = { + key: 'adapters', + kind: 'recordMap', + recordMap: { + mode: 'keyed', + keyPlaceholder: 'Adapter key', + schemas: {}, + unknownSchema: { + fields: [] + }, + unknownEditor: 'json' + } + } + + const html = renderToStaticMarkup( + + ) + + expect(html).toContain('adapter-account-manager__state') + expect(html).not.toContain('config-view__complex-editor') + expect(onChange).not.toHaveBeenCalled() + }) + + it('keeps the JSON fallback for an unknown adapter without an account route', () => { + const uiSection: ConfigUiSection = { + key: 'adapters', + kind: 'recordMap', + recordMap: { + mode: 'keyed', + keyPlaceholder: 'Adapter key', + schemas: {}, + unknownSchema: { + fields: [] + }, + unknownEditor: 'json' + } + } + + const html = renderToStaticMarkup( + undefined} + mergedModelServices={{}} + mergedAdapters={{}} + detailRoute={{ + kind: 'detailCollectionItem', + fieldPath: [], + itemKey: 'custom' + }} + t={t} + /> + ) + + expect(html).toContain('config-view__complex-editor') + expect(html).not.toContain('adapter-account-manager__') + }) + it('renders a schema-driven adapter detail route as a second-level config page', () => { const uiSection: ConfigUiSection = { key: 'adapters', diff --git a/apps/client/src/components/config/ConfigSectionForm.tsx b/apps/client/src/components/config/ConfigSectionForm.tsx index 632f5fb4..ed448b50 100644 --- a/apps/client/src/components/config/ConfigSectionForm.tsx +++ b/apps/client/src/components/config/ConfigSectionForm.tsx @@ -1733,6 +1733,36 @@ export const SectionForm = ({ }) const shouldRenderJsonFallback = !isKnownEntry && uiSection.recordMap.unknownEditor === 'json' const discriminatorField = uiSection.recordMap.discriminatorField ?? 'type' + const accountItemSchema = sectionKey === 'adapters' + ? itemSchema?.recordFields?.accounts?.itemSchema + : undefined + const isAdapterAccountsNestedRoute = sectionKey === 'adapters' && + detailRoute?.nestedPath?.[0] === 'accounts' + + if (isAdapterAccountsNestedRoute) { + return ( +
+ {detailNotice} + { + onOpenDetailRoute?.({ + kind: detailRoute.kind, + fieldPath: detailMeta.field.path, + itemKey: detailMeta.itemKey, + nestedPath: nextPath + }) + }} + t={t} + /> +
+ ) + } if (shouldRenderJsonFallback) { return ( @@ -1749,8 +1779,6 @@ export const SectionForm = ({ if (itemSchema != null) { if (sectionKey === 'adapters') { - const accountItemSchema = itemSchema.recordFields?.accounts?.itemSchema - const isAccountsNestedRoute = detailRoute?.nestedPath?.[0] === 'accounts' const hiddenFieldPaths = [ ...(isKnownEntry && uiSection.recordMap.mode === 'discriminated' ? [[discriminatorField]] : []), ['accounts'] @@ -1854,31 +1882,6 @@ export const SectionForm = ({ } ] - if (isAccountsNestedRoute) { - return ( -
- {detailNotice} - { - onOpenDetailRoute?.({ - kind: detailRoute?.kind ?? 'detailCollectionItem', - fieldPath: detailMeta.field.path, - itemKey: detailMeta.itemKey, - nestedPath: nextPath - }) - }} - t={t} - /> -
- ) - } - return (
{detailNotice} diff --git a/changelog/0.1.0-beta.10/adapter-account-detail-redacted.png b/changelog/0.1.0-beta.10/adapter-account-detail-redacted.png new file mode 100644 index 00000000..d915c346 Binary files /dev/null and b/changelog/0.1.0-beta.10/adapter-account-detail-redacted.png differ diff --git a/changelog/0.1.0-beta.10/client.md b/changelog/0.1.0-beta.10/client.md index 37ae3c92..7dbe69f4 100644 --- a/changelog/0.1.0-beta.10/client.md +++ b/changelog/0.1.0-beta.10/client.md @@ -4,8 +4,11 @@ - Polish Launcher settings with a full-bleed, content-sized tab strip and consistent 10px spacing, fix empty shortcut input rendering, and support `Command+,` on macOS or `Ctrl+,` on Windows and Linux to open settings directly. - Refine Launcher menu surfaces with opaque theme-owned root and language submenus, keep icon-label spacing consistent at 6px, and show the platform settings shortcut alongside the settings command. - Keep sender status-bar menus anchored and clickable when the account popup opens, including correct stacking above the composer input. +- Show runtime adapter account details even when the workspace has no adapter configuration schema, instead of falling back to an empty JSON editor. - Remove the duplicate plugin configuration entry from the settings sidebar now that plugin management lives in the plugin marketplace, and safely redirect obsolete plugin settings links to General. - Keep the new-session environment menu coherent when only the built-in default is available, and preserve a visible, keyboard-accessible control for restoring a collapsed status bar. - Normalize new-session composer edge spacing to the shared 10px inset across compact and medium desktop windows while keeping the wide 800px layout centered. ![New-session composer with consistent edge spacing](./compact-composer-padding.jpg) + +![Runtime adapter account detail with personal identifiers redacted](./adapter-account-detail-redacted.png)