Browse Source

Api keys fixes after review.

pull/14074/head
deaflynx 11 months ago
parent
commit
7f56611ae9
  1. 8
      ui-ngx/src/app/modules/home/components/api-key/components/dialog/add-api-key-dialog.component.html
  2. 34
      ui-ngx/src/app/modules/home/components/api-key/components/dialog/add-api-key-dialog.component.ts
  3. 71
      ui-ngx/src/app/modules/home/components/api-key/components/dialog/api-key-generated-dialog.component.html
  4. 12
      ui-ngx/src/app/modules/home/components/api-key/components/dialog/api-key-generated-dialog.component.scss
  5. 22
      ui-ngx/src/app/modules/home/components/api-key/components/dialog/api-key-generated-dialog.component.ts
  6. 38
      ui-ngx/src/app/modules/home/components/api-key/components/dialog/api-keys-table-dialog.component.html
  7. 25
      ui-ngx/src/app/modules/home/components/api-key/components/dialog/api-keys-table-dialog.component.scss
  8. 3
      ui-ngx/src/app/modules/home/components/home-components.module.ts
  9. 2
      ui-ngx/src/app/modules/home/pages/user/user-tabs.component.html
  10. 1
      ui-ngx/src/app/shared/models/id/public-api.ts
  11. 6
      ui-ngx/src/assets/locale/locale.constant-en_US.json

8
ui-ngx/src/app/modules/home/components/api-key/components/dialog/add-api-key-dialog.component.html

@ -46,9 +46,11 @@
<section class="flex gap-3"> <section class="flex gap-3">
<mat-form-field appearance="outline" subscriptSizing="dynamic" class="flex-1"> <mat-form-field appearance="outline" subscriptSizing="dynamic" class="flex-1">
<mat-select formControlName="expirationTime" aria-label="Expiration date selector" (selectionChange)="onExpirationDateChange()"> <mat-select formControlName="expirationTime" aria-label="Expiration date selector" (selectionChange)="onExpirationDateChange()">
<mat-option [value]="value" *ngFor="let value of expirationDates"> @for (value of expirationTimeOptions; track value) {
{{ value | dateExpiration }} <mat-option [value]="value">
</mat-option> {{ value | dateExpiration }}
</mat-option>
}
<mat-option value="never">{{'api-key.expiration-time-never' | translate}}</mat-option> <mat-option value="never">{{'api-key.expiration-time-never' | translate}}</mat-option>
<mat-option value="custom">{{'api-key.expiration-time-custom' | translate}}</mat-option> <mat-option value="custom">{{'api-key.expiration-time-custom' | translate}}</mat-option>
</mat-select> </mat-select>

34
ui-ngx/src/app/modules/home/components/api-key/components/dialog/add-api-key-dialog.component.ts

@ -15,13 +15,13 @@
/// ///
import { Component, OnInit, Inject } from '@angular/core'; import { Component, Inject } from '@angular/core';
import { DialogComponent } from '@shared/components/dialog.component'; import { DialogComponent } from '@shared/components/dialog.component';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { FormBuilder, Validators, UntypedFormGroup } from '@angular/forms'; import { FormBuilder, Validators } from '@angular/forms';
import { deepTrim } from '@core/utils'; import { deepTrim } from '@core/utils';
import { ApiKeyService } from '@core/http/api-key.service'; import { ApiKeyService } from '@core/http/api-key.service';
import { ApiKeyInfo } from '@shared/models/api-key.models'; import { ApiKeyInfo } from '@shared/models/api-key.models';
@ -33,14 +33,16 @@ import { DAY } from '@shared/models/time/time.models';
templateUrl: './add-api-key-dialog.component.html', templateUrl: './add-api-key-dialog.component.html',
styleUrls: ['./add-api-key-dialog.component.scss'] styleUrls: ['./add-api-key-dialog.component.scss']
}) })
export class AddApiKeyDialogComponent extends DialogComponent<AddApiKeyDialogComponent, ApiKeyInfo | string> implements OnInit{ export class AddApiKeyDialogComponent extends DialogComponent<AddApiKeyDialogComponent, ApiKeyInfo | string> {
apiKeyForm: UntypedFormGroup;
readonly startDate = new Date(); readonly startDate = new Date();
readonly expirationDates = [7, 30, 60, 90].map(days => days * DAY); readonly expirationTimeOptions: Array<number> = [7, 30, 60, 90].map(days => days * DAY);
readonly apiKeyForm = this.fb.group({
private defaultExpirationDate = this.expirationDates[1]; description: [{value: null, disabled: false}, [Validators.required]],
enabled: [{value: true, disabled: false}, []],
expirationTime: [{value: this.expirationTimeOptions[1] as string | number, disabled: false}, [Validators.required]],
customExpirationTime: [{value: null, disabled: true}, []],
});
constructor( constructor(
protected store: Store<AppState>, protected store: Store<AppState>,
@ -53,15 +55,6 @@ export class AddApiKeyDialogComponent extends DialogComponent<AddApiKeyDialogCom
super(store, router, dialogRef); super(store, router, dialogRef);
} }
ngOnInit() {
this.apiKeyForm = this.fb.group({
description: [{value: null, disabled: false}, [Validators.required]],
enabled: [{value: true, disabled: false}, []],
expirationTime: [{value: this.defaultExpirationDate, disabled: false}, [Validators.required]],
customExpirationTime: [{value: null, disabled: true}, []],
});
}
close(): void { close(): void {
this.dialogRef.close(null); this.dialogRef.close(null);
} }
@ -89,11 +82,10 @@ export class AddApiKeyDialogComponent extends DialogComponent<AddApiKeyDialogCom
onExpirationDateChange() { onExpirationDateChange() {
const customExpirationTimeControl = this.apiKeyForm.get('customExpirationTime'); const customExpirationTimeControl = this.apiKeyForm.get('customExpirationTime');
if (this.isCustomExpirationTime()) { if (this.isCustomExpirationTime()) {
customExpirationTimeControl.enable(); customExpirationTimeControl.enable({emitEvent: false});
} else { } else {
customExpirationTimeControl.disable(); customExpirationTimeControl.disable({emitEvent: false});
} }
customExpirationTimeControl.updateValueAndValidity();
} }
private calcExpirationTime(): number { private calcExpirationTime(): number {
@ -104,7 +96,7 @@ export class AddApiKeyDialogComponent extends DialogComponent<AddApiKeyDialogCom
} else if (expirationTimeValue === 'never') { } else if (expirationTimeValue === 'never') {
value = 0; value = 0;
} else { } else {
value = expirationTimeValue + Date.now(); value = expirationTimeValue as number + Date.now();
} }
return value; return value;
} }

71
ui-ngx/src/app/modules/home/components/api-key/components/dialog/api-key-generated-dialog.component.html

@ -16,7 +16,7 @@
--> -->
<mat-toolbar color="primary"> <mat-toolbar color="primary">
<h2>{{ 'api-key.generated-title' | translate }}</h2> <h2>{{ 'api-key.generated-api-key-title' | translate }}</h2>
<span class="flex-1"></span> <span class="flex-1"></span>
<button mat-icon-button <button mat-icon-button
(click)="close()" (click)="close()"
@ -25,14 +25,62 @@
</button> </button>
</mat-toolbar> </mat-toolbar>
<div mat-dialog-content> <div mat-dialog-content>
<span translate>api-key.generated-text</span> <div class="tb-form-panel no-padding no-border">
<div class="tb-form-panel no-padding no-border tb-tab-body"> <div class="tb-no-data-text font-normal" translate>api-key.generated-api-key-copy</div>
<tb-markdown usePlainMarkdown containerClass="tb-command-code" <div class="tb-form-panel no-padding no-border">
[data]='createMarkDownCommand(data.apiKey.value)'></tb-markdown>
<div class="tb-form-panel stroked">
<div class="tb-form-panel-title" translate>api-key.generated-command-title</div>
<tb-markdown usePlainMarkdown containerClass="tb-command-code" <tb-markdown usePlainMarkdown containerClass="tb-command-code"
[data]='createMarkDownCommand(apiKeyCommand)'></tb-markdown> [data]='createMarkDownCommand(data.apiKey.value)'></tb-markdown>
</div>
<div class="tb-form-panel no-padding no-border tb-tab-body">
<div class="tb-no-data-text font-normal" translate>api-key.generated-api-key-command</div>
<mat-tab-group [selectedIndex]="selectedTab">
<mat-tab>
<ng-template mat-tab-label>
<mat-icon class="tabs-icon" svgIcon="windows"></mat-icon>
Windows
</ng-template>
<ng-template matTabContent>
<div class="tb-form-panel no-padding no-border tb-tab-body">
<div class="tb-form-panel stroked">
<div class="tb-form-panel-title" translate>device.connectivity.install-necessary-client-tools</div>
<div class="tb-install-instruction-text" translate>device.connectivity.install-curl-windows</div>
</div>
<ng-container *ngTemplateOutlet="executeCommand"></ng-container>
</div>
</ng-template>
</mat-tab>
<mat-tab>
<ng-template mat-tab-label>
<mat-icon class="tabs-icon" svgIcon="macos"></mat-icon>
MacOS
</ng-template>
<ng-template matTabContent>
<div class="tb-form-panel no-padding no-border tb-tab-body">
<div class="tb-form-panel stroked">
<div class="tb-form-panel-title" translate>device.connectivity.install-necessary-client-tools</div>
<div class="tb-install-instruction-text" translate>device.connectivity.install-curl-macos</div>
</div>
<ng-container *ngTemplateOutlet="executeCommand"></ng-container>
</div>
</ng-template>
</mat-tab>
<mat-tab>
<ng-template mat-tab-label>
<mat-icon class="tabs-icon" svgIcon="linux"></mat-icon>
Linux
</ng-template>
<ng-template matTabContent>
<div class="tb-form-panel no-padding no-border tb-tab-body">
<div class="tb-form-panel stroked">
<div class="tb-form-panel-title" translate>device.connectivity.install-necessary-client-tools</div>
<tb-markdown usePlainMarkdown containerClass="tb-command-code"
[data]='createMarkDownCommand("sudo apt-get install curl")'></tb-markdown>
</div>
<ng-container *ngTemplateOutlet="executeCommand"></ng-container>
</div>
</ng-template>
</mat-tab>
</mat-tab-group>
</div> </div>
</div> </div>
</div> </div>
@ -44,3 +92,10 @@
{{ 'action.close' | translate }} {{ 'action.close' | translate }}
</button> </button>
</div> </div>
<ng-template #executeCommand>
<div class="tb-form-panel stroked">
<div class="tb-form-panel-title" translate>device.connectivity.execute-following-command</div>
<tb-markdown usePlainMarkdown containerClass="tb-command-code" [data]='createMarkDownCommand(apiKeyCommand)'></tb-markdown>
</div>
</ng-template>

12
ui-ngx/src/app/modules/home/components/api-key/components/dialog/api-key-generated-dialog.component.scss

@ -14,10 +14,16 @@
* limitations under the License. * limitations under the License.
*/ */
:host{ :host{
display: block; display: grid;
width: 600px; width: 500px;
height: 100%;
max-width: 100%; max-width: 100%;
color: rgba(0, 0, 0, 0.76); max-height: 100vh;
grid-template-rows: min-content minmax(auto, 1fr) min-content;
.tb-install-instruction-text {
min-height: 42px;
}
} }
:host ::ng-deep { :host ::ng-deep {

22
ui-ngx/src/app/modules/home/components/api-key/components/dialog/api-key-generated-dialog.component.ts

@ -21,6 +21,7 @@ import { AppState } from '@core/core.state';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { userInfoCommand, ApiKey } from '@shared/models/api-key.models'; import { userInfoCommand, ApiKey } from '@shared/models/api-key.models';
import { getOS } from '@core/utils';
export interface ApiKeyGeneratedDialogData { export interface ApiKeyGeneratedDialogData {
apiKey: ApiKey; apiKey: ApiKey;
@ -34,12 +35,14 @@ export interface ApiKeyGeneratedDialogData {
export class ApiKeyGeneratedDialogComponent extends DialogComponent<ApiKeyGeneratedDialogComponent, void> { export class ApiKeyGeneratedDialogComponent extends DialogComponent<ApiKeyGeneratedDialogComponent, void> {
apiKeyCommand = userInfoCommand(this.data.apiKey.value); apiKeyCommand = userInfoCommand(this.data.apiKey.value);
selectedTab: number;
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
protected router: Router, protected router: Router,
protected dialogRef: MatDialogRef<ApiKeyGeneratedDialogComponent, void>, protected dialogRef: MatDialogRef<ApiKeyGeneratedDialogComponent, void>,
@Inject(MAT_DIALOG_DATA) public data: ApiKeyGeneratedDialogData) { @Inject(MAT_DIALOG_DATA) public data: ApiKeyGeneratedDialogData) {
super(store, router, dialogRef); super(store, router, dialogRef);
this.selectTabIndexForUserOS();
} }
close(): void { close(): void {
@ -52,4 +55,23 @@ export class ApiKeyGeneratedDialogComponent extends DialogComponent<ApiKeyGenera
'{:copy-code}\n' + '{:copy-code}\n' +
'```'; '```';
} }
private selectTabIndexForUserOS() {
const currentOS = getOS();
switch (currentOS) {
case 'linux':
case 'android':
this.selectedTab = 2;
break;
case 'macos':
case 'ios':
this.selectedTab = 1;
break;
case 'windows':
this.selectedTab = 0;
break;
default:
this.selectedTab = 2;
}
}
} }

38
ui-ngx/src/app/modules/home/components/api-key/components/dialog/api-keys-table-dialog.component.html

@ -15,21 +15,25 @@
limitations under the License. limitations under the License.
--> -->
<mat-toolbar color="primary"> <div class="api-keys-dialog-container flex flex-col xs:h-full">
<h2>{{ 'api-key.manage-api-keys' | translate }}</h2> <mat-toolbar color="primary">
<span class="flex-1"></span> <h2>{{ 'api-key.manage-api-keys' | translate }}</h2>
<div tb-help="apiKeys"></div> <span class="flex-1"></span>
<button mat-icon-button <div tb-help="apiKeys"></div>
(click)="close()" <button mat-icon-button
type="button"> (click)="close()"
<mat-icon class="material-icons">close</mat-icon> type="button">
</button> <mat-icon class="material-icons">close</mat-icon>
</mat-toolbar> </button>
<tb-api-keys-table [active]="true" [userId]="data.userId"/> </mat-toolbar>
<div mat-dialog-actions class="justify-end"> <div mat-dialog-content class="tb-form-panel stroked api-keys-dialog-content xs:flex-1">
<button mat-raised-button color="primary" <tb-api-keys-table [active]="true" [userId]="data.userId"/>
type="button" </div>
(click)="close()"> <div mat-dialog-actions class="justify-end">
{{ 'action.close' | translate }} <button mat-raised-button color="primary"
</button> type="button"
(click)="close()">
{{ 'action.close' | translate }}
</button>
</div>
</div> </div>

25
ui-ngx/src/app/modules/home/components/api-key/components/dialog/api-keys-table-dialog.component.scss

@ -14,23 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
:host ::ng-deep { :host {
tb-api-keys-table { .api-keys-dialog-container {
tb-entities-table { width: 1080px;
.tb-absolute-fill { max-width: 100%;
position: relative;
} .api-keys-dialog-content {
.table-container { height: 65vh;
width: 1000px; border-radius: 0;
min-height: 625px;
max-height: 625px;
}
.no-data-found {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
} }
} }
} }

3
ui-ngx/src/app/modules/home/components/home-components.module.ts

@ -512,9 +512,6 @@ import {
ResourcesLibraryComponent, ResourcesLibraryComponent,
ApiKeysTableComponent, ApiKeysTableComponent,
ApiKeysTableDialogComponent, ApiKeysTableDialogComponent,
AddApiKeyDialogComponent,
EditApiKeyDescriptionPanelComponent,
ApiKeyGeneratedDialogComponent,
], ],
providers: [ providers: [
WidgetComponentService, WidgetComponentService,

2
ui-ngx/src/app/modules/home/pages/user/user-tabs.component.html

@ -40,7 +40,7 @@
label="{{ 'audit-log.audit-logs' | translate }}" #auditLogsTab="matTab"> label="{{ 'audit-log.audit-logs' | translate }}" #auditLogsTab="matTab">
<tb-audit-log-table [active]="auditLogsTab.isActive" [auditLogMode]="auditLogModes.USER" [userId]="entity.id" detailsMode="true"></tb-audit-log-table> <tb-audit-log-table [active]="auditLogsTab.isActive" [auditLogMode]="auditLogModes.USER" [userId]="entity.id" detailsMode="true"></tb-audit-log-table>
</mat-tab> </mat-tab>
<mat-tab *ngIf="entity && authUser.authority === authorities.TENANT_ADMIN" <mat-tab *ngIf="entity"
label="{{ 'api-key.api-keys' | translate }}" #apiKeysTab="matTab"> label="{{ 'api-key.api-keys' | translate }}" #apiKeysTab="matTab">
<tb-api-keys-table [active]="apiKeysTab.isActive" [userId]="entity.id"></tb-api-keys-table> <tb-api-keys-table [active]="apiKeysTab.isActive" [userId]="entity.id"></tb-api-keys-table>
</mat-tab> </mat-tab>

1
ui-ngx/src/app/shared/models/id/public-api.ts

@ -45,3 +45,4 @@ export * from './widgets-bundle-id';
export * from './edge-id'; export * from './edge-id';
export * from './asset-id'; export * from './asset-id';
export * from './ai-model-id'; export * from './ai-model-id';
export * from './api-key-id';

6
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -998,9 +998,9 @@
"generate": "Generate", "generate": "Generate",
"generate-title": "Generate API key", "generate-title": "Generate API key",
"generate-text": "Note: The API key's permissions will inherit the rights of the user account that generates it.", "generate-text": "Note: The API key's permissions will inherit the rights of the user account that generates it.",
"generated-title": "API key successfully generated", "generated-api-key-title": "API key generated. Let’s check connectivity!",
"generated-text": "Make sure to copy and save your API key now as you will not be able to see it again.", "generated-api-key-copy": "Make sure to copy and save your API key now as you will not be able to see it again.",
"generated-command-title": "Execute following command to display information about current user:", "generated-api-key-command": "Use the following instructions to check connectivity. As a result, you should receive the current user information:",
"list": "{ count, plural, =1 {One API key} other {List of # API keys} }", "list": "{ count, plural, =1 {One API key} other {List of # API keys} }",
"manage": "Manage", "manage": "Manage",
"manage-api-keys": "Manage API keys", "manage-api-keys": "Manage API keys",

Loading…
Cancel
Save