Repository navigation
feat(plugin-detail): the record activity timeline folds consecutive updates by one actor into one row with a count - #26055
Conversation
…e record activity timeline The sys_activity -> FeedItem mapper now carries the raw activity type, the row's metadata.kind, actor_id and changed_fields as optional FeedItem members. RecordActivityTimeline folds runs of adjacent 'updated' rows by one actor (at most 10 minutes apart) into one row with the entry count and the union of the changed fields' labels; the row expands to its entries. Claude-Session: https://claude.ai/code/session_01PoTpJPgXim1ybDgRyat4BY Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PoTpJPgXim1ybDgRyat4BY Co-authored-by: Claude <noreply@anthropic.com>
…module Keeps RecordActivityTimeline.tsx a components-only module (react-refresh). Claude-Session: https://claude.ai/code/session_01PoTpJPgXim1ybDgRyat4BY Co-authored-by: Claude <noreply@anthropic.com>
…list punctuation Intl.ListFormat is outside the package's TS lib, and the repo measured and rejected it for field lists (no separator in zh/ru unit styles). Claude-Session: https://claude.ai/code/session_01PoTpJPgXim1ybDgRyat4BY Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PoTpJPgXim1ybDgRyat4BY Co-authored-by: Claude <noreply@anthropic.com>
…-nv45n5 # Conflicts: # scripts/sdui-manifest.record.json
Claude-Session: https://claude.ai/code/session_01PoTpJPgXim1ybDgRyat4BY Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Scope: the declaration face ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
席位核对ACCEPT ·
|
TimelineEntry is already exported by app-shell (buildDebugApi.ts); the one-authority-per-exported-name pin refuses a second declaration. Claude-Session: https://claude.ai/code/session_01PoTpJPgXim1ybDgRyat4BY Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PoTpJPgXim1ybDgRyat4BY Co-authored-by: Claude <noreply@anthropic.com>
|
Seat 2 · head update · 2026-10-26T10:52Z FAIL round 1 (Test UI 14/16, |
…-nv45n5 # Conflicts: # scripts/sdui-manifest.record.json
Claude-Session: https://claude.ai/code/session_01PoTpJPgXim1ybDgRyat4BY Co-authored-by: Claude <noreply@anthropic.com>
…-nv45n5 # Conflicts: # scripts/sdui-manifest.record.json
…ds after merging main Claude-Session: https://claude.ai/code/session_01PoTpJPgXim1ybDgRyat4BY Co-authored-by: Claude <noreply@anthropic.com>
…-nv45n5 # Conflicts: # scripts/sdui-manifest.sources/i18n.json # scripts/sdui-manifest.sources/types.json
…g main Claude-Session: https://claude.ai/code/session_01PoTpJPgXim1ybDgRyat4BY Co-authored-by: Claude <noreply@anthropic.com>
…-nv45n5 # Conflicts: # scripts/sdui-manifest.sources/i18n.json
Claude-Session: https://claude.ai/code/session_01PoTpJPgXim1ybDgRyat4BY Co-authored-by: Claude <noreply@anthropic.com>
维护者速读改了什么:记录的讨论/动态面板里,同一人(或系统)连续修改同一条记录、相邻间隔不超过 10 分钟的「更新」合成一行,显示次数和改过的字段名,点开可看每一条。 席位核对seat 2 · 2026-10-26T23:05Z · head
|
Requested by Steve · project thread
Fixes #25959
Clause-②: yes
Metadata-protocol: none
What
The record activity timeline folds a run of consecutive update entries by one actor into one row with a count. This is the renderer half of #25787 (its server half, PR #25958, made each generic update summary name its changed fields).
ui/packages/plugin-detail/src/renderers/recordActivityFeed.ts).activityRowToFeedItemnow carries what it used to drop: the row's ownsys_activity.type(activityType), itsmetadata.kind(activityKind),actor_id(actorId,nullwhen the row names no user) andchanged_fields(changedFields, only when the column is an array, so an unstampednullrow is not read as "no fields"). Onlymetadata.kindis read from the metadata JSON; the recorded old/new values are never looked at.foldFeedItems, same module, pure). A run is adjacent items of the list the reader sees (after the filter): each anupdatedrow with no domain kind, by the sameactorIdAND the same display name (so two unnamed writers are never merged), each at mostFOLD_WINDOW_MS= 10 minutes after its neighbour. Any other row ends the run. A run of one is an ordinary row.RecordActivityTimeline.tsx). The folded row shows the actor, the latest entry's time,N updates, andUpdated FIELDS: the union of the changed fields, by the object's field label (fromRecordContextProvider'sobjectSchema, through the same translatedfieldLabelthe record sections use) and by machine name outside a record page; three names, thenN more. A button witharia-expandedexpands the run to its entries, each rendered exactly as an unfolded row. The panel heading still counts every entry.@object-ui/types). Four new optionalFeedItemmembers (Clause-② yes). A host item without them renders as before and never folds.detail.foldedUpdates,detail.foldedUpdateCount(count family),detail.foldedMoreFields(count family),detail.expandFolded,detail.collapseFolded, appended afterdetail.viewSourcein all ten packs and mirrored inDETAIL_DEFAULT_TRANSLATIONS. The field list is joined with the existingvalidation.formInvalidJoinerkey, notIntl.ListFormat(outside the package's TS lib, and measured and rejected for field lists inform-invalid-toast-joiner.test.tsx).scripts/sdui-manifest.record.jsonre-recorded; root changeset.changeset/25959-activity-fold.md(patch,@object-ui/types,@object-ui/plugin-detail,@object-ui/i18n).No host plumbing:
RecordDetailViewalready renders the discussion insideRecordContextProviderwithobjectSchema={objectDef}, soRecordDetailView.tsxis untouched.Choices for the seat
activityTypeis notupdated(created, deleted, assigned, shared, completed, comments, host items) and any row with ametadata.kind(a fired milestone).Tests
Head
1c8752a0(after mergingorigin/main):RecordActivityTimeline.fold-25959.test.tsx(new, 17 tests): the mapper carries the four members;foldFeedItemsfolds a run in order, splits on actor / system-vs-person / differing unnamed writers / a gap over the window, never folds the excluded kinds, counts entries without a summary; the timeline renders the thirteen-update campaign as one row with13 updatesand the field labels, keeps the comment visible, togglesaria-expandedand shows all 13 entries, falls back to machine names, truncates long lists, and reads a no-field run asUpdated record.recordActivityFeed.test.ts(two exact item shapes gainactivityType/actorId) andrecordActivityFeed.milestoneKind-12106.test.tsx(the marked item also carriesactivityKind).updatedtest mutated to never match, the new file goes 9 failed / 8 passed of 17; restored bygit checkout HEAD --, hash-verified.1c8752a0, underos-verify-lock.sh:vitest run packages/plugin-detail/ packages/i18n/plus the app-shell activity and defaults-mirror tests (RecordDetailView.activity*,.feed*,.replyCountOnRead,.recordOpenWaves,.authoredActivityThreading,.discussionFallbackPipeline,defaults-maps-mirror-en-pack,activityItemType): Test Files 403 passed, 1 skipped (404); Tests 4327 passed, 31 skipped. The rest of app-shell is left to CITest Core.pnpm --filter @object-ui/types --filter @object-ui/plugin-detail --filter @object-ui/i18n run type-check: exit 0. eslint on the touched files: 0 errors.dispatch-gates --commandsderived 46 commands on1c8752a0; all 46 exit 0, and--ranreconciles 46 derived / 46 run / 0 NOT-MEASURED (a derived zero).check-sdui-manifestincluded.Acceptance notes
kind(the reader is not served a field the milestone watches) and whose declaration names notypearrives as a plainupdatedrow and can fold. That is the redaction's documented behaviour, not a new gap.applyFeedConfig's page window, so a page oflimitentries can render as fewer rows. The window still counts entries, which is what "Load more" pages over.Generated by Claude Code