Skip to content

UIU-3388: Add user version history to user detail view#3035

Merged
slaemmer merged 30 commits into
masterfrom
UIU-3388
May 18, 2026
Merged

UIU-3388: Add user version history to user detail view#3035
slaemmer merged 30 commits into
masterfrom
UIU-3388

Conversation

@slaemmer
Copy link
Copy Markdown
Contributor

@slaemmer slaemmer commented Apr 16, 2026

UIU-3388

Purpose

Staff users need to be able to track changes made to user records in order to investigate irregularities or answer queries. This PR adds a version history panel to the user detail view, displaying a chronological list of all recorded changes within the configured retention period, along with their source and a detailed diff per version.

Approach

A clock icon button (UserVersionHistoryButton) is added to the UserDetail pane header, to the right of the tags icon. It only renders when the user has ui-users.versionHistory.view and audit is enabled in settings, so it is automatically hidden when Version History is set to "Never". When the panel is open, the Actions button, tags icon, and clock icon are all disabled; Actions is replaced with a tooltip-wrapped disabled surrogate ("To enable Actions, close Version history.").

The panel itself (UserVersionHistory) delegates rendering to AuditLogPane from @folio/stripes/components, following the same pattern established by ui-inventory. Audit data is fetched via useUserAuditDataQuery, cursor-paginated by eventTs). useUserVersionHistory batch-fetches user display names and maps the raw audit items to the shape AuditLogPane expects, filtering out metadata-only updates (no user-visible change) and stripping internal fields (createdDate, updatedByUserId, etc.) from diffs. useUserVersionHistoryFormatters builds the field label map (including custom fields), action labels, per-field value renderers (patron group, contact type, department, dates, custom field types), and the card summary item formatter.

A new permission ui-users.versionHistory.view is declared, bundling ui-users.view and the required mod-audit read permissions. audit-data: 1.0 is added as a required Okapi interface.

Pre-Merge Checklist

Before merging this PR, please go through the following list and take appropriate actions.

  • I've added appropriate record to the CHANGELOG.md
  • Does this PR meet or exceed the expected quality standards?
    • Code coverage on new code is 80% or greater
    • Duplications on new code is 3% or less
    • There are no major code smells or security issues
  • Does this introduce breaking changes?
    • If any API-related changes - okapi interfaces and permissions are reviewed/changed correspondingly
      • Added a new permissions, additive only.
      • Added optional dependency on audit-config and audit-user interface. Version History Button is not shown when interface is not provided
    • There are no breaking changes in this PR.

Should be merged after the Trillium release is fixed with CHANGELOG at the correct location.

Should be merged at the same time as the version history settings PR for UIU-3385 as both together complement each other (user facing vs settings).

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 16, 2026

Jest Unit Test Results

    1 files  ± 0    288 suites  +9   5m 16s ⏱️ +4s
1 452 tests +57  1 449 ✅ +57  3 💤 ±0  0 ❌ ±0 
1 487 runs  +51  1 484 ✅ +51  3 💤 ±0  0 ❌ ±0 

Results for commit 118c83d. ± Comparison against base commit 542677d.

♻️ This comment has been updated with latest results.

slaemmer and others added 15 commits April 16, 2026 12:52
Correct the optional okapi interface declaration (no `audit-data`
interface exists — the feature depends on `audit-user` for the history
data and `audit-config` for the runtime enabled flag) and wrap the
version history button with `IfInterface` so the button does not mount
and no audit requests fire on tenants without mod-audit.
Adopt UIU-3385's hook implementation (constants-backed URL/namespace,
optional options arg) so both branches carry byte-identical content
for the shared hook + test files. Removes the add/add merge conflict
between the branches; remaining conflicts are mechanical additive
unions (constants, translations, package.json).
renderDetailsLastMenu uses FormattedMessage but the import was
missing, causing a runtime ReferenceError when the version history
pane is open.
Drop the central-tenant routing in the version history pane: real users
live in their home tenant (which may be a member, not the central one),
and mod-audit stores user audit events under whichever tenant emitted
the Kafka event. Always forcing central skipped audit data for users
whose primary affiliation is a member tenant. Defer to the operational
tenant, matching how the rest of UserDetail resolves patron groups,
departments, and user lookups.
- Move shared hasPerm mock reset to afterEach so a failing test does
  not poison sibling tests in UserVersionHistoryButton.
- Replace inline 'users.item.get' with a local VIEW_USER_PERMISSION
  constant in UserVersionHistory.
- Surface isError from useDepartmentsQuery, matching useAuditSettingsQuery.
- Add CUSTOM_FIELD_TYPES to src/constants.js and use it in
  useUserVersionHistoryFormatters in place of magic strings
  (stripes-smart-components fieldTypes is not exported publicly).
The version history formatter ran expirationDate, dateOfBirth,
enrollmentDate, and DATE_PICKER custom fields through FormattedTime
with hour/minute, displaying a spurious time. Replace with a
FormattedUTCDate-based renderDate helper, matching ExtendedInfo's
treatment of the same fields.
Match the options shape used by usePatronGroups, useUsersQuery, and
useStagingUsersQuery so the hook can be reused across tenants. Set
retry: false to avoid four failing GETs on permission denials when a
caller has ui-users.versionHistory.view but lacks
inventory-storage.departments.collection.get.
UserVersionHistoryButton previously returned null both when audit was
disabled and when the settings query failed, hiding the failure. Pass
isError through useIsAuditEnabled, log via stripes.logger when it
fires, and render a Loading spinner while the query is in flight so
the menu does not pop in once the request resolves.
Version history was wedged into the helperApp registry by storing
HELPER_APP.VERSION_HISTORY in the same slot as the tags helper, then
excluded from <HelperApp> dispatch with a guard. Give it its own
isVersionHistoryOpen state and openVersionHistory / closeVersionHistory
handlers so the two panes stop sharing a slot, and drop the now-unused
HELPER_APP.VERSION_HISTORY constant.
UserVersionHistoryButton briefly renders a Loading spinner on cold
cache. Mount a small PrefetchAuditSettings component at the top of
UsersRouting (gated by the audit-user / audit-config interfaces) so
the react-query cache is warm by the time the user opens a record
from the list, eliminating the spinner on the dominant flow. Deep
links to /users/preview/:id still race and fall back to the spinner.
@slaemmer slaemmer requested a review from a team May 5, 2026 09:24
@slaemmer slaemmer marked this pull request as ready for review May 5, 2026 09:24
@s3fs s3fs requested a review from Dmytro-Melnyshyn May 5, 2026 09:39
Comment thread package.json Outdated
Comment thread src/views/UserDetail/components/UserVersionHistory/UserVersionHistoryButton.js Outdated
Comment thread src/views/UserDetail/UserDetail.js Outdated
Comment thread src/views/UserDetail/components/UserVersionHistory/UserVersionHistory.js Outdated
Comment thread src/index.js Outdated
Comment thread src/hooks/useUserAuditDataQuery/useUserAuditDataQuery.js
Comment thread src/hooks/useUserVersionHistory/useUserVersionHistory.js Outdated
Comment thread src/utils/renderDate.js
Comment thread src/views/UserDetail/UserDetail.test.js
Comment thread src/views/UserDetail/components/UserVersionHistory/UserVersionHistory.js Outdated
Comment thread src/utils/renderDate.js
Comment thread src/views/UserDetail/UserDetail.test.js
Comment thread src/views/UserDetail/UserDetail.js Outdated
Comment thread src/views/UserDetail/UserDetail.js Outdated
Comment thread src/hooks/useAuditSettingsQuery/useAuditSettingsQuery.js
Comment thread src/views/UserDetail/components/UserVersionHistory/UserVersionHistory.js Outdated
@sonarqubecloud
Copy link
Copy Markdown

@sonarqubecloud
Copy link
Copy Markdown

@slaemmer slaemmer merged commit d3bb208 into master May 18, 2026
16 checks passed
@slaemmer slaemmer deleted the UIU-3388 branch May 18, 2026 13:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants