Skip to content
Merged
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
4 changes: 2 additions & 2 deletions src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('AppComponent', () => {
azureLoggedUser$ = new Subject<AppUser>();
natsLiveMessage$ = new Subject<NatsMessage | null>();
natsMessageCount$ = new Subject<number>();
mockAzureService = jasmine.createSpyObj('AzureService', ['initialize', 'login', 'logout', 'refreshToken'], { loggedUser$: azureLoggedUser$.asObservable() });
mockAzureService = jasmine.createSpyObj('AzureService', ['initialize', 'login', 'logout', 'getAccessToken'], { loggedUser$: azureLoggedUser$.asObservable() });
mockNatsService = jasmine.createSpyObj('NatsService', ['initialize', 'initializeUser', 'readMessages', 'isValidMessage'], { liveMessage$: natsLiveMessage$.asObservable(), unreadMessagesCount$: natsMessageCount$.asObservable() });
mockToastService = jasmine.createSpyObj('AppShellToastService', ['showToast'], { toasts$: of([]) });
mockCatalogService = jasmine.createSpyObj(
Expand Down Expand Up @@ -77,7 +77,7 @@ describe('AppComponent', () => {
mockCatalogService.getSelectedCatalogSlug.and.returnValue(null);
mockCatalogService.getSelectedCatalogDescriptor.and.returnValue({ slug: 'test-catalog', id: '1' });
mockAppConfigService.getConfig.and.returnValue({ natsUrl: 'nats://localhost:4222' });
mockAzureService.refreshToken.and.returnValue(Promise.resolve({ accessToken: 'new-token' } as any));
mockAzureService.getAccessToken.and.returnValue(Promise.resolve('new-token'));
mockProjectService.getUserProjects.and.returnValue(of([]));
mockDialogRef.afterClosed.and.returnValue(dialogSubject.asObservable());
mockMatDialog.open.and.returnValue(mockDialogRef);
Expand Down
4 changes: 2 additions & 2 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ export class AppComponent implements OnInit, OnDestroy {
// Apply optimistic UI, start with it and later apply validations after fetching projects to avoid empty parts
this.projectPicker = {...this.projectPicker, label: 'Project: ', selected: currentProjectForUi.projectKey};
}
this.azureService.refreshToken().then((azureData) => {
this.projectService.getUserProjects(azureData.accessToken).subscribe((projects: string[]) => {
this.azureService.getAccessToken().then((accessToken: string) => {
this.projectService.getUserProjects(accessToken).subscribe((projects: string[]) => {
user.projects = projects;
this.initializeNats(user);
if (projects.length > 0) {
Expand Down
16 changes: 12 additions & 4 deletions src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { AppConfigService } from './services/app-config.service';
import { msalProviders } from './azure.config';
import { ApplicationConfig, provideZoneChangeDetection, provideAppInitializer, inject } from '@angular/core';
import { ApplicationConfig, provideZoneChangeDetection, provideAppInitializer, inject, Injector } from '@angular/core';
import { MsalService } from '@azure/msal-angular';
import { firstValueFrom } from 'rxjs';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { provideMarkdown } from 'ngx-markdown';
Expand Down Expand Up @@ -30,9 +32,15 @@ export const appConfig: ApplicationConfig = {
provideAppInitializer(() => {
const appConfigService = inject(AppConfigService);
const iconService = inject(IconRegistryService);
return appConfigService.loadConfig().then(() =>
iconService.registerIconsFromManifest()
);
const injector = inject(Injector);
return appConfigService.loadConfig()
.then(() => iconService.registerIconsFromManifest())
.then(() => {
const msalService = injector.get(MsalService);
return firstValueFrom(msalService.initialize()).then(() =>
firstValueFrom(msalService.handleRedirectObservable())
);
});
}),
{
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
Expand Down
2 changes: 1 addition & 1 deletion src/app/azure.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export function MSALGuardConfigFactory(config: AppConfigService): MsalGuardConfi
return {
interactionType: InteractionType.Redirect,
authRequest: {
scopes: [...config.getConfig()?.apiConfig?.scopes || []],
scopes: [...config.getConfig()?.apiConfig?.scopes || [], 'User.Read'],
},
loginFailedRoute: '/login-failed',
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ describe('RequestDeletionDialogComponent', () => {
changeNumber: '-',
reason: 'Test reason',
projectKey: 'test-project',
componentName: 'test-component',
location: 'test-location'
componentName: 'test-component'
});
});

Expand All @@ -95,8 +94,7 @@ describe('RequestDeletionDialogComponent', () => {
changeNumber: 'CHG1234567',
reason: 'Test reason',
projectKey: 'test-project',
componentName: 'test-component',
location: 'test-location'
componentName: 'test-component'
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ export class RequestDeletionDialogComponent {
changeNumber: this.deploymentStatus ? this.changeNumber : '-',
reason: this.reason,
projectKey: this.data.projectKey,
componentName: this.data.componentName,
location: this.data.location
componentName: this.data.componentName
};
this.dialogRef.close(result);
}
Expand Down
1 change: 0 additions & 1 deletion src/app/models/request-deletion-dialog-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,4 @@ export interface RequestDeletionDialogResult {
deploymentStatus: boolean;
changeNumber: string;
reason: string;
location: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,7 @@ describe('ProductActionScreenComponent', () => {
{ name: 'param_4', type: 'string', value: '' },
{ name: 'param_5', type: 'string', value: 'value_location_1' },
{ name: 'param_6', type: 'singlelist', value: '' },
{ name: 'catalog_item_id', type: 'string', value: 'fakeId' },
{ name: 'access_token', type: 'string', value: 'fakeAccessToken' }
{ name: 'catalog_item_id', type: 'string', value: 'fakeId' }
]
})
req.flush({});
Expand Down Expand Up @@ -292,8 +291,7 @@ describe('ProductActionScreenComponent', () => {
expect(req.request.body).toEqual({
id: 'fakeAction',
parameters: [
{ name: 'catalog_item_id', type: 'string', value: 'fakeId' },
{ name: 'access_token', type: 'string', value: 'fakeAccessToken' }
{ name: 'catalog_item_id', type: 'string', value: 'fakeId' }
],
})
req.flush({});
Expand Down Expand Up @@ -325,8 +323,7 @@ describe('ProductActionScreenComponent', () => {
expect(req.request.body).toEqual({
id: 'fakeAction',
parameters: [
{ name: 'catalog_item_id', type: 'string', value: 'fakeId' },
{ name: 'access_token', type: 'string', value: 'fakeAccessToken' }
{ name: 'catalog_item_id', type: 'string', value: 'fakeId' }
],
})
req.flush({});
Expand Down Expand Up @@ -366,8 +363,7 @@ describe('ProductActionScreenComponent', () => {
parameters: [
{ name: 'param_1', type: 'string', value: 'value1' },
{ name: 'param_2', type: 'string', value: 'value2' },
{ name: 'catalog_item_id', type: 'string', value: 'fakeId' },
{ name: 'access_token', type: 'string', value: 'fakeAccessToken' }
{ name: 'catalog_item_id', type: 'string', value: 'fakeId' }
],
});

Expand Down Expand Up @@ -413,8 +409,7 @@ describe('ProductActionScreenComponent', () => {
id: 'fakeAction',
parameters: [
{ name: 'param_1', type: 'string', value: 'value1' },
{ name: 'catalog_item_id', type: 'string', value: 'fakeId' },
{ name: 'access_token', type: 'string', value: 'fakeAccessToken' },
{ name: 'catalog_item_id', type: 'string', value: 'fakeId' }
],
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { ProductActionParameterValidation } from '../../models/product-action-pa
import { MatOptionModule } from '@angular/material/core';
import { MatSelectModule } from '@angular/material/select';
import { ProjectService } from '../../services/project.service';
import { Subject, switchMap, takeUntil } from 'rxjs';
import { Subject, takeUntil } from 'rxjs';
import { AppProject } from '../../models/project';
import { AzureService } from '../../services/azure.service';
import { AppUser } from '../../models/app-user';
Expand Down Expand Up @@ -358,32 +358,23 @@ export class ProductActionScreenComponent implements OnInit, OnDestroy {
if (this.formGroup.valid && this.action.url && this.selectedProject) {
this.isExecutingAction = true;
const actionUrl = this.action.url;
this.azureService.getRefreshedAccessToken().pipe(
switchMap((refreshedAccessToken: string) => {
const actionBody = {
id: this.action.id,
parameters: this.actionParams.map(param => ({
name: param.name,
type: param.type,
value: this.formGroup.getRawValue()[param.name] || this.getParamDefaultValue(param) || ''
})),
};
actionBody.parameters.push(
{
name: 'catalog_item_id',
type: 'string',
value: this.product.id
},
{
name: 'access_token', // ToDo: when using access token in headers, this parameter is not needed and the provisioner should retrieve it and add the param.
type: 'string',
value: refreshedAccessToken
}
);
this.formGroup.disable();
return this.http.post(actionUrl, actionBody);
})
).subscribe({
const actionBody = {
id: this.action.id,
parameters: this.actionParams.map(param => ({
name: param.name,
type: param.type,
value: this.formGroup.getRawValue()[param.name] || this.getParamDefaultValue(param) || ''
})),
};
actionBody.parameters.push(
{
name: 'catalog_item_id',
type: 'string',
value: this.product.id
}
);
this.formGroup.disable();
this.http.post(actionUrl, actionBody).subscribe({
next: () => {
if(this.action.triggerMessage && this.action.triggerMessage !== '') {
this.toastService.showToast({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,7 @@ describe('ProjectComponentsScreenComponent', () => {
autoFocus: false,
data: {
componentName: 'test-component',
projectKey: 'PROJECT_1',
location: 'LOC_1'
projectKey: 'PROJECT_1'
}
});
});
Expand All @@ -202,8 +201,7 @@ describe('ProjectComponentsScreenComponent', () => {
autoFocus: false,
data: {
componentName: 'another-test-component',
projectKey: 'PROJECT_2',
location: 'LOC_2'
projectKey: 'PROJECT_2'
}
});
});
Expand All @@ -229,8 +227,7 @@ describe('ProjectComponentsScreenComponent', () => {
changeNumber: 'CHG1234567',
reason: 'Test reason',
projectKey: 'PROJECT_1',
componentName: 'test-component',
location: 'LOC_1'
componentName: 'test-component'
};
spyOn(component.dialog, 'open').and.returnValue({
afterClosed: () => of(mockResult)
Expand All @@ -239,12 +236,9 @@ describe('ProjectComponentsScreenComponent', () => {
component.onRequestDeletionClicked(testComponent);
expect(component.projectComponents[0].status).toBe('DELETING');
const incidentParams: CreateIncidentParameter[] = [
{ name: 'cluster_location', type: 'string', value: 'LOC_1' as String },
{ name: 'caller', type: 'string', value: 'test-user' as String },
{ name: 'is_deployed', type: 'boolean', value: true as Boolean },
{ name: 'change_number', type: 'string', value: 'CHG1234567' as String },
{ name: 'reason', type: 'string', value: 'Test reason' as String },
{ name: 'access_token', type: 'string', value: 'test-access-token' as String }
{ name: 'reason', type: 'string', value: 'Test reason' as String }
]
expect(provisionerServiceSpy.requestComponentDeletion).toHaveBeenCalledWith(
'PROJECT_1',
Expand Down Expand Up @@ -280,21 +274,17 @@ describe('ProjectComponentsScreenComponent', () => {
changeNumber: 'CHG1234567',
reason: 'Test reason',
projectKey: 'PROJECT_1',
componentName: 'test-component',
location: 'LOC_1'
componentName: 'test-component'
};
spyOn(component.dialog, 'open').and.returnValue({
afterClosed: () => of(mockResult)
} as any);
provisionerServiceSpy.requestComponentDeletion.and.returnValue(throwError(() => new Error('Deletion failed')));
component.onRequestDeletionClicked(testComponent);
const incidentParams: CreateIncidentParameter[] = [
{ name: 'cluster_location', type: 'string', value: 'LOC_1' as String },
{ name: 'caller', type: 'string', value: 'test-user' as String },
{ name: 'is_deployed', type: 'boolean', value: true as Boolean },
{ name: 'change_number', type: 'string', value: 'CHG1234567' as String },
{ name: 'reason', type: 'string', value: 'Test reason' as String },
{ name: 'access_token', type: 'string', value: 'test-access-token' as String }
{ name: 'reason', type: 'string', value: 'Test reason' as String }
]
expect(provisionerServiceSpy.requestComponentDeletion).toHaveBeenCalledWith(
'PROJECT_1',
Expand Down Expand Up @@ -330,21 +320,17 @@ describe('ProjectComponentsScreenComponent', () => {
changeNumber: 'CHG1234567',
reason: 'Test reason',
projectKey: 'PROJECT_1',
componentName: 'test-component',
location: 'LOC_1'
componentName: 'test-component'
};
spyOn(component.dialog, 'open').and.returnValue({
afterClosed: () => of(mockResult)
} as any);
component.loggedUser = null;
component.onRequestDeletionClicked(testComponent);
const incidentParams: CreateIncidentParameter[] = [
{ name: 'cluster_location', type: 'string', value: 'LOC_1' as String },
{ name: 'caller', type: 'string', value: 'unknown' as String },
{ name: 'is_deployed', type: 'boolean', value: true as Boolean },
{ name: 'change_number', type: 'string', value: 'CHG1234567' as String },
{ name: 'reason', type: 'string', value: 'Test reason' as String },
{ name: 'access_token', type: 'string', value: 'test-access-token' as String }
{ name: 'reason', type: 'string', value: 'Test reason' as String }
]
expect(provisionerServiceSpy.requestComponentDeletion).toHaveBeenCalledWith(
'PROJECT_1',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ export class ProjectComponentsScreenComponent implements OnInit, OnDestroy {
data: {
componentName: component.name,
projectKey: this.selectedProject.projectKey,
location: this.selectedProject.location
}
});

Expand All @@ -147,56 +146,37 @@ export class ProjectComponentsScreenComponent implements OnInit, OnDestroy {
originalStatus = this.projectComponents[componentIndex].status;
this.projectComponents[componentIndex].status = 'DELETING';
}
this.azureService.getRefreshedAccessToken().subscribe({
next: (accessToken) => {
/* eslint-disable @typescript-eslint/no-wrapper-object-types */
const incidentParams: CreateIncidentParameter[] = [
{
name: 'cluster_location',
type: 'string',
value: result.location as String // NOSONAR
},
{
name: 'caller',
type: 'string',
value: this.loggedUser?.username as String || 'unknown' // NOSONAR
},
{
name: 'is_deployed',
type: 'boolean',
value: result.deploymentStatus as Boolean // NOSONAR

},
{
name: 'change_number',
type: 'string',
value: result.changeNumber as String // NOSONAR
},
{
name: 'reason',
type: 'string',
value: result.reason as String // NOSONAR
},
{
name: 'access_token',
type: 'string',
value: accessToken as String // NOSONAR
},
];
/* eslint-enable @typescript-eslint/no-wrapper-object-types */
this.provisionerService.requestComponentDeletion(
result.projectKey,
result.componentName,
incidentParams
).subscribe({
next: () => this.onDeletionRequestSuccess(),
error: (error) => {
this.onDeletionRequestError(error)
if (originalStatus && componentIndex !== -1) {
this.projectComponents[componentIndex].status = originalStatus;
}
}
});
/* eslint-disable @typescript-eslint/no-wrapper-object-types */
const incidentParams: CreateIncidentParameter[] = [
{
name: 'is_deployed',
type: 'boolean',
value: result.deploymentStatus as Boolean // NOSONAR

},
{
name: 'change_number',
type: 'string',
value: result.changeNumber as String // NOSONAR
},
{
name: 'reason',
type: 'string',
value: result.reason as String // NOSONAR
}
];
/* eslint-enable @typescript-eslint/no-wrapper-object-types */
this.provisionerService.requestComponentDeletion(
result.projectKey,
result.componentName,
incidentParams
).subscribe({
next: () => this.onDeletionRequestSuccess(),
error: (error) => {
this.onDeletionRequestError(error)
if (originalStatus && componentIndex !== -1) {
this.projectComponents[componentIndex].status = originalStatus;
}
}
});
}
Expand Down
Loading
Loading