feat/fix: toc sorting, signup redirection, anchor scrolling
MODIFY
src/app/components/home/home.component.ts
src/app/components/home/home.component.ts
@@ -3,6 +3,7 @@ import { HeroService } from '../../services/hero/hero.service';
import { TranslateService } from '@ngx-translate/core';
import { ConfigService } from '../../services/config/config.service';
import { IHero } from '../../interfaces/IConfig';
+import {Router} from "@angular/router";
@Component({
selector: 'app-home',

MODIFY
src/app/components/marketplace-signup-stepper/marketplace-signup-stepper.component.ts
src/app/components/marketplace-signup-stepper/marketplace-signup-stepper.component.ts
@@ -15,6 +15,7 @@ import { BackendService } from '../../services/backend/backend.service';
import { MatStepper } from '@angular/material/stepper';
import { IContractExt } from '../../interfaces/IContractExt';
import {map, switchMap} from "rxjs/operators";
+import {TocService} from "../../services/toc.service";
@Component({
selector: 'app-marketplace-signup-stepper',
@@ -37,7 +38,8 @@ export class MarketplaceSignupStepperComponent implements OnInit {
private configService: ConfigService,
private signUpService: SignUpService,
private router: Router,
- private backend: BackendService
+ private backend: BackendService,
+ private tocService: TocService
) {
this.termsEnabled = this.configService.getTerms().enabled;
this.newContractDetails = this.signUpService.getSignUpInfo();
@@ -106,7 +108,7 @@ export class MarketplaceSignupStepperComponent implements OnInit {
.createContract(client.organizationId, client.id, '1.0', contract).pipe(
switchMap(contract => {
return this.backend.getManagedApiEndpoint(
- contract.client.client.organization.id,
+ contract.api.api.organization.id,
contract.api.api.id,
contract.api.version).pipe(
map(endpoint => {
@@ -135,6 +137,6 @@ export class MarketplaceSignupStepperComponent implements OnInit {
}
finish(): void {
- void this.router.navigate(['applications']);
+ void this.router.navigate(['applications'], {fragment: this.tocService.formatClientId(this.contract!)});
}
}

MODIFY
src/app/components/my-apps/my-apps.component.html
src/app/components/my-apps/my-apps.component.html
<div *ngIf="contractsLoaded" class="wrapper">
<div id="contracts" class="first">
- <mat-card *ngFor="let cliCon of clientContractsMap | keyvalue" class="mb-40" [id]="formatClientContractTitle(cliCon.key)">
+ <mat-card *ngFor="let cliCon of clientContractsMap | keyvalue" class="mb-40" [id]="tocService.formatClientId(cliCon.value[0])">
<div class="app-header">
<div class="app-icon-wrapper">
<img class="app-icon" [src]="tmpUrl" alt="app-icon" />
<div class="app-api-header-icon-wrapper">
<img class="app-api-header-icon" [src]="tmpUrl2" alt="app-icon" />
</div>
- <div class="app-api-header-title" [id]="formatApiVersionPlanTitleWithClient(contract)">
+ <div class="app-api-header-title" [id]="tocService.formatApiVersionPlanId(contract)">
<h3 class="primary">
{{formatApiVersionPlanTitle(contract)}}
</h3>

MODIFY
src/app/components/my-apps/my-apps.component.ts
src/app/components/my-apps/my-apps.component.ts
@@ -21,6 +21,8 @@ import {flatArray} from "../../shared/utility";
import {SpinnerService} from "../../services/spinner/spinner.service";
import {ApiService} from "../../services/api/api.service";
import {ITocLink} from "../../interfaces/ITocLink";
+import {KeyValue} from "@angular/common";
+import {TocService} from "../../services/toc.service";
@Component({
selector: 'app-my-apps',
@@ -33,24 +35,27 @@ export class MyAppsComponent implements OnInit {
contractsLoaded = false;
tmpUrl = 'https://pbs.twimg.com/media/Ez-AaifWYAIiFSQ.jpg';
- tmpUrl2 =
- 'https://cdn0.iconfinder.com/data/icons/customicondesignoffice5/256/examples.png';
+ tmpUrl2 = 'https://cdn0.iconfinder.com/data/icons/customicondesignoffice5/256/examples.png';
tocLinks: ITocLink[] = [];
+
constructor(
private spinnerService: SpinnerService,
private heroService: HeroService,
private translator: TranslateService,
private backend: BackendService,
private policyService: PolicyService,
- private apiService: ApiService
- ) {}
+ private apiService: ApiService,
+ public tocService: TocService
+ ) {
+ }
ngOnInit(): void {
this.setUpHero();
this.fetchContracts();
}
+
// Detailed explanation of request chain: https://stackoverflow.com/questions/69421293/how-to-chain-requests-correctly-with-rxjs
private fetchContracts() {
this.spinnerService.startWaiting();
@@ -127,11 +132,8 @@ export class MyAppsComponent implements OnInit {
this.contracts = this.contracts.concat(contracts);
this.contracts.forEach((contract: IContractExt) => {
- const clientNameVersionMapped =
- contract.client.client.name + ':' + contract.client.version;
- const foundContracts = this.clientContractsMap.get(
- clientNameVersionMapped
- );
+ const clientNameVersionMapped = (contract.client.client.name + ':' + contract.client.version).toLowerCase();
+ const foundContracts = this.clientContractsMap.get(clientNameVersionMapped);
if (foundContracts) {
const contractIfPartOfArray = foundContracts.find((c: IContractExt) => {
@@ -150,6 +152,9 @@ export class MyAppsComponent implements OnInit {
this.clientContractsMap.set(clientNameVersionMapped, [contract]);
}
});
+
+ // Sort Clients by name
+ this.clientContractsMap = new Map([...this.clientContractsMap.entries()].sort());
}
private setUpHero() {
@@ -167,17 +172,15 @@ export class MyAppsComponent implements OnInit {
return statusColorMap.get(status);
}
- formatClientContractTitle(key: string) {
- return key.replace(':', ' - ');
+ formatClientContractTitle(key: string): string {
+ return this.clientContractsMap.get(key)![0].client.client.name + ' - ' + this.clientContractsMap.get(key)![0].client.version;
}
private generateTocLinks() {
this.clientContractsMap.forEach((value: IContractExt[], key: string) => {
- const formated = this.formatClientContractTitle(key);
-
this.tocLinks.push({
- name: formated,
- destination: formated,
+ name: this.formatClientContractTitle(key),
+ destination: this.tocService.formatClientId(value[0]),
subLinks: this.generateTocSubLinks(value)
});
});
@@ -189,7 +192,7 @@ export class MyAppsComponent implements OnInit {
contracts.forEach((contract: IContractExt) => {
subLinks.push({
name: this.formatApiVersionPlanTitle(contract),
- destination: this.formatApiVersionPlanTitleWithClient(contract)
+ destination: this.tocService.formatApiVersionPlanId(contract)
})
});
@@ -199,8 +202,4 @@ export class MyAppsComponent implements OnInit {
formatApiVersionPlanTitle(contract: IContractExt) {
return `${contract.api.api.name} ${contract.api.version} - ${contract.plan.plan.name}`;
}
-
- formatApiVersionPlanTitleWithClient(contract: IContractExt): string {
- return this.formatApiVersionPlanTitle(contract) + '-forClient-' + contract.client.client.name;
- }
}

MODIFY
src/app/components/toc/toc.component.ts
src/app/components/toc/toc.component.ts
-import {AfterViewInit, Component, Input} from '@angular/core';
+import {AfterViewInit, Component, Input, OnChanges, SimpleChanges} from '@angular/core';
import {ITocLink} from '../../interfaces/ITocLink';
+import {Router} from "@angular/router";
@Component({
selector: 'app-toc',
@@ -10,11 +11,14 @@ export class TocComponent implements AfterViewInit{
@Input() links: ITocLink[] = [];
linksInViewPort: ITocLink[] = [];
- constructor() {}
+ constructor(private router: Router) {}
+
ngAfterViewInit() {
if (this.links.length > 0)
this.links[0].active = true;
+
+ this.scroll(window.location.hash.replace('#', ''));
}
onWindowScroll() {
@@ -51,7 +55,15 @@ export class TocComponent implements AfterViewInit{
}
scroll(id: string) {
- const clientToScroll = document.getElementById(id)!;
- clientToScroll.scrollIntoView({behavior: 'smooth'})
+ const clientToScroll = document.getElementById(id);
+
+ if (clientToScroll)
+ clientToScroll.scrollIntoView({behavior: 'smooth'});
+
+ if(history.pushState && id) {
+ history.pushState(null, '/applications', '/applications#' + id);
+ }else{
+ history.pushState(null, '/applications', '/applications')
+ }
}
}

MODIFY
src/app/services/backend/backend.service.ts
src/app/services/backend/backend.service.ts
@@ -58,7 +58,7 @@ export class BackendService {
* Get Api
*/
public getApi(orgId: string, apiId: string): Observable<IApi> {
- const path = `/organizations/${orgId}/apis/${apiId}`;
+ const path = `organizations/${orgId}/apis/${apiId}`;
return this.http.get(
this.generateUrl(path),
this.httpOptions
@@ -72,7 +72,7 @@ export class BackendService {
orgId: string,
apiId: string
): Observable<IApiVersionSummary[]> {
- const path = `/organizations/${orgId}/apis/${apiId}/versions`;
+ const path = `organizations/${orgId}/apis/${apiId}/versions`;
return this.http.get<IApiVersionSummary[]>(
this.generateUrl(path),
this.httpOptions

MODIFY
src/app/services/keycloak-helper/keycloak-helper.service.ts
src/app/services/keycloak-helper/keycloak-helper.service.ts
@@ -88,7 +88,6 @@ export class KeycloakHelperService {
}
private static setTokensToSessionStorage(keycloakInstance: KeycloakInstance) {
- console.log('Set token:' + keycloakInstance.token);
window.sessionStorage.setItem(
'KEYCLOAK_SESSION_STORAGE_TOKEN',
keycloakInstance.token!

ADD
src/app/services/toc.service.spec.ts
+import { TestBed } from '@angular/core/testing';
+
+import { TocService } from './toc.service';
+
+describe('TocService', () => {
+ let service: TocService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ service = TestBed.inject(TocService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+});

ADD
src/app/services/toc.service.ts
+import { Injectable } from '@angular/core';
+import {IContractExt} from "../interfaces/IContractExt";
+
+@Injectable({
+ providedIn: 'root'
+})
+export class TocService {
+
+ constructor() { }
+
+ /**
+ * Schema Example: applications#SpringCorp.-1.0-SupportManager-1.0
+ * @param contract
+ */
+ formatApiVersionPlanId(contract: IContractExt): string {
+ return this.formatClientId(contract) + '-' + contract.api.api.id + '-' + contract.api.version;
+ }
+
+ /**
+ * Schema Example: applications#SpringCorp.-1.0
+ * @param contract
+ */
+ formatClientId(contract: IContractExt) {
+ return contract.client.client.id + '-' + contract.client.version;
+ }
+}

MODIFY
tsconfig.json
tsconfig.json
"module": "es2020",
"lib": [
"es2018",
- "dom"
+ "dom",
+ "ESNext.String"
]
},
"angularCompilerOptions": {

feat/fix: toc sorting, signup redirection, anchor scrolling