From 1b6ca4a0f41fa213beeb46439737182799cc3613 Mon Sep 17 00:00:00 2001 From: Marco Hamann Date: Wed, 10 Dec 2025 10:41:47 +0100 Subject: [PATCH 1/9] add custom formatter to use for objects in auditlog --- lib/AuditLog/AuditLogCard.js | 5 ++++- lib/AuditLog/AuditLogModal.js | 5 +++-- lib/AuditLog/AuditLogPane.js | 7 +++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/AuditLog/AuditLogCard.js b/lib/AuditLog/AuditLogCard.js index 707919509..8dcf795d9 100644 --- a/lib/AuditLog/AuditLogCard.js +++ b/lib/AuditLog/AuditLogCard.js @@ -18,6 +18,7 @@ const AuditLogCard = ({ fieldLabelsMap, isOriginal, isCurrentVersion, + itemFormatter, showSharedLabel, source, userName, @@ -89,6 +90,7 @@ const AuditLogCard = ({ onClose={() => setIsModalOpen(false)} fieldLabelsMap={fieldLabelsMap} fieldFormatter={fieldFormatter} + customItemFormatter={itemFormatter} actionsMap={actionsMap} columnWidths={columnWidths} /> @@ -105,8 +107,9 @@ AuditLogCard.propTypes = { fieldLabelsMap: PropTypes.object, isCurrentVersion: PropTypes.bool, isOriginal: PropTypes.bool, - showSharedLabel: PropTypes.bool, + itemFormatter: PropTypes.func, modalFieldChanges: PropTypes.arrayOf(PropTypes.object), + showSharedLabel: PropTypes.bool, source: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired, userName: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired, }; diff --git a/lib/AuditLog/AuditLogModal.js b/lib/AuditLog/AuditLogModal.js index ead99e827..1a9670d88 100644 --- a/lib/AuditLog/AuditLogModal.js +++ b/lib/AuditLog/AuditLogModal.js @@ -12,6 +12,7 @@ const AuditLogModal = ({ columnWidths, contentData, fieldFormatter, + customItemFormatter, fieldLabelsMap, label, onClose, @@ -38,13 +39,13 @@ const AuditLogModal = ({ changedFrom: item => changedFieldsFormatter({ fieldValue: item.oldValue, fieldName: item.fieldName, - listItemFormatter: itemFormatter, + listItemFormatter: customItemFormatter || itemFormatter, fieldFormatter, }), changedTo: item => changedFieldsFormatter({ fieldValue: item.newValue, fieldName: item.fieldName, - listItemFormatter: itemFormatter, + listItemFormatter: customItemFormatter || itemFormatter, fieldFormatter, }), }; diff --git a/lib/AuditLog/AuditLogPane.js b/lib/AuditLog/AuditLogPane.js index fa35db304..4ffc15f67 100644 --- a/lib/AuditLog/AuditLogPane.js +++ b/lib/AuditLog/AuditLogPane.js @@ -19,6 +19,7 @@ const AuditLogPane = ({ actionsMap, columnWidths, fieldFormatter, + itemFormatter, fieldLabelsMap, handleLoadMore, isInitialLoading, @@ -82,13 +83,14 @@ const AuditLogPane = ({ fieldChanges={fieldChanges} fieldLabelsMap={fieldLabelsMap} fieldFormatter={fieldFormatter} + itemFormatter={itemFormatter} actionsMap={actionsMap} columnWidths={columnWidths} modalFieldChanges={modalFieldChanges} /> ); }); - }, [versions, fieldLabelsMap, fieldFormatter, actionsMap, columnWidths, showSharedLabel]); + }, [versions, fieldLabelsMap, fieldFormatter, itemFormatter, actionsMap, columnWidths, showSharedLabel]); return ( Date: Thu, 11 Dec 2025 15:39:22 +0100 Subject: [PATCH 2/9] add collectionName to itemFormatter --- lib/AuditLog/changedFieldsFormatter.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/AuditLog/changedFieldsFormatter.js b/lib/AuditLog/changedFieldsFormatter.js index b1c9097d4..4437f2ea4 100644 --- a/lib/AuditLog/changedFieldsFormatter.js +++ b/lib/AuditLog/changedFieldsFormatter.js @@ -2,7 +2,6 @@ import { map } from 'lodash'; import List from '../List'; import NoValue from '../NoValue'; - const changedFieldsFormatter = ({ fieldFormatter, fieldValue, @@ -16,7 +15,7 @@ const changedFieldsFormatter = ({ if (typeof fieldValue === 'object' && !Array.isArray(fieldValue)) { return ( ({ name, value }))} + items={map(fieldValue, (value, name) => ({ name, value, collectionName: fieldName }))} itemFormatter={listItemFormatter} listStyle="bullets" marginBottom0 From def6eeb1311b1cc89a956bbb01fa5d04118f75cc Mon Sep 17 00:00:00 2001 From: Marco Hamann Date: Thu, 11 Dec 2025 16:13:05 +0100 Subject: [PATCH 3/9] add customItemFormatter to props validation --- lib/AuditLog/AuditLogModal.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/AuditLog/AuditLogModal.js b/lib/AuditLog/AuditLogModal.js index 1a9670d88..41298079d 100644 --- a/lib/AuditLog/AuditLogModal.js +++ b/lib/AuditLog/AuditLogModal.js @@ -91,6 +91,7 @@ AuditLogModal.propTypes = { oldValue: PropTypes.oneOf([PropTypes.string, PropTypes.array, PropTypes.object]), })).isRequired, fieldFormatter: PropTypes.object, + customItemFormatter: PropTypes.func, fieldLabelsMap: PropTypes.object, label: PropTypes.node.isRequired, onClose: PropTypes.func, From 1e22bca438fd11567263bf35f5682d46be3cb824 Mon Sep 17 00:00:00 2001 From: Marco Hamann Date: Fri, 12 Dec 2025 10:07:11 +0100 Subject: [PATCH 4/9] rename default and custom item formatter variables --- lib/AuditLog/AuditLogModal.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/AuditLog/AuditLogModal.js b/lib/AuditLog/AuditLogModal.js index 41298079d..f090b5a32 100644 --- a/lib/AuditLog/AuditLogModal.js +++ b/lib/AuditLog/AuditLogModal.js @@ -12,7 +12,7 @@ const AuditLogModal = ({ columnWidths, contentData, fieldFormatter, - customItemFormatter, + itemFormatter, fieldLabelsMap, label, onClose, @@ -26,7 +26,7 @@ const AuditLogModal = ({ changedTo: , }; - const itemFormatter = (field, i) => { + const defaultItemFormatter = (field, i) => { return (
  • {fieldFormatter?.[field.name]?.(field.value) || field.value} @@ -39,13 +39,13 @@ const AuditLogModal = ({ changedFrom: item => changedFieldsFormatter({ fieldValue: item.oldValue, fieldName: item.fieldName, - listItemFormatter: customItemFormatter || itemFormatter, + listItemFormatter: itemFormatter || defaultItemFormatter, fieldFormatter, }), changedTo: item => changedFieldsFormatter({ fieldValue: item.newValue, fieldName: item.fieldName, - listItemFormatter: customItemFormatter || itemFormatter, + listItemFormatter: itemFormatter || defaultItemFormatter, fieldFormatter, }), }; @@ -91,7 +91,7 @@ AuditLogModal.propTypes = { oldValue: PropTypes.oneOf([PropTypes.string, PropTypes.array, PropTypes.object]), })).isRequired, fieldFormatter: PropTypes.object, - customItemFormatter: PropTypes.func, + itemFormatter: PropTypes.func, fieldLabelsMap: PropTypes.object, label: PropTypes.node.isRequired, onClose: PropTypes.func, From be36e69a28912dc7daabc9851e5435ee4a571b12 Mon Sep 17 00:00:00 2001 From: elsenhans Date: Mon, 15 Dec 2025 10:27:57 +0100 Subject: [PATCH 5/9] STCOM-1475-add-custom-item-formatter renaming prop to itemFormatter --- lib/AuditLog/AuditLogCard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/AuditLog/AuditLogCard.js b/lib/AuditLog/AuditLogCard.js index 8dcf795d9..095dd1802 100644 --- a/lib/AuditLog/AuditLogCard.js +++ b/lib/AuditLog/AuditLogCard.js @@ -90,7 +90,7 @@ const AuditLogCard = ({ onClose={() => setIsModalOpen(false)} fieldLabelsMap={fieldLabelsMap} fieldFormatter={fieldFormatter} - customItemFormatter={itemFormatter} + itemFormatter={itemFormatter} actionsMap={actionsMap} columnWidths={columnWidths} /> From f706261b63c4fdacc7d096a53a0e7f483fef1587 Mon Sep 17 00:00:00 2001 From: elsenhans Date: Mon, 15 Dec 2025 12:05:59 +0100 Subject: [PATCH 6/9] STCOM-1475-add-custom-item-formatter add test for itemFormatter, fix eslint errors --- lib/AuditLog/AuditLogModal.js | 2 +- lib/AuditLog/changedFieldsFormatter.js | 1 + lib/AuditLog/tests/AuditLogModal-test.js | 97 ++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/lib/AuditLog/AuditLogModal.js b/lib/AuditLog/AuditLogModal.js index f090b5a32..70c1f2d90 100644 --- a/lib/AuditLog/AuditLogModal.js +++ b/lib/AuditLog/AuditLogModal.js @@ -91,8 +91,8 @@ AuditLogModal.propTypes = { oldValue: PropTypes.oneOf([PropTypes.string, PropTypes.array, PropTypes.object]), })).isRequired, fieldFormatter: PropTypes.object, - itemFormatter: PropTypes.func, fieldLabelsMap: PropTypes.object, + itemFormatter: PropTypes.func, label: PropTypes.node.isRequired, onClose: PropTypes.func, open: PropTypes.bool.isRequired, diff --git a/lib/AuditLog/changedFieldsFormatter.js b/lib/AuditLog/changedFieldsFormatter.js index 4437f2ea4..130e0ddaf 100644 --- a/lib/AuditLog/changedFieldsFormatter.js +++ b/lib/AuditLog/changedFieldsFormatter.js @@ -2,6 +2,7 @@ import { map } from 'lodash'; import List from '../List'; import NoValue from '../NoValue'; + const changedFieldsFormatter = ({ fieldFormatter, fieldValue, diff --git a/lib/AuditLog/tests/AuditLogModal-test.js b/lib/AuditLog/tests/AuditLogModal-test.js index d5437015f..aba933b81 100644 --- a/lib/AuditLog/tests/AuditLogModal-test.js +++ b/lib/AuditLog/tests/AuditLogModal-test.js @@ -155,4 +155,101 @@ describe('AuditLogModal', () => { it('the onClose callback should be fired', () => converge(() => onClose.called)); }); + + describe('itemFormatter', () => { + describe('when using DEFAULT itemFormatter', () => { + const contentDataWithArray = [{ + changeType: 'MODIFIED', + fieldName: 'arrayField', + newValue: ['item1', 'item2', 'item3'], + oldValue: ['oldItem1', 'oldItem2'], + }]; + + beforeEach(async () => { + await mountWithContext( + + + + ); + }); + + it('should render list items with default
  • tags', async () => { + await mcl.find(MultiColumnListCell({ row: 0, columnIndex: 2 })).perform(el => { + expect(el.querySelectorAll('li')).to.have.length(2); + expect(el.querySelectorAll('.custom-item')).to.have.length(0); + }); + + await mcl.find(MultiColumnListCell({ row: 0, columnIndex: 3 })).perform(el => { + expect(el.querySelectorAll('li')).to.have.length(3); + expect(el.querySelectorAll('.custom-item')).to.have.length(0); + }); + }); + }); + + describe('when using CUSTOM itemFormatter (object)', () => { + const customItemFormatter = (field, i) => { + return ( +
    + CUSTOM: {field.value} +
    + ); + }; + + const contentDataWithObject = [{ + changeType: 'MODIFIED', + fieldName: 'objectField', + newValue: { + a: 'item1', + b: 'item2', + c: 'item3', + }, + oldValue: { + x: 'oldItem1', + y: 'oldItem2', + }, + }]; + + beforeEach(async () => { + await mountWithContext( + + + + ); + }); + + it('should render object values using the custom itemFormatter', async () => { + await mcl.find(MultiColumnListCell({ row: 0, columnIndex: 2 })).perform(el => { + expect(el.textContent).to.include('CUSTOM: oldItem1'); + expect(el.textContent).to.include('CUSTOM: oldItem2'); + + const customItems = el.querySelectorAll('.custom-item'); + expect(customItems.length).to.equal(2); + }); + + await mcl.find(MultiColumnListCell({ row: 0, columnIndex: 3 })).perform(el => { + expect(el.textContent).to.include('CUSTOM: item1'); + expect(el.textContent).to.include('CUSTOM: item2'); + expect(el.textContent).to.include('CUSTOM: item3'); + + const customItems = el.querySelectorAll('.custom-item'); + expect(customItems.length).to.equal(3); + }); + }); + }); + }); }); From 0f910fc50af8ad150880986a8ae065ac663d89fc Mon Sep 17 00:00:00 2001 From: elsenhans Date: Fri, 19 Dec 2025 08:54:19 +0100 Subject: [PATCH 7/9] STCOM-1475-add-custom-item-formatter add itemFormatter to readme.md --- lib/AuditLog/AuditLogModal.js | 1 + lib/AuditLog/readme.md | 3 +++ 2 files changed, 4 insertions(+) diff --git a/lib/AuditLog/AuditLogModal.js b/lib/AuditLog/AuditLogModal.js index 70c1f2d90..2c389c580 100644 --- a/lib/AuditLog/AuditLogModal.js +++ b/lib/AuditLog/AuditLogModal.js @@ -33,6 +33,7 @@ const AuditLogModal = ({
  • ); }; + const formatter = { action: item => actionsMap?.[item.changeType] || item.changeType, field: item => fieldLabelsMap?.[item.fieldName] || item.fieldName, diff --git a/lib/AuditLog/readme.md b/lib/AuditLog/readme.md index 9fb679994..369129bf1 100644 --- a/lib/AuditLog/readme.md +++ b/lib/AuditLog/readme.md @@ -68,6 +68,9 @@ handleLoadMore | func | Callback fired when the "Load more" button is clicked isInitialLoading | bool | Flag that indicates whether data is being loaded for the first time | | false isLoading | bool | Flag that indicates whether data is being loaded | | false isLoadMoreVisible | bool | Flag that indicates whether "Load more" button visible or not | true | false +itemFormatter | func | +Formats changed field values of objects or arrays in modal content, used to format oldValue/newValue fields. +Receives a field object with `name`, `value`, and `collectionName` properties and the item index. Returns a list item element. | `(field, i) =>
  • {fieldFormatter?.[field.name]?.(field.value) || field.value}
  • ` | false onClose | func | Callback fired when the pane is closed using its dismiss button | | false showSharedLabel | bool | Flag indicating whether the original version should display "Shared" label | false | false totalVersions | number | Total number of versions | | false From 3cc711d9522d099178eac086ad744511f8df5ad5 Mon Sep 17 00:00:00 2001 From: elsenhans Date: Fri, 19 Dec 2025 09:47:48 +0100 Subject: [PATCH 8/9] STCOM-1475-add-custom-item-formatter adapt itemFormatter in readme.md --- lib/AuditLog/readme.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/AuditLog/readme.md b/lib/AuditLog/readme.md index 369129bf1..6cd7cc7e2 100644 --- a/lib/AuditLog/readme.md +++ b/lib/AuditLog/readme.md @@ -32,6 +32,21 @@ const fieldFormatter = { primary: value => value.toString(), }; +const itemFormatter = (fieldLabelsMap, fieldFormatter) => (element, i) => { + if (!element) return null; + + const { name: fieldName, value } = element; + const label = fieldLabelsMap?.[fieldName] || fieldName; + const formattedValue = fieldFormatter?.[fieldName]?.(value) || value; + + return ( +
  • + {fieldName && {label}: } + {formattedValue} +
  • + ); +}; + const handleClose = () => console.log('Pane closed'); const handleLoadMore = () => console.log('Load more clicked'); const isLoading = false; @@ -48,6 +63,7 @@ return ( handleLoadMore={handleLoadMore} isLoading={isLoading} isInitialLoading={isInitialLoading} + itemFormatter={itemFormatter} showSharedLabel={showSharedLabel} fieldLabelsMap={fieldLabelsMap} fieldFormatter={fieldFormatter} @@ -69,8 +85,8 @@ isInitialLoading | bool | Flag that indicates whether data is being loaded for isLoading | bool | Flag that indicates whether data is being loaded | | false isLoadMoreVisible | bool | Flag that indicates whether "Load more" button visible or not | true | false itemFormatter | func | -Formats changed field values of objects or arrays in modal content, used to format oldValue/newValue fields. -Receives a field object with `name`, `value`, and `collectionName` properties and the item index. Returns a list item element. | `(field, i) =>
  • {fieldFormatter?.[field.name]?.(field.value) || field.value}
  • ` | false +Formats changed field values of objects or arrays in modal content, used to format oldValue/newValue items of object or array, e.g. showing the field name before the field value. +Receives a field object with `name`, `value`, and `collectionName` properties and the item index. Returns a list item element. | `
  • {field.value}
  • ` | false onClose | func | Callback fired when the pane is closed using its dismiss button | | false showSharedLabel | bool | Flag indicating whether the original version should display "Shared" label | false | false totalVersions | number | Total number of versions | | false From ec3e2be5ce30f4dbca9476584eb86bc22dee6de9 Mon Sep 17 00:00:00 2001 From: elsenhans Date: Mon, 22 Dec 2025 08:19:50 +0100 Subject: [PATCH 9/9] STCOM-1475-add-custom-item-formatter fix bug in readme --- lib/AuditLog/readme.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/AuditLog/readme.md b/lib/AuditLog/readme.md index 6cd7cc7e2..6edb86ffe 100644 --- a/lib/AuditLog/readme.md +++ b/lib/AuditLog/readme.md @@ -84,9 +84,7 @@ handleLoadMore | func | Callback fired when the "Load more" button is clicked isInitialLoading | bool | Flag that indicates whether data is being loaded for the first time | | false isLoading | bool | Flag that indicates whether data is being loaded | | false isLoadMoreVisible | bool | Flag that indicates whether "Load more" button visible or not | true | false -itemFormatter | func | -Formats changed field values of objects or arrays in modal content, used to format oldValue/newValue items of object or array, e.g. showing the field name before the field value. -Receives a field object with `name`, `value`, and `collectionName` properties and the item index. Returns a list item element. | `
  • {field.value}
  • ` | false +itemFormatter | func | Formats changed field values of objects or arrays in modal content, used to format oldValue/newValue items of object or array, e.g. showing the field name before the field value. Receives a field object with `name`, `value`, and `collectionName` properties and the item index. Returns a list item element. | `
  • {field.value}
  • ` | false onClose | func | Callback fired when the pane is closed using its dismiss button | | false showSharedLabel | bool | Flag indicating whether the original version should display "Shared" label | false | false totalVersions | number | Total number of versions | | false