@memberjunction/ng-record-changes 2.43.0 → 2.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +203 -63
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
# @memberjunction/ng-record-changes
|
|
2
2
|
|
|
3
|
-
The `@memberjunction/ng-record-changes` package provides an Angular dialog component that displays a chronological history of changes made to a MemberJunction entity record. It
|
|
3
|
+
The `@memberjunction/ng-record-changes` package provides an Angular dialog component that displays a chronological history of changes made to a MemberJunction entity record. It features an interactive timeline view with advanced filtering, search capabilities, and visual diff comparison for text changes.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
7
|
+
- **Interactive Timeline View**: Modern timeline interface showing chronological change history
|
|
8
|
+
- **Advanced Filtering**: Filter by change type (Create/Update/Delete) and source (Internal/External)
|
|
9
|
+
- **Search Functionality**: Full-text search across changes, users, and comments
|
|
10
|
+
- **Visual Diff Comparison**: Character-by-character or word-by-word diff highlighting for text changes
|
|
11
|
+
- **Expandable Details**: Click to expand/collapse detailed change information
|
|
12
|
+
- **Field-Level Changes**: Detailed tracking of individual field modifications
|
|
13
|
+
- **Smart Formatting**: Intelligent display of different data types (dates, booleans, numbers)
|
|
14
|
+
- **Accessibility**: Full keyboard navigation and ARIA support
|
|
15
|
+
- **Responsive Design**: Resizable dialog window with minimum dimensions
|
|
16
|
+
- **Status Indicators**: Visual badges for change types, sources, and statuses
|
|
15
17
|
|
|
16
18
|
## Installation
|
|
17
19
|
|
|
@@ -22,10 +24,15 @@ npm install @memberjunction/ng-record-changes
|
|
|
22
24
|
## Requirements
|
|
23
25
|
|
|
24
26
|
- Angular 18+
|
|
25
|
-
- @memberjunction/core
|
|
26
|
-
- @memberjunction/global
|
|
27
|
-
- @
|
|
28
|
-
- @
|
|
27
|
+
- @memberjunction/core (^2.43.0)
|
|
28
|
+
- @memberjunction/global (^2.43.0)
|
|
29
|
+
- @memberjunction/core-entities
|
|
30
|
+
- @memberjunction/ng-notifications
|
|
31
|
+
- @progress/kendo-angular-grid (^16.2.0)
|
|
32
|
+
- @progress/kendo-angular-indicators (^16.2.0)
|
|
33
|
+
- @progress/kendo-angular-dialog
|
|
34
|
+
- @progress/kendo-angular-buttons
|
|
35
|
+
- diff (^8.0.2)
|
|
29
36
|
|
|
30
37
|
## Usage
|
|
31
38
|
|
|
@@ -76,9 +83,10 @@ export class RecordDetailComponent {
|
|
|
76
83
|
constructor(private metadata: Metadata) {}
|
|
77
84
|
|
|
78
85
|
async ngOnInit() {
|
|
79
|
-
// Load your entity record
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
// Load your entity record using MemberJunction pattern
|
|
87
|
+
const md = new Metadata();
|
|
88
|
+
this.entityRecord = await md.GetEntityObject<BaseEntity>('Customer');
|
|
89
|
+
await this.entityRecord.Load(1); // Load by ID
|
|
82
90
|
}
|
|
83
91
|
|
|
84
92
|
showChanges() {
|
|
@@ -107,47 +115,134 @@ export class RecordDetailComponent {
|
|
|
107
115
|
|------|------|-------------|
|
|
108
116
|
| `dialogClosed` | `EventEmitter<void>` | Emitted when the dialog is closed |
|
|
109
117
|
|
|
110
|
-
|
|
118
|
+
#### Component Properties
|
|
119
|
+
|
|
120
|
+
| Property | Type | Description |
|
|
121
|
+
|----------|------|-------------|
|
|
122
|
+
| `showloader` | `boolean` | Loading state indicator |
|
|
123
|
+
| `viewData` | `RecordChangeEntity[]` | All change records |
|
|
124
|
+
| `filteredData` | `RecordChangeEntity[]` | Filtered change records |
|
|
125
|
+
| `expandedItems` | `Set<string>` | IDs of expanded timeline items |
|
|
126
|
+
| `searchTerm` | `string` | Current search filter |
|
|
127
|
+
| `selectedType` | `string` | Selected change type filter |
|
|
128
|
+
| `selectedSource` | `string` | Selected source filter |
|
|
129
|
+
|
|
130
|
+
## Features in Detail
|
|
131
|
+
|
|
132
|
+
### Timeline Interface
|
|
133
|
+
|
|
134
|
+
The component displays changes in an interactive timeline format:
|
|
135
|
+
- **Visual Markers**: Icons indicate change type (Create/Update/Delete)
|
|
136
|
+
- **Connecting Lines**: Visual connection between sequential changes
|
|
137
|
+
- **Expandable Items**: Click or use keyboard to expand/collapse details
|
|
138
|
+
- **Relative Time**: Shows "2 hours ago", "3 days ago", etc.
|
|
139
|
+
- **Full Timestamps**: Hover or expand to see complete date/time
|
|
140
|
+
|
|
141
|
+
### Filtering and Search
|
|
142
|
+
|
|
143
|
+
The component includes powerful filtering capabilities:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
// The component automatically filters based on:
|
|
147
|
+
// - Search term (across description, user, comments)
|
|
148
|
+
// - Change type (Create, Update, Delete)
|
|
149
|
+
// - Source (Internal, External)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Visual Diff Display
|
|
111
153
|
|
|
112
|
-
|
|
154
|
+
For text field changes, the component provides visual diff highlighting:
|
|
155
|
+
- **Character Diff**: For short text, codes, IDs
|
|
156
|
+
- **Word Diff**: For longer text with multiple words
|
|
157
|
+
- **Color Coding**:
|
|
158
|
+
- Green background for additions
|
|
159
|
+
- Red background with strikethrough for deletions
|
|
160
|
+
- No highlighting for unchanged text
|
|
113
161
|
|
|
114
|
-
|
|
162
|
+
### Field Change Display
|
|
115
163
|
|
|
116
|
-
|
|
117
|
-
- The field name that was changed
|
|
118
|
-
- The old value (in gray)
|
|
119
|
-
- The new value (in blue)
|
|
164
|
+
Different field types are handled intelligently:
|
|
120
165
|
|
|
121
|
-
|
|
166
|
+
```typescript
|
|
167
|
+
// Boolean fields - show only new value
|
|
168
|
+
{ field: 'IsActive', newValue: true } // Displays as "true"
|
|
169
|
+
|
|
170
|
+
// Text fields - show diff view with highlighting
|
|
171
|
+
{ field: 'Description', oldValue: 'Old text', newValue: 'New text' }
|
|
172
|
+
|
|
173
|
+
// Date fields - formatted display
|
|
174
|
+
{ field: 'CreatedAt', newValue: '2024-01-15T10:30:00Z' }
|
|
175
|
+
// Displays as "January 15, 2024, 10:30 AM EST"
|
|
122
176
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
177
|
+
// Empty values
|
|
178
|
+
{ field: 'Notes', oldValue: null, newValue: 'New note' }
|
|
179
|
+
// Displays as "(empty) → New note"
|
|
180
|
+
```
|
|
127
181
|
|
|
128
|
-
## Styling
|
|
182
|
+
## Styling and Customization
|
|
183
|
+
|
|
184
|
+
### CSS Classes
|
|
185
|
+
|
|
186
|
+
The component uses these main CSS classes for customization:
|
|
187
|
+
|
|
188
|
+
```css
|
|
189
|
+
/* Main container classes */
|
|
190
|
+
.kendo-window-custom /* Dialog window wrapper */
|
|
191
|
+
.record-changes-container /* Main content container */
|
|
192
|
+
.timeline-container /* Timeline wrapper */
|
|
193
|
+
|
|
194
|
+
/* Timeline item classes */
|
|
195
|
+
.timeline-item /* Individual change item */
|
|
196
|
+
.timeline-item.expanded /* Expanded state */
|
|
197
|
+
.timeline-marker /* Visual marker/icon */
|
|
198
|
+
.timeline-content /* Content area */
|
|
199
|
+
|
|
200
|
+
/* Change type classes */
|
|
201
|
+
.change-create /* Create changes (green) */
|
|
202
|
+
.change-update /* Update changes (blue) */
|
|
203
|
+
.change-delete /* Delete changes (red) */
|
|
204
|
+
|
|
205
|
+
/* Status and badge classes */
|
|
206
|
+
.badge-create /* Create type badge */
|
|
207
|
+
.badge-update /* Update type badge */
|
|
208
|
+
.badge-delete /* Delete type badge */
|
|
209
|
+
.status-complete /* Completed status */
|
|
210
|
+
.status-pending /* Pending status */
|
|
211
|
+
.status-error /* Error status */
|
|
212
|
+
|
|
213
|
+
/* Diff view classes */
|
|
214
|
+
.diff-container /* Diff display wrapper */
|
|
215
|
+
.diff-added /* Added text (green) */
|
|
216
|
+
.diff-removed /* Removed text (red) */
|
|
217
|
+
.diff-unchanged /* Unchanged text */
|
|
218
|
+
```
|
|
129
219
|
|
|
130
|
-
|
|
220
|
+
### Dialog Configuration
|
|
131
221
|
|
|
132
|
-
|
|
133
|
-
-
|
|
222
|
+
The dialog window is configured with:
|
|
223
|
+
- **Width**: 800px (resizable)
|
|
224
|
+
- **Height**: 650px (resizable)
|
|
225
|
+
- **Min Width**: 600px
|
|
226
|
+
- **Min Height**: 400px
|
|
227
|
+
- **Position**: Top: 50px, Left: 50px
|
|
134
228
|
|
|
135
229
|
## Advanced Usage
|
|
136
230
|
|
|
137
|
-
### Conditional Display Based on Entity
|
|
231
|
+
### Conditional Display Based on Entity Configuration
|
|
138
232
|
|
|
139
|
-
|
|
233
|
+
Show the history button only for entities with change tracking enabled:
|
|
140
234
|
|
|
141
235
|
```html
|
|
142
236
|
<button *ngIf="entityRecord?.EntityInfo?.TrackRecordChanges"
|
|
143
|
-
(click)="showChanges()"
|
|
144
|
-
|
|
237
|
+
(click)="showChanges()"
|
|
238
|
+
class="btn btn-secondary">
|
|
239
|
+
<i class="fa-solid fa-history"></i> View History
|
|
145
240
|
</button>
|
|
146
241
|
```
|
|
147
242
|
|
|
148
243
|
### Integration with Form Components
|
|
149
244
|
|
|
150
|
-
|
|
245
|
+
Integrate with MemberJunction form components for a complete solution:
|
|
151
246
|
|
|
152
247
|
```typescript
|
|
153
248
|
import { Component } from '@angular/core';
|
|
@@ -160,35 +255,80 @@ import { BaseFormComponent } from '@memberjunction/ng-base-forms';
|
|
|
160
255
|
export class CustomerFormComponent extends BaseFormComponent {
|
|
161
256
|
isHistoryDialogOpen: boolean = false;
|
|
162
257
|
|
|
163
|
-
|
|
164
|
-
this.
|
|
258
|
+
showHistory() {
|
|
259
|
+
if (this.record?.EntityInfo?.TrackRecordChanges) {
|
|
260
|
+
this.isHistoryDialogOpen = true;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
onHistoryDialogClosed() {
|
|
265
|
+
this.isHistoryDialogOpen = false;
|
|
165
266
|
}
|
|
166
267
|
}
|
|
167
268
|
```
|
|
168
269
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
270
|
+
### Handling Different Change Types
|
|
271
|
+
|
|
272
|
+
The component automatically handles different change scenarios:
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
// Record Creation - shows all initial field values
|
|
276
|
+
{
|
|
277
|
+
Type: 'Create',
|
|
278
|
+
FullRecordJSON: '{"Name": "John Doe", "Email": "john@example.com"}'
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Record Update - shows field-by-field changes
|
|
282
|
+
{
|
|
283
|
+
Type: 'Update',
|
|
284
|
+
ChangesJSON: '{"Name": {"field": "Name", "oldValue": "John", "newValue": "John Doe"}}'
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Record Deletion - shows deletion message
|
|
288
|
+
{
|
|
289
|
+
Type: 'Delete',
|
|
290
|
+
ChangesDescription: 'Record deleted'
|
|
291
|
+
}
|
|
179
292
|
```
|
|
180
293
|
|
|
181
|
-
##
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
-
|
|
194
|
-
-
|
|
294
|
+
## Integration with MemberJunction
|
|
295
|
+
|
|
296
|
+
The component integrates seamlessly with MemberJunction's audit system:
|
|
297
|
+
|
|
298
|
+
1. **Automatic Loading**: Uses `Metadata.GetRecordChanges()` to fetch history
|
|
299
|
+
2. **Entity Awareness**: Respects entity field metadata for display names
|
|
300
|
+
3. **Type Safety**: Full TypeScript support with `RecordChangeEntity` type
|
|
301
|
+
4. **Performance**: Efficient loading with built-in pagination support
|
|
302
|
+
|
|
303
|
+
## Accessibility
|
|
304
|
+
|
|
305
|
+
The component includes comprehensive accessibility features:
|
|
306
|
+
- **ARIA Labels**: Descriptive labels for all interactive elements
|
|
307
|
+
- **Keyboard Navigation**: Full keyboard support (Enter/Space to expand)
|
|
308
|
+
- **Screen Reader Support**: Meaningful announcements for all changes
|
|
309
|
+
- **Focus Management**: Proper focus handling in the dialog
|
|
310
|
+
|
|
311
|
+
## Performance Considerations
|
|
312
|
+
|
|
313
|
+
- **Lazy Loading**: Details are only rendered when expanded
|
|
314
|
+
- **Virtual Scrolling**: Ready for integration with Kendo's virtual scrolling
|
|
315
|
+
- **Efficient Diff**: Smart algorithm selection based on content type
|
|
316
|
+
- **Minimal Re-renders**: Optimized change detection strategy
|
|
317
|
+
|
|
318
|
+
## Error Handling
|
|
319
|
+
|
|
320
|
+
The component includes built-in error handling:
|
|
321
|
+
- Displays notification toast on load failure
|
|
322
|
+
- Gracefully handles missing or invalid data
|
|
323
|
+
- Shows error logs when available in change records
|
|
324
|
+
|
|
325
|
+
## Build and Development
|
|
326
|
+
|
|
327
|
+
To build the package locally:
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
cd packages/Angular/Explorer/record-changes
|
|
331
|
+
npm run build
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
The package uses Angular's ng-packagr for building the library.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-record-changes",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.45.0",
|
|
4
4
|
"description": "MemberJunction: Angular pop-up window and grid to show changes made to a specific individual record",
|
|
5
5
|
"main": "./dist/public-api.js",
|
|
6
6
|
"typings": "./dist/public-api.d.ts",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"@progress/kendo-angular-indicators": "16.2.0"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@memberjunction/core": "2.
|
|
31
|
-
"@memberjunction/global": "2.
|
|
32
|
-
"@memberjunction/ng-compare-records": "2.
|
|
33
|
-
"@memberjunction/ng-container-directives": "2.
|
|
34
|
-
"@memberjunction/ng-notifications": "2.
|
|
30
|
+
"@memberjunction/core": "2.45.0",
|
|
31
|
+
"@memberjunction/global": "2.45.0",
|
|
32
|
+
"@memberjunction/ng-compare-records": "2.45.0",
|
|
33
|
+
"@memberjunction/ng-container-directives": "2.45.0",
|
|
34
|
+
"@memberjunction/ng-notifications": "2.45.0",
|
|
35
35
|
"diff": "8.0.2",
|
|
36
36
|
"tslib": "^2.3.0"
|
|
37
37
|
},
|