Repository navigation
feat(app-shell,i18n): Home's My work section — approvals first, then notifications, with the pending-drafts row under its heading (objectui#12602) - #12656
Conversation
…fications, with the pending-drafts row under its heading The "Needs your attention" card becomes section 3 of the approved home artboard: a heading with the bell's total and an "Open inbox" link, an Approvals column listing the requests themselves (from the one shared pending-approvals read, so its count is the bell's), and a Notifications column. Two columns, not three: an inbox row carries no declared kind and no due date, so nothing guesses "assigned to me" or "overdue" from a topic. The pending-drafts banner above the greeting retires into a 40 px row under the heading that runs the same publish. A column is drawn only for a source the caller may read; the section renders nothing when neither is readable and nothing is waiting to publish. Claude-Session: https://claude.ai/code/session_015TchXBvZyEQx21tksAMaNv Co-authored-by: Claude <noreply@anthropic.com>
…llows the drafts count key The row's top rule sat outside its 40 px button, so each row measured 41 px at 1280 px; the rule now belongs to the 40 px row. The (s)-marker pin in perm-home-namespace-3546 reads `home.pendingDrafts.title`, the key that replaced `home.pendingDrafts.message`. Claude-Session: https://claude.ai/code/session_015TchXBvZyEQx21tksAMaNv Co-authored-by: Claude <noreply@anthropic.com>
|
changeset-claim-re-read
|
|
| Step | Outcome |
|---|---|
| Build packages | success |
| Check console performance budget | failure |
Which half objected:
| Eager-closure half | Verdict |
|---|---|
| Aggregate closure ceiling | ✅ pass |
| Per-chunk ceilings | ✅ pass |
| Per-chunk membership (declared packages) | ✅ pass |
| Ceiling sensitivity (headroom) | ✅ pass |
| Ceiling freshness (checkout vs. base branch) |
⚠️ A superseded ceiling is neither a size regression nor a drifted gauge. The bundle was measured correctly and the ceilings on the base branch are correct — but this checkout predates a change to them, so the verdicts above were weighed against numbers that are no longer in force. Nothing grew. Update this branch onto the base branch and letBundle Analysisrun again; do not widen a ceiling to clear it. TheCheck console performance budgetstep log names each superseded constant with both values (objectui#6245).
Reason: The entry chunk measured 75.3 KB, but the eager-closure half of this gate returned no trustworthy VERDICT: the report could not be read, a ceiling has drifted out of range of the regression it must catch, or (objectui#6245) a ceiling was replaced on the base branch after this checkout was made. The step log says which. This is not a passing budget — and it is not a size regression either.
See the workflow run for details.
📦 Bundle Size Report
| Package | Size | Gzipped |
|---|---|---|
| app-shell (consoleActionDispatch.js) | 0.20KB | 0.19KB |
| app-shell (index.js) | 21.19KB | 7.76KB |
| 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) | 20.39KB | 6.02KB |
| 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.62KB | 0.83KB |
| auth (authStyles.js) | 5.27KB | 1.86KB |
| 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.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) | 597.83KB | 144.29KB |
| core (index.js) | 10.18KB | 4.04KB |
| create-plugin (index.js) | 27.94KB | 9.51KB |
| data-objectstack (index.js) | 248.20KB | 69.22KB |
| fields (index.js) | 290.12KB | 74.14KB |
| 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.67KB | 11.85KB |
| 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.94KB | 16.05KB |
| plugin-charts (index.js) | 84.97KB | 23.36KB |
| plugin-chatbot (index.js) | 201.89KB | 48.13KB |
| plugin-dashboard (index.js) | 146.15KB | 39.55KB |
| plugin-designer (index.js) | 233.95KB | 50.08KB |
| plugin-detail (index.js) | 262.91KB | 69.49KB |
| plugin-editor (index.js) | 2.23KB | 1.05KB |
| plugin-form (index.js) | 180.92KB | 46.73KB |
| plugin-gantt (index.js) | 178.36KB | 45.08KB |
| plugin-grid (index.js) | 265.13KB | 73.29KB |
| plugin-kanban (index.js) | 59.42KB | 18.48KB |
| plugin-list (index.js) | 131.40KB | 33.50KB |
| plugin-map (index.js) | 27.07KB | 8.96KB |
| plugin-markdown (index.js) | 13.88KB | 4.80KB |
| plugin-report (index.js) | 46.66KB | 13.13KB |
| plugin-timeline (index.js) | 39.21KB | 11.85KB |
| plugin-tree (index.js) | 15.07KB | 5.33KB |
| plugin-view (index.js) | 93.43KB | 23.94KB |
| 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.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 (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
|
✅ Console Performance Budget
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
Size Limits
|
Contract reviewServed-tier: Face: the ① Derived judgments
② Semver level
③ Boundary flagsThe dev's three open questions:
Implemented-by: VERDICT: PASS Generated by Claude Code |
席位核对 · ACCEPT ·
|
Fixes #12602
Clause-②: yes
Summary
The "Needs your attention" card becomes the My work section of the approved home artboard (section ③ of 系统首页 · 四段式). The pending-drafts banner above the greeting moves into it.
usePublishAllDrafts().publishAllthe banner called. The banner is gone from both places it rendered; with no app yet, the row sits where the banner was.--primary, is the request count from the one shared pending-approvals read the bell and the greeting line use. A row opens the request in the Approvals inbox through its?request=deep link; View all opens the Approvals inbox.unreadTopicCount. Targets go throughresolveNotificationTarget, the bell's own helper.The fork: two columns, not three (Target 5)
sys_inbox_message, as objectstack declares it at f7e836d, hastopic(free text),title,severity(info, warning, critical),action_urlandcreated_at. It has no declared kind and no due date. So the section ships Approvals / Notifications, and nothing infers "assigned to me", "reminder" or "overdue" from a topic or a title.The field the three-column form needs is a declared kind on the notification and inbox row (assignment, mention, reminder, system), written by the emitter, plus a due-date datetime for the overdue line. Acceptance 1's "a notification with a past due date reads 逾期" is therefore not implemented. A test pins the opposite: a row whose topic reads like an assignment lands under Notifications, with no overdue text.
Who sees it
sys_inbox_message. Unknown permissions count as readable. This is the predicate the activity card uses forsys_activity.Measurements: /home at 1280 px, live showcase backend (published @objectstack packages)
Drafts publish, live: with one draft present, a click sent
POST /api/v1/meta/object/ticket/publish(200), and the row left the page.Tests
New pins:
HomePage.myWork-12602.test.tsx: the approvals column is first, the two-column form, the drafts row, and who sees the section.useHomeInbox.myWork-12602.test.tsx: approval rows deduped per id with count equal to the list length; the readability predicates.sharedInboxFeed.twoSurfaces.test.tsx: the approvals column pill equals the bell badge, over the real store and the real bell.Eight one-time ablations, each red and each restored: count taken from the preview, dedupe removed, approvals column removed, publish made a no-op, drafts row put back above the greeting, hide guard removed, inbox predicate forced true, notice shown only when the column is empty.
Runs:
pnpm exec vitest run packages/i18n/ packages/app-shell/src/console/home/ packages/app-shell/src/hooks/at 9bf4170: 177 files, 2066 tests passed.packages/app-shell/andpackages/i18n/at the first commit: 15000 passed, 1 failed. The failure was an i18n pin reading the renamed drafts key, repointed in 9bf4170.Acceptance 3 names
pnpm --filter @object-ui/app-shell testandpnpm check:i18n. The first is the package-cwd form AGENTS.md routes to the repo-root vitest invocation, so these runs use that form. The second does not exist; check:i18n-keys, check:i18n-drift and check:i18n-dead-keys all exit 0.Acceptance notes
useSharedPendingApprovalskeeps its shape (count plus status). It now reads a feed that holds the request rows, so the count is still the distinct ids from one request._drafts).home.myWork.*andhome.pendingDrafts.title/inPackage/waiting/nameSeparator. Removed:home.actionCenter.*and thehome.pendingDrafts.messagefamily.Provenance: built by the cloud session
session_015TchXBvZyEQx21tksAMaNv(claim6212954349) and opened by thedomain:uiseat 1 PM (session_011K9g23W67dy2zwnyzaoB6o) from that session's final message, because a cloud session cannot open a PR from its container. The seat changed nothing in the text.Generated by Claude Code