Skip to content

fix(fields): report a failed ImageField upload instead of leaking the rejection - #10310

Merged
os-project-manager merged 4 commits into
mainfrom
claude/issue-10226-image-upload-failure-reported
Sep 24, 2026
Merged

os-project-manager merged 4 commits into
mainfrom
claude/issue-10226-image-upload-failure-reported

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #10226
Clause-②: no

What changed

ImageField (@object-ui/fields) has two upload paths: the native picker (handleFileChange) and the crop dialog's confirm (handleCropConfirm). On main at 8b1f066 both ran the upload inside try … finally with no catch. Both handlers are fire-and-forget: React ignores the promise an onChange handler returns, and ImageCropperDialog calls onConfirm(blob, name) without awaiting it. So a rejected upload (network error, 413, storage outage) showed nothing and escaped as an unhandled promise rejection.

This PR catches the failure on both paths and renders the same message FileField renders for the same failure through the same useUpload() transport: key fields.file.uploadFailed, same name / error arguments, same defaultValue. The message goes in the widget's existing error row (the one the oversize-pick rejections already use, objectui#4141).

  • Picker path: each pick is caught on its own, as in FileField's useFileUploads. A failed pick is reported and not added. In a multi-select, the picks that did upload still land, and the oversize rejections are kept beside the upload failures.
  • Crop path: the original image stays (no onChange). The dialog still closes in finally, so the message shows in the field's error row instead of behind the dialog.
  • The message is a module-level helper, uploadFailedMessage(t, name, err), in the same shape as maxSizeError. A component-scoped useCallback made the React Compiler skip one more memoization, so the helper lives outside the component.

The key exists in every locale pack @object-ui/i18n ships. all-locales-key-parity.test.ts re-derives that, and pnpm check:i18n-keys checks the call site's arguments and inline defaultValue against the en pack.

Files: packages/fields/src/widgets/ImageField.tsx, packages/fields/src/widgets/ImageField.uploadFailure.test.tsx (new), .changeset/10226-image-upload-failure-reported.md (patch, @object-ui/fields).

Evidence (head 737663e)

Red first, on unmodified source. I ran the new test against 8b1f066 before touching the widget. All three failure cases went red, and each saw exactly one unhandledRejection carrying network down, with no failure text in the DOM:

× picker: shows the translated failure, adds nothing, leaks no rejection
× picker (multiple): adds the successful picks and reports only the failed one
× crop: shows the translated failure, keeps the original image, leaks no rejection
AssertionError: expected [ Error: network down ] to have a length of +0 but got 1   (x3)
TestingLibraryElementError: Unable to find an element with the text: Failed to upload "bad.png": network down
Tests  3 failed | 2 passed (5)

The two success controls (picker and crop, resolving transport) pass on both trees.

Ablation on the committed fix (head 737663e). A trap-guarded script replaced ImageField.tsx with its 8b1f066 blob, ran the test, and restored the file with git checkout HEAD -- PATH.

  • On-disk proof of the mutation: uploadFailed occurrences went 4 → 0 and catch (err) went to 0.
  • Result on the mutated tree: Tests 3 failed | 2 passed (5), the same three failures as above.
  • Restore proof: the file's hash equals its HEAD blob, and git diff HEAD is empty.

Local gates, on head 737663e, exit codes written to files before being read:

  • pnpm --filter @object-ui/fields type-check (tsc --noEmit && tsc -p tsconfig.test.json) → exit 0. I built the dependency closure first with pnpm --filter '@object-ui/fields^...' build.
  • pnpm exec vitest run packages/fields/ → exit 0, Test Files 179 passed | 1 skipped (180), Tests 3010 passed | 7 skipped (3017).
  • eslint on the two touched .ts(x) files → 0 errors. ImageField.tsx has 7 warnings against 6 on 8b1f066; the one new warning is below. lint.yml sets no --max-warnings.
  • check:i18n-keys, check:i18n-dead-keys, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:new-line-citations, check:control-bytes, check:test-path-roots, check:unreferenced-sources, scripts/check-changeset-presence.mjs, scripts/check-changeset-no-major.mjs → all exit 0.

Scope of local runs: repo-wide pnpm lint, the full pnpm test, and every other check:* family were left to CI. I ran lint only on the touched files. That narrowing is not a proof that no other file's verdict can move, and I did not check whether type-aware rules are on in eslint.config.js.

Acceptance notes

  • One new lint warning, not fixed here. react-hooks/preserve-manual-memoization now also fires on handleCropConfirm. Adding the catch makes the React Compiler skip memoizing that callback; it already skipped openCropper on main. This only affects optimization, and the file already carries the same warning. lint.yml sets no --max-warnings.
  • Non-Error rejections read undefined. For a rejection that is not an Error, (err as Error).message puts undefined in the message. FileField does exactly the same, and I copied its behaviour on purpose so the two widgets say the same thing. Carrier: none.
  • Possible shared helper. FileField and ImageField now each build the fields.file.uploadFailed call the same way. file-size-guard.ts explains why the size guard is shared rather than copied per widget, and the same argument could apply to this message. Moving it would touch FileField.tsx, which is outside this claim's file surface. Carrier: none.
  • Title strings in the crop dialog are hard-coded English. ImageCropperDialog's title and description do not go through t(). I left them alone: they are not part of this defect and not in scope.
  • Commit trailer. The first commit (2091538) has a Co-Authored-By trailer that names a model version. The later commits use the plain Claude form. History was not rewritten.

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


Generated by Claude Code

… rejection

Both upload paths (picker and crop confirm) were try/finally with no catch,
so a rejected upload rendered nothing and escaped as an unhandled promise
rejection. Catch per pick / per crop and render the translated
fields.file.uploadFailed message FileField shows for the same failure; the
failed image is not added, successful picks of a multi-select still land.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D486C1axmXnrkJMNUfz2eb
The fields test program carries no Node types by design; reach process
through globalThis with the two members the test uses.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D486C1axmXnrkJMNUfz2eb
…dule helper

A component-scoped useCallback for the message made the React Compiler skip
one more memoization (react-hooks/preserve-manual-memoization, 1 -> 2 on this
file); a pure module-level function taking t, as maxSizeError does, adds none.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D486C1axmXnrkJMNUfz2eb
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3039.2 KB 3104.5 KB
Main entry chunk (gzip) 147.8 KB 350 KB
Entry file index-DpyY1e7h.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 (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.68KB 6.20KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
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) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 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) 541.66KB 129.51KB
core (index.js) 8.94KB 3.59KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 222.47KB 61.83KB
fields (index.js) 253.79KB 64.11KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.22KB 2.26KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 33.36KB 10.88KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.15KB 11.05KB
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) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
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) 14.81KB 3.63KB
plugin-calendar (index.js) 51.44KB 14.62KB
plugin-charts (index.js) 71.82KB 20.13KB
plugin-chatbot (index.js) 198.27KB 47.18KB
plugin-dashboard (index.js) 133.00KB 35.19KB
plugin-designer (index.js) 215.98KB 44.34KB
plugin-detail (index.js) 258.85KB 67.53KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 144.77KB 37.17KB
plugin-gantt (index.js) 167.99KB 41.37KB
plugin-grid (index.js) 215.46KB 58.88KB
plugin-kanban (index.js) 48.83KB 15.21KB
plugin-list (index.js) 113.90KB 28.11KB
plugin-map (index.js) 21.74KB 7.07KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.55KB 11.99KB
plugin-timeline (index.js) 30.68KB 8.95KB
plugin-tree (index.js) 10.56KB 3.71KB
plugin-view (index.js) 85.18KB 21.05KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
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) 110.46KB 36.33KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.78KB 2.56KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.20KB
types (ai.js) 4.11KB 2.06KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
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) 0.20KB 0.18KB
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) 4.74KB 2.25KB
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 (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.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) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: 62/62 CONTRACT_REVIEW_TIER
Head-sha: 737663e1c92ed91132d18b3be043978201597e30

Adopted from an isolated at-tier reviewer by domain:ui seat 3, 2026-09-24T17:15Z. The reviewer wrote a model word on the Served-tier: line; this seat corrected it to the constant's name. Tier read off the reviewer's transcript: 62 of 62 stamped requests claude-fable-5-1 = CONTRACT_REVIEW_TIER.

① Derived judgments

  • Both upload paths catch the failure. handleCropConfirm is try / catch / finally. handleFileChange catches per pick inside Promise.all, so one rejection no longer rejects the outer promise. Base 8b1f066 has 0 uploadFailed and 0 catch (err).
  • The message is the same as FileField's: same key, same defaultValue, same name/error arguments. The key is present in all 10 locale packs.
  • A failed image is not added; successful picks still land; oversize rejections are kept. A crop failure keeps the original image, and finally closes the dialog.
  • The tests witness the defect. At head: Tests 5 passed (5). With the base blob swapped in: 3 failed | 2 passed (5), the three failure cases, and the restore is clean.
  • The changeset and PR body are true where checkable. One nuance with no contract effect: ImageField reports failures after all picks settle, while FileField reports each as it fails; the end state is the same.

② Semver level

  • patch for @object-ui/fields: correct. No export, prop, type or acceptance set changes.

③ Boundary flags

  • The file surface holds to the claim (3 files).
  • The dev's three out-of-scope notes are accurate and left alone: a non-Error rejection message (FileField parity), the key built in two places, and the cropper dialog's English strings.
  • Commit 2091538 carries a model-named Co-Authored-By trailer. No published artefact names a model: the diff and PR body scan returned 0. ⚠️ The squash commit message must be checked at landing so the trailer does not reach main.
  • One new optimisation-only lint warning; Lint is green.
  • Spec Main Shape Gate: the upstream drift, objectui#10287.

Implemented-by: claude/issue-10226-image-upload-failure-reported
Reviewed-by: session_01D486C1axmXnrkJMNUfz2eb

VERDICT: PASS


Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3039.6 KB 3104.5 KB
Main entry chunk (gzip) 147.8 KB 350 KB
Entry file index-Ll_IvPi8.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 (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.68KB 6.20KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
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) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 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) 541.66KB 129.51KB
core (index.js) 8.94KB 3.59KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 222.47KB 61.83KB
fields (index.js) 253.79KB 64.11KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.22KB 2.26KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 33.36KB 10.88KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.15KB 11.05KB
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) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
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) 14.81KB 3.63KB
plugin-calendar (index.js) 51.44KB 14.62KB
plugin-charts (index.js) 71.82KB 20.13KB
plugin-chatbot (index.js) 198.27KB 47.18KB
plugin-dashboard (index.js) 133.00KB 35.19KB
plugin-designer (index.js) 216.12KB 44.37KB
plugin-detail (index.js) 260.44KB 67.80KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 144.77KB 37.17KB
plugin-gantt (index.js) 167.99KB 41.37KB
plugin-grid (index.js) 215.46KB 58.88KB
plugin-kanban (index.js) 49.30KB 15.39KB
plugin-list (index.js) 113.90KB 28.11KB
plugin-map (index.js) 21.74KB 7.07KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.55KB 11.99KB
plugin-timeline (index.js) 30.68KB 8.95KB
plugin-tree (index.js) 10.56KB 3.71KB
plugin-view (index.js) 85.18KB 21.05KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
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) 110.46KB 36.33KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.78KB 2.56KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.20KB
types (ai.js) 4.11KB 2.06KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
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) 0.20KB 0.18KB
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) 4.74KB 2.25KB
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 (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.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) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
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

@os-project-manager
os-project-manager marked this pull request as ready for review September 24, 2026 18:31
@os-project-manager
os-project-manager added this pull request to the merge queue Sep 24, 2026
@os-project-manager
os-project-manager marked this pull request as draft September 24, 2026 18:32
Merged via the queue into main with commit 1f8ef0a Sep 24, 2026
45 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-10226-image-upload-failure-reported branch September 24, 2026 19:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants