feat: add register button to my clients page
Closes:
MODIFY
src/app/components/marketplace-signup-stepper/marketplace-signup-stepper.component.ts
src/app/components/marketplace-signup-stepper/marketplace-signup-stepper.component.ts
@@ -19,6 +19,7 @@ import { Router } from '@angular/router';
import { HeroService } from '../../services/hero/hero.service';
import { TranslateService } from '@ngx-translate/core';
import {
+ IAction,
IClientSummary,
IContract,
IContractSummary,
@@ -32,10 +33,11 @@ import { ISignUpInfo } from '../../interfaces/ISignUpInfo';
import { BackendService } from '../../services/backend/backend.service';
import { MatStepper } from '@angular/material/stepper';
import { IContractExt } from '../../interfaces/IContractExt';
-import { catchError, map, switchMap } from 'rxjs/operators';
+import { map, switchMap } from 'rxjs/operators';
import { TocService } from '../../services/toc/toc.service';
import { HttpErrorResponse } from '@angular/common/http';
-import { EMPTY, throwError } from 'rxjs';
+import { Observable } from 'rxjs';
+import { ClientService } from '../../services/client/client.service';
@Component({
selector: 'app-marketplace-signup-stepper',
@@ -60,7 +62,8 @@ export class MarketplaceSignupStepperComponent implements OnInit {
private signUpService: SignUpService,
private router: Router,
private backend: BackendService,
- private tocService: TocService
+ private tocService: TocService,
+ private clientService: ClientService
) {
this.termsEnabled = this.configService.getTerms().enabled;
this.newContractDetails = this.signUpService.getSignUpInfo();
@@ -204,25 +207,14 @@ export class MarketplaceSignupStepperComponent implements OnInit {
);
}
- private registerClient() {
- return this.backend
- .sendAction({
+ private registerClient(): Observable<void> {
+ const action: IAction = {
type: 'registerClient',
entityVersion: '1.0',
organizationId: this.contract.client.client.organization.id,
entityId: this.contract.client.client.id
- })
- .pipe(
- catchError((err: HttpErrorResponse) => {
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
- if (err.error.type === 'InvalidContractStatusException') {
- // Ignore this error because this is still valid
- return EMPTY;
- } else {
- return throwError(() => err);
- }
- })
- );
+ };
+ return this.clientService.registerClient(action);
}
finish(): void {

MODIFY
src/app/components/my-apps/my-apps.component.html
src/app/components/my-apps/my-apps.component.html
matTooltip="{{ 'CLIENTS.REMOVE_CLIENT_TOOLTIP' | translate }}">
<mat-icon>delete</mat-icon>
</button>
+ <button
+ id="client-register-btn"
+ *ngIf="cliCon.value[0].registerable"
+ (click)="register(cliCon.value[0])"
+ mat-icon-button
+ color="primary"
+ matTooltip="{{ 'CLIENTS.REGISTER' | translate }}">
+ <mat-icon>app_registration</mat-icon>
+ </button>
<span
id="client-status-label"
matTooltip="Client Status"

MODIFY
src/app/components/my-apps/my-apps.component.scss
src/app/components/my-apps/my-apps.component.scss
.app-client-header-label {
white-space: nowrap;
text-align: right;
+ display: grid;
+ grid-auto-flow: column;
+ align-items: center;
span {
margin-left: 8px;
span:last-child {
margin-right: 0;
}
+
+ mat-icon {
+ font-size: 28px;
+ height: 28px;
+ width: 28px;
+ }
}
/* stylelint-disable no-descending-specificity */

MODIFY
src/app/components/my-apps/my-apps.component.ts
src/app/components/my-apps/my-apps.component.ts
@@ -26,6 +26,7 @@ import {
statusColorMap
} from '../../interfaces/IStatus';
import {
+ IAction,
IClientSummary,
IClientVersionSummary,
IContract,
@@ -54,6 +55,7 @@ import { SnackbarService } from '../../services/snackbar/snackbar.service';
import { ConfigService } from '../../services/config/config.service';
import { IPolicyExt, IPolicyProbe } from '../../interfaces/IPolicy';
import { PermissionsService } from '../../services/permissions/permissions.service';
+import { ClientService } from '../../services/client/client.service';
@Component({
selector: 'app-my-apps',
@@ -90,7 +92,8 @@ export class MyAppsComponent implements OnInit {
private snackbarService: SnackbarService,
public configService: ConfigService,
private cdr: ChangeDetectorRef,
- private permissionsService: PermissionsService
+ private permissionsService: PermissionsService,
+ private clientService: ClientService
) {}
ngOnInit(): void {
@@ -194,7 +197,8 @@ export class MyAppsComponent implements OnInit {
docsAvailable: this.apiService.isApiDocAvailable(
contract.api
),
- deletable: this.isDeleteAllowed(contract)
+ deletable: this.isDeleteAllowed(contract),
+ registerable: this.isRegisterable(contract)
} as IContractExt;
})
);
@@ -413,6 +417,21 @@ export class MyAppsComponent implements OnInit {
return `${contract.api.api.name} ${contract.api.version} - ${contract.plan.plan.name}`;
}
+ register(contract: IContractExt) {
+ const action: IAction = {
+ type: 'registerClient',
+ organizationId: contract.client.client.organization.id,
+ entityId: contract.client.client.id,
+ entityVersion: contract.client.version
+ };
+ this.clientService.registerClient(action).subscribe(() => {
+ console.info(
+ `Client ${action.organizationId}/${action.entityId}/${action.entityVersion} successfully registered`
+ );
+ contract.client.status = 'Registered';
+ });
+ }
+
unregister(contract: IContractExt, clientNameVersion: string): void {
const dialogRef = this.dialog.open(UnregisterClientComponent, {
autoFocus: false
@@ -432,6 +451,12 @@ export class MyAppsComponent implements OnInit {
});
}
+ private getClientAdminOrgs() {
+ return this.permissionsService.getAllowedOrganizations({
+ name: 'clientAdmin'
+ } as IPermission);
+ }
+
private isDeleteAllowed(contract: IContract): boolean {
const clientAdminOrganizations =
this.permissionsService.getAllowedOrganizations({
@@ -443,6 +468,16 @@ export class MyAppsComponent implements OnInit {
);
}
+ private isRegisterable(contract: IContract): boolean {
+ const clientAdminOrganizations = this.getClientAdminOrgs();
+ return (
+ (contract.client.status === 'Ready' ||
+ contract.client.status === 'Unregistered' ||
+ contract.client.status === 'Retired') &&
+ clientAdminOrganizations.includes(contract.client.client.organization.id)
+ );
+ }
+
onSetSection($event: { contract: IContractExt; section: ISection }): void {
this.setSection($event.contract, $event.section);
this.cdr.detectChanges();

MODIFY
src/app/interfaces/IContractExt.ts
src/app/interfaces/IContractExt.ts
/*
- * Copyright 2021 Scheer PAS Schweiz AG
+ * Copyright 2022 Scheer PAS Schweiz AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,4 +28,5 @@ export interface IContractExt extends IContract {
policies: IPolicyExt[];
docsAvailable: boolean;
deletable: boolean;
+ registerable: boolean;
}

ADD
src/app/services/client/client.service.spec.ts
+/*
+ * Copyright 2022 Scheer PAS Schweiz AG
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * imitations under the License.
+ */
+
+import { TestBed } from '@angular/core/testing';
+
+import { ClientService } from './client.service';
+
+describe('ClientService', () => {
+ let service: ClientService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ service = TestBed.inject(ClientService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+});

ADD
src/app/services/client/client.service.ts
+/*
+ * Copyright 2022 Scheer PAS Schweiz AG
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * imitations under the License.
+ */
+
+import { Injectable } from '@angular/core';
+import { catchError } from 'rxjs/operators';
+import { HttpErrorResponse } from '@angular/common/http';
+import { EMPTY, Observable, throwError } from 'rxjs';
+import { BackendService } from '../backend/backend.service';
+import { IAction } from '../../interfaces/ICommunication';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class ClientService {
+ constructor(private backend: BackendService) {}
+
+ /**
+ * This method registers a client, if we got an InvalidContractStatusException which can happen
+ * if one API needs approval we will do nothing as this is okay
+ * @param action - the action with the client to register
+ */
+ public registerClient(action: IAction): Observable<void> {
+ return this.backend.sendAction(action).pipe(
+ catchError((err: HttpErrorResponse) => {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+ if (err.error.type === 'InvalidContractStatusException') {
+ // Ignore this error because this is still valid
+ return EMPTY;
+ } else {
+ return throwError(() => err);
+ }
+ })
+ );
+ }
+}

MODIFY
src/assets/i18n/en.json
src/assets/i18n/en.json
"RETIRED_API": "This API is retired and can no longer be used.",
"SELECT": "Select from available Clients",
"CLIENT_TOOLTIP": "Client Organization: {{ client.client.organization.name }}\nClient Name (Version): {{ client.client.name }} ({{ client.version }})",
- "API_TOOLTIP": "API Organization: {{ api.api.organization.name }}\nAPI Name (Version): {{ api.api.name }} ({{ api.version }})\nPlan Name (Version): {{ plan.plan.name }} ({{ plan.version }})"
+ "API_TOOLTIP": "API Organization: {{ api.api.organization.name }}\nAPI Name (Version): {{ api.api.name }} ({{ api.version }})\nPlan Name (Version): {{ plan.plan.name }} ({{ plan.version }})",
+ "REGISTER": "Register client"
},
"WIZARD": {
"FIRST_STEP_LABEL": "Select/create Client",

feat: add register button to my clients page

Closes: #129