Skip to content

Commit

Permalink
Merge branch 'master' into task/exui-1808-angular-upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
olusegz07 committed Jun 14, 2024
2 parents 9ab31e9 + d738c77 commit 830133c
Show file tree
Hide file tree
Showing 12 changed files with 423 additions and 260 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ <h2 class="heading-h2 error-summary-heading" id="edit-case-event_error-summary-h
</div>
<div *ngIf="hasEventSelector" class="column-one-half">
<ccd-event-trigger [isDisabled]="isTriggerButtonDisabled()" [triggers]="caseDetails.triggers"
[triggerText]="triggerText" (onTriggerChange)="clearErrorsAndWarnings()"
[triggerText]="triggerText"
[eventId]="eventId"
(onTriggerChange)="clearErrorsAndWarnings()"
(onTriggerSubmit)="applyTrigger($event)"></ccd-event-trigger>
</div>
</div>
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { MatLegacyTab as MatTab, MatLegacyTabGroup as MatTabGroup } from '@angul
import { ActivatedRoute, NavigationEnd, Params, Router } from '@angular/router';
import { plainToClass } from 'class-transformer';
import { RpxTranslatePipe } from 'rpx-xui-translation';
import { Observable, Subject, Subscription } from 'rxjs';
import { Observable, Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';
import {
NotificationBannerConfig,
Expand Down Expand Up @@ -76,8 +76,9 @@ export class CaseFullAccessViewComponent implements OnInit, OnDestroy, OnChanges
public caseFlagsExternalUser = false;
private readonly caseFlagsReadExternalMode = '#ARGUMENT(READ,EXTERNAL)';
private subs: Subscription[] = [];
public eventId: string;

public callbackErrorsSubject: Subject<any> = new Subject();
public callbackErrorsSubject: Observable<any>;
@ViewChild('tabGroup', { static: false }) public tabGroup: MatTabGroup;

constructor(
Expand All @@ -100,22 +101,21 @@ export class CaseFullAccessViewComponent implements OnInit, OnDestroy, OnChanges
}

public ngOnInit(): void {
this.callbackErrorsSubject = this.errorNotifierService.errorSource.pipe(filter((x) => {
if(x && x.status !== 401 && x.status !== 403) {
this.error = x;
return true;
}
return false;
}));

initDialog();
this.init();
this.callbackErrorsSubject.subscribe(errorEvent => {
this.error = errorEvent;
});
this.errorSubscription = this.errorNotifierService.error.subscribe(error => {
if (error && error.status !== 401 && error.status !== 403) {
this.error = error;
this.callbackErrorsSubject.next(this.error);
}
});
this.markdownUseHrefAsRouterLink = true;

this.sessionStorageService.removeItem('eventUrl');
this.sessionStorageService?.removeItem('eventUrl');

this.subscription = this.convertHrefToRouterService.getHrefMarkdownLinkContent().subscribe((hrefMarkdownLinkContent: string) => {
this.subscription = this.convertHrefToRouterService?.getHrefMarkdownLinkContent().subscribe((hrefMarkdownLinkContent: string) => {
// do not convert router with initial default value; convert to router only on updated link content
if (hrefMarkdownLinkContent !== 'Default') {
this.convertHrefToRouterService.callAngularRouter(hrefMarkdownLinkContent);
Expand Down Expand Up @@ -184,7 +184,7 @@ export class CaseFullAccessViewComponent implements OnInit, OnDestroy, OnChanges
}

public postViewActivity(): Observable<Activity[]> {
return this.activityPollingService.postViewActivity(this.caseDetails.case_id);
return this.activityPollingService.postViewActivity(this.caseDetails?.case_id);
}

public clearErrorsAndWarnings(): void {
Expand All @@ -194,8 +194,7 @@ export class CaseFullAccessViewComponent implements OnInit, OnDestroy, OnChanges
}

public async applyTrigger(trigger: CaseViewTrigger): Promise<void> {
this.error = null;

this.errorNotifierService.announceError(null);
const theQueryParams: Params = {};

if (this.ignoreWarning) {
Expand Down Expand Up @@ -246,6 +245,7 @@ export class CaseFullAccessViewComponent implements OnInit, OnDestroy, OnChanges
public callbackErrorsNotify(callbackErrorsContext: CallbackErrorsContext): void {
this.ignoreWarning = callbackErrorsContext.ignoreWarning;
this.triggerText = callbackErrorsContext.triggerText;
this.eventId = callbackErrorsContext.eventId;
}

public isDraft(): boolean {
Expand Down Expand Up @@ -358,7 +358,7 @@ export class CaseFullAccessViewComponent implements OnInit, OnDestroy, OnChanges

public hasActiveCaseFlags(): boolean {
// Determine which tab contains the FlagLauncher CaseField type, from the CaseView object in the snapshot data
const caseFlagsTab = this.caseDetails.tabs
const caseFlagsTab = this.caseDetails?.tabs
? (this.caseDetails.tabs).filter(
tab => tab.fields && tab.fields.some(caseField => FieldsUtils.isFlagLauncherCaseField(caseField)))[0]
: null;
Expand Down Expand Up @@ -414,27 +414,26 @@ export class CaseFullAccessViewComponent implements OnInit, OnDestroy, OnChanges

private init(): void {
// Clone and sort tabs array
this.sortedTabs = this.orderService.sort(this.caseDetails.tabs);
this.sortedTabs = this.orderService.sort(this.caseDetails?.tabs);
this.caseFields = this.getTabFields();
this.sortedTabs = this.sortTabFieldsAndFilterTabs(this.sortedTabs);
this.formGroup = this.buildFormGroup(this.caseFields);
if (this.caseDetails.triggers && this.error) {
if (this.caseDetails?.triggers && this.error) {
this.resetErrors();
}
}

private sortTabFieldsAndFilterTabs(tabs: CaseTab[]): CaseTab[] {
return tabs
.map(tab => Object.assign({}, tab, { fields: this.orderService.sort(tab.fields) }))
return tabs?.map(tab => Object.assign({}, tab, { fields: this.orderService.sort(tab.fields) }))
.filter(tab => ShowCondition.getInstance(tab.show_condition).matchByContextFields(this.caseFields));
}

private getTabFields(): CaseField[] {
const caseDataFields = this.sortedTabs.reduce((acc, tab) => {
const caseDataFields = this.sortedTabs?.reduce((acc, tab) => {
return acc.concat(plainToClass(CaseField, tab.fields));
}, []);

return caseDataFields.concat(this.caseDetails.metadataFields);
return caseDataFields?.concat(this.caseDetails.metadataFields);
}

/**
Expand All @@ -457,16 +456,7 @@ export class CaseFullAccessViewComponent implements OnInit, OnDestroy, OnChanges
}

private resetErrors(): void {
this.error = null;
this.callbackErrorsSubject.next(null);
this.errorNotifierService.announceError(null);
this.alertService.clear();
}

private getUrlFragment(url: string) {
return url.split('#')[url.split('#').length - 1];
}

private getTabIndexByTabLabel(tabGroup: MatTabGroup, tabLabel) {
return tabGroup._tabs.toArray().findIndex((t) => t.textLabel.toLowerCase() === tabLabel.toLowerCase());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AbstractAppConfig } from '../../../../app.config';
import { CaseEventTrigger, HttpError, Profile } from '../../../domain';
import { createAProfile } from '../../../domain/profile/profile.test.fixture';
import { createCaseEventTrigger } from '../../../fixture';
import { HttpService, ProfileNotifier, ProfileService } from '../../../services';
import { ErrorNotifierService, HttpService, ProfileNotifier, ProfileService } from '../../../services';
import { CaseResolver } from './case.resolver';
import { EventTriggerResolver } from './event-trigger.resolver';

Expand Down Expand Up @@ -37,6 +37,7 @@ describe('EventTriggerResolver', () => {
let router: any;
let profileService: any;
let profileNotifier: any;
let errorNotifier: any;
let appConfig: any;
let httpService: any;
const MOCK_PROFILE: Profile = createAProfile();
Expand Down Expand Up @@ -70,10 +71,12 @@ describe('EventTriggerResolver', () => {

beforeEach(() => {
casesService = createSpyObj('casesService', ['getEventTrigger']);
alertService = createSpyObj('alertService', ['error']);
alertService = createSpyObj('alertService', ['error', 'setPreserveAlerts']);
orderService = createSpyObj('orderService', ['sort']);
errorNotifier = createSpyObj('errorNotifierService', ['announceError']);
profileService = createSpyObj<ProfileService>('profileService', ['get']);
profileNotifier = new ProfileNotifier();
errorNotifier = new ErrorNotifierService();

router = createSpyObj('router', ['navigate']);

Expand All @@ -83,7 +86,7 @@ describe('EventTriggerResolver', () => {
httpService = createSpyObj<HttpService>('httpService', ['get']);
httpService.get.and.returnValue(of(MOCK_PROFILE));

eventTriggerResolver = new EventTriggerResolver(casesService, alertService, profileService, profileNotifier);
eventTriggerResolver = new EventTriggerResolver(casesService, alertService, profileService, profileNotifier, router, appConfig, errorNotifier);

route = {
firstChild: {
Expand Down Expand Up @@ -200,8 +203,11 @@ describe('EventTriggerResolver', () => {
.then(data => {
fail(data);
}, err => {
expect(err).toBeTruthy();
expect(alertService.error).toHaveBeenCalledWith(ERROR.message);
err.details = { eventId: 'createBundle', ...err.details };
expect(err).toBeTruthy();
expect(alertService.setPreserveAlerts).toHaveBeenCalledWith(true);
expect(alertService.error).toHaveBeenCalledWith(ERROR.message);
expect(router.navigate).toHaveBeenCalled();
done();
});
expect(profileService.get).toHaveBeenCalledWith();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router';
import { throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { CaseEventTrigger } from '../../../domain/case-view/case-event-trigger.model';
Expand All @@ -8,6 +8,8 @@ import { AlertService } from '../../../services/alert/alert.service';
import { ProfileNotifier } from '../../../services/profile/profile.notifier';
import { ProfileService } from '../../../services/profile/profile.service';
import { CasesService } from '../../case-editor/services/cases.service';
import { AbstractAppConfig } from '../../../../app.config';
import { ErrorNotifierService } from '../../../services/error/error-notifier.service';

@Injectable()
export class EventTriggerResolver implements Resolve<CaseEventTrigger> {
Expand All @@ -22,6 +24,9 @@ export class EventTriggerResolver implements Resolve<CaseEventTrigger> {
private readonly alertService: AlertService,
private readonly profileService: ProfileService,
private readonly profileNotifier: ProfileNotifier,
private router: Router,
private appConfig: AbstractAppConfig,
private errorNotifier: ErrorNotifierService,
) {}

public resolve(route: ActivatedRouteSnapshot): Promise<CaseEventTrigger> {
Expand Down Expand Up @@ -59,7 +64,11 @@ export class EventTriggerResolver implements Resolve<CaseEventTrigger> {
.pipe(
map(eventTrigger => this.cachedEventTrigger = eventTrigger),
catchError(error => {
error.details = { eventId: eventTriggerId, ...error.details };
this.alertService.setPreserveAlerts(true);
this.alertService.error(error.message);
this.errorNotifier.announceError(error);
this.router.navigate([`/cases/case-details/${cid}/tasks`]);
return throwError(error);
})
).toPromise();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,21 @@ describe('CallbackErrorsComponent', () => {

const VALID_WARNING = {
callbackErrors: [],
callbackWarnings: ['callbackWarning1', 'callbackWarning2']
callbackWarnings: ['callbackWarning1', 'callbackWarning2'],
eventId: undefined
};

const VALID_ERROR = {
callbackErrors: ['callbackError1', 'callbackError2'],
callbackWarnings: []
};

const VALID_INVALID_DATA = {
details: {
field_errors: ['fieldError1', 'fieldError2']
}
};

const $ERROR_SUMMARY = By.css('.error-summary');
const $ERROR_MESSAGES = By.css('#errors');
const $WARNING_MESSAGES = By.css('#warnings');
Expand Down Expand Up @@ -66,6 +73,7 @@ describe('CallbackErrorsComponent', () => {
const expectedCallbackErrorsContext: CallbackErrorsContext = new CallbackErrorsContext();
expectedCallbackErrorsContext.ignoreWarning = true;
expectedCallbackErrorsContext.triggerText = triggerTextIgnore;
expectedCallbackErrorsContext.eventId = undefined;
expect(mockCallbackErrorsContext.emit).toHaveBeenCalledWith(expectedCallbackErrorsContext);
});

Expand All @@ -77,6 +85,7 @@ describe('CallbackErrorsComponent', () => {
const expectedCallbackErrorsContext: CallbackErrorsContext = new CallbackErrorsContext();
expectedCallbackErrorsContext.ignoreWarning = false;
expectedCallbackErrorsContext.triggerText = triggerTextContinue;
expectedCallbackErrorsContext.eventId = undefined;
expect(mockCallbackErrorsContext.emit).toHaveBeenCalledWith(expectedCallbackErrorsContext);
});

Expand All @@ -87,6 +96,7 @@ describe('CallbackErrorsComponent', () => {
const expectedCallbackErrorsContext: CallbackErrorsContext = new CallbackErrorsContext();
expectedCallbackErrorsContext.ignoreWarning = false;
expectedCallbackErrorsContext.triggerText = triggerTextContinue;
expectedCallbackErrorsContext.eventId = undefined;
expect(mockCallbackErrorsContext.emit).toHaveBeenCalledWith(expectedCallbackErrorsContext);
});

Expand Down Expand Up @@ -134,7 +144,48 @@ describe('CallbackErrorsComponent', () => {
const expectedCallbackErrorsContext: CallbackErrorsContext = new CallbackErrorsContext();
expectedCallbackErrorsContext.ignoreWarning = false;
expectedCallbackErrorsContext.triggerText = triggerTextContinue;
expectedCallbackErrorsContext.eventId = undefined;
expect(mockCallbackErrorsContext.emit).toHaveBeenCalledWith(expectedCallbackErrorsContext);
});

it('should build callback errors context with eventId if available', () => {
const VALID_ERROR_WITH_EVENT_ID = {
callbackErrors: ['callbackError1'],
callbackWarnings: [],
details: {
eventId: '1234'
}
};

const error = HttpError.from(new HttpErrorResponse({ error: VALID_ERROR_WITH_EVENT_ID }));
callbackErrorsSubject.next(error);

const expectedCallbackErrorsContext: CallbackErrorsContext = new CallbackErrorsContext();
expectedCallbackErrorsContext.ignoreWarning = false;
expectedCallbackErrorsContext.triggerText = triggerTextContinue;
expectedCallbackErrorsContext.eventId = '1234';
expect(mockCallbackErrorsContext.emit).toHaveBeenCalledWith(expectedCallbackErrorsContext);
});

it('should handle errors with invalid data', () => {
const error = HttpError.from(new HttpErrorResponse({ error: VALID_INVALID_DATA }));
callbackErrorsSubject.next(error);

const expectedCallbackErrorsContext: CallbackErrorsContext = new CallbackErrorsContext();
expectedCallbackErrorsContext.ignoreWarning = false;
expectedCallbackErrorsContext.triggerText = triggerTextContinue;
expectedCallbackErrorsContext.eventId = undefined;
expect(mockCallbackErrorsContext.emit).toHaveBeenCalledWith(expectedCallbackErrorsContext);
});

it('should handle errors with no callbackErrors, callbackWarnings, or field_errors', () => {
const EMPTY_ERROR = {
details: {}
};

const error = HttpError.from(new HttpErrorResponse({ error: EMPTY_ERROR }));
callbackErrorsSubject.next(error);

expect(component.error).toEqual(error);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export class CallbackErrorsComponent implements OnInit {
errorContext.ignoreWarning = false;
errorContext.triggerText = this.triggerTextContinue;
}
errorContext.eventId = this.error?.details?.eventId;
return errorContext;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export class CallbackErrorsContext {
public triggerText: string;
public ignoreWarning: boolean;
public eventId?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
<label class="form-label" for="next-step">{{'Next step' | rpxTranslate}}</label>
<select class="form-control ccd-dropdown" id="next-step" (change)="triggerChange()" formControlName="trigger" [ngClass]="{
'EventTrigger-empty': !triggerForm.value['trigger']
}">
}" [compareWith]="compareFn">
<option *ngIf="1 !== triggers.length" value="" data-default>{{'Select action' | rpxTranslate}}</option>
<option *ngFor="let trigger of triggers" [ngValue]="trigger" [title]="trigger.description">{{trigger.name | rpxTranslate}}</option>
<option *ngFor="let trigger of triggers" [ngValue]="trigger" [title]="trigger.description">{{trigger.name | rpxTranslate}}</option>
</select>
</div>
<button [disabled]="isButtonDisabled()" type="submit" class="button">{{triggerText | rpxTranslate}}</button>
Expand Down
Loading

0 comments on commit 830133c

Please sign in to comment.