Repository navigation
Show audit changes in words: one line per list element, named - #999
Merged
Merged
Conversation
The change history read like a database dump: one line per stored field, list elements shown by their ids, property names and true/false. - Changes of one list element are one line, named by the element: "Specification attributes › Color family: added (Specification attribute option: Black, Show on product page: Yes, …)"; a removed element is one "removed" line - The element name is taken when the change is recorded (AuditChange .ElementNames), from the element's [AuditName] or Name; a reference names it by the referenced record. Element types without a Name are marked - Field names in words, Yes/No, names without the stored ids - The history popup text is cut to 300 characters and values to 60, with "…"; the full entry stays one click away - The detail page shows the field in words above the stored path; the CSV gets an ElementNames column. Stored paths and values do not change
…yments and tasks in the audit log
Comment on lines
+97
to
+100
| catch (Exception) | ||
| { | ||
| //keep the path only | ||
| } |
added 3 commits
October 30, 2026 07:24
A note is a record of its own, so adding one to a merchandise return, shipment or customer never showed in that record's history; order notes were recorded twice (the note itself and a hand-written entry on the order). [AuditOwner] marks the property holding the id of the record a note belongs to. The tracker stamps OwnerType/OwnerId on the note's entry, and the owner's store when the note has none, and the history of a record also lists the entries owned by it (new index OwnerType_OwnerId_CreatedOnUtc_Id). The hand-written IAuditEventRecorder.OwnedChange is gone.
…w blog and article comments in their post's history
Comment on lines
+157
to
+160
| catch (Exception) | ||
| { | ||
| //no store | ||
| } |
… language's history
A language pack holds thousands of resources, and each new one was an Insert
entry of its own. IAuditTracker.CountInserts<T> counts the inserts of a type
in a scope and records them as one bulk entry ("Import: language: Polish;
inserted: 9842") linked to the language; a changed value stays an entry of its
own. The import no longer writes a resource the file does not change.
TranslationResource.LanguageId is the owner, so a resource edit shows in the
language's change history. The history shows the details of an entry without
changes.
This was referenced Oct 30, 2026
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.
Type: feature
Issue
Follow-up to #998. The change history still read like a database dump. Adding one specification attribute to a product showed six lines:
true/falseand the ids stored next to names.This applies to every list of the domain (37 element types; 12 lists on a product alone, plus order items, addresses, shipment items, store domains, …). A large change also made the history popup cell very long.
Solution
Specification attributes › Color family: added (Attribute type: Option, Specification attribute option: Black, Allow filtering: No, Show on product page: Yes, Display order: 0). A changed element lists its fields (… › Color family: Display order: 0 → 2), and a removed one is one line,Categories › Lamps: removed.AuditChange.ElementNames), because a change of onlyDisplayOrderdoes not carry the element's name. It comes from the element's[AuditName], else itsName; on an[AuditReference]property it is the referenced record's name.[AuditName]is added to 19 element types (specification, category, collection, attribute mapping, warehouse, bundle/related/similar product, order/shipment/approval/cart item, gift voucher usage, product price, attribute combination SKU, store domain, discount rule); related/similar product and cart item also get the missing[AuditReference]. An element with nothing to name it by shows only its list (Tier prices: added (Quantity: 5, Price: 9.5)), never an id.AuditChangeText): field names from the property names (AttributeTypeId→ "Attribute type", the entity's own prefix dropped), Yes/No, names without the stored id. The history popup text is cut to 300 characters and each value to 60, with "…"; the list's Changes column to 200.ElementNamescolumn.AuditReferencesnow keys on the reference'sKeytoo.Gaps found while using it, fixed here too:
[AuditOwner]marks the property holding the id of the record a note belongs to (order, merchandise return, shipment and customer notes; blog post and knowledge base comments). The tracker stampsOwnerType/OwnerIdon the entry, plus the owner's store when the note has none, and a record's history also lists the entries it owns: "Merchandise return note: Note: — → Called the customer". New indexOwnerType_OwnerId_CreatedOnUtc_Id(installer and the 2.5 migration).IAuditEventRecorder.OwnedChangeis removed.entity-type="Permission,PermissionAction"), so the permissions page shows both the matrix and the actions.IAuditTracker.CountInserts<T>counts the inserts of a type in a scope and records one bulk entry linked to the language ("Import: language: Polish; inserted: 9842"); a changed value stays an entry of its own, and the import no longer writes resources the file does not change.TranslationResource.LanguageIdis the owner, so a resource edit shows in the language's history. Entries without changes show their details in the history.[AuditName]; a name is cut to the stored value length.Breaking changes
ElementNamescolumn betweenPathandOldValue; a script that reads the columns by position needs updating.IAuditEventRecorder.OwnedChange(added in Make the audit trail readable: real changes only, names instead of ids #998, not released) is removed.AuditEntrySearch.EntityTypemay hold several comma-separated types;IAuditTrackerhas a new memberCountInserts<T>(its one implementation isAuditTracker). New members only otherwise:AuditChange.ElementNames,AuditEntry.OwnerType/OwnerId,AuditChangeModel.Label.Testing
Grand.Infrastructure.Tests274 andGrand.Web.Admin.Tests1773 pass, with new tests for element naming (by reference, nested, removed element, unnamed element) and for the text (added/changed/removed element, keyed user field, masked field, cutting values and the whole text).Specification attributes › <attribute>: added (…).Specification attributes › <attribute>: Display order: 0 → 1.Specification attributes › <attribute>: removed.ElementNamescolumn holds the element name of the rows above.Grand.Business.Common.Tests(history with owned entries, several types) andGrand.Web.Common.Testspass.