Edge instructions show after add - UI
This commit is contained in:
parent
8412b61812
commit
c3f4f8d3a1
@ -114,7 +114,7 @@ export class EdgeService {
|
||||
return this.http.post<BulkImportResult>('/api/edge/bulk_import', entitiesData, defaultHttpOptionsFromConfig(config));
|
||||
}
|
||||
|
||||
public getEdgeDockerInstallInstructions(edgeId: string, config?: RequestConfig): Observable<EdgeInstallInstructions> {
|
||||
return this.http.get<EdgeInstallInstructions>(`/api/edge/instructions/${edgeId}`, defaultHttpOptionsFromConfig(config));
|
||||
public getEdgeDockerInstallInstructions(edgeId: string, method: string, config?: RequestConfig): Observable<EdgeInstallInstructions> {
|
||||
return this.http.get<EdgeInstallInstructions>(`/api/edge/instructions/${edgeId}/${method}`, defaultHttpOptionsFromConfig(config));
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,29 +15,74 @@
|
||||
limitations under the License.
|
||||
|
||||
-->
|
||||
<div style="min-width: 800px;">
|
||||
<mat-toolbar color="primary">
|
||||
<h2><mat-icon>info_outline</mat-icon>
|
||||
{{ 'edge.install-connect-instructions' | translate }}</h2>
|
||||
<mat-toolbar color="primary">
|
||||
<h2 translate>{{ dialogTitle }}</h2>
|
||||
<span fxFlex></span>
|
||||
<button mat-icon-button
|
||||
(click)="cancel()"
|
||||
(click)="close()"
|
||||
type="button">
|
||||
<mat-icon class="material-icons">close</mat-icon>
|
||||
</button>
|
||||
</mat-toolbar>
|
||||
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
|
||||
</mat-progress-bar>
|
||||
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
|
||||
<div mat-dialog-content>
|
||||
<tb-markdown [data]="instructions" lineNumbers fallbackToPlainMarkdown></tb-markdown>
|
||||
</mat-toolbar>
|
||||
<div mat-dialog-content>
|
||||
<section *ngIf="loadedInstructions; else loadingInstructions" class="tb-form-panel no-padding no-border">
|
||||
<div class="tb-form-panel no-padding no-border">
|
||||
<mat-tab-group [(selectedIndex)]="tabIndex" (selectedTabChange)="selectedTabChange(tabIndex)">
|
||||
<mat-tab>
|
||||
<ng-template mat-tab-label>
|
||||
<mat-icon class="tabs-icon" svgIcon="linux"></mat-icon>
|
||||
Ubuntu
|
||||
</ng-template>
|
||||
<ng-template matTabContent>
|
||||
<div class="tb-form-panel no-padding no-border tb-tab-body">
|
||||
<div class="tb-form-panel stroked">
|
||||
<tb-markdown lineNumbers fallbackToPlainMarkdown [data]='contentData.ubuntu'></tb-markdown>
|
||||
</div>
|
||||
<div mat-dialog-actions fxLayout="row" fxLayoutAlign="end center">
|
||||
<button mat-button color="primary"
|
||||
type="button"
|
||||
[disabled]="(isLoading$ | async)"
|
||||
(click)="cancel()" cdkFocusInitial>
|
||||
{{ 'action.close' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</ng-template>
|
||||
</mat-tab>
|
||||
<mat-tab>
|
||||
<ng-template mat-tab-label>
|
||||
<mat-icon class="tabs-icon" svgIcon="mdi:centos"></mat-icon>
|
||||
CentOS
|
||||
</ng-template>
|
||||
<ng-template matTabContent>
|
||||
<div class="tb-form-panel no-padding no-border tb-tab-body">
|
||||
<div class="tb-form-panel stroked">
|
||||
<tb-markdown lineNumbers fallbackToPlainMarkdown [data]='contentData.centos'></tb-markdown>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</mat-tab>
|
||||
<mat-tab>
|
||||
<ng-template mat-tab-label>
|
||||
<mat-icon class="tabs-icon" svgIcon="docker"></mat-icon>
|
||||
Docker
|
||||
</ng-template>
|
||||
<ng-template matTabContent>
|
||||
<div class="tb-form-panel no-padding no-border tb-tab-body">
|
||||
<div class="tb-form-panel stroked">
|
||||
<tb-markdown lineNumbers fallbackToPlainMarkdown [data]='contentData.docker'></tb-markdown>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div mat-dialog-actions class="tb-dialog-actions">
|
||||
<mat-slide-toggle fxShow="{{ showDontShowAgain }}" [(ngModel)]="notShowAgain">{{ 'action.dont-show-again' | translate}}</mat-slide-toggle>
|
||||
<span fxFlex></span>
|
||||
<button mat-button
|
||||
[disabled]="(isLoading$ | async)"
|
||||
(click)="close()">{{ 'action.close' | translate }}</button>
|
||||
</div>
|
||||
<ng-template #loadingInstructions>
|
||||
<div class="tb-loader">
|
||||
<mat-spinner color="accent" diameter="65" strokeWidth="4"></mat-spinner>
|
||||
<span class="mat-subtitle-1 label">
|
||||
{{ 'edge.loading-edge-instructions' | translate }}
|
||||
</span>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Copyright © 2016-2023 The Thingsboard Authors
|
||||
*
|
||||
* 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
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@import "../../../../../scss/constants";
|
||||
|
||||
:host {
|
||||
height: 100%;
|
||||
max-height: 100vh;
|
||||
display: grid;
|
||||
grid-template-rows: min-content minmax(auto, 1fr) min-content;
|
||||
|
||||
.tb-loader {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
height: 300px;
|
||||
max-height: 100%;
|
||||
|
||||
.label {
|
||||
margin-bottom: 0;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.tb-font-14 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.tb-flex-1 {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@media #{$mat-sm} {
|
||||
width: 470px;
|
||||
}
|
||||
|
||||
@media #{$mat-gt-sm} {
|
||||
width: 720px;
|
||||
}
|
||||
}
|
||||
|
||||
:host-context(.mat-mdc-dialog-container) {
|
||||
.tb-dialog-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
.mat-mdc-dialog-content {
|
||||
max-height: 80vh;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
:host ::ng-deep {
|
||||
.tb-markdown-view {
|
||||
.tb-command-code {
|
||||
.code-wrapper {
|
||||
padding: 0;
|
||||
pre[class*=language-] {
|
||||
margin: 0;
|
||||
background: #F3F6FA;
|
||||
border-color: #305680;
|
||||
padding-right: 38px;
|
||||
overflow: scroll;
|
||||
padding-bottom: 4px;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
button.clipboard-btn {
|
||||
right: -2px;
|
||||
p {
|
||||
color: #305680;
|
||||
}
|
||||
p, div {
|
||||
background-color: #F3F6FA;
|
||||
}
|
||||
div {
|
||||
img {
|
||||
display: none;
|
||||
}
|
||||
&:after {
|
||||
content: "";
|
||||
position: initial;
|
||||
display: block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: #305680;
|
||||
mask-image: url(/assets/copy-code-icon.svg);
|
||||
mask-repeat: no-repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.mdc-button__label > span {
|
||||
.mat-icon {
|
||||
vertical-align: text-bottom;
|
||||
box-sizing: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.tabs-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.tb-form-panel.tb-tab-body {
|
||||
padding: 16px 0 0;
|
||||
}
|
||||
}
|
||||
@ -14,33 +14,83 @@
|
||||
/// limitations under the License.
|
||||
///
|
||||
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog";
|
||||
import { DialogComponent } from "@shared/components/dialog.component";
|
||||
import { Store } from "@ngrx/store";
|
||||
import { AppState } from "@core/core.state";
|
||||
import { Router } from "@angular/router";
|
||||
import { Component, Inject, OnDestroy, OnInit } from '@angular/core';
|
||||
import { DialogComponent } from '@shared/components/dialog.component';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { AppState } from '@core/core.state';
|
||||
import { Router } from '@angular/router';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { ActionPreferencesPutUserSettings } from '@core/auth/auth.actions';
|
||||
import { EdgeInfo, EdgeInstructionsMethod } from '@shared/models/edge.models';
|
||||
import { EdgeService } from '@core/http/edge.service';
|
||||
|
||||
export interface EdgeInstructionsData {
|
||||
instructions: string;
|
||||
export interface EdgeInstructionsDialogData {
|
||||
edge: EdgeInfo;
|
||||
afterAdd: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'tb-edge-instructions',
|
||||
templateUrl: './edge-instructions-dialog.component.html'
|
||||
selector: 'tb-edge-installation-dialog',
|
||||
templateUrl: './edge-instructions-dialog.component.html',
|
||||
styleUrls: ['./edge-instructions-dialog.component.scss']
|
||||
})
|
||||
export class EdgeInstructionsDialogComponent extends DialogComponent<EdgeInstructionsDialogComponent, EdgeInstructionsData> {
|
||||
export class EdgeInstructionsDialogComponent extends DialogComponent<EdgeInstructionsDialogComponent> implements OnInit, OnDestroy {
|
||||
|
||||
instructions: string = this.data.instructions;
|
||||
dialogTitle: string;
|
||||
showDontShowAgain: boolean;
|
||||
|
||||
loadedInstructions = false;
|
||||
notShowAgain = false;
|
||||
tabIndex = 0;
|
||||
instructionsMethod = EdgeInstructionsMethod;
|
||||
contentData: any = {};
|
||||
|
||||
constructor(protected store: Store<AppState>,
|
||||
protected router: Router,
|
||||
public dialogRef: MatDialogRef<EdgeInstructionsDialogComponent, EdgeInstructionsData>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: EdgeInstructionsData) {
|
||||
@Inject(MAT_DIALOG_DATA) private data: EdgeInstructionsDialogData,
|
||||
public dialogRef: MatDialogRef<EdgeInstructionsDialogComponent>,
|
||||
private edgeService: EdgeService) {
|
||||
super(store, router, dialogRef);
|
||||
|
||||
if (this.data.afterAdd) {
|
||||
this.dialogTitle = 'edge.install-connect-instructions-edge-created';
|
||||
this.showDontShowAgain = true;
|
||||
} else {
|
||||
this.dialogTitle = 'edge.install-connect-instructions';
|
||||
this.showDontShowAgain = false;
|
||||
}
|
||||
}
|
||||
|
||||
cancel(): void {
|
||||
ngOnInit() {
|
||||
this.getInstructions(this.instructionsMethod[this.tabIndex]);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
super.ngOnDestroy();
|
||||
}
|
||||
|
||||
close(): void {
|
||||
if (this.notShowAgain && this.showDontShowAgain) {
|
||||
this.store.dispatch(new ActionPreferencesPutUserSettings({notDisplayInstructionsAfterAddEdge: true}));
|
||||
this.dialogRef.close(null);
|
||||
} else {
|
||||
this.dialogRef.close(null);
|
||||
}
|
||||
}
|
||||
|
||||
selectedTabChange(index: number) {
|
||||
this.getInstructions(this.instructionsMethod[index]);
|
||||
}
|
||||
|
||||
getInstructions(method: string) {
|
||||
if (!this.contentData[method]) {
|
||||
this.loadedInstructions = false;
|
||||
this.edgeService.getEdgeDockerInstallInstructions(this.data.edge.id.id, method).subscribe(
|
||||
res => {
|
||||
this.contentData[method] = res.installInstructions;
|
||||
this.loadedInstructions = true;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,10 +29,10 @@ import {
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models';
|
||||
import { EntityAction } from '@home/models/entity/entity-component.models';
|
||||
import { AddEntityDialogData, EntityAction } from '@home/models/entity/entity-component.models';
|
||||
import { forkJoin, Observable, of } from 'rxjs';
|
||||
import { select, Store } from '@ngrx/store';
|
||||
import { selectAuthUser } from '@core/auth/auth.selectors';
|
||||
import { selectAuthUser, selectUserSettingsProperty } from '@core/auth/auth.selectors';
|
||||
import { map, mergeMap, take, tap } from 'rxjs/operators';
|
||||
import { AppState } from '@core/core.state';
|
||||
import { Authority } from '@app/shared/models/authority.enum';
|
||||
@ -51,7 +51,7 @@ import {
|
||||
AddEntitiesToCustomerDialogData
|
||||
} from '../../dialogs/add-entities-to-customer-dialog.component';
|
||||
import { HomeDialogsService } from '@home/dialogs/home-dialogs.service';
|
||||
import { Edge, EdgeInfo, EdgeInstallInstructions } from '@shared/models/edge.models';
|
||||
import { Edge, EdgeInfo } from '@shared/models/edge.models';
|
||||
import { EdgeService } from '@core/http/edge.service';
|
||||
import { EdgeComponent } from '@home/pages/edge/edge.component';
|
||||
import { EdgeTableHeaderComponent } from '@home/pages/edge/edge-table-header.component';
|
||||
@ -59,9 +59,10 @@ import { EdgeId } from '@shared/models/id/edge-id';
|
||||
import { EdgeTabsComponent } from '@home/pages/edge/edge-tabs.component';
|
||||
import { ActionNotificationShow } from '@core/notification/notification.actions';
|
||||
import {
|
||||
EdgeInstructionsData,
|
||||
EdgeInstructionsDialogComponent
|
||||
} from "@home/pages/edge/edge-instructions-dialog.component";
|
||||
EdgeInstructionsDialogComponent,
|
||||
EdgeInstructionsDialogData
|
||||
} from '@home/pages/edge/edge-instructions-dialog.component';
|
||||
import { AddEntityDialogComponent } from '@home/components/entity/add-entity-dialog.component';
|
||||
|
||||
@Injectable()
|
||||
export class EdgesTableConfigResolver implements Resolve<EntityTableConfig<EdgeInfo>> {
|
||||
@ -140,6 +141,7 @@ export class EdgesTableConfigResolver implements Resolve<EntityTableConfig<EdgeI
|
||||
this.config.addEnabled = this.config.componentsData.edgeScope !== 'customer_user';
|
||||
this.config.entitiesDeleteEnabled = this.config.componentsData.edgeScope === 'tenant';
|
||||
this.config.deleteEnabled = () => this.config.componentsData.edgeScope === 'tenant';
|
||||
this.config.addEntity = () => { this.addEdge(); return of(null); };
|
||||
return this.config;
|
||||
})
|
||||
);
|
||||
@ -530,21 +532,50 @@ export class EdgesTableConfigResolver implements Resolve<EntityTableConfig<EdgeI
|
||||
);
|
||||
}
|
||||
|
||||
openInstructions($event, edge) {
|
||||
if ($event) {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
this.edgeService.getEdgeDockerInstallInstructions(edge.id.id).subscribe(
|
||||
(edgeInstructionsTemplate: EdgeInstallInstructions) => {
|
||||
this.dialog.open<EdgeInstructionsDialogComponent, EdgeInstructionsData>(EdgeInstructionsDialogComponent, {
|
||||
disableClose: false,
|
||||
addEdge() {
|
||||
this.dialog.open<AddEntityDialogComponent, AddEntityDialogData<EdgeInfo>,
|
||||
EdgeInfo>(AddEntityDialogComponent, {
|
||||
disableClose: true,
|
||||
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||
data: {
|
||||
instructions: edgeInstructionsTemplate.dockerInstallInstructions
|
||||
entitiesTableConfig: this.config
|
||||
}
|
||||
}).afterClosed().subscribe(
|
||||
(entity) => {
|
||||
if (entity) {
|
||||
this.store.pipe(select(selectUserSettingsProperty('notDisplayInstructionsAfterAddEdge'))).pipe(
|
||||
take(1)
|
||||
).subscribe((settings: boolean) => {
|
||||
if (!settings) {
|
||||
this.openInstructions(null, entity, true);
|
||||
} else {
|
||||
this.config.updateData();
|
||||
this.config.entityAdded(entity);
|
||||
}
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
openInstructions($event, edge: EdgeInfo, afterAdd = false) {
|
||||
if ($event) {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
this.dialog.open<EdgeInstructionsDialogComponent, EdgeInstructionsDialogData>
|
||||
(EdgeInstructionsDialogComponent, {
|
||||
disableClose: true,
|
||||
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||
data: {
|
||||
edge,
|
||||
afterAdd
|
||||
}
|
||||
}).afterClosed().subscribe(() => {
|
||||
if (afterAdd) {
|
||||
this.config.updateData();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
onEdgeAction(action: EntityAction<EdgeInfo>, config: EntityTableConfig<EdgeInfo>): boolean {
|
||||
|
||||
@ -179,5 +179,11 @@ export interface EdgeEvent extends BaseData<EventId> {
|
||||
}
|
||||
|
||||
export interface EdgeInstallInstructions {
|
||||
dockerInstallInstructions: string;
|
||||
installInstructions: string;
|
||||
}
|
||||
|
||||
export enum EdgeInstructionsMethod {
|
||||
ubuntu,
|
||||
centos,
|
||||
docker
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
export interface UserSettings {
|
||||
openedMenuSections?: string[];
|
||||
notDisplayConnectivityAfterAddDevice?: boolean;
|
||||
notDisplayInstructionsAfterAddEdge?: boolean;
|
||||
}
|
||||
|
||||
export const initialUserSettings: UserSettings = {
|
||||
|
||||
@ -1962,6 +1962,8 @@
|
||||
"make-private-edge-text": "After the confirmation the edge and all its data will be made private and won't be accessible by others.",
|
||||
"import": "Import edge",
|
||||
"install-connect-instructions": "Install & Connect Instructions",
|
||||
"install-connect-instructions-edge-created": "Edge created! Check Install & Connect Instructions",
|
||||
"loading-edge-instructions": "Loading edge instructions...",
|
||||
"label": "Label",
|
||||
"load-entity-error": "Failed to load data. Entity has been deleted.",
|
||||
"assign-new-edge": "Assign new edge",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user