edge upgrade instructions ui implementation

This commit is contained in:
deaflynx 2023-11-22 16:59:21 +02:00
parent 855b9c054b
commit 7fad29e059
8 changed files with 95 additions and 23 deletions

View File

@ -36,6 +36,7 @@ enum EdgeVersion {
V_3_4_0 = 2; V_3_4_0 = 2;
V_3_6_0 = 3; V_3_6_0 = 3;
V_3_6_1 = 4; V_3_6_1 = 4;
V_3_6_2 = 5;
} }
/** /**

View File

@ -21,7 +21,7 @@ import { HttpClient } from '@angular/common/http';
import { PageLink, TimePageLink } from '@shared/models/page/page-link'; import { PageLink, TimePageLink } from '@shared/models/page/page-link';
import { PageData } from '@shared/models/page/page-data'; import { PageData } from '@shared/models/page/page-data';
import { EntitySubtype } from '@app/shared/models/entity-type.models'; import { EntitySubtype } from '@app/shared/models/entity-type.models';
import { Edge, EdgeEvent, EdgeInfo, EdgeInstallInstructions, EdgeSearchQuery } from '@shared/models/edge.models'; import { Edge, EdgeEvent, EdgeInfo, EdgeInstructions, EdgeSearchQuery } from '@shared/models/edge.models';
import { EntityId } from '@shared/models/id/entity-id'; import { EntityId } from '@shared/models/id/entity-id';
import { BulkImportRequest, BulkImportResult } from '@home/components/import-export/import-export.models'; import { BulkImportRequest, BulkImportResult } from '@home/components/import-export/import-export.models';
@ -114,7 +114,11 @@ export class EdgeService {
return this.http.post<BulkImportResult>('/api/edge/bulk_import', entitiesData, defaultHttpOptionsFromConfig(config)); return this.http.post<BulkImportResult>('/api/edge/bulk_import', entitiesData, defaultHttpOptionsFromConfig(config));
} }
public getEdgeInstallInstructions(edgeId: string, method: string = 'ubuntu', config?: RequestConfig): Observable<EdgeInstallInstructions> { public getEdgeInstallInstructions(edgeId: string, method: string = 'ubuntu', config?: RequestConfig): Observable<EdgeInstructions> {
return this.http.get<EdgeInstallInstructions>(`/api/edge/instructions/${edgeId}/${method}`, defaultHttpOptionsFromConfig(config)); return this.http.get<EdgeInstructions>(`/api/edge/instructions/install/${edgeId}/${method}`, defaultHttpOptionsFromConfig(config));
}
public getEdgeUpgradeInstructions(edgeVersion: string, method: string = 'ubuntu', config?: RequestConfig): Observable<EdgeInstructions> {
return this.http.get<EdgeInstructions>(`/api/edge/instructions/upgrade/${edgeVersion}/${method}`, defaultHttpOptionsFromConfig(config));
} }
} }

View File

@ -21,12 +21,21 @@ 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 { ActionPreferencesPutUserSettings } from '@core/auth/auth.actions'; import { ActionPreferencesPutUserSettings } from '@core/auth/auth.actions';
import { EdgeInfo, EdgeInstructionsMethod } from '@shared/models/edge.models'; import {
EdgeInfo,
EdgeInstructions,
EdgeInstructionsMethod,
edgeVersionAttributeKey
} from '@shared/models/edge.models';
import { EdgeService } from '@core/http/edge.service'; import { EdgeService } from '@core/http/edge.service';
import { AttributeService } from '@core/http/attribute.service';
import { AttributeScope } from '@shared/models/telemetry/telemetry.models';
import { mergeMap, Observable } from 'rxjs';
export interface EdgeInstructionsDialogData { export interface EdgeInstructionsDialogData {
edge: EdgeInfo; edge: EdgeInfo;
afterAdd: boolean; afterAdd: boolean;
upgradeAvailable: boolean;
} }
@Component({ @Component({
@ -49,6 +58,7 @@ export class EdgeInstructionsDialogComponent extends DialogComponent<EdgeInstruc
protected router: Router, protected router: Router,
@Inject(MAT_DIALOG_DATA) private data: EdgeInstructionsDialogData, @Inject(MAT_DIALOG_DATA) private data: EdgeInstructionsDialogData,
public dialogRef: MatDialogRef<EdgeInstructionsDialogComponent>, public dialogRef: MatDialogRef<EdgeInstructionsDialogComponent>,
private attributeService: AttributeService,
private edgeService: EdgeService) { private edgeService: EdgeService) {
super(store, router, dialogRef); super(store, router, dialogRef);
@ -85,12 +95,22 @@ export class EdgeInstructionsDialogComponent extends DialogComponent<EdgeInstruc
getInstructions(method: string) { getInstructions(method: string) {
if (!this.contentData[method]) { if (!this.contentData[method]) {
this.loadedInstructions = false; this.loadedInstructions = false;
this.edgeService.getEdgeInstallInstructions(this.data.edge.id.id, method).subscribe( let edgeInstructions$: Observable<EdgeInstructions>;
res => { if (this.data.upgradeAvailable) {
this.contentData[method] = res.installInstructions; edgeInstructions$ = this.attributeService.getEntityAttributes(this.data.edge.id, AttributeScope.SERVER_SCOPE, [edgeVersionAttributeKey])
this.loadedInstructions = true; .pipe(mergeMap(attributes => {
} if (attributes.length) {
); const edgeVersion = attributes[0].value;
return this.edgeService.getEdgeUpgradeInstructions(edgeVersion, method);
}
}));
} else {
edgeInstructions$ = this.edgeService.getEdgeInstallInstructions(this.data.edge.id.id, method);
}
edgeInstructions$.subscribe(res => {
this.contentData[method] = res.instructions;
this.loadedInstructions = true;
});
} }
} }
} }

View File

@ -114,13 +114,26 @@
</button> </button>
</div> </div>
<div fxLayout="row" fxLayout.xs="column"> <div fxLayout="row" fxLayout.xs="column">
<button mat-raised-button color="primary" <div [ngSwitch]="upgradeAvailable">
[disabled]="(isLoading$ | async)" <ng-container *ngSwitchCase="false">
(click)="onEntityAction($event, 'openInstructions')" <button mat-raised-button color="primary"
[fxShow]="!isEdit && edgeScope !== 'customer_user'"> [disabled]="(isLoading$ | async)"
<mat-icon>info_outline</mat-icon> (click)="onEntityAction($event, 'openInstallInstructions')"
<span>{{ 'edge.install-connect-instructions' | translate }}</span> [fxShow]="!isEdit && edgeScope !== 'customer_user'">
</button> <mat-icon>info_outline</mat-icon>
<span>{{ 'edge.install-connect-instructions' | translate }}</span>
</button>
</ng-container>
<ng-container *ngSwitchCase="true">
<button mat-raised-button color="primary"
[disabled]="(isLoading$ | async)"
(click)="onEntityAction($event, 'openUpgradeInstructions')"
[fxShow]="!isEdit && edgeScope !== 'customer_user'">
<mat-icon>info_outline</mat-icon>
<span>{{ 'edge.upgrade-instructions' | translate }}</span>
</button>
</ng-container>
</div>
</div> </div>
</div> </div>
<div class="mat-padding" fxLayout="column"> <div class="mat-padding" fxLayout="column">

View File

@ -20,12 +20,15 @@ import { AppState } from '@core/core.state';
import { EntityComponent } from '@home/components/entity/entity.component'; import { EntityComponent } from '@home/components/entity/entity.component';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { EntityType } from '@shared/models/entity-type.models'; import { EntityType } from '@shared/models/entity-type.models';
import { EdgeInfo } from '@shared/models/edge.models'; import { EdgeInfo, edgeVersionAttributeKey } from '@shared/models/edge.models';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { NULL_UUID } from '@shared/models/id/has-uuid'; import { NULL_UUID } from '@shared/models/id/has-uuid';
import { ActionNotificationShow } from '@core/notification/notification.actions'; import { ActionNotificationShow } from '@core/notification/notification.actions';
import { generateSecret, guid } from '@core/utils'; import { generateSecret, guid } from '@core/utils';
import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; import { EntityTableConfig } from '@home/models/entity/entities-table-config.models';
import { environment as env } from '@env/environment';
import { AttributeService } from '@core/http/attribute.service';
import { AttributeScope } from '@shared/models/telemetry/telemetry.models';
@Component({ @Component({
selector: 'tb-edge', selector: 'tb-edge',
@ -37,9 +40,11 @@ export class EdgeComponent extends EntityComponent<EdgeInfo> {
entityType = EntityType; entityType = EntityType;
edgeScope: 'tenant' | 'customer' | 'customer_user'; edgeScope: 'tenant' | 'customer' | 'customer_user';
upgradeAvailable: boolean = false;
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
protected translate: TranslateService, protected translate: TranslateService,
private attributeService: AttributeService,
@Inject('entity') protected entityValue: EdgeInfo, @Inject('entity') protected entityValue: EdgeInfo,
@Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<EdgeInfo>, @Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<EdgeInfo>,
public fb: UntypedFormBuilder, public fb: UntypedFormBuilder,
@ -95,6 +100,7 @@ export class EdgeComponent extends EntityComponent<EdgeInfo> {
} }
}); });
this.generateRoutingKeyAndSecret(entity, this.entityForm); this.generateRoutingKeyAndSecret(entity, this.entityForm);
this.checkEdgeVersion();
} }
updateFormState() { updateFormState() {
@ -133,4 +139,25 @@ export class EdgeComponent extends EntityComponent<EdgeInfo> {
form.get('secret').patchValue(generateSecret(20), {emitEvent: false}); form.get('secret').patchValue(generateSecret(20), {emitEvent: false});
} }
} }
checkEdgeVersion() {
this.attributeService.getEntityAttributes(this.entity.id, AttributeScope.SERVER_SCOPE, [edgeVersionAttributeKey])
.subscribe(attributes => {
if (attributes?.length) {
const edgeVersion = attributes[0].value;
const tbVersion = 'V_' + env.tbVersion.replaceAll('.', '_');
this.upgradeAvailable = this.versionUpgradeSupported(edgeVersion) && (edgeVersion !== tbVersion);
} else {
this.upgradeAvailable = false;
}
}
);
}
private versionUpgradeSupported(edgeVersion: string): boolean {
const edgeVersionArray = edgeVersion.split('_');
const major = parseInt(edgeVersionArray[1]);
const minor = parseInt(edgeVersionArray[2]);
return major >= 3 && minor >= 6;
}
} }

View File

@ -558,7 +558,7 @@ export class EdgesTableConfigResolver implements Resolve<EntityTableConfig<EdgeI
); );
} }
openInstructions($event, edge: EdgeInfo, afterAdd = false) { openInstructions($event, edge: EdgeInfo, afterAdd = false, upgradeAvailable = false) {
if ($event) { if ($event) {
$event.stopPropagation(); $event.stopPropagation();
} }
@ -568,7 +568,8 @@ export class EdgesTableConfigResolver implements Resolve<EntityTableConfig<EdgeI
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: { data: {
edge, edge,
afterAdd afterAdd,
upgradeAvailable
} }
}).afterClosed().subscribe(() => { }).afterClosed().subscribe(() => {
if (afterAdd) { if (afterAdd) {
@ -610,9 +611,12 @@ export class EdgesTableConfigResolver implements Resolve<EntityTableConfig<EdgeI
case 'syncEdge': case 'syncEdge':
this.syncEdge(action.event, action.entity); this.syncEdge(action.event, action.entity);
return true; return true;
case 'openInstructions': case 'openInstallInstructions':
this.openInstructions(action.event, action.entity); this.openInstructions(action.event, action.entity);
return true; return true;
case 'openUpgradeInstructions':
this.openInstructions(action.event, action.entity,false, true);
return true;
} }
} }

View File

@ -178,8 +178,8 @@ export interface EdgeEvent extends BaseData<EventId> {
body: string; body: string;
} }
export interface EdgeInstallInstructions { export interface EdgeInstructions {
installInstructions: string; instructions: string;
} }
export enum EdgeInstructionsMethod { export enum EdgeInstructionsMethod {
@ -187,3 +187,5 @@ export enum EdgeInstructionsMethod {
centos, centos,
docker docker
} }
export const edgeVersionAttributeKey = 'edgeVersion';

View File

@ -2017,6 +2017,7 @@
"sync-process-started-successfully": "Sync process started successfully!", "sync-process-started-successfully": "Sync process started successfully!",
"missing-related-rule-chains-title": "Edge has missing related rule chain(s)", "missing-related-rule-chains-title": "Edge has missing related rule chain(s)",
"missing-related-rule-chains-text": "Assigned to edge rule chain(s) use rule nodes that forward message(s) to rule chain(s) that are not assigned to this edge. <br><br> List of missing rule chain(s): <br> {{missingRuleChains}}", "missing-related-rule-chains-text": "Assigned to edge rule chain(s) use rule nodes that forward message(s) to rule chain(s) that are not assigned to this edge. <br><br> List of missing rule chain(s): <br> {{missingRuleChains}}",
"upgrade-instructions": "Upgrade Instructions",
"widget-datasource-error": "This widget supports only EDGE entity datasource" "widget-datasource-error": "This widget supports only EDGE entity datasource"
}, },
"edge-event": { "edge-event": {