Browse Source

Merge pull request #9245 from AndriiLandiak/feature/improve-edge-instruction

Edge instructions for ubuntu, centos
pull/9263/head
Andrew Shvayka 3 years ago
committed by GitHub
parent
commit
68b6be536d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 230
      application/src/main/data/json/edge/install_instructions/centos/instructions.md
  2. 14
      application/src/main/data/json/edge/install_instructions/docker/instructions.md
  3. 163
      application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md
  4. 6
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  5. 50
      application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java
  6. 3
      application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallService.java
  7. 2
      application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java
  8. 4
      common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeInstallInstructions.java
  9. 4
      ui-ngx/src/app/core/http/edge.service.ts
  10. 95
      ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.html
  11. 123
      ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss
  12. 84
      ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.ts
  13. 65
      ui-ngx/src/app/modules/home/pages/edge/edges-table-config.resolver.ts
  14. 8
      ui-ngx/src/app/shared/models/edge.models.ts
  15. 1
      ui-ngx/src/app/shared/models/user-settings.models.ts
  16. 2
      ui-ngx/src/assets/locale/locale.constant-en_US.json

230
application/src/main/data/json/edge/install_instructions/centos/instructions.md

@ -0,0 +1,230 @@
Here is the list of commands, that can be used to quickly install ThingsBoard Edge on RHEL/CentOS 7/8 and connect to the cloud.
#### Prerequisites
Before continue to installation execute the following commands in order to install necessary tools:
```bash
sudo yum install -y nano wget
sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
```
#### Install Java 11 (OpenJDK)
ThingsBoard service is running on Java 11. Follow these instructions to install OpenJDK 11:
```bash
sudo yum install java-11-openjdk
{:copy-code}
```
Please don't forget to configure your operating system to use OpenJDK 11 by default.
You can configure which version is the default using the following command:
```bash
sudo update-alternatives --config java
{:copy-code}
```
You can check the installation using the following command:
```bash
java -version
{:copy-code}
```
Expected command output is:
```text
openjdk version "11.0.xx"
OpenJDK Runtime Environment (...)
OpenJDK 64-Bit Server VM (build ...)
```
#### Configure PostgreSQL
ThingsBoard Edge uses PostgreSQL database as a local storage.
Instructions listed below will help you to install PostgreSQL.
```bash
# Update your system
sudo yum update
{:copy-code}
```
**For CentOS 7:**
```bash
# Install the repository RPM (for CentOS 7):
sudo yum -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
# Install packages
sudo yum -y install epel-release yum-utils
sudo yum-config-manager --enable pgdg12
sudo yum install postgresql12-server postgresql12
# Initialize your PostgreSQL DB
sudo /usr/pgsql-12/bin/postgresql-12-setup initdb
sudo systemctl start postgresql-12
# Optional: Configure PostgreSQL to start on boot
sudo systemctl enable --now postgresql-12
{:copy-code}
```
**For CentOS 8:**
```bash
# Install the repository RPM (for CentOS 8):
sudo yum -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm
# Install packages
sudo dnf -qy module disable postgresql
sudo dnf -y install postgresql12 postgresql12-server
# Initialize your PostgreSQL DB
sudo /usr/pgsql-12/bin/postgresql-12-setup initdb
sudo systemctl start postgresql-12
# Optional: Configure PostgreSQL to start on boot
sudo systemctl enable --now postgresql-12
{:copy-code}
```
Once PostgreSQL is installed you may want to create a new user or set the password for the main user.
The instructions below will help to set the password for main PostgreSQL user:
```text
sudo su - postgres
psql
\password
\q
```
Then, press "Ctrl+D" to return to main user console.
After configuring the password, edit the pg_hba.conf to use MD5 authentication with the postgres user.
Edit pg_hba.conf file:
```bash
sudo nano /var/lib/pgsql/12/data/pg_hba.conf
{:copy-code}
```
Locate the following lines:
```text
# IPv4 local connections:
host all all 127.0.0.1/32 ident
```
Replace `ident` with `md5`:
```text
host all all 127.0.0.1/32 md5
```
Finally, you should restart the PostgreSQL service to initialize the new configuration:
```bash
sudo systemctl restart postgresql-12.service
{:copy-code}
```
Connect to the database to create ThingsBoard Edge DB:
```bash
psql -U postgres -d postgres -h 127.0.0.1 -W
{:copy-code}
```
Execute create database statement:
```bash
CREATE DATABASE tb_edge;
\q
{:copy-code}
```
#### ThingsBoard Edge service installation
Download installation package:
```bash
wget https://github.com/thingsboard/thingsboard-edge/releases/download/v${TB_EDGE_VERSION}/tb-edge-${TB_EDGE_VERSION}.rpm
{:copy-code}
```
Go to the download repository and install ThingsBoard Edge service:
```bash
sudo rpm -Uvh tb-edge-${TB_EDGE_VERSION}.rpm
{:copy-code}
```
#### Configure ThingsBoard Edge
To configure ThingsBoard Edge, you can use the following command to automatically update the configuration file with specific values:
```bash
sudo sh -c 'cat <<EOL >> /etc/tb-edge/conf/tb-edge.conf
export CLOUD_ROUTING_KEY=${CLOUD_ROUTING_KEY}
export CLOUD_ROUTING_SECRET=${CLOUD_ROUTING_SECRET}
export CLOUD_RPC_HOST=${BASE_URL}
export CLOUD_RPC_PORT=${CLOUD_RPC_PORT}
export CLOUD_RPC_SSL_ENABLED=${CLOUD_RPC_SSL_ENABLED}
EOL'
{:copy-code}
```
##### [Optional] Database Configuration
In case you changed default PostgreSQL datasource settings (**postgres**/**postgres**) please update the configuration file (**/etc/tb-edge/conf/tb-edge.conf**) with your actual values:
```bash
sudo nano /etc/tb-edge/conf/tb-edge.conf
{:copy-code}
```
Please update the following lines in your configuration file. Make sure **to replace**:
- Replace 'postgres' with your actual PostgreSQL username;
- Replace 'PUT_YOUR_POSTGRESQL_PASSWORD_HERE' with your actual PostgreSQL password.
```bash
export SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/tb_edge
export SPRING_DATASOURCE_USERNAME=postgres
export SPRING_DATASOURCE_PASSWORD=PUT_YOUR_POSTGRESQL_PASSWORD_HERE
{:copy-code}
```
##### [Optional] Update bind ports
If ThingsBoard Edge is going to be running on the same machine where ThingsBoard server (cloud) is running, you'll need to update configuration parameters to avoid port collision between ThingsBoard server and ThingsBoard Edge.
Please execute the following command to update ThingsBoard Edge configuration file (**/etc/tb-edge/conf/tb-edge.conf**):
```bash
sudo sh -c 'cat <<EOL >> /etc/tb-edge/conf/tb-edge.conf
export HTTP_BIND_PORT=18080
export MQTT_BIND_PORT=11883
export COAP_BIND_PORT=15683
export LWM2M_ENABLED=false
EOL'
{:copy-code}
```
Make sure that ports above (18080, 11883, 15683) are not used by any other application.
#### Run installation script
Once ThingsBoard Edge is installed and configured please execute the following install script:
```bash
sudo /usr/share/tb-edge/bin/install/install.sh
{:copy-code}
```
#### Restart ThingsBoard Edge service
```bash
sudo service tb-edge restart
{:copy-code}
```
#### Open ThingsBoard Edge UI
Once started, you will be able to open **ThingsBoard Edge UI** using the following link http://localhost:8080.
###### NOTE: Edge HTTP bind port update
Use next **ThingsBoard Edge UI** link **http://localhost:18080** if you updated HTTP 8080 bind port to **18080**.

14
application/src/main/data/json/edge/install_instructions/docker/instructions.md

@ -1,12 +1,10 @@
## Install ThingsBoard Edge and connect to cloud instructions
Here is the list of commands, that can be used to quickly install ThingsBoard Edge using docker compose and connect to the cloud.
Here is the list of commands, that can be used to quickly install and connect ThingsBoard Edge to the cloud using docker compose.
### Prerequisites
#### Prerequisites
Install <a href="https://docs.docker.com/engine/install/" target="_blank"> Docker CE</a> and <a href="https://docs.docker.com/compose/install/" target="_blank"> Docker Compose</a>.
### Create data and logs folders
#### Create data and logs folders
Run following commands, before starting docker container(s), to create folders for storing data and logs.
These commands additionally will change owner of newly created folders to docker container user.
@ -18,7 +16,7 @@ mkdir -p ~/.mytb-edge-logs && sudo chown -R 799:799 ~/.mytb-edge-logs
{:copy-code}
```
### Running ThingsBoard Edge as docker service
#### Running ThingsBoard Edge as docker service
${LOCALHOST_WARNING}
@ -64,12 +62,12 @@ services:
{:copy-code}
```
#### [Optional] Update bind ports
##### [Optional] Update bind ports
If ThingsBoard Edge is going to be running on the same machine where ThingsBoard server (cloud) is running, you'll need to update docker compose port mapping to avoid port collision between ThingsBoard server and ThingsBoard Edge.
Please update next lines of `docker-compose.yml` file:
```bash
```text
ports:
- "18080:8080"
- "11883:1883"

163
application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md

@ -0,0 +1,163 @@
Here is the list of commands, that can be used to quickly install ThingsBoard Edge on Ubuntu Server and connect to the cloud.
#### Install Java 11 (OpenJDK)
ThingsBoard service is running on Java 11. Follow these instructions to install OpenJDK 11:
```bash
sudo apt update
sudo apt install openjdk-11-jdk
{:copy-code}
```
Please don't forget to configure your operating system to use OpenJDK 11 by default.
You can configure which version is the default using the following command:
```bash
sudo update-alternatives --config java
{:copy-code}
```
You can check the installation using the following command:
```bash
java -version
{:copy-code}
```
Expected command output is:
```text
openjdk version "11.0.xx"
OpenJDK Runtime Environment (...)
OpenJDK 64-Bit Server VM (build ...)
```
#### Configure PostgreSQL
ThingsBoard Edge uses PostgreSQL database as a local storage.
Instructions listed below will help you to install PostgreSQL.
```bash
# install **wget** if not already installed:
sudo apt install -y wget
# import the repository signing key:
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
# add repository contents to your system:
RELEASE=$(lsb_release -cs)
echo "deb http://apt.postgresql.org/pub/repos/apt/ ${RELEASE}"-pgdg main | sudo tee /etc/apt/sources.list.d/pgdg.list
# install and launch the postgresql service:
sudo apt update
sudo apt -y install postgresql-12
sudo service postgresql start
{:copy-code}
```
Once PostgreSQL is installed you may want to create a new user or set the password for the main user.
The instructions below will help to set the password for main PostgreSQL user:
```text
sudo su - postgres
psql
\password
\q
```
Then, press “Ctrl+D” to return to main user console and connect to the database to create ThingsBoard Edge DB:
```text
psql -U postgres -d postgres -h 127.0.0.1 -W
CREATE DATABASE tb_edge;
\q
```
#### Thingsboard Edge service installation
Download installation package:
```bash
wget https://github.com/thingsboard/thingsboard-edge/releases/download/v${TB_EDGE_VERSION}/tb-edge-${TB_EDGE_VERSION}.deb
{:copy-code}
```
Go to the download repository and install ThingsBoard Edge service:
```bash
sudo dpkg -i tb-edge-${TB_EDGE_VERSION}.deb
{:copy-code}
```
#### Configure ThingsBoard Edge
To configure ThingsBoard Edge, you can use the following command to automatically update the configuration file with specific values:
```bash
sudo sh -c 'cat <<EOL >> /etc/tb-edge/conf/tb-edge.conf
export CLOUD_ROUTING_KEY=${CLOUD_ROUTING_KEY}
export CLOUD_ROUTING_SECRET=${CLOUD_ROUTING_SECRET}
export CLOUD_RPC_HOST=${BASE_URL}
export CLOUD_RPC_PORT=${CLOUD_RPC_PORT}
export CLOUD_RPC_SSL_ENABLED=${CLOUD_RPC_SSL_ENABLED}
EOL'
{:copy-code}
```
##### [Optional] Database Configuration
In case you changed default PostgreSQL datasource settings (**postgres**/**postgres**) please update the configuration file (**/etc/tb-edge/conf/tb-edge.conf**) with your actual values:
```bash
sudo nano /etc/tb-edge/conf/tb-edge.conf
{:copy-code}
```
Please update the following lines in your configuration file. Make sure **to replace**:
- Replace 'postgres' with your actual PostgreSQL username;
- Replace 'PUT_YOUR_POSTGRESQL_PASSWORD_HERE' with your actual PostgreSQL password.
```bash
export SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/tb_edge
export SPRING_DATASOURCE_USERNAME=postgres
export SPRING_DATASOURCE_PASSWORD=PUT_YOUR_POSTGRESQL_PASSWORD_HERE
{:copy-code}
```
##### [Optional] Update bind ports
If ThingsBoard Edge is going to be running on the same machine where ThingsBoard server (cloud) is running, you'll need to update configuration parameters to avoid port collision between ThingsBoard server and ThingsBoard Edge.
Please execute the following command to update ThingsBoard Edge configuration file (**/etc/tb-edge/conf/tb-edge.conf**):
```bash
sudo sh -c 'cat <<EOL >> /etc/tb-edge/conf/tb-edge.conf
export HTTP_BIND_PORT=18080
export MQTT_BIND_PORT=11883
export COAP_BIND_PORT=15683
export LWM2M_ENABLED=false
EOL'
{:copy-code}
```
Make sure that ports above (18080, 11883, 15683) are not used by any other application.
#### Run installation script
Once ThingsBoard Edge is installed and configured please execute the following install script:
```bash
sudo /usr/share/tb-edge/bin/install/install.sh
{:copy-code}
```
#### Restart ThingsBoard Edge service
```bash
sudo service tb-edge restart
{:copy-code}
```
#### Open ThingsBoard Edge UI
Once started, you will be able to open **ThingsBoard Edge UI** using the following link http://localhost:8080.
###### NOTE: Edge HTTP bind port update
Use next **ThingsBoard Edge UI** link **http://localhost:18080** if you updated HTTP 8080 bind port to **18080**.

6
application/src/main/java/org/thingsboard/server/controller/EdgeController.java

@ -557,17 +557,19 @@ public class EdgeController extends BaseController {
notes = "Get a docker install instructions for provided edge id." + TENANT_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/instructions/{edgeId}", method = RequestMethod.GET)
@RequestMapping(value = "/edge/instructions/{edgeId}/{method}", method = RequestMethod.GET)
@ResponseBody
public EdgeInstallInstructions getEdgeDockerInstallInstructions(
@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable("edgeId") String strEdgeId,
@ApiParam(value = "Installation method ('docker', 'ubuntu' or 'centos')")
@PathVariable("method") String installationMethod,
HttpServletRequest request) throws ThingsboardException {
if (isEdgesEnabled() && edgeInstallServiceOpt.isPresent()) {
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
edgeId = checkNotNull(edgeId);
Edge edge = checkEdgeId(edgeId, Operation.READ);
return checkNotNull(edgeInstallServiceOpt.get().getDockerInstallInstructions(getTenantId(), edge, request));
return checkNotNull(edgeInstallServiceOpt.get().getInstallInstructions(getTenantId(), edge, installationMethod, request));
} else {
throw new ThingsboardException("Edges support disabled", ThingsboardErrorCode.GENERAL);
}

50
application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java

@ -28,7 +28,6 @@ import org.thingsboard.server.service.install.InstallScripts;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@ -56,7 +55,20 @@ public class DefaultEdgeInstallService implements EdgeInstallService {
private String appVersion;
@Override
public EdgeInstallInstructions getDockerInstallInstructions(TenantId tenantId, Edge edge, HttpServletRequest request) {
public EdgeInstallInstructions getInstallInstructions(TenantId tenantId, Edge edge, String installationMethod, HttpServletRequest request) {
switch (installationMethod.toLowerCase()) {
case "docker":
return getDockerInstallInstructions(edge, request);
case "ubuntu":
return getUbuntuInstallInstructions(edge, request);
case "centos":
return getCentosInstallInstructions(edge, request);
default:
throw new IllegalArgumentException("Unsupported installation method for Edge: " + installationMethod);
}
}
private EdgeInstallInstructions getDockerInstallInstructions(Edge edge, HttpServletRequest request) {
String dockerInstallInstructions = readFile(resolveFile("docker", "instructions.md"));
String baseUrl = request.getServerName();
if (baseUrl.contains("localhost") || baseUrl.contains("127.0.0.1")) {
@ -70,16 +82,40 @@ public class DefaultEdgeInstallService implements EdgeInstallService {
String edgeVersion = appVersion + "EDGE";
edgeVersion = edgeVersion.replace("-SNAPSHOT", "");
dockerInstallInstructions = dockerInstallInstructions.replace("${TB_EDGE_VERSION}", edgeVersion);
dockerInstallInstructions = dockerInstallInstructions.replace("${CLOUD_ROUTING_KEY}", edge.getRoutingKey());
dockerInstallInstructions = dockerInstallInstructions.replace("${CLOUD_ROUTING_SECRET}", edge.getSecret());
dockerInstallInstructions = dockerInstallInstructions.replace("${CLOUD_RPC_PORT}", Integer.toString(rpcPort));
dockerInstallInstructions = dockerInstallInstructions.replace("${CLOUD_RPC_SSL_ENABLED}", Boolean.toString(sslEnabled));
dockerInstallInstructions = replacePlaceholders(dockerInstallInstructions, edge);
return new EdgeInstallInstructions(dockerInstallInstructions);
}
private EdgeInstallInstructions getUbuntuInstallInstructions(Edge edge, HttpServletRequest request) {
String ubuntuInstallInstructions = readFile(resolveFile("ubuntu", "instructions.md"));
ubuntuInstallInstructions = replacePlaceholders(ubuntuInstallInstructions, edge);
ubuntuInstallInstructions = ubuntuInstallInstructions.replace("${BASE_URL}", request.getServerName());
String edgeVersion = appVersion.replace("-SNAPSHOT", "");
ubuntuInstallInstructions = ubuntuInstallInstructions.replace("${TB_EDGE_VERSION}", edgeVersion);
return new EdgeInstallInstructions(ubuntuInstallInstructions);
}
private EdgeInstallInstructions getCentosInstallInstructions(Edge edge, HttpServletRequest request) {
String centosInstallInstructions = readFile(resolveFile("centos", "instructions.md"));
centosInstallInstructions = replacePlaceholders(centosInstallInstructions, edge);
centosInstallInstructions = centosInstallInstructions.replace("${BASE_URL}", request.getServerName());
String edgeVersion = appVersion.replace("-SNAPSHOT", "");
centosInstallInstructions = centosInstallInstructions.replace("${TB_EDGE_VERSION}", edgeVersion);
return new EdgeInstallInstructions(centosInstallInstructions);
}
private String replacePlaceholders(String instructions, Edge edge) {
instructions = instructions.replace("${CLOUD_ROUTING_KEY}", edge.getRoutingKey());
instructions = instructions.replace("${CLOUD_ROUTING_SECRET}", edge.getSecret());
instructions = instructions.replace("${CLOUD_RPC_PORT}", Integer.toString(rpcPort));
instructions = instructions.replace("${CLOUD_RPC_SSL_ENABLED}", Boolean.toString(sslEnabled));
return instructions;
}
private String readFile(Path file) {
try {
return new String(Files.readAllBytes(file), StandardCharsets.UTF_8);
return Files.readString(file);
} catch (IOException e) {
log.warn("Failed to read file: {}", file, e);
throw new RuntimeException(e);

3
application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallService.java

@ -23,6 +23,5 @@ import javax.servlet.http.HttpServletRequest;
public interface EdgeInstallService {
EdgeInstallInstructions getDockerInstallInstructions(TenantId tenantId, Edge edge, HttpServletRequest request);
EdgeInstallInstructions getInstallInstructions(TenantId tenantId, Edge edge, String installationMethod, HttpServletRequest request);
}

2
application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java

@ -1107,7 +1107,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
public void testGetEdgeInstallInstructions() throws Exception {
Edge edge = constructEdge(tenantId, "Edge for Test Docker Install Instructions", "default", "7390c3a6-69b0-9910-d155-b90aca4b772e", "l7q4zsjplzwhk16geqxy");
Edge savedEdge = doPost("/api/edge", edge, Edge.class);
String installInstructions = doGet("/api/edge/instructions/" + savedEdge.getId().getId().toString(), String.class);
String installInstructions = doGet("/api/edge/instructions/" + savedEdge.getId().getId().toString() + "/docker", String.class);
Assert.assertTrue(installInstructions.contains("l7q4zsjplzwhk16geqxy"));
Assert.assertTrue(installInstructions.contains("7390c3a6-69b0-9910-d155-b90aca4b772e"));
}

4
common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeInstallInstructions.java

@ -27,6 +27,6 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
public class EdgeInstallInstructions {
@ApiModelProperty(position = 1, value = "Markdown with docker install instructions")
private String dockerInstallInstructions;
@ApiModelProperty(position = 1, value = "Markdown with install instructions")
private String installInstructions;
}

4
ui-ngx/src/app/core/http/edge.service.ts

@ -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 getEdgeInstallInstructions(edgeId: string, method: string = 'ubuntu', config?: RequestConfig): Observable<EdgeInstallInstructions> {
return this.http.get<EdgeInstallInstructions>(`/api/edge/instructions/${edgeId}/${method}`, defaultHttpOptionsFromConfig(config));
}
}

95
ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.html

@ -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>
<span fxFlex></span>
<button mat-icon-button
(click)="cancel()"
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>
</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>
<mat-toolbar color="primary">
<h2 translate>{{ dialogTitle }}</h2>
<span fxFlex></span>
<button mat-icon-button
(click)="close()"
type="button">
<mat-icon class="material-icons">close</mat-icon>
</button>
</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="mdi:ubuntu"></mat-icon>
Ubuntu
</ng-template>
<ng-template matTabContent>
<div class="tb-form-panel no-padding no-border">
<div class="tb-form-panel no-padding stroked">
<tb-markdown [data]='contentData.ubuntu'></tb-markdown>
</div>
</div>
</ng-template>
</mat-tab>
<mat-tab>
<ng-template mat-tab-label>
<mat-icon class="tabs-icon" svgIcon="mdi:centos"></mat-icon>
CentOS/RHEL
</ng-template>
<ng-template matTabContent>
<div class="tb-form-panel no-padding no-border">
<div class="tb-form-panel no-padding stroked">
<tb-markdown [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">
<div class="tb-form-panel no-padding stroked">
<tb-markdown [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>

123
ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss

@ -0,0 +1,123 @@
/**
* 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: 705px;
}
@media #{$mat-gt-sm} {
width: 1080px;
}
}
: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 {
padding: 16px 16px 32px 16px;
div.code-wrapper button.clipboard-btn {
right: -2px !important;
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;
}
}
&.multiline {
right: -2px !important;
}
}
& > *:not(ul) {
padding-right: unset !important;
padding-left: unset !important;
}
}
.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;
}
.mat-mdc-tab-body {
padding: 16px 0;
}
}

84
ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.ts

@ -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";
export interface EdgeInstructionsData {
instructions: string;
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 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 {
dialogTitle: string;
showDontShowAgain: boolean;
instructions: string = this.data.instructions;
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;
}
}
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]);
}
cancel(): void {
this.dialogRef.close(null);
getInstructions(method: string) {
if (!this.contentData[method]) {
this.loadedInstructions = false;
this.edgeService.getEdgeInstallInstructions(this.data.edge.id.id, method).subscribe(
res => {
this.contentData[method] = res.installInstructions;
this.loadedInstructions = true;
}
);
}
}
}

65
ui-ngx/src/app/modules/home/pages/edge/edges-table-config.resolver.ts

@ -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) {
addEdge() {
this.dialog.open<AddEntityDialogComponent, AddEntityDialogData<EdgeInfo>,
EdgeInfo>(AddEntityDialogComponent, {
disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
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.edgeService.getEdgeDockerInstallInstructions(edge.id.id).subscribe(
(edgeInstructionsTemplate: EdgeInstallInstructions) => {
this.dialog.open<EdgeInstructionsDialogComponent, EdgeInstructionsData>(EdgeInstructionsDialogComponent, {
disableClose: false,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
instructions: edgeInstructionsTemplate.dockerInstallInstructions
}
});
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 {

8
ui-ngx/src/app/shared/models/edge.models.ts

@ -179,5 +179,11 @@ export interface EdgeEvent extends BaseData<EventId> {
}
export interface EdgeInstallInstructions {
dockerInstallInstructions: string;
installInstructions: string;
}
export enum EdgeInstructionsMethod {
ubuntu,
centos,
docker
}

1
ui-ngx/src/app/shared/models/user-settings.models.ts

@ -17,6 +17,7 @@
export interface UserSettings {
openedMenuSections?: string[];
notDisplayConnectivityAfterAddDevice?: boolean;
notDisplayInstructionsAfterAddEdge?: boolean;
}
export const initialUserSettings: UserSettings = {

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

@ -1958,6 +1958,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…
Cancel
Save