Skip to content

fix(plugin-grid): the Import Wizard stops offering the two control opt-outs the import doors refuse (objectui#12985) - #12989

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-12985-import-optouts
Oct 18, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-12985-import-optouts

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #12985
Clause-②: no

The Import Wizard no longer offers "Run automations & triggers" or "Import as historical data". Both import doors (POST /api/v1/data/:object/import and /import/jobs) honour runAutomations: false and treatAsHistorical: true for the system principal only and refuse every other caller 403 PERMISSION_DENIED (objectstack-ai/objectstack#24348, PR objectstack-ai/objectstack#24379, measured there by import-control-opt-out-gate.test.ts). A browser request is never the system principal, so a user who unticked the first box or ticked the second had the whole import refused.

What changed

  • packages/plugin-grid/src/ImportWizard.tsx: the two checkboxes, their useState pairs, their props on ImportOptions, their entries in the dependency lists and the reset, and the two fields assembleImportRequest set are removed. The wizard's import, dry-run and background-job requests (all three go through assembleImportRequest) carry neither key. Omitting both is the server's declared default (readImportControlFlags: runAutomations is on unless the body sends false; treatAsHistorical is on only for a literal true), so the default import is unchanged: automations run and the state machine is walked. No capability or entitlement is added.
  • packages/i18n/src/locales/*.ts (all ten packs) and the wizard's English fallback map IMPORT_DEFAULT_TRANSLATIONS: the three keys only those options read, grid.import.optRunAutomations, grid.import.optTreatHistorical, grid.import.optTreatHistoricalHint, are retired. A repo-wide git grep for the two leaf names is empty after the change (control: optCreateOptions still hits every pack).
  • Two comments (en.ts and makerEmptyState-v1-scope-8329.test.ts) listed dataImport.optRunAutomations as a live manual automation surface. That key is retired here, so the name is dropped from both lists.
  • .changeset/12985-import-optouts.md: @object-ui/plugin-grid and @object-ui/i18n, patch.

Contract note for the seat (Clause-② no, narrowing): ImportWizardProps and ImportResult are unchanged. The locale objects exported under @object-ui/i18n/locales/* lose three members of grid.import. The internal __testables.assembleImportRequest options type loses runAutomations and treatAsHistorical. ImportRequestOptions in @object-ui/types still declares both fields, because the server still accepts them from the system principal.

Pins

New file packages/plugin-grid/src/ImportWizard.controlOptOuts-12985.test.tsx, over the real wizard:

  • (a) "draws neither the run-automations nor the treat-as-historical option": in the preview step neither import-opt-run-automations nor import-opt-treat-historical is drawn, and no text matches automations or historical. CONTROL: the import-options panel and import-opt-create-options are drawn.
  • (b) + (c) "a completed default import sends neither opt-out and still imports": the request handed to importRecords has neither property, and equals the default import's request exactly (format, rows, writeMode: insert, createMissingOptions: false, skipBlankMatchKey: false) as the CONTROL that nothing else moved; onComplete receives 2 of 2 rows imported.

importDryRun.test.ts and importSavedMapping.test.ts drop the two option inputs and the assertions that the fields were sent.

Ablation (once): with the fix committed, ablation-replace.mjs put a data-testid="import-opt-run-automations" checkbox labelled "Run automations & triggers" back into ImportOptions (anchor 1 to 0, blob 3cdd0e998baf to 37f2a414044c), and pin (a) went red: Tests 1 failed | 1 passed (2), failing on queryByTestId('import-opt-run-automations'). Restore: blob after restore 3cdd0e998baf equals the HEAD blob and git diff HEAD is empty. A first attempt was a no-op: its replacement contained its own anchor, so the tool refused it (anchor count 1 to 1) and the test never ran. It was re-run with a new anchor, and that second run is the one quoted here.

Verification (at ac0198b332)

All of it ran on the committed tree at ac0198b332.

  • Closure build turbo run build --filter=@object-ui/plugin-grid^... (13 tasks): exit 0.
  • type-check for @object-ui/plugin-grid and @object-ui/i18n (tsc --noEmit && tsc -p tsconfig.test.json): exit 0. --listFiles confirms the new and edited test files are in the test program.
  • vitest --maxWorkers=1: the new and edited files plus the parity test, 4 files and 20 tests, passed. Every test file that names ImportWizard, runAutomations or treatAsHistorical, in plugin-grid (21 files, 148 tests) and elsewhere, plus the i18n parity and retired-key suites (20 files, 301 tests), passed.
  • Declared to CI: the full packages/plugin-grid/ and packages/i18n/ directories.
  • The pre-tsc battery, all exit 0: check:phantom-deps, check:self-import, check:unreferenced-sources, check:doc-example-readers, check:handler-key-reads, check:side-effects-array, check:element-data-source-declaration, check:spec-symbols, check:action-forward-parity, check:designer-field-key-parity, check:icon-record-names, check:i18n-keys, check:i18n-dead-keys, check:i18n-drift, check:i18n-designer-parity and check:control-bytes. Also exit 0: node scripts/check-hand-rolled-comment-mask.mjs, node scripts/check-changeset-fixed.mjs, node scripts/check-changeset-presence.mjs and check:new-line-citations (0 new).
  • Narrowed lint, run as eslint --no-inline-config over the 15 changed .ts / .tsx files:
    • Population: eslint.config.js scopes **/*.{ts,tsx}. The JSON output counts 15 files linted, 0 errors and 9 warnings.
    • The 9 warnings are all in ImportWizard.tsx. The same 9 rules fire on the base blob of that file, so the change adds none.
    • Invariance: the config sets no parserOptions.project, so linting is not type-aware and this diff cannot move a verdict on an untouched file.

Acceptance notes

  • Another caller of the fields: no other objectui caller sends runAutomations or treatAsHistorical. git grep hits only this file, its tests and the type ImportRequestOptions in packages/types/src/data.ts, which is outside this file surface and still correct as a wire type. data-objectstack forwards the request object and names neither field.
  • Doc drift, not filed (carrier: none): the JSDoc on ImportRequestOptions.runAutomations in packages/types/src/data.ts reads "off by default for bulk". The spec and server default is on (ImportRequestSchema, runAutomations declared default). No producer reads it.

Session: https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB


Generated by Claude Code

…t-outs the import doors refuse

Removes the "run automations" and "treat as historical" options, their
state and the request fields they set. Both import doors honour
runAutomations: false and treatAsHistorical: true for the system
principal only (objectstack-ai/objectstack#24348), so every signed-in
user who touched either option had the whole import refused 403. The
default import is unchanged: omitting both keys is the server's declared
default. Retires the three locale keys only those options read in all
ten packs and in the wizard's English fallback map.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XVp19E1MYUTFM3dnkwz8gB
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 76 chunks) 3164.6 KB 3744.1 KB
Main entry chunk (gzip) 79.8 KB 350 KB
Entry file index-BR8Fk4yj.js —
Status PASS —

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (buildIdentity.js) 0.80KB 0.49KB
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 21.41KB 7.88KB
app-shell (runtime-config.js) 24.52KB 8.48KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.11KB 3.87KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 45.59KB 12.03KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 20.67KB 6.12KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.74KB 3.94KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.62KB 0.83KB
auth (authStyles.js) 5.27KB 1.86KB
auth (createAuthClient.js) 42.84KB 11.66KB
auth (createAuthenticatedFetch.js) 8.54KB 3.46KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.26KB 8.03KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (commentAuthorship.js) 1.39KB 0.78KB
collaboration (index.js) 1.93KB 0.85KB
collaboration (useCollaborationTranslation.js) 6.50KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 612.39KB 149.02KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 248.83KB 69.44KB
fields (index.js) 292.36KB 74.70KB
i18n (LocalizationContext.js) 2.92KB 1.42KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.52KB 2.39KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.35KB 12.88KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 36.87KB 9.88KB
i18n (useSafeTranslation.js) 7.14KB 2.92KB
layout (index.js) 41.33KB 11.96KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 15.35KB 5.51KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.82KB 2.38KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.04KB 3.92KB
plugin-calendar (index.js) 55.04KB 16.10KB
plugin-charts (index.js) 85.06KB 23.39KB
plugin-chatbot (index.js) 232.44KB 54.60KB
plugin-dashboard (index.js) 147.53KB 39.95KB
plugin-designer (index.js) 233.95KB 50.08KB
plugin-detail (index.js) 266.04KB 70.50KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 181.16KB 46.84KB
plugin-gantt (index.js) 178.46KB 45.13KB
plugin-grid (index.js) 271.30KB 75.32KB
plugin-kanban (index.js) 63.37KB 19.51KB
plugin-list (index.js) 140.49KB 36.24KB
plugin-map (index.js) 27.17KB 9.00KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 46.66KB 13.13KB
plugin-timeline (index.js) 39.31KB 11.88KB
plugin-tree (index.js) 15.27KB 5.40KB
plugin-view (index.js) 94.68KB 24.36KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 12.07KB 3.68KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 125.37KB 41.04KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.71KB 2.11KB
react (schema-input.js) 4.31KB 2.07KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.50KB 1.99KB
sdui-parser (codegen.js) 9.45KB 3.76KB
sdui-parser (dashboard-widget-options.js) 3.07KB 1.30KB
sdui-parser (index.js) 7.30KB 3.12KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 25.28KB 7.81KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 23.87KB 7.83KB
types (ai.js) 4.39KB 2.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 4.12KB 1.61KB
types (authoring-nodes.js) 0.20KB 0.19KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (cloud.js) 0.20KB 0.18KB
types (complex.js) 4.44KB 2.07KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (dashboard-widget-layout.js) 2.06KB 0.96KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 1.13KB 0.65KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 5.78KB 2.70KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (node-slots.js) 7.18KB 2.34KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (product-blocks.js) 0.20KB 0.19KB
types (record-approval-decision.js) 0.20KB 0.20KB
types (record-components.js) 0.20KB 0.19KB
types (record-panels.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 4.99KB 1.96KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 19.93KB 7.26KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.48KB 3.50KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants