Historical
This page will explain how to display the modification historical of a CRUD.
Overview
You can access to the historical of an entity by using the dedicated button when using calc mode :
Or by opening the details of your entity (popup, split, fullpage) into the Historical tab :
Configuration
You must first implements dedicated audit for your CRUD entity : see documentation.
For projects from BIAFramework V6 :
- Enable audit onto your entity (see documentation)
- Use the BIAToolKit :
- Generate DTO with
Use dedicated audit
option enabled (as described into Dedicated Audit Table documentation) - Then, generate CRUD with
Display Historical
feature enabled
- Generate DTO with
Back-end
Controller
Add into your entity controller the endpoint historical
:
/// <summary>
/// Return the historical of an item by its id.
/// </summary>
/// <param name="id">ID of the item to update.</param>
/// <returns>Item's historical.</returns>
[HttpGet("{id}/historical")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[Authorize(Roles = Rights.MyEntities.Read)]
public virtual async Task<IActionResult> GetHistorical(int id)
{
try
{
var dto = await this.myEntityService.GetHistoricalAsync(id);
return this.Ok(dto);
}
catch (ElementNotFoundException)
{
return this.NotFound();
}
}
Mapper
Add or complete into your entity mapper the constructor with following instructions :
/// <summary>
/// Initializes a new instance of the <see cref="MyEntityMapper"/> class.
/// </summary>
/// <param name="auditMappers">The injected collection of <see cref="IAuditMapper"/>.</param>
public MyEntityMapper(IEnumerable<IAuditMapper> auditMappers)
{
this.AuditMapper = auditMappers.FirstOrDefault(x => x.EntityType == typeof(MyEntity));
}
Front-end
Enable the displayHistorical
of your entity CrudConfig
:
export const myEntityCRUDConfiguration: CrudConfig<MyEntity> = new CrudConfig({
// [...]
displayHistorical: true,
});
Historical Component
Add your entity historical component into the views
of your feature :
@Component({
selector: 'app-my-entity-historical',
imports: [
CrudItemHistoricalTimelineComponent,
AsyncPipe,
TranslateModule,
Button,
],
templateUrl:
'../../../../../../packages/bia-ng/shared/feature-templates/crud-items/views/crud-item-historical/crud-item-historical.component.html',
styleUrl:
'../../../../../../packages/bia-ng/shared/feature-templates/crud-items/views/crud-item-historical/crud-item-historical.component.scss',
})
export class PlaneHistoricalComponent extends CrudItemHistoricalComponent<MyEntity> {
constructor(
protected injector: Injector,
protected myEntityService: MyEntityService
) {
super(injector, myEntityService, myEntityCRUDConfiguration);
}
}
Add the routing to the historical component into your entity module into the children of the path :crudItemId
:
export const ROUTES: Routes = [
{
// [...]
children: [
// [...]
{
path: ':crudItemId',
data: {
breadcrumb: '',
canNavigate: false,
},
component: MyEntityItemComponent,
canActivate: [PermissionGuard],
children: [
// [...]
// ROUTING TO HISTORICAL OF CRUD ITEM
{
path: 'historical',
data: {
breadcrumb: 'bia.historical',
canNavigate: false,
layoutMode: LayoutMode.popup,
style: {
minWidth: '50vw',
},
title: 'bia.historical',
permission: Permission.MyEntity_Read,
},
component: MyEntityHistoricalComponent,
canActivate: [PermissionGuard],
},
// [...]
],
},
],
},
];
Index component
Into the HTML template of your entity index component, add the [showHistoricalButton]
configuration for the <bia-table-header>
:
<bia-table-header
[showHistoricalButton]="crudConfiguration.displayHistorical && crudConfiguration.useCalcMode"></bia-table-header>
Edit component
Into the HTML template of your entity edit component, add the [displayHistorical]
and [historicalEntries]
configuration for your <app-my-entity-form>
:
<app-my-entity-form
[displayHistorical]="crudConfiguration.displayHistorical"
[historicalEntries]="(myEntityService.crudItemHistorical$ | async) ?? []"></app-my-entity-form>
Service
Add the definition of crudItemHistorical$
observable and loadHistoric
method into your entity service :
export class MyEntityService extends CrudItemService<MyEntity> {
// [...]
public crudItemHistorical$: Observable<HistoricalEntryDto[]> =
this.store.select(FeatureMyEntitiesStore.getCurrentMyEntityHistorical);
public loadHistoric(id: any): void {
this.store.dispatch(FeatureMyEntitiesActions.loadHistorical({ id: id }));
}
}
Store
Reducer
Add the currentItemHistorical
array of HistoricalEntryDto
definition and usage into your entity store reducer :
export interface State extends CrudState<MyEntity>, EntityState<MyEntity> {
currentItemHistorical: HistoricalEntryDto[];
// [...]
}
export const INIT_STATE: State = myEntitiesAdapter.getInitialState({
...DEFAULT_CRUD_STATE(),
currentItemHistorical: [],
// [...]
});
export const planeReducers = createReducer<State>(
// [...]
on(FeatureMyEntitiesActions.clearCurrent, state => {
return { ...state, currentItem: <MyEntity>{}, currentItemHistorical: [] };
}),
// [...]
on(FeatureMyEntitiesActions.loadHistoricalSuccess, (state, { historical }) => {
return { ...state, currentItemHistorical: historical };
}),
);
Action
Add the loadHistorical
and loadHistoricalSuccess
action into your entity store actions :
export namespace FeatureMyEntitiesActions {
// [...]
export const loadHistorical = createAction(
'[' + myEntityCRUDConfiguration.storeKey + '] Load historical',
props<{ id: number }>()
);
export const loadHistoricalSuccess = createAction(
'[' + myEntityCRUDConfiguration.storeKey + '] Load historical success',
props<{ historical: HistoricalEntryDto[] }>()
);
}
Effects
Add the loadHistorical$
effect and the call into load$
in your entity store effects :
@Injectable()
export class MyEntitiesEffects {
// [...]
load$ = createEffect(() =>
this.actions$.pipe(
ofType(FeatureMyEntitiesActions.load),
map(x => x?.id),
switchMap(id => {
return this.myEntityDas.get({ id: id }).pipe(
map(myEntity => {
// Add this condition
if (myEntityCRUDConfiguration.displayHistorical) {
this.store.dispatch(
FeatureMyEntitiesActions.loadHistorical({ id: myEntity.id })
);
}
return FeatureMyEntitiesActions.loadSuccess({ myEntity });
}),
catchError(err => {
this.biaMessageService.showErrorHttpResponse(err);
return of(FeatureMyEntitiesActions.failure({ error: err }));
})
);
})
)
);
// [...]
loadHistorical$ = createEffect(() =>
this.actions$.pipe(
ofType(FeatureMyEntitiesActions.loadHistorical),
map(x => x?.id),
switchMap(id => {
return this.myEntityDas.getHistorical({ id: id }).pipe(
map(historical => {
return FeatureMyEntitiesActions.loadHistoricalSuccess({ historical });
}),
catchError(err => {
this.biaMessageService.showErrorHttpResponse(err);
return of(FeatureMyEntitiesActions.failure({ error: err }));
})
);
})
)
);
// [...]
}