feat(ui): display names in activities + refactor feeds to tables/timelines on datum-ui#192
Closed
mattdjenkinson wants to merge 3 commits into
Closed
feat(ui): display names in activities + refactor feeds to tables/timelines on datum-ui#192mattdjenkinson wants to merge 3 commits into
mattdjenkinson wants to merge 3 commits into
Conversation
Switch the activity, events, and audit-log feeds from card-row lists to data-table layouts. Add a `timeline` variant on each so all three views can also render as a flat icon-list when the host prefers a denser presentation. Key changes: - Activity / Events / Audit-log feeds render via datum-ui Table with consistent columns, expand-row details, and a manual "Load more" pagination footer (no infinite-scroll observer loops). - New `Timestamp` component shows UTC / browser-local / Relative / microsecond timestamp on hover; used everywhere a time is rendered. - New shared `details` primitives (Section, Field, CopyButton, DetailGrid, DetailPanelShell) standardise the look of every expanded detail panel; values truncate with hover tooltips and copy buttons that fade in. - Drop-in primitives (alert, card, input, label, separator, skeleton, tabs, textarea, checkbox, sheet, select, button) are imported directly from @datum-cloud/datum-ui across the codebase; the local src/components/ui shadcn copies are gone. - Tooltip shim is now a thin wrapper around Radix directly so truncation downstream isn't broken by datum-ui's inline-flex trigger wrapper; styling mirrors datum-ui's bg-secondary popover with arrow. - Pause/Resume on the activity + events feeds now respects user intent (auto-restart effects skip while userPaused is set). - Pagination Intersection Observer no longer rebuilds on isLoading toggles; manual pagination is the default. - ChangeSourceToggle / EventTypeToggle / ActionToggle use datum-ui's primary/quaternary variants and force borderRadius:0 inline so the segmented control fills its wrapper edge-to-edge. - Hardcoded brand-pink CTAs (#BF9595) across policy / reindex views replaced by bg-primary / theme tokens. - Backend changes (DisplayName/Email on Actor/Link, iam User resolver, summary enrichment, CEL paths) included from the earlier display-name PR and tested locally. Drops the rollup PostCSS/Tailwind pipeline (no CSS shipped), removes VerbToggle and EventFeedItemSkeleton as unused, and deletes src/styles.css + tailwind.config.js + postcss.config.js.
The library no longer ships its own tailwind/postcss pipeline (host app provides Tailwind via @source). The example app's configs remain in place at example/postcss.config.js and example/tailwind.config.js for the Remix demo.
Contributor
|
@mattdjenkinson thoughts on separating the user enrichment stuff into a separate PR? I have some concerns around the pressure this could put on the control plane that I need to think through and don't want to hold up the UI improvements. |
Contributor
Author
|
@scotwells yeah i probs should have done that to begin with. Will sort. |
This was referenced May 1, 2026
Contributor
Author
|
Splitting this into two focused PRs for easier review:
The UI PR can merge independently — the new |
mattdjenkinson
added a commit
that referenced
this pull request
May 1, 2026
## Summary Rebuilds the activity UI to consume `@datum-cloud/datum-ui` as a peer dependency and converts the activity feed, events, and audit views to table + timeline layouts with manual pagination. This is the **UI half** of the work previously bundled in #192; the matching backend display-name enrichment ships in #193. ## What changes **Design system migration** - Promote `@datum-cloud/datum-ui` to a peer dependency - Replace local shadcn primitives with datum-ui exports where possible - Drop Tailwind/PostCSS configs and unused local components - Externalize peer deps in `rollup.config.mjs` - Update `Dockerfile` to drop postcss/tailwind copies **Layout refactor** - Convert `ActivityFeed`, `EventsFeed`, `AuditLogQueryComponent` to table/timeline views - Manual "Load more" pagination (replaces auto-scroll observer that was misfiring on tab switches) - Add `Timestamp` component using `Intl.DateTimeFormat` for timezone-aware rendering with a single tooltip - Add reusable details-panel primitives in `components/details.tsx`; apply across activity/audit/event expanded views - Truncation with tooltips on summary/notes columns - Tooltip shim renders Radix Tooltip directly (mirroring datum-ui styles) so flex truncation actually engages - Normalize toolbar styling, filter chips, and details-panel padding across feeds - Remove "unsaved changes" badge **Display name support** - Mirror `displayName` / `email` (both optional) on `Actor` and `ActivityLink` TS types - Render `actor.displayName ?? actor.name` with email/UID hover; user-typed link markers swap in `displayName` as visible text - Falls back cleanly when backend hasn't populated the new fields, so this PR can land independently of #193 ## Tooltip / truncation notes datum-ui's Tooltip wraps the trigger in a `relative inline-flex` span which broke parent flex truncation. To keep datum-ui's visual styling, the local Tooltip in `ui/tooltip.tsx` re-implements Radix Tooltip directly with the same class tokens — same look, no flex-chain breakage. <img width="1502" height="829" alt="Screenshot 2026-05-01 at 16 27 29" src="https://github.com/user-attachments/assets/57a564c5-dfd3-4d8c-91f8-3e5bc46367ba" /> <img width="1624" height="1061" alt="Screenshot 2026-05-01 at 13 55 32" src="https://github.com/user-attachments/assets/716e691e-3b80-4928-a139-54aafd2839fe" /> <img width="1624" height="1061" alt="Screenshot 2026-05-01 at 13 55 40" src="https://github.com/user-attachments/assets/53e7ff60-8132-4645-bb13-d4d989190e4f" /> <img width="1624" height="1061" alt="Screenshot 2026-05-01 at 13 55 54" src="https://github.com/user-attachments/assets/9c013a99-3e0a-4120-aa14-b69126510632" /> <img width="1624" height="1061" alt="Screenshot 2026-05-01 at 13 56 07" src="https://github.com/user-attachments/assets/38bed23d-40a1-4a05-949d-d9871cc39c1f" /> <img width="1624" height="1061" alt="Screenshot 2026-05-01 at 14 09 47" src="https://github.com/user-attachments/assets/a8f94d88-5038-4cfe-83b9-19ed75a14ab7" />
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two large pieces of work landed on this branch:
ActivityActorandActivityLinkcarry a server-resolvedDisplayName(andEmailfor links) so the UI can render human-readable user names instead of raw emails / UIDs.@datum-cloud/datum-ui, and share a single set of detail-panel primitives.Backend changes (Go)
pkg/apis/activity/v1alpha1/types_activity.go— addedActivityActor.DisplayNameandActivityLink.DisplayName/ActivityLink.Email(allomitempty). Marker fields preserved for backwards compatibility.internal/processor/userlookup.go(new) —UserResolverinterface +NoopUserResolver+CachedUserResolverwith TTL cache, single-flight collapse, and negative caching for misses.internal/processor/classifier.go—ResolveActorWithResolver(ctx, user, resolver)populatesDisplayNamefrom the iam User'sgivenName+familyName. Resolver errors are silently ignored; the activity is still emitted with whatever data is available.internal/processor/activity.go—ActivityBuildergains aUserResolver. NewenrichSummaryWithDisplayNamesrewrites the summary to substituteactor.Name(typically email) withactor.DisplayName, upgrades existing actorlink()entries in place (or appends a synthetic actor link for templates that didn't wrap the actor), and hydrates User-typed link targets via the resolver.internal/processor/evaluate.go+internal/activityprocessor/policycache.go— added*WithResolveroverloads alongside the existing functions so callers can opt into enrichment without changing the public API.internal/activityprocessor/userresolver.go(new) —IAMUserResolverqueriesiam.miloapis.com/v1alpha1/Userresources via a controller-runtime client, exposed asUnstructuredso we don't pull in milo's Go types as a dependency.internal/activityprocessor/processor.go— wiresNewCachedUserResolver(NewIAMUserResolver(k8sClient), 0, 0)into the Processor at startup.internal/processor/userlookup_test.go(cache hit, neg-cache, TTL expiry, single-flight, error-not-cached, empty-key short-circuit) andinternal/processor/enrichment_test.go(actor replacement, link upgrade in place, actor-not-in-summary, user link hydration, non-user link untouched, ResolveActorWithResolver paths). Full Go test suite green;go vet+go buildclean.UI refactor (
ui/)Datum-ui adoption + primitive sweep
@datum-cloud/datum-ui ^0.8.0as a peer dep (and devDep so the rollup build resolves locally). Externalised@datum-cloud/datum-ui/*inrollup.config.mjs— consumers bring their own pinned copy.alert,card,checkbox,input,label,select,separator,sheet,skeleton,tabs,textarea).src/components/ui/for the four datum-ui APIs that don't match the legacy shadcn shape:badge—variant=…→type=…+theme=….dialog— flatDialog{Header,Title,…}over datum-ui's compoundDialog.Header/.Title/….tooltip— re-built directly on@radix-ui/react-tooltip(datum-ui's<Tooltip message=…>wraps the trigger inrelative inline-flexwhich broke truncation downstream); styling mirrors datum-ui's secondary popover with arrow.<Button variant=… size=…>call sites rewritten to use datum-ui'stype=… theme=… size=…props (Python script that walked each opening tag); native HTMLtype="button|submit|reset"renamed tohtmlType.#BF9595/#0C1D31/#A88080/#E6F59F) across policy + reindex views replaced by theme tokens (bg-primary,text-primary-foreground, etc.).dist/). Removedtailwindcss,@tailwindcss/postcss,autoprefixer,rollup-plugin-postcss,tailwindcss-animatefrom deps.VerbToggle.tsxandEventFeedItemSkeleton.tsx.Feed refactor (table + timeline variants)
ActivityFeed— Card-row list →<Table>with columns Actor (avatar w/ tooltip) | Summary (truncated, full on hover) | Tenant (TenantBadge) | When (<Timestamp>) | expand. Row click toggles expansion; expanded panel spans all columns. Manual "Load more" pagination footer (count + button); IntersectionObserver path retained behindinfiniteScroll={true}.AuditLogQueryComponent+AuditLogFeedItem— same treatment with columns Verb (badge) | Summary | Status (✓/✗ + code) | When | expand.EventsFeed+EventFeedItem— Type (Normal/Warning) | Reason | Note | Object | When | expand.variant: 'feed' | 'timeline'. The'timeline'variant renders a flat icon-list (action-keyed icon square + summary + status/object + timestamp + expand) matching the existingActivityFeedItemtimeline shape so all three activity-hub tabs can present consistently.Timestampcomponent<Timestamp>(usesIntl.DateTimeFormat— no extra deps). Three visible variants:relative(default),utc,iso-utc,local. Hover always reveals a four-row tooltip (UTC / browser-tz / Relative / microsecond timestamp), matching staff-portal's<DateTime variant="detailed">pattern. Used everywhere a time is shown — feed rows, expanded panels, timeline variants.Detail panels
src/components/details.tsx:Section,Field,CopyButton,DetailGrid,DetailPanelShell. EachFieldrenders label-above-value; values truncate with a hover tooltip (disableTooltipopt-out for cells whose value already provides its own, e.g.<Timestamp>); copy button fades in on row hover.Pause/Resume + pagination correctness
userPausedtouseActivityFeedanduseEventsFeed. The auto-restart effects that previously re-opened the watch immediately afterstopStreamingnow skip whileuserPausedis true. Clicking Pause stays paused; tab switching while paused fetches but doesn't silently resume the stream.feed.tsx. The IntersectionObserver dependency cycle (re-creating on everyisLoadingtoggle, refiringloadMore()until items filled the viewport) is fixed by mirroringhasMore/isLoadinginto refs.TenantBadge / toolbars
ChangeSourceToggle/EventTypeToggle/ActionTogglenow use datum-ui'stype=primary theme=solidfor the active state (so Button picks up the matching foreground colour) and forceborderRadius: 0+border: 0inline on the active button so the segmented control fills its wrapper edge-to-edge with no internal seam.border-b border-border py-4); search inputs match (Search icon + Input + clear-X button).Notable verification
pnpm run type-check✓pnpm run build(rollup) ✓ (no warnings)go build ./...,go vet ./...,go test ./...— all green; new tests cover cache + enrichment paths.