Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ export class AuditLogParamsValidator {

@IsOptional()
@IsString()
@IsUUID('4')
@IsUUID()
public experimentId?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export class LogsService {
this.store$.dispatch(logsActions.actionSetErrorLogFilter({ filterType }));
}

fetchExperimentLogsById(experimentId: string) {
getExperimentLogsById(experimentId: string) {
return this.store$.pipe(select(selectExperimentLogs, { experimentId }));
}

Expand Down
13 changes: 5 additions & 8 deletions frontend/projects/upgrade/src/app/core/logs/store/logs.model.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { AppState } from '../../core.module';
import { EntityState } from '@ngrx/entity';
import { LOG_TYPE, SERVER_ERROR } from 'upgrade_types';
import { User } from '../../users/store/users.model';

export const NUMBER_OF_LOGS = 20;
export const SYSTEM_USER_EMAIL = 'system@gmail.com';

export enum LogType {
ERROR_LOG = 'Error log',
Expand Down Expand Up @@ -34,12 +36,7 @@ export interface AuditLogs {
versionNumber: number;
type: LOG_TYPE;
data: any;
user?: {
firstName: string;
lastName: string;
email?: string;
imageUrl?: string;
};
user?: User;
}

export interface ErrorLogs {
Expand All @@ -54,7 +51,7 @@ export interface ErrorLogs {
name: string;
}

export interface ExperimentLogsMetadata {
export interface AuditLogsMetadata {
logs: AuditLogs[];
skip: number;
total: number | null;
Expand All @@ -71,7 +68,7 @@ export interface LogState extends EntityState<AuditLogs | ErrorLogs> {
totalErrorLogs: number;
auditLogFilter: LOG_TYPE;
errorLogFilter: SERVER_ERROR;
experimentLogs: Record<string, ExperimentLogsMetadata>;
experimentAuditLogs: Record<string, AuditLogsMetadata>;
}

export interface State extends AppState {
Expand Down
30 changes: 15 additions & 15 deletions frontend/projects/upgrade/src/app/core/logs/store/logs.reducer.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { createReducer, on, Action } from '@ngrx/store';
import { createEntityAdapter, EntityAdapter } from '@ngrx/entity';
import { AuditLogs, LogState, ErrorLogs, ExperimentLogsMetadata } from './logs.model';
import { AuditLogs, LogState, ErrorLogs, AuditLogsMetadata } from './logs.model';
import * as logsActions from './logs.actions';

export const adapter: EntityAdapter<AuditLogs | ErrorLogs> = createEntityAdapter<AuditLogs | ErrorLogs>();

export const { selectIds, selectEntities, selectAll, selectTotal } = adapter.getSelectors();

const initialExperimentLogsMetadata: ExperimentLogsMetadata = {
const initialAuditLogsMetadata: AuditLogsMetadata = {
logs: [],
skip: 0,
total: null,
Expand All @@ -24,7 +24,7 @@ export const initialState: LogState = adapter.getInitialState({
totalErrorLogs: null,
auditLogFilter: null,
errorLogFilter: null,
experimentLogs: {},
experimentAuditLogs: {},
});

const reducer = createReducer(
Expand Down Expand Up @@ -67,11 +67,11 @@ const reducer = createReducer(
on(logsActions.actionSetErrorLogFilter, (state, { filterType }) => ({ ...state, errorLogFilter: filterType })),
// Experiment-specific log handlers
on(logsActions.actionGetExperimentLogs, (state, { experimentId, fromStart }) => {
const experimentLog = state.experimentLogs[experimentId] || initialExperimentLogsMetadata;
const experimentLog = state.experimentAuditLogs[experimentId] || initialAuditLogsMetadata;
return {
...state,
experimentLogs: {
...state.experimentLogs,
experimentAuditLogs: {
...state.experimentAuditLogs,
[experimentId]: {
...experimentLog,
isLoading: true,
Expand All @@ -81,13 +81,13 @@ const reducer = createReducer(
};
}),
on(logsActions.actionGetExperimentLogsSuccess, (state, { experimentId, auditLogs, totalAuditLogs, fromStart }) => {
const experimentLog = state.experimentLogs[experimentId] || initialExperimentLogsMetadata;
const experimentLog = state.experimentAuditLogs[experimentId] || initialAuditLogsMetadata;
const updatedLogs = fromStart ? auditLogs : [...experimentLog.logs, ...auditLogs];

return {
...state,
experimentLogs: {
...state.experimentLogs,
experimentAuditLogs: {
...state.experimentAuditLogs,
[experimentId]: {
...experimentLog,
logs: updatedLogs,
Expand All @@ -99,11 +99,11 @@ const reducer = createReducer(
};
}),
on(logsActions.actionGetExperimentLogsFailure, (state, { experimentId }) => {
const experimentLog = state.experimentLogs[experimentId] || initialExperimentLogsMetadata;
const experimentLog = state.experimentAuditLogs[experimentId] || initialAuditLogsMetadata;
return {
...state,
experimentLogs: {
...state.experimentLogs,
experimentAuditLogs: {
...state.experimentAuditLogs,
[experimentId]: {
...experimentLog,
isLoading: false,
Expand All @@ -112,11 +112,11 @@ const reducer = createReducer(
};
}),
on(logsActions.actionSetExperimentLogFilter, (state, { experimentId, filterType }) => {
const experimentLog = state.experimentLogs[experimentId] || initialExperimentLogsMetadata;
const experimentLog = state.experimentAuditLogs[experimentId] || initialAuditLogsMetadata;
return {
...state,
experimentLogs: {
...state.experimentLogs,
experimentAuditLogs: {
...state.experimentAuditLogs,
[experimentId]: {
...experimentLog,
filter: filterType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const selectAuditFilterType = createSelector(selectLogState, (state) => s
export const selectErrorFilterType = createSelector(selectLogState, (state) => state.errorLogFilter);

// Experiment-specific log selectors
export const selectExperimentLogsState = createSelector(selectLogState, (state) => state.experimentLogs);
export const selectExperimentLogsState = createSelector(selectLogState, (state) => state.experimentAuditLogs);

export const selectExperimentLogsMetadata = createSelector(
selectExperimentLogsState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@

<!-- Timeline Content -->
<ng-container content *ngIf="isSectionCardExpanded">
<app-experiment-logs-timeline
<common-audit-log-timeline
[groupedLogs]="timelineDataSource$ | async"
[isLoading]="isLoading$ | async"
[isEmpty]="(experimentLogs$ | async)?.length === 0"
[config]="timelineConfig"
(scrolledToBottom)="fetchLogsOnScroll()"
>
</app-experiment-logs-timeline>
</common-audit-log-timeline>
</ng-container>
</app-common-section-card>
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ import { ExperimentService } from '../../../../../../../core/experiments/experim
import { Experiment } from '../../../../../../../core/experiments/store/experiments.model';
import { LogsService } from '../../../../../../../core/logs/logs.service';
import { SharedModule } from '../../../../../../../shared/shared.module';
import { ExperimentLogsTimelineComponent } from './experiment-logs-timeline/experiment-logs-timeline.component';
import { CommonAuditLogTimelineComponent } from '../../../../../../../shared-standalone-component-lib/components/common-audit-log-timeline/common-audit-log-timeline.component';
import { AuditLogs, LogDateFormatType } from '../../../../../../../core/logs/store/logs.model';
import { LOG_TYPE } from 'upgrade_types';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { combineLatest, Subject, Observable, BehaviorSubject } from 'rxjs';
import { map, filter, takeUntil, switchMap, tap, take } from 'rxjs/operators';
import { groupBy } from 'lodash';
import { AuditLogTimelineConfig } from '../../../../../../../shared-standalone-component-lib/components/common-audit-log-timeline/common-audit-log-timeline-config.model';
import { EXPERIMENT_TIMELINE_LOG_TYPE_CONFIG } from '../../../../../../../shared-standalone-component-lib/components/common-audit-log-timeline/configs/experiment-timeline.config';

/**
* Section card component for displaying experiment-specific audit logs in a timeline format.
Expand All @@ -39,7 +41,7 @@ import { groupBy } from 'lodash';
CommonSectionCardSearchHeaderComponent,
TranslateModule,
SharedModule,
ExperimentLogsTimelineComponent,
CommonAuditLogTimelineComponent,
MatProgressSpinnerModule,
],
standalone: true,
Expand Down Expand Up @@ -67,6 +69,7 @@ export class ExperimentLogSectionCardComponent implements OnInit, OnDestroy {
private currentExperimentId: string | null = null;

LogDateFormatType = LogDateFormatType;
timelineConfig: AuditLogTimelineConfig = EXPERIMENT_TIMELINE_LOG_TYPE_CONFIG;

constructor(private readonly experimentService: ExperimentService, private readonly logsService: LogsService) {}

Expand All @@ -86,7 +89,7 @@ export class ExperimentLogSectionCardComponent implements OnInit, OnDestroy {
// Get raw logs observable
this.experimentLogs$ = this.selectedExperiment$.pipe(
filter((exp): exp is Experiment => !!exp),
switchMap((exp) => this.logsService.fetchExperimentLogsById(exp.id)),
switchMap((exp) => this.logsService.getExperimentLogsById(exp.id)),
tap((logs) => {
this.buildFilterOptions(logs);
}),
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
import * as env from '../../../../../../environments/environment';
import { LogType } from '../../../../../core/logs/store/logs.model';
import { LogType, SYSTEM_USER_EMAIL } from '../../../../../core/logs/store/logs.model';
import { EXPERIMENT_LIST_OPERATION, FEATURE_FLAG_LIST_OPERATION, LOG_TYPE, SERVER_ERROR } from 'upgrade_types';
import Convert from 'ansi-to-html';

Expand All @@ -15,7 +15,7 @@ export class TimelineComponent {
@Input() logData;
@Input() logType: LogType;
// Used to change setting icon based on theme
systemUserEmail = 'system@gmail.com';
systemUserEmail = SYSTEM_USER_EMAIL;
endPoint = env.environment.apiBaseUrl.substring(0, env.environment.apiBaseUrl.lastIndexOf('/'));

get LogType() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@ import { Component, ChangeDetectionStrategy, Input, AfterViewInit } from '@angul
import { CommonModule } from '@angular/common';
import { MatExpansionModule } from '@angular/material/expansion';
import { TranslateModule } from '@ngx-translate/core';
import { LOG_TYPE } from 'upgrade_types';
import Convert from 'ansi-to-html';

/**
* Sub-component for displaying diffs in experiment logs.
* Generic component for displaying diffs in audit logs.
* Supports any entity type (experiments, feature flags, segments).
*/
@Component({
selector: 'app-experiment-log-diff-display',
templateUrl: './experiment-log-diff-display.component.html',
styleUrls: ['./experiment-log-diff-display.component.scss'],
selector: 'common-audit-log-diff-display',
templateUrl: './common-audit-log-diff-display.component.html',
styleUrls: ['./common-audit-log-diff-display.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [CommonModule, MatExpansionModule, TranslateModule],
})
export class ExperimentLogDiffDisplayComponent implements AfterViewInit {
export class CommonAuditLogDiffDisplayComponent implements AfterViewInit {
@Input() logId: string;
@Input() logData: any;
@Input() logType: LOG_TYPE;
@Input() logType: string;
@Input() createdAt: string;
@Input() actionMessage: string;

Expand Down
Loading
Loading