Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 118x 88x 118x 37x 36x 38x 38x 38x | import { ChangeItem, ChangelogData } from "@services/api/changelog/changelog";
/**
* `fieldChanges` is a free-form JSON column on the BE, and not every writer
* stores the same shape. Almost all of them store a list of field changes
* (`[{ operation, fieldName, oldValue, newValue }]`), but a few audit-only
* rows store a flat `{ key: value }` map instead — e.g. a blocked owner
* reassignment attempt, which records
* `{ owner_reassignment_blocked: "person_declined", attempted_email: "..." }`.
*
* The changelog UI iterates `fieldChanges`, so a single map-shaped row used to
* throw "fieldChanges.map is not a function" and take the whole side panel
* down with the "Technical Difficulties" fallback (GB-21601).
*
* @returns The value itself when it is already a list, an empty list otherwise
*/
export const toFieldChangeList = (fieldChanges: unknown): ChangeItem[] =>
Array.isArray(fieldChanges) ? (fieldChanges as ChangeItem[]) : [];
/**
* Coerces every row's `fieldChanges` to a list and drops the rows left with
* nothing to render, so an audit row the UI has no description for is skipped
* instead of rendering as an empty timeline entry.
*/
export const normalizeChangelogData = (
data: ChangelogData[],
): ChangelogData[] => {
if (!Array.isArray(data)) return [];
return data.reduce<ChangelogData[]>((normalized, item) => {
const fieldChanges = toFieldChangeList(item?.fieldChanges);
if (fieldChanges.length) normalized.push({ ...item, fieldChanges });
return normalized;
}, []);
};
|