Merge pull request #7878 from volodymyr-babak/edge-install-instructions
[3.5] Add edge install instructions for docker
This commit is contained in:
commit
3cf5fb1a0d
@ -0,0 +1,107 @@
|
||||
## Install ThingsBoard Edge and connect to cloud instructions
|
||||
|
||||
Here is the list of commands, that can be used to quickly install and connect ThingsBoard Edge to the cloud using docker compose.
|
||||
|
||||
### 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
|
||||
|
||||
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.
|
||||
To do this (to change user) **chown** command is used, and this command requires *sudo* permissions (command will request password for a *sudo* access):
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.mytb-edge-data && sudo chown -R 799:799 ~/.mytb-edge-data
|
||||
mkdir -p ~/.mytb-edge-logs && sudo chown -R 799:799 ~/.mytb-edge-logs
|
||||
{:copy-code}
|
||||
```
|
||||
|
||||
### Running ThingsBoard Edge as docker service
|
||||
|
||||
${LOCALHOST_WARNING}
|
||||
|
||||
Create docker compose file for ThingsBoard Edge service:
|
||||
|
||||
```bash
|
||||
nano docker-compose.yml
|
||||
{:copy-code}
|
||||
```
|
||||
|
||||
Add the following lines to the yml file:
|
||||
|
||||
```bash
|
||||
version: '3.0'
|
||||
services:
|
||||
mytbedge:
|
||||
restart: always
|
||||
image: "thingsboard/tb-edge:${TB_EDGE_VERSION}"
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- "1883:1883"
|
||||
- "5683-5688:5683-5688/udp"
|
||||
environment:
|
||||
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/tb-edge
|
||||
CLOUD_ROUTING_KEY: ${CLOUD_ROUTING_KEY}
|
||||
CLOUD_ROUTING_SECRET: ${CLOUD_ROUTING_SECRET}
|
||||
CLOUD_RPC_HOST: ${BASE_URL}
|
||||
CLOUD_RPC_PORT: ${CLOUD_RPC_PORT}
|
||||
CLOUD_RPC_SSL_ENABLED: ${CLOUD_RPC_SSL_ENABLED}
|
||||
volumes:
|
||||
- ~/.mytb-edge-data:/data
|
||||
- ~/.mytb-edge-logs:/var/log/tb-edge
|
||||
postgres:
|
||||
restart: always
|
||||
image: "postgres:12"
|
||||
ports:
|
||||
- "5432"
|
||||
environment:
|
||||
POSTGRES_DB: tb-edge
|
||||
POSTGRES_PASSWORD: postgres
|
||||
volumes:
|
||||
- ~/.mytb-edge-data/db:/var/lib/postgresql/data
|
||||
{: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 docker compose port mapping to avoid port collision between ThingsBoard server and ThingsBoard Edge.
|
||||
|
||||
Please update next lines of `docker-compose.yml` file:
|
||||
|
||||
```bash
|
||||
ports:
|
||||
- "18080:8080"
|
||||
- "11883:1883"
|
||||
- "15683-15688:5683-5688/udp"
|
||||
```
|
||||
Make sure that ports above (18080, 11883, 15683-15688) are not used by any other application.
|
||||
|
||||
#### Start ThingsBoard Edge
|
||||
Set the terminal in the directory which contains the `docker-compose.yml` file and execute the following commands to up this docker compose directly:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
docker compose logs -f mytbedge
|
||||
{:copy-code}
|
||||
```
|
||||
|
||||
###### NOTE: Docker Compose V2 vs docker-compose (with a hyphen)
|
||||
|
||||
ThingsBoard supports Docker Compose V2 (Docker Desktop or Compose plugin) starting from **3.4.2** release, because **docker-compose** as standalone setup is no longer supported by Docker.
|
||||
We **strongly** recommend to update to Docker Compose V2 and use it.
|
||||
If you still rely on using Docker Compose as docker-compose (with a hyphen), then please execute the following commands to start ThingsBoard Edge:
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
docker-compose logs -f mytbedge
|
||||
```
|
||||
|
||||
#### 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**.
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
###### WARNING NOTE: 'localhost' can not be used as CLOUD_RPC_HOST
|
||||
|
||||
Please note that your ThingsBoard base URL is **'localhost'** at the moment. **'localhost'** cannot be used for docker containers - please update **CLOUD_RPC_HOST** environment variable below to the IP address of your machine (*docker **host** machine*). IP address must be `192.168.1.XX` or similar format. In other case - ThingsBoard Edge service, that is running in docker container, will not be able to connect to the cloud.
|
||||
@ -135,6 +135,7 @@ import org.thingsboard.server.queue.discovery.PartitionService;
|
||||
import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
|
||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||
import org.thingsboard.server.service.component.ComponentDiscoveryService;
|
||||
import org.thingsboard.server.service.edge.instructions.EdgeInstallService;
|
||||
import org.thingsboard.server.service.edge.rpc.EdgeRpcService;
|
||||
import org.thingsboard.server.service.entitiy.TbNotificationEntityService;
|
||||
import org.thingsboard.server.service.ota.OtaPackageStateService;
|
||||
@ -287,6 +288,9 @@ public abstract class BaseController {
|
||||
@Autowired(required = false)
|
||||
protected EdgeRpcService edgeRpcService;
|
||||
|
||||
@Autowired(required = false)
|
||||
protected EdgeInstallService edgeInstallService;
|
||||
|
||||
@Autowired
|
||||
protected TbNotificationEntityService notificationEntityService;
|
||||
|
||||
|
||||
@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.Customer;
|
||||
import org.thingsboard.server.common.data.EntitySubtype;
|
||||
import org.thingsboard.server.common.data.edge.Edge;
|
||||
import org.thingsboard.server.common.data.edge.EdgeInfo;
|
||||
import org.thingsboard.server.common.data.edge.EdgeInstallInstructions;
|
||||
import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
|
||||
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
|
||||
import org.thingsboard.server.common.data.exception.ThingsboardException;
|
||||
@ -63,6 +64,7 @@ import org.thingsboard.server.service.security.model.SecurityUser;
|
||||
import org.thingsboard.server.service.security.permission.Operation;
|
||||
import org.thingsboard.server.service.security.permission.Resource;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
@ -595,4 +597,24 @@ public class EdgeController extends BaseController {
|
||||
|
||||
return edgeBulkImportService.processBulkImport(request, user);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "Get Edge Docker Install Instructions (getEdgeDockerInstallInstructions)",
|
||||
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)
|
||||
@ResponseBody
|
||||
public EdgeInstallInstructions getEdgeDockerInstallInstructions(
|
||||
@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
|
||||
@PathVariable("edgeId") String strEdgeId,
|
||||
HttpServletRequest request) throws ThingsboardException {
|
||||
try {
|
||||
EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
|
||||
edgeId = checkNotNull(edgeId);
|
||||
Edge edge = checkEdgeId(edgeId, Operation.READ);
|
||||
return checkNotNull(edgeInstallService.getDockerInstallInstructions(getTenantId(), edge, request));
|
||||
} catch (Exception e) {
|
||||
throw handleException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 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.
|
||||
*/
|
||||
package org.thingsboard.server.service.edge.instructions;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.common.data.edge.Edge;
|
||||
import org.thingsboard.server.common.data.edge.EdgeInstallInstructions;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||
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;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@ConditionalOnProperty(prefix = "edges", value = "enabled", havingValue = "true")
|
||||
@TbCoreComponent
|
||||
public class DefaultEdgeInstallService implements EdgeInstallService {
|
||||
|
||||
private static final String EDGE_DIR = "edge";
|
||||
|
||||
private static final String EDGE_INSTALL_INSTRUCTIONS_DIR = "install_instructions";
|
||||
|
||||
private final InstallScripts installScripts;
|
||||
|
||||
@Value("${edges.rpc.port}")
|
||||
private int rpcPort;
|
||||
|
||||
@Value("${edges.rpc.ssl.enabled}")
|
||||
private boolean sslEnabled;
|
||||
|
||||
@Value("${app.version:unknown}")
|
||||
private String appVersion;
|
||||
|
||||
@Override
|
||||
public EdgeInstallInstructions getDockerInstallInstructions(TenantId tenantId, 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")) {
|
||||
String localhostWarning = readFile(resolveFile("docker", "localhost_warning.md"));
|
||||
dockerInstallInstructions = dockerInstallInstructions.replace("${LOCALHOST_WARNING}", localhostWarning);
|
||||
dockerInstallInstructions = dockerInstallInstructions.replace("${BASE_URL}", "!!!REPLACE_ME_TO_HOST_IP_ADDRESS!!!");
|
||||
} else {
|
||||
dockerInstallInstructions = dockerInstallInstructions.replace("${LOCALHOST_WARNING}", "");
|
||||
dockerInstallInstructions = dockerInstallInstructions.replace("${BASE_URL}", baseUrl);
|
||||
}
|
||||
dockerInstallInstructions = dockerInstallInstructions.replace("${TB_EDGE_VERSION}", appVersion + "EDGE");
|
||||
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));
|
||||
return new EdgeInstallInstructions(dockerInstallInstructions);
|
||||
}
|
||||
|
||||
private String readFile(Path file) {
|
||||
try {
|
||||
return new String(Files.readAllBytes(file), StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
log.warn("Failed to read file: {}", file, e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Path resolveFile(String subDir, String... subDirs) {
|
||||
return getEdgeInstallInstructionsDir().resolve(Paths.get(subDir, subDirs));
|
||||
}
|
||||
|
||||
private Path getEdgeInstallInstructionsDir() {
|
||||
return Paths.get(installScripts.getDataDir(), InstallScripts.JSON_DIR, EDGE_DIR, EDGE_INSTALL_INSTRUCTIONS_DIR);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 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.
|
||||
*/
|
||||
package org.thingsboard.server.service.edge.instructions;
|
||||
|
||||
import org.thingsboard.server.common.data.edge.Edge;
|
||||
import org.thingsboard.server.common.data.edge.EdgeInstallInstructions;
|
||||
import org.thingsboard.server.common.data.id.TenantId;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
public interface EdgeInstallService {
|
||||
|
||||
EdgeInstallInstructions getDockerInstallInstructions(TenantId tenantId, Edge edge, HttpServletRequest request);
|
||||
|
||||
}
|
||||
@ -702,16 +702,16 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
|
||||
}
|
||||
|
||||
protected Edge constructEdge(String name, String type) {
|
||||
return constructEdge(tenantId, name, type);
|
||||
return constructEdge(tenantId, name, type, StringUtils.randomAlphanumeric(20), StringUtils.randomAlphanumeric(20));
|
||||
}
|
||||
|
||||
protected Edge constructEdge(TenantId tenantId, String name, String type) {
|
||||
protected Edge constructEdge(TenantId tenantId, String name, String type, String routingKey, String secret) {
|
||||
Edge edge = new Edge();
|
||||
edge.setTenantId(tenantId);
|
||||
edge.setName(name);
|
||||
edge.setType(type);
|
||||
edge.setSecret(StringUtils.randomAlphanumeric(20));
|
||||
edge.setRoutingKey(StringUtils.randomAlphanumeric(20));
|
||||
edge.setRoutingKey(routingKey);
|
||||
edge.setSecret(secret);
|
||||
return edge;
|
||||
}
|
||||
|
||||
|
||||
@ -57,6 +57,10 @@ import org.thingsboard.server.gen.edge.v1.RuleChainUpdateMsg;
|
||||
import org.thingsboard.server.gen.edge.v1.UserCredentialsUpdateMsg;
|
||||
import org.thingsboard.server.gen.edge.v1.UserUpdateMsg;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -92,7 +96,7 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
@Before
|
||||
public void beforeTest() throws Exception {
|
||||
loginSysAdmin();
|
||||
|
||||
@ -327,7 +331,7 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
|
||||
String customerIdStr = customerId.getId().toString();
|
||||
|
||||
String msgError = msgErrorNoFound("Customer", customerIdStr);
|
||||
doPost("/api/customer/" + customerIdStr+ "/edge/" + savedEdge.getId().getId().toString())
|
||||
doPost("/api/customer/" + customerIdStr + "/edge/" + savedEdge.getId().getId().toString())
|
||||
.andExpect(status().isNotFound())
|
||||
.andExpect(statusReason(containsString(msgError)));
|
||||
|
||||
@ -886,4 +890,13 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
|
||||
Edge edge = constructEdge(name, "default");
|
||||
return doPost("/api/edge", edge, Edge.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
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);
|
||||
Assert.assertTrue(installInstructions.contains("l7q4zsjplzwhk16geqxy"));
|
||||
Assert.assertTrue(installInstructions.contains("7390c3a6-69b0-9910-d155-b90aca4b772e"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 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.
|
||||
*/
|
||||
package org.thingsboard.server.common.data.edge;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@ApiModel
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class EdgeInstallInstructions {
|
||||
|
||||
@ApiModelProperty(position = 1, value = "Markdown with docker install instructions")
|
||||
private String dockerInstallInstructions;
|
||||
}
|
||||
@ -81,6 +81,7 @@ import org.thingsboard.server.common.data.device.DeviceSearchQuery;
|
||||
import org.thingsboard.server.common.data.edge.Edge;
|
||||
import org.thingsboard.server.common.data.edge.EdgeEvent;
|
||||
import org.thingsboard.server.common.data.edge.EdgeInfo;
|
||||
import org.thingsboard.server.common.data.edge.EdgeInstallInstructions;
|
||||
import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
|
||||
import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
|
||||
import org.thingsboard.server.common.data.id.AlarmId;
|
||||
@ -3130,6 +3131,12 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
|
||||
}).getBody();
|
||||
}
|
||||
|
||||
public Optional<EdgeInstallInstructions> getEdgeDockerInstallInstructions(EdgeId edgeId) {
|
||||
ResponseEntity<EdgeInstallInstructions> edgeInstallInstructionsResult =
|
||||
restTemplate.getForEntity(baseURL + "/api/edge/instructions/{edgeId}", EdgeInstallInstructions.class, edgeId.getId());
|
||||
return Optional.ofNullable(edgeInstallInstructionsResult.getBody());
|
||||
}
|
||||
|
||||
public UUID saveEntitiesVersion(VersionCreateRequest request) {
|
||||
return restTemplate.postForEntity(baseURL + "/api/entities/vc/version", request, UUID.class).getBody();
|
||||
}
|
||||
@ -3146,6 +3153,7 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PageData<EntityVersion> listEntityVersions(EntityId externalEntityId, String branch, PageLink pageLink) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("entityType", externalEntityId.getEntityType().name());
|
||||
|
||||
@ -21,7 +21,7 @@ import { HttpClient } from '@angular/common/http';
|
||||
import { PageLink, TimePageLink } from '@shared/models/page/page-link';
|
||||
import { PageData } from '@shared/models/page/page-data';
|
||||
import { EntitySubtype } from '@app/shared/models/entity-type.models';
|
||||
import { Edge, EdgeEvent, EdgeInfo, EdgeSearchQuery } from '@shared/models/edge.models';
|
||||
import { Edge, EdgeEvent, EdgeInfo, EdgeInstallInstructions, EdgeSearchQuery } from '@shared/models/edge.models';
|
||||
import { EntityId } from '@shared/models/id/entity-id';
|
||||
import { BulkImportRequest, BulkImportResult } from '@home/components/import-export/import-export.models';
|
||||
|
||||
@ -113,4 +113,8 @@ export class EdgeService {
|
||||
public bulkImportEdges(entitiesData: BulkImportRequest, config?: RequestConfig): Observable<BulkImportResult> {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
<!--
|
||||
|
||||
Copyright © 2016-2022 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.
|
||||
|
||||
-->
|
||||
<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-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>
|
||||
</div>
|
||||
@ -0,0 +1,46 @@
|
||||
///
|
||||
/// Copyright © 2016-2022 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 { 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;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'tb-edge-instructions',
|
||||
templateUrl: './edge-instructions-dialog.component.html'
|
||||
})
|
||||
export class EdgeInstructionsDialogComponent extends DialogComponent<EdgeInstructionsDialogComponent, EdgeInstructionsData> {
|
||||
|
||||
instructions: string = this.data.instructions;
|
||||
|
||||
constructor(protected store: Store<AppState>,
|
||||
protected router: Router,
|
||||
public dialogRef: MatDialogRef<EdgeInstructionsDialogComponent, EdgeInstructionsData>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: EdgeInstructionsData) {
|
||||
super(store, router, dialogRef);
|
||||
}
|
||||
|
||||
cancel(): void {
|
||||
this.dialogRef.close(null);
|
||||
}
|
||||
}
|
||||
@ -112,6 +112,15 @@
|
||||
<span translate>edge.sync</span>
|
||||
</button>
|
||||
</div>
|
||||
<div fxLayout="row" fxLayout.xs="column">
|
||||
<button mat-raised-button color="primary"
|
||||
[disabled]="(isLoading$ | async)"
|
||||
(click)="onEntityAction($event, 'openInstructions')"
|
||||
[fxShow]="!isEdit">
|
||||
<mat-icon>info_outline</mat-icon>
|
||||
<span>{{ 'edge.install-connect-instructions' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mat-padding" fxLayout="column">
|
||||
<mat-form-field class="mat-block"
|
||||
|
||||
@ -23,12 +23,14 @@ import { EdgeRoutingModule } from '@home/pages/edge/edge-routing.module';
|
||||
import { EdgeComponent } from '@modules/home/pages/edge/edge.component';
|
||||
import { EdgeTableHeaderComponent } from '@home/pages/edge/edge-table-header.component';
|
||||
import { EdgeTabsComponent } from '@home/pages/edge/edge-tabs.component';
|
||||
import { EdgeInstructionsDialogComponent } from './edge-instructions-dialog.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
EdgeComponent,
|
||||
EdgeTableHeaderComponent,
|
||||
EdgeTabsComponent
|
||||
EdgeTabsComponent,
|
||||
EdgeInstructionsDialogComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
|
||||
@ -51,13 +51,17 @@ import {
|
||||
AddEntitiesToCustomerDialogData
|
||||
} from '../../dialogs/add-entities-to-customer-dialog.component';
|
||||
import { HomeDialogsService } from '@home/dialogs/home-dialogs.service';
|
||||
import { Edge, EdgeInfo } from '@shared/models/edge.models';
|
||||
import { Edge, EdgeInfo, EdgeInstallInstructions } 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';
|
||||
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";
|
||||
|
||||
@Injectable()
|
||||
export class EdgesTableConfigResolver implements Resolve<EntityTableConfig<EdgeInfo>> {
|
||||
@ -526,6 +530,23 @@ 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,
|
||||
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
|
||||
data: {
|
||||
instructions: edgeInstructionsTemplate.dockerInstallInstructions
|
||||
}
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
onEdgeAction(action: EntityAction<EdgeInfo>, config: EntityTableConfig<EdgeInfo>): boolean {
|
||||
switch (action.action) {
|
||||
case 'open':
|
||||
@ -558,6 +579,9 @@ export class EdgesTableConfigResolver implements Resolve<EntityTableConfig<EdgeI
|
||||
case 'syncEdge':
|
||||
this.syncEdge(action.event, action.entity);
|
||||
return true;
|
||||
case 'openInstructions':
|
||||
this.openInstructions(action.event, action.entity);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -167,3 +167,7 @@ export interface EdgeEvent extends BaseData<EventId> {
|
||||
uid: string;
|
||||
body: string;
|
||||
}
|
||||
|
||||
export interface EdgeInstallInstructions {
|
||||
dockerInstallInstructions: string;
|
||||
}
|
||||
|
||||
@ -1749,6 +1749,7 @@
|
||||
"make-private-edge-title": "Are you sure you want to make the edge '{{edgeName}}' private?",
|
||||
"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",
|
||||
"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