Api data is not correctly mapped (includes style changes)
MODIFY
src/app/components/admin/admin.component.scss
src/app/components/admin/admin.component.scss
button {
display: flex;
align-items: center;
+ margin-left: 0px;
}
.button-text {

MODIFY
src/app/components/admin/create-developer/create-developer.component.scss
src/app/components/admin/create-developer/create-developer.component.scss
min-height: 130px;
}
+// stepper styling
::ng-deep .mat-step-icon {
background-color: var(--scheer-grey-color-fill) !important;
}
-
+// stepper styling
::ng-deep .mat-step-icon-selected, ::ng-deep .mat-step-icon-state-edit {
background-color: var(--scheer-bg-color) !important;
}
-
+// stepper styling
::ng-deep .mat-form-field.mat-focused .mat-form-field-label {
color: black!important;
-}
+}// stepper styling
::ng-deep .mat-form-field.mat-focused .mat-form-field-ripple {
background-color: black!important;
}
-
-mat-card {
- display: flex;
- color: white;
- border-radius: 0;
- padding: .75rem 1.25rem;
- margin-bottom: 1rem;
- border: 1px solid transparent;
- opacity: 0.75;
-}
-
-.warning {
- background-color: var(--branding-message-warn);
-}
-
-.info {
- background-color: var(--branding-message-info);
-}
-
-.box-content {
- padding-left: 5px;
- padding-top: 3px;
-}

MODIFY
src/app/components/admin/developer-list.component.html
src/app/components/admin/developer-list.component.html
+<div class="wrapper">
<mat-nav-list>
<mat-list-item *ngFor="let developer of developers">
{{ developer.name }}
<span *ngIf="developer.clients.length > 0">(</span>
- <div class="developer-list-client-list" *ngFor="let client of developer.clients"> {{client.organizationId}}/{{client.clientId}}</div>
+ <div class="developer-list-client-list" *ngFor="let client of developer.clients"> {{client.organizationId}}
+ /{{client.clientId}}</div>
<span *ngIf="developer.clients.length > 0">)</span>
<mat-icon [routerLink]="['/admin/edit/developer', developer.id]">edit</mat-icon>
<mat-icon class="deleteIcon" (click)="deleteDeveloper(developer)">delete</mat-icon>
</mat-list-item>
- <mat-list-item *ngIf="!developers || developers.length === 0">No developers there, click button above to create one.</mat-list-item>
</mat-nav-list>
+ <mat-card
+ class="info"
+ *ngIf="!developers || developers.length === 0">
+ <mat-icon>info</mat-icon>
+ <div class="box-content">No developers there, click button above to create one.</div>
+ </mat-card>
+</div>

MODIFY
src/app/components/admin/developer-list.component.scss
src/app/components/admin/developer-list.component.scss
.developer-list-client-list {
margin: 0 5px;
}
+
+.wrapper {
+ min-width: 150px;
+ max-width: 700px;
+ width: 100%;
+}

MODIFY
src/app/components/developer/api-list/api-list.component.html
src/app/components/developer/api-list/api-list.component.html
<table *ngIf="sortedApiData.length > 0" matSort matSortStart="desc" (matSortChange)="sortData($event)" mat-table [dataSource]="sortedApiData" multiTemplateDataRows>
<ng-container matColumnDef="api">
<th mat-header-cell mat-sort-header="api" *matHeaderCellDef>API</th>
- <td mat-cell *matCellDef="let element" (click)="expandedElement = expandedElement === element ? null : element" class="clickable">
+ <td mat-cell *matCellDef="let element">
<mat-icon class="status" [ngClass]="element.status" matTooltip="{{this.computeStatusText(element.status)}}">brightness_1</mat-icon>
- {{element.apiOrganization}} / <b>{{element.apiName}}</b>
+ <span class="apiName">{{element.apiOrganization}} / <b>{{element.apiName}}</b></span>
</td>
</ng-container>
<ng-container matColumnDef="apiVersion">
<ng-container matColumnDef="options">
<th mat-header-cell *matHeaderCellDef>Options</th>
<td mat-cell *matCellDef="let element">
- <mat-icon class="button" (click)="this.copyEndpointToClipboard(element)" matTooltip="Copy endpoint to clipboard" [matTooltipClass]="'tooltip'">file_copy</mat-icon>
+ <mat-icon class="button" (click)="this.copyEndpointToClipboard($event, element)" matTooltip="Copy endpoint to clipboard" [matTooltipClass]="'tooltip'">file_copy</mat-icon>
</td>
</ng-container>
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
<ng-container matColumnDef="expandedDetail">
- <td mat-cell *matCellDef="let element" [attr.colspan]="columnHeaders.length" class="expandedTd" [ngClass]="element === expandedElement ? 'displayed': 'hidden'">
+ <td mat-cell *matCellDef="let element" [attr.colspan]="columnHeaders.length" class="expandedTd" [ngClass]="isExpanded(element) ? 'displayed': 'hidden'">
<div class="api-detail"
- [@detailExpand]="element === expandedElement ? 'expanded' : 'collapsed'">
+ [@detailExpand]="isExpanded(element) ? 'expanded' : 'collapsed'">
<div class="expand-content">
<div class="expanded-header">API Endpoint</div>
<div>{{element.endpoint}}</div>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columnHeaders"></tr>
- <tr mat-row *matRowDef="let row; columns: columnHeaders;"></tr>
+ <tr mat-row *matRowDef="let listElement; columns: columnHeaders;" (click)="isExpanded(listElement) ? collapse(listElement) : expand(listElement)" class="clickable"></tr>
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="api-detail-row"></tr>
</table>

MODIFY
src/app/components/developer/api-list/api-list.component.scss
src/app/components/developer/api-list/api-list.component.scss
@@ -11,6 +11,10 @@ p {
padding-top: 4px;
}
+.button {
+ z-index: 1;
+}
+
.button, .clickable {
cursor: pointer;
}
@@ -58,9 +62,13 @@ tr.api-detail-row {
color: inherit;
}
+.apiName {
+ padding-left: 10px;
+}
+
.status {
font-size: 12px;
- padding-top: 9px;
+ display: contents;
}
.Retired {

MODIFY
src/app/components/developer/api-list/api-list.component.ts
src/app/components/developer/api-list/api-list.component.ts
@@ -39,7 +39,7 @@ export interface ApiListElement {
export class ApiListComponent implements OnChanges {
columnHeaders: string[] = ['api', 'apiVersion', 'tryApi', 'options'];
- expandedElement: ApiListElement | null;
+ expandedElements: Array<ApiListElement> = [];
apiData: Array<ApiListElement> = [];
sortedApiData: Array<ApiListElement>;
@@ -149,13 +149,15 @@ export class ApiListComponent implements OnChanges {
* Copies endpoint to clipboard
* @param entry the table entry
*/
- copyEndpointToClipboard(entry: ApiListElement) {
+ copyEndpointToClipboard(event, entry: ApiListElement) {
const el = document.createElement('textarea');
document.body.appendChild(el);
el.value = entry.endpoint + '?apiKey=' + entry.apikey;
el.select();
document.execCommand('copy');
document.body.removeChild(el);
+
+ event.stopPropagation();
}
/**
@@ -197,6 +199,8 @@ export class ApiListComponent implements OnChanges {
/**
* Compute combined status from API and Client Status
+ * @param clientStatus the client status
+ * @param apiStatus the api status
*/
private computeStatus(clientStatus, apiStatus): string {
const registered = 'Registered';
@@ -205,26 +209,27 @@ export class ApiListComponent implements OnChanges {
if (clientStatus === retired || apiStatus === retired) {
return this.status.retired;
- }
- if (clientStatus === registered && apiStatus === published) {
+ } else if (clientStatus === registered && apiStatus === published) {
return this.status.active;
- }
+ } else {
return this.status.inactive;
}
+ }
/**
* Compute tooltip status text
- * @param status the computed status
+ * @param apiStatus the computed status text
*/
public computeStatusText(apiStatus) {
- if (apiStatus === this.status.active) {
+ switch (apiStatus) {
+ case this.status.active:
return 'API is active';
- }
- if (apiStatus === this.status.inactive) {
- return 'API coming soon';
- }
+ case this.status.inactive:
+ return 'API is coming soon';
+ default:
return 'API is retired';
}
+ }
/**
* Compares two values
@@ -268,4 +273,28 @@ export class ApiListComponent implements OnChanges {
this.toasterService.pop('warning', 'No gateway data available');
}
}
+
+ /**
+ * Is list element expanded
+ * @param apiListElement the api list element
+ */
+ public isExpanded(apiListElement: ApiListElement) {
+ return this.expandedElements.find((e) => e === apiListElement) !== undefined;
+ }
+
+ /**
+ * Collapse list element
+ * @param apiListElement the api list element
+ */
+ public collapse(apiListElement: ApiListElement) {
+ this.expandedElements.splice(this.expandedElements.findIndex((e) => e === apiListElement), 1);
+ }
+
+ /**
+ * Expand list element
+ * @param apiListElement the api list element
+ */
+ public expand(apiListElement: ApiListElement) {
+ this.expandedElements.push(apiListElement);
+ }
}

MODIFY
src/app/components/swagger/swagger.component.ts
src/app/components/swagger/swagger.component.ts
@@ -21,8 +21,15 @@ export class SwaggerComponent implements OnInit {
const apiId = this.route.snapshot.paramMap.get('apiId');
const version = this.route.snapshot.paramMap.get('version');
+ let apiStatus = history.state.data ? history.state.data.apiStatus : null;
let apiKey = history.state.data ? history.state.data.apikey : null;
- const apiStatus = history.state.data ? history.state.data.apiStatus : null;
+
+ if (apiStatus) {
+ // save status for reloading page
+ sessionStorage.setItem('lastApiStatus', apiStatus);
+ } else {
+ apiStatus = sessionStorage.getItem('lastApiStatus');
+ }
if (apiKey) {
// save key for reloading page
@@ -50,7 +57,11 @@ export class SwaggerComponent implements OnInit {
};
};
- const swaggerUI = SwaggerUIBundle({
+ const DisableAuthorizePlugin = () => ({ wrapComponents: { authorizeBtn: () => () => null } });
+
+ let apiKeySecuritySettingName = 'X-API-Key';
+
+ const swaggerOptions = {
dom_id: '#swagger-editor',
layout: 'BaseLayout',
presets: [
@@ -63,12 +74,6 @@ export class SwaggerComponent implements OnInit {
url: swaggerURL,
docExpansion: 'none',
operationsSorter: 'alpha',
- onComplete: () => {
- // set api key in swagger view to make it look like authorized for calls
- // this option is not enough to send OPTION requests to gateway protected apis
- // sending this api key as header in option requests are blocked by the browser
- swaggerUI.preauthorizeApiKey('X-API-Key', apiKey);
- },
requestInterceptor: (request) => {
if (request.url === swaggerURL) {
// set bearer token for authentication to get swagger file
@@ -78,8 +83,35 @@ export class SwaggerComponent implements OnInit {
request.url += '?apiKey=' + apiKey;
}
return request;
+ },
+ responseInterceptor: (response) => {
+ if (response.url === swaggerURL) {
+ // determine apiKeySecuritySettingName by request of getting swagger definition
+ if (response.body && response.body.securityDefinitions) {
+ const securityDefinitions = Object.values(response.body.securityDefinitions);
+ // @ts-ignore
+ const apiKeySecuritySetting = securityDefinitions.find((securitySetting) => securitySetting.type === 'apiKey');
+ if (apiKeySecuritySetting) {
+ // @ts-ignore
+ // overwrite the default api key name
+ apiKeySecuritySettingName = apiKeySecuritySetting.name;
}
- });
+ }
+ }
+ },
+ onComplete: () => {
+ // set api key in swagger view to make it look like authorized for calls
+ // this option is not enough to send OPTION requests to gateway protected apis
+ // sending this api key as header in option requests are blocked by the browser
+ swaggerUI.preauthorizeApiKey(apiKeySecuritySettingName, apiKey);
+ }
+ };
+ if (apiStatus === 'Inactive') {
+ // @ts-ignore
+ swaggerOptions.plugins.push(DisableAuthorizePlugin);
+ }
+
+ const swaggerUI = SwaggerUIBundle(swaggerOptions);
}
}

MODIFY
src/styles/styles.scss
src/styles/styles.scss
@@ -100,3 +100,26 @@ button[disabled], button[disabled], button[disabled]:hover {
border-color: var(--scheer-button-border-color);
color: var(--scheer-button-bg);
}
+
+mat-card {
+ display: flex !important;
+ color: white !important;
+ border-radius: 0 !important;
+ padding: .75rem 1.25rem;
+ margin-bottom: 1rem;
+ border: 1px solid transparent;
+ opacity: 0.75 !important;
+}
+
+.warning {
+ background-color: var(--branding-message-warn);
+}
+
+.info {
+ background-color: var(--branding-message-info);
+}
+
+.box-content {
+ padding-left: 5px;
+ padding-top: 3px;
+}

GW-304: Api data is not correctly mapped (includes style changes)