Repository navigation
fix(app-shell): a new datasource starts on External and says what each schema mode does; a driver box's default is a placeholder, not a value - #30561
Merged
Conversation
…hema modes, box defaults as placeholders Claude-Session: https://claude.ai/code/session_01L6bhgTJT1f9c473zqg7Zhd Co-authored-by: Claude <noreply@anthropic.com>
…entences, box placeholders and managed no-sync note Claude-Session: https://claude.ai/code/session_01L6bhgTJT1f9c473zqg7Zhd Co-authored-by: Claude <noreply@anthropic.com>
…and box placeholders Claude-Session: https://claude.ai/code/session_01L6bhgTJT1f9c473zqg7Zhd Co-authored-by: Claude <noreply@anthropic.com>
…n the next commit) Claude-Session: https://claude.ai/code/session_01L6bhgTJT1f9c473zqg7Zhd Co-authored-by: Claude <noreply@anthropic.com>
… the previous commit) Claude-Session: https://claude.ai/code/session_01L6bhgTJT1f9c473zqg7Zhd Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
|
domain:ui#5 · os-sales · session_01L6bhgVwQZbHRRM9CaXeKif Contract reviewServed-tier: Reviewed 2026-11-05T16:16Z. Face: the ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
Contributor
Author
|
domain:ui#5 · os-sales · session_01L6bhgVwQZbHRRM9CaXeKif 维护者速读
席位核对 — ACCEPT · domain:ui#5 · head
|
This was referenced Nov 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Sales · project thread
Fixes #30327
Fixes #30331
Clause-②: yes (widening)
Metadata-protocol: none
维护者速读
_id的表会被删表重建、数据丢失。Filename 预填:memory:,用户输入路径会拼成:memory:/…。ui/packages/app-shell/src/views/metadata-admin/datasource/DatasourceResourcePage.tsx(SCHEMA_MODES、defaultConfig/withBoxDefaults、explainsNoSync)、ui/packages/i18n/src/namespaces/studio/zh.ts的engine.datasource.schemaMode*与noSyncManaged。pnpm --dir ui exec vitest run packages/app-shell/src/views/metadata-admin/datasource/,预期 9 个文件全绿(新文件 7 个用例)。What changes
Cards #30327 and the domain:ui half of #30331 (its server half, the test and save doors refusing a SQLite filename that is neither
:memory:nor a usable path, landed in #30395). Both are the New datasource dialog inDatasourceResourcePage.tsx.NEW_DATASOURCE_SCHEMA_MODE), sent with theexternal: {}block the schema requires (the existingdraftBodyrule). The page says it connects external databases and syncs their tables in as objects; only a federation source offers Sync. The spec's default (managedwhen a record declares none) is unchanged; only the dialog's starting choice moved. No reason was found that a new datasource needs managed: see What managed does to a source database below.data-testid="datasource-schema-mode-hint") says what the chosen mode does and which one reads an existing database.explainsNoSync): any managed row except the primarydefaultcarries "No Sync objects: this datasource is managed, so ObjectStack creates its tables and there are none to bring in. To read an existing database's tables, create a datasource for it with the schema mode External." It points to a new datasource rather than an edit to External, because what a switch does to objects already stored on a managed datasource was not measured.defaultConfigno longer seeds a text or number box with its JSON-Schema default; the box starts empty with the default as its placeholder (:memory:for SQLite Filename).withBoxDefaultsfills a still-empty box (or one typed then cleared) with its default for a new datasource's Test and Create, so the request is byte-for-byte what it was. This applies to every defaulted text or number box, not only Filename (PostgreSQL / MySQL / Mongohostandport, PostgreSQLschema): they had the same append trap, and their request is equally unchanged. An edit shows the stored values with no placeholder and sends them as they stand. Switches and selects keep their default as their value.studiorows in@object-ui/i18n(en and zh):engine.datasource.schemaModeExternalHint,schemaModeManagedHint,schemaModeValidateOnlyHint,noSyncManaged; the en and zh text ofschemaModeExternalandschemaModeManagedchanges. Thestudionamespace ships en and zh only by its recorded ruling..changeset/30327-new-datasource-mode-and-placeholders.md,@object-ui/app-shelland@object-ui/i18npatch.Branch: the harness-assigned
claude/project-thread-5qt4jg, notclaude/issue-30327-*; the cards are #30327 and #30331.What managed does to a source database (the card's first question)
Measured on the live rig (base
8e5fabe5): a SQLite file withparts (part_no, part_name, qty), 2 rows, andlegacy_items (_id, title), 2 rows. Registered once as a managed runtime datasource and once (a copy) as an external one, then an object bound to each table (PUT /api/v1/meta/object/NAMEwithdatasource).partsgained 9 columns (organization_id,created_at,created_by,updated_at,updated_by,owner_id,owning_business_unit_id,queue,__search), rows kept.legacy_itemswas dropped and recreated: 11 platform columns,_idgone, 0 rows (2 before). Code: driver-sqlinitObjects(sql-driver-rotation.ts) drops a table that has_idand noid, andALTER TABLE ADD COLUMNs every declared field an existing table lacks. A managed datasource is a DDL target by ADR-0015 §4.1 ("ObjectStack owns this schema: DDL + migrations allowed").external.remoteNameand are bound DDL-free (registerExternalObject).So binding an object on a managed datasource does alter a customer's tables, and can lose rows. That is why the dialog now starts on External, and why the managed sentence says to use it only for an empty database set aside for ObjectStack. The drop is a defect of its own, reported for the seat to file (see Acceptance notes).
Tests
DatasourceResourcePage.newDatasourceModes-30327.test.tsx(new, 7 cases; expectations read from Studio's table, never retyped):schemaMode: 'external'withexternal: {}and the typed filename;external;:memory:as its placeholder; typing gives exactly the typed path; Test sends it;filename: ':memory:',host: 'localhost',port: 5432); a switch keeps its default (wal: true);defaulthas no note;externalBlock-11368now chooses a mode unless it is External (it used to skip choosing for Managed);locale-13460reads the External option on the new dialog instead of Managed.Acceptance notes
Filename,Auto-migrate schema,Host,Portand the field descriptions (Database file path, or ":memory:" for an ephemeral database) are the JSON-Schematitle/descriptionof the driver config Zod schemas inpackages/spec/src/data/driver/*.zod.ts(.meta({ title }),.describe()), served byGET /api/v1/datasources/drivers(packages/services/service-datasource/src/driver-catalog.ts), as is the driver's description (File-backed (or in-memory) SQL database…). Measured live: the served sqlite entry carries"title": "Filename","title": "Auto-migrate schema". Per the dispatch,packages/**is untouched; the seat files adomain:servercard. The console does not translate them by key on its side, which would be a consumer-side dictionary of a producer's strings._idand noiddrops that table and recreates it empty (driver-sqlinitObjects,sql-driver-rotation.ts, theexistingColumns.includes('_id') && !existingColumns.includes('id')branch). reach:PUT /api/v1/meta/object/legacy_itemswithdatasource: customer_managed(runtime managed sqlite datasource on an existing file), 2 rows before, 0 after. Dedupe words: managed datasource drop table _id, initObjects legacy _id rebuild, schema sync data loss.validate-onlyas "Like external, but mismatches warn instead of fail", but no runtime code distinguishes the two (the boot validation readsexternal.validation.onMismatchonly). The Validate only sentence therefore claims only what holds: it reads an existing database like External and never changes its tables. Not measured live.Verification
Code head
21745ff7(base8e5fabe5); the PR head adds an evidence commit (83b029a7) and its removal, tree identical to21745ff7.Live rig and screenshots (zh-CN, 1440 wide)
examples/app-showcaseobjectstack dev --seed-adminon a private port with a file platform database, the console viaviteinui/apps/consolewithDEV_PROXY_TARGET, Chromium at browser locale zh-CN. Before shots: the page and the two studio tables restored to the base withgit restore --source=8e5fabe5on a freshly started vite; after shots:HEADrestored and vite restarted (served module confirmed by greppingNEW_DATASOURCE_SCHEMA_MODE).Before (main): the dialog opens on 托管(表结构由 ObjectStack 管理), Filename holds
:memory:as its value, typing a path gives:memory:/srv/data/parts.db, and the managed rowcustomer_managedhas no Sync and no word.After: the dialog opens on 外部:读取现有数据库 with its sentence; Filename is empty with
:memory:as placeholder, typing gives/srv/data/parts.db; choosing 托管 shows the managed sentence; the managed row carries the note. A datasource created through the dialog with only Name and Filename filled was sentschemaMode: 'external',external: {},config.filenameexactly the typed path; its row offers 同步对象, which listspartsandlegacy_items; the source file was unchanged.Tests, ablation, type-check, lint, gates
pnpm --dir ui exec vitest run packages/app-shell/src/views/metadata-admin/datasource packages/app-shell/src/views/metadata-admin/ResourceHistoryPage.rollbackConfirm-13333.test.tsx packages/i18nonce7fe5a1(source identical to21745ff7): Test Files 105 passed (105), Tests 1509 passed, 13 skipped; lock VERDICT command-exit 0.scripts/ablation-replace.mjs, each anchor x1 to x0, each restored with blob equal to HEAD andgit diff HEADempty), against the new test file:managed: 2 failed / 5 passed ((a), (g));explainsNoSyncreturns false: 2 failed / 5 passed ((f), (g));pnpm exec turbo run type-check --filter=@object-ui/app-shell --filter=@object-ui/i18n(tsc --noEmitandtsc -p tsconfig.test.json): 69 tasks successful, lock VERDICT command-exit 0.node scripts/pm/dispatch-gates.mjs --commands: 35 derived families, each exit 0;--ran: 35 derived, 35 run, 0 NOT-MEASURED (derived zero).Type Check UIjob's 21 ui checks run locally (type-check:coverage,check:phantom-deps…check:spec-symbols…check:i18n-keys,check:i18n-drift,type-check:scripts,type-check:vitest-config,type-check:e2e,type-check:vitest-setup): exit 0 each.check:new-line-citations: 0 new.Human Minimum
packages/specholds no runtime logic. (not touched)main, one pull request.packages/specnot touched.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_01L6bhgTJT1f9c473zqg7Zhd