Skip to content

feat(web): cascading record-type filter on the Audit page - #521

Merged
mforce merged 2 commits into
mainfrom
feat/520-audit-cascading-type-filter
Aug 13, 2026
Merged

feat(web): cascading record-type filter on the Audit page#521
mforce merged 2 commits into
mainfrom
feat/520-audit-cascading-type-filter

Conversation

@mforce

@mforce mforce commented Aug 13, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds a second "Record type" dropdown to the Audit page, ahead of the existing "Action" dropdown — picking a type narrows Action to only the ~48 codes actually recorded against that entity type, instead of one flat list.
  • AUDIT_ACTION_ENTITY_TYPE (web/src/i18n/enums.ts) is the action→entity-type map, read off every audit.WriteAsync(...) call site — not derived from the action's own "Entity.Verb" prefix, which is wrong for Account.SetLogo/RemoveLogo/SetBanner/RemoveBanner (prefixed Account, recorded against FarmLogo, a shared row per FarmLogo.cs).
  • Purely client-side narrowing: /api/v1/audit still filters on action alone, same as before — no backend change, no new query param sent.
  • Changing "Record type" clears a now-mismatched action so a hidden filter can never keep querying against a type no longer shown.
  • entityType is a third URL search param, independent of the existing action/entityId params from Audit: entity-scoped "View history" — who created/changed a specific record, and when #493.

Closes #520.

Test plan

  • npm run typecheck clean
  • AuditPage.test.tsx (46 tests) + enums.test.ts — narrowing, action-reset-on-type-change, URL round-trip, garbage-query-value fallback
  • Full web suite: 1776/1776 passing
  • Local pi (deepseek-v4-flash) review pass

A second "Record type" dropdown narrows the existing action dropdown to
only actions actually recorded against that entity type, instead of one
flat ~48-item list. The action->entity-type map is read off each
audit.WriteAsync(...) call site (not derived from the action's own
"Entity.Verb" prefix, which is wrong for the four Account.*Logo/Banner
actions — recorded against FarmLogo, a shared row). Client-side narrowing
only; the /api/v1/audit query still filters on `action` alone.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a34ab607cf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +106 to +108
const availableActions = entityTypeFilter
? AUDIT_ACTION_VALUES.filter((a) => AUDIT_ACTION_ENTITY_TYPE[a] === entityTypeFilter)
: AUDIT_ACTION_VALUES;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Normalize incompatible type/action URLs

When a shared or hand-edited URL contains a valid but incompatible pair such as ?entityType=Flock&action=User.Create, this list omits the selected action, so the Action control visually falls back to “All actions” while fetchPage continues querying User.Create. Validate actionFilter against availableActions and clear or ignore it when the pair is incompatible so a hidden filter cannot produce misleading results.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 983af91: actionFilter is now validated against availableActions for the current entityTypeFilter and ignored (not just reset on a dropdown click) when the URL's action isn't in scope for its type — closes it for both a manual click and a direct/shared URL load. Mutation-verified: reverting the validation makes the new test fail on its own action: undefined assertion.

Comment on lines 203 to +205
<div className="filters">
<label>{t("entityTypeFilterLabel")}
<select value={entityTypeFilter} onChange={(e) => updateEntityTypeFilter(e.target.value)}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Document the new cascading filter

This adds a user-visible control with non-obvious semantics—the record type narrows the Action choices but does not itself filter audit rows—without updating the SPA Help page or its in-app glossary. Add guidance to the Audit help section so users can understand the two-step filtering behavior, as required for every user-visible behavior change.

AGENTS.md reference: AGENTS.md:L251-L251

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in 983af91: a new Help bullet (auditRecordTypeFilter, en/es/tl) explaining the two-step narrow-then-filter behavior, plus a GLOSSARY.md entry (#520). Full web suite green (1778/1778), typecheck clean.

#520)

codex review of #521: a URL like ?entityType=Flock&action=User.Create paired
a valid but incompatible action with the record-type filter — the Action
select fell back to no visible selection while fetchPage kept silently
querying the hidden action. actionFilter is now validated against
availableActions for the current entityTypeFilter (ignored, not just reset
on a dropdown change), closing the gap for both a click and a direct URL
load. Also documents the new filter in the SPA Help page + GLOSSARY.md
(#520 was missing both, per AGENTS.md's per-PR doc-sync rule) and adds two
tests: the incompatible-URL-pair case (mutation-verified — reverting the
validation makes it fail on its own action:undefined assertion) and
clearing entityType back to "All types".
@mforce

mforce commented Aug 13, 2026

Copy link
Copy Markdown
Owner Author

@codex both findings addressed in 983af91 — see the two thread replies above for details.

@chatgpt-codex-connector

Copy link
Copy Markdown

Both findings are addressed in 983af91; no additional changes are needed.

Testing

  • npm run typecheck
  • ⚠️ npm test -- --run src/routes/AuditPage.test.tsx src/i18n/enums.test.ts (environment uses Node 20.20.2, while the installed Vitest worker invokes the newer --no-experimental-webstorage Node option; the worker could not start)

View task →

@mforce
mforce merged commit 64bab23 into main Aug 13, 2026
10 checks passed
@mforce
mforce deleted the feat/520-audit-cascading-type-filter branch August 13, 2026 02:13
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.

Audit page: cascading record-type filter to narrow the action dropdown

1 participant