Skip to content

fix(app-shell,plugin-detail): the record page counts each comment's replies on read, and a comment with none offers the reply input (objectui#12144) - #12147

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-12144-reply-count-on-read
Oct 11, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-12144-reply-count-on-read

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #12144

Clause-②: no

On the record page's discussion, a reply stored on the server now shows under its comment, and every comment read from the server offers the reply input wherever the caller may post one.

Measured first, on the base (158c75d)

The pin RecordDetailView.replyCountOnRead-12144.test.tsx (@object-ui/app-shell) renders RecordDetailView with no authored page. buildDefaultPageSchema then composes record:discussion, whose renderer (record-chatter.tsx) turns feed.enableThreading on. A fake data source answers the record's sys_comment and sys_activity reads, and the test drives the real panel. Run on commit 7a19eaa, which adds only the pin to the base: Tests 6 failed | 1 passed (7). The one green case is the threading-off control.

  • Effect 1 confirmed. With one parent row and one child row read, the child is on screen nowhere. It is not a root row, and the parent has no reply-count toggle (Unable to find an accessible element with the role "button" and name /1 reply/).
  • Effect 2 confirmed. No comment read from the server offers the reply input, with or without replies (Unable to find an element with the placeholder text of: Reply…). So the first reply on a comment cannot be posted from the page.

Cause, read on the base:

  • The sys_comment read maps parentId: c.parent_id and never sets replyCount. Only handleAddReply bumps replyCount, and it runs only after a reply is posted through the input.
  • With threading on, RecordActivityTimeline takes every item with a parentId out of the root list. It drew ThreadedReplies, the only place the reply list and the reply input render, only when item.replyCount is above zero.

The fix

  • @object-ui/app-shell RecordDetailView. In the same step that maps parentId, the sys_comment read counts each comment's children among the rows it returned and sets replyCount. This follows the platform's own contract: objectstack's sys_comment object definition (plugin-audit, sys-comment.object.ts) retired the stored reply_count and prescribes "count parent_id children at read time". The count groups by a truthy parent_id in a Map, the same way the timeline groups replies, so the two cannot disagree.
  • @object-ui/plugin-detail RecordActivityTimeline. The reply input is offered on every comment row the host hands onAddReply for, with or without replies, and on no other row (module-private canTakeReply). The reason matches objectui#11035's canStoreReaction: a reply is a sys_comment whose parent is a comment. An activity row's id would store a comment under an activity, and no read shows it there. The reply list keeps its one replyCount gate: a row whose replyCount is zero is handed no replies. So whether replies show never depends on whether the caller may post one, and no second threading model is added.

No prop, export, type member or locale key is added. The two new identifiers, canTakeReply and NO_REPLIES, are module-private, so the claim's Clause-②: no holds.

Dispatch hypotheses

  • H1, confirmed on 158c75d, by the git grep and reads above.
  • H2, confirmed through the host path: the synthesized default page, the real sys_comment read and mapping, and the real panel. The page pin above is the measurement. A pin of the timeline alone is kept separate and is not counted as the host measurement.
  • H3, confirmed and unchanged. onAddReply reaches the panel only under the feedComment grant (objectui#12140). With the create grant on sys_comment, every comment offers the input, a zero-reply comment included. With a read-only grant, no row offers it, and the stored reply still shows under its parent.
  • H4, confirmed. The zero-reply input needed a change to the timeline's render condition, and that change fits inside the file. No new prop, export or locale key was needed, so there was no needs_decision.

Pins (both new)

  • packages/app-shell/src/views/RecordDetailView.replyCountOnRead-12144.test.tsx, through the default record page, 7 cases:
    • (a) a parent and one child shows the child under the parent;
    • (a2) two children read as 2 replies;
    • (b) under a create grant, every comment row offers the input, a zero-reply one included;
    • (b2) a sys_activity row offers none;
    • (b3) the first reply on a read comment posts with parent_id and then shows under it;
    • (d) a read-only grant gives no input, and the stored reply still shows;
    • (c) CONTROL: with threading off (an authored record:discussion with feed.enableThreading: false), the list is unchanged: three rows in read order, no toggle, no input.
  • packages/plugin-detail/src/__tests__/RecordActivityTimeline.zeroReplyInput-12144.test.tsx, the timeline's render condition alone, 6 cases:
    • the input on a zero-reply comment, with a no-onAddReply control;
    • no input on an activity row;
    • a threading-off control;
    • the list's replyCount gate in both directions.

Ablations (one-shot, not left in the tree)

Each mutation went through ablation-replace.mjs, which reports the anchor hit count, the replacement count and the blob change. Each was restored with blob equal to HEAD and an empty git diff HEAD. vitest resolves @object-ui/plugin-detail to src through the root vitest.config.mts alias table, so no dist/ is in the path.

  1. Read mapping without the count (replyCount: undefined): the page pin goes red on (a), (a2) and (d), 3 failed | 4 passed. The input cases stay green, because the input no longer depends on the count.
  2. Input re-gated on replyCount (the base's condition): 6 failed | 7 passed across both pins, which is the three input cases in each file.
  3. Input on every row (comment-only check removed): 2 failed | 11 passed, the two activity-row cases.
  4. List without the replyCount gate: 1 failed | 12 passed, the timeline's list-gate case.

Verification (all on f7f477a; main unmoved at 158c75d when the PR opened)

  • Dependency closure build: turbo run build --filter='@object-ui/app-shell^...' --filter='@object-ui/plugin-detail^...' --concurrency=2 gave Tasks: 28 successful, 28 total.
  • pnpm --filter @object-ui/plugin-detail --filter @object-ui/app-shell run type-check: both packages echoed type-check and printed Done. tsc -p tsconfig.test.json --listFiles lists both new pins.
  • pnpm exec vitest run packages/plugin-detail/: Test Files 256 passed | 1 skipped (257), Tests 2491 passed | 8 skipped.
  • pnpm exec vitest run packages/app-shell/: Test Files 1270 passed | 1 skipped (1271), Tests 12306 passed | 9 skipped.
  • node scripts/check-changeset-presence.mjs, pnpm check:changeset-claims, pnpm check:pending-changeset-literals, pnpm check:control-bytes, pnpm check:new-line-citations and pnpm check:phantom-deps: all exited 0.
  • node scripts/check-governed-queue-guard.mjs --test on the diff answered NOT GOVERNED.
  • Lint, narrowed and not the repo-wide run (CI owns that). eslint --format json on the four changed source files read 4 files and 0 errors. RecordDetailView.tsx carries 109 warnings at both base and head. The config enables no type-aware linting (no parserOptions in eslint.config.js), and no rule under eslint-rules/ reads another file, so this diff cannot move the verdict on an untouched file.
  • Browser: NOT MEASURED. The sibling ../objectstack checkout in this container has no node_modules and no built spec/cli dist, so the per-agent backend cannot boot within the foreground budget. The host render above is the required measurement.

Acceptance notes

  • A reply whose parent is not in the read. The sys_comment read carries no $top, so it is one page of whatever size the server answers by default. A reply whose parent is not in that page counts toward no item. With threading on, it is still shown nowhere, as before. No second fetch was added.
  • The page window. record:discussion's window (feed.limit, default 20) takes the last N items of the merged feed, and a reply counts toward it. A reply whose parent is older than the window shows nowhere until "Load more" reaches the parent. That is the paging as it already stands, unchanged here.
  • A header comment this change falsifies. The header of RecordDetailView.commentWriteFailure-10899.test.tsx says the reply writer's input "is not reachable from a loaded feed … no read sets that". That is no longer true. It is outside the claim's file surface, so it is left for the seat. The reply writer's failure path is now reachable through the page.
  • Stale docs, unchanged here. In content/docs/plugins/plugin-detail.mdx, the "Console Integration" sample still uses camelCase sys_comment field names (threadId, _id, author). The ThreadedReplies table lists showReplyInput's default as false, where the code defaults to true. Neither describes the threading this change touches, so the docs page is unchanged.

Dev session: https://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sK (domain:ui seat 1 dispatch, os-dev).


Generated by Claude Code

… on read (objectui#12144)

Red on the base: through the synthesized default record page, a stored
reply shows nowhere and no comment read from the server offers the reply
input. The threading-off control is green.

Claude-Session: https://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sK
Co-authored-by: Claude <noreply@anthropic.com>
…eplies on read, and a comment with none offers the reply input (objectui#12144)

The record page mapped each sys_comment row to a feed item with its
parentId and never a replyCount, while the timeline takes every reply out
of the top-level list and draws a comment's replies, and the reply input
with them, only under a replyCount above zero. So a stored reply showed
nowhere, and no comment read from the server offered the reply input.

- RecordDetailView counts each comment's children in the rows its
  sys_comment read returned and sets replyCount beside parentId, as the
  sys_comment object definition prescribes (count parent_id children at
  read time).
- RecordActivityTimeline offers the reply input on every comment row the
  host hands onAddReply for, replies or not, and on no other row. The
  reply list keeps its one replyCount gate.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 290 chunks) 3175.5 KB 3204.6 KB
Main entry chunk (gzip) 74.2 KB 350 KB
Entry file index-DsEpc_ym.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) 20.05KB 7.41KB
app-shell (runtime-config.js) 22.59KB 7.89KB
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) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 41.19KB 11.12KB
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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
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) 587.31KB 141.42KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 240.39KB 67.09KB
fields (index.js) 275.07KB 70.00KB
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) 40.26KB 11.71KB
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) 54.31KB 15.86KB
plugin-charts (index.js) 84.72KB 23.27KB
plugin-chatbot (index.js) 201.52KB 47.99KB
plugin-dashboard (index.js) 144.20KB 38.95KB
plugin-designer (index.js) 233.53KB 49.80KB
plugin-detail (index.js) 250.31KB 66.05KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 177.80KB 46.04KB
plugin-gantt (index.js) 179.37KB 45.17KB
plugin-grid (index.js) 255.15KB 70.92KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 122.77KB 31.19KB
plugin-map (index.js) 27.24KB 9.03KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 92.11KB 23.27KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
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.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
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 (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) 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

…rd page (objectui#12144)

The header of RecordDetailView.commentWriteFailure-10899.test.tsx said
the reply writer's input was not reachable from a loaded feed, because
no read set replyCount. The record page now offers the reply input on
every comment it reads, so the header says that, and the file pins the
reply writer the way it pins the comment writer: a rejected sys_comment
create adds no reply, raises a localized error and keeps the draft.

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

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 290 chunks) 3175.5 KB 3204.6 KB
Main entry chunk (gzip) 74.2 KB 350 KB
Entry file index-DsEpc_ym.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) 20.05KB 7.41KB
app-shell (runtime-config.js) 22.59KB 7.89KB
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) 40.22KB 10.61KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.40KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.72KB 2.24KB
auth (SocialSignInButtons.js) 9.70KB 3.93KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 41.19KB 11.12KB
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.11KB 7.97KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.28KB 2.60KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
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) 587.31KB 141.42KB
core (index.js) 10.18KB 4.04KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 240.39KB 67.09KB
fields (index.js) 275.07KB 70.00KB
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) 40.26KB 11.71KB
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) 54.31KB 15.86KB
plugin-charts (index.js) 84.72KB 23.27KB
plugin-chatbot (index.js) 201.52KB 47.99KB
plugin-dashboard (index.js) 144.20KB 38.95KB
plugin-designer (index.js) 233.53KB 49.80KB
plugin-detail (index.js) 250.31KB 66.05KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 177.80KB 46.04KB
plugin-gantt (index.js) 179.37KB 45.17KB
plugin-grid (index.js) 255.15KB 70.92KB
plugin-kanban (index.js) 53.23KB 16.71KB
plugin-list (index.js) 122.77KB 31.19KB
plugin-map (index.js) 27.24KB 9.03KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 44.12KB 12.29KB
plugin-timeline (index.js) 39.21KB 11.85KB
plugin-tree (index.js) 15.07KB 5.33KB
plugin-view (index.js) 92.11KB 23.27KB
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) 120.63KB 39.56KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.50KB 2.06KB
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.80KB
sdui-parser (provenance.js) 3.84KB 1.90KB
sdui-parser (types.js) 0.28KB 0.23KB
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 (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) 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

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 11, 2026 16:32
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 11, 2026 16:32
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 11, 2026
Merged via the queue into main with commit a7d4920 Oct 11, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-12144-reply-count-on-read branch October 11, 2026 16:50
zhuangjianguo pushed a commit that referenced this pull request Oct 11, 2026
Brings main to faf4ce9 (objectui#12151, #12152, #12153, #12154, #12148,
#12149, #12147, #12158, #12159); none of them touches this branch's files.

Claude-Session: https://claude.ai/code/session_01TYgwmFK1q4KJ6Qq2WRLzsD
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants