Skip to content

Commit cce0dc7

Browse files
heiskrCopilot
andauthored
Article API: extract common base fields in audit log events (#60074)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 8b2e2d4 commit cce0dc7

3 files changed

Lines changed: 62 additions & 4 deletions

File tree

src/article-api/templates/audit-logs-page.template.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@
66

77
## Audit log events
88

9+
{% if baseFields.size > 0 %}
10+
### Common fields
11+
12+
The following fields are included in most audit log events: {% for field in baseFields %}`{{ field }}`{% unless forloop.last %}, {% endunless %}{% endfor %}
13+
14+
Each event below lists only its additional fields beyond these common fields.
15+
16+
{% endif %}
917
{% for categoryEntry in categorizedEvents %}
1018
{% assign categoryName = categoryEntry[0] %}
1119
{% assign events = categoryEntry[1] %}
@@ -20,7 +28,7 @@
2028

2129
{{ event.description }}
2230

23-
**Fields:** {% if event.fields %}{% for field in event.fields %}`{{ field }}`{% unless forloop.last %}, {% endunless %}{% endfor %}{% else %}No fields available{% endif %}
31+
{% if event.fields.size > 0 %}**Additional fields:** {% for field in event.fields %}`{{ field }}`{% unless forloop.last %}, {% endunless %}{% endfor %}{% endif %}
2432

2533
{% if event.docs_reference_links and event.docs_reference_links != 'N/A' %}
2634
**Reference:** {{ event.docs_reference_links }}

src/article-api/tests/audit-logs-transformer.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,30 @@ describe('Audit Logs transformer', () => {
7676
// #### `action.name`
7777
expect(res.body).toMatch(/#### `[\w.]+`/)
7878

79-
// Check for fields section
80-
expect(res.body).toContain('**Fields:**')
79+
// Check for fields section - either common fields summary or additional fields per event
80+
const body = res.body
81+
const hasCommonFields = body.includes('### Common fields')
82+
const hasAdditionalFields = body.includes('**Additional fields:**')
83+
expect(hasCommonFields || hasAdditionalFields).toBe(true)
84+
85+
// Validate that a known common field is in the common section and not duplicated
86+
if (hasCommonFields) {
87+
const commonFieldsIndex = body.indexOf('### Common fields')
88+
const commonFieldsSection = body.slice(
89+
commonFieldsIndex,
90+
body.indexOf('\n###', commonFieldsIndex + 1),
91+
)
92+
expect(commonFieldsSection).toContain('`action`')
93+
}
94+
95+
// Ensure common fields do not appear in any "Additional fields" section
96+
if (hasAdditionalFields) {
97+
const additionalSections = body.split('**Additional fields:**').slice(1)
98+
for (const section of additionalSections) {
99+
const fieldsLine = section.split('\n')[0]
100+
expect(fieldsLine).not.toContain('`action`')
101+
}
102+
}
81103

82104
// Check for reference section
83105
expect(res.body).toContain('**Reference:**')

src/article-api/transformers/audit-logs-transformer.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ export class AuditLogsTransformer implements PageTransformer {
9999
// Prepare page intro
100100
const intro = page.intro ? await page.renderProp('intro', context, { textOnly: true }) : ''
101101

102-
// Sort categories and events
102+
// Sort categories and events, and compute fields shared by most (≥80%) events
103+
const allFieldSets: string[][] = []
103104
const sortedCategorizedEvents: CategorizedEvents = {}
104105
const sortedCategories = Object.keys(categorizedEvents).sort((a, b) => a.localeCompare(b))
105106

@@ -117,11 +118,37 @@ export class AuditLogsTransformer implements PageTransformer {
117118
context,
118119
)
119120
}
121+
if (newEvent.fields) {
122+
allFieldSets.push(newEvent.fields)
123+
}
120124
return newEvent
121125
}),
122126
)
123127
}
124128

129+
// Compute base fields that appear in ≥80% of events
130+
const fieldCounts = new Map<string, number>()
131+
for (const fields of allFieldSets) {
132+
for (const f of fields) {
133+
fieldCounts.set(f, (fieldCounts.get(f) || 0) + 1)
134+
}
135+
}
136+
const threshold = allFieldSets.length * 0.8
137+
const baseFields = [...fieldCounts.entries()]
138+
.filter(([, count]) => count >= threshold)
139+
.map(([field]) => field)
140+
.sort()
141+
142+
// Remove base fields from each event's field list
143+
const baseFieldSet = new Set(baseFields)
144+
for (const category of Object.keys(sortedCategorizedEvents)) {
145+
for (const event of sortedCategorizedEvents[category]) {
146+
if (event.fields) {
147+
event.fields = event.fields.filter((f: string) => !baseFieldSet.has(f))
148+
}
149+
}
150+
}
151+
125152
return {
126153
page: {
127154
title: page.title,
@@ -130,6 +157,7 @@ export class AuditLogsTransformer implements PageTransformer {
130157
manualContent,
131158
categorizedEvents: sortedCategorizedEvents,
132159
categoryNotes,
160+
baseFields,
133161
}
134162
}
135163
}

0 commit comments

Comments
 (0)