Merge branch 'feature/image-resources' of github.com:thingsboard/thingsboard into feature/image-resources
This commit is contained in:
commit
cd3b4257b8
@ -23,6 +23,8 @@ import com.google.common.util.concurrent.ListenableFuture;
|
|||||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
import com.google.protobuf.AbstractMessage;
|
import com.google.protobuf.AbstractMessage;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.awaitility.Awaitility;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -78,10 +80,11 @@ import org.thingsboard.server.gen.edge.v1.UserUpdateMsg;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
|
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
|
||||||
@ -92,6 +95,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
|
|||||||
})
|
})
|
||||||
@ContextConfiguration(classes = {EdgeControllerTest.Config.class})
|
@ContextConfiguration(classes = {EdgeControllerTest.Config.class})
|
||||||
@DaoSqlTest
|
@DaoSqlTest
|
||||||
|
@Slf4j
|
||||||
public class EdgeControllerTest extends AbstractControllerTest {
|
public class EdgeControllerTest extends AbstractControllerTest {
|
||||||
|
|
||||||
public static final String EDGE_HOST = "localhost";
|
public static final String EDGE_HOST = "localhost";
|
||||||
@ -863,10 +867,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
|
|||||||
|
|
||||||
Edge edge = doPost("/api/edge", constructEdge("Test Sync Edge", "test"), Edge.class);
|
Edge edge = doPost("/api/edge", constructEdge("Test Sync Edge", "test"), Edge.class);
|
||||||
|
|
||||||
// simulate edge activation
|
simulateEdgeActivation(edge);
|
||||||
ObjectNode attributes = JacksonUtil.newObjectNode();
|
|
||||||
attributes.put("active", true);
|
|
||||||
doPost("/api/plugins/telemetry/EDGE/" + edge.getId() + "/attributes/" + DataConstants.SERVER_SCOPE, attributes);
|
|
||||||
|
|
||||||
doPost("/api/edge/" + edge.getId().getId().toString()
|
doPost("/api/edge/" + edge.getId().getId().toString()
|
||||||
+ "/device/" + savedDevice.getId().getId().toString(), Device.class);
|
+ "/device/" + savedDevice.getId().getId().toString(), Device.class);
|
||||||
@ -878,7 +879,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
|
|||||||
|
|
||||||
edgeImitator.expectMessageAmount(24);
|
edgeImitator.expectMessageAmount(24);
|
||||||
edgeImitator.connect();
|
edgeImitator.connect();
|
||||||
assertThat(edgeImitator.waitForMessages()).as("await for messages on first connect").isTrue();
|
waitForMessages(edgeImitator);
|
||||||
|
|
||||||
verifyFetchersMsgs(edgeImitator);
|
verifyFetchersMsgs(edgeImitator);
|
||||||
// verify queue msgs
|
// verify queue msgs
|
||||||
@ -890,7 +891,7 @@ public class EdgeControllerTest extends AbstractControllerTest {
|
|||||||
|
|
||||||
edgeImitator.expectMessageAmount(20);
|
edgeImitator.expectMessageAmount(20);
|
||||||
doPost("/api/edge/sync/" + edge.getId());
|
doPost("/api/edge/sync/" + edge.getId());
|
||||||
assertThat(edgeImitator.waitForMessages()).as("await for messages after edge sync rest api call").isTrue();
|
waitForMessages(edgeImitator);
|
||||||
|
|
||||||
verifyFetchersMsgs(edgeImitator);
|
verifyFetchersMsgs(edgeImitator);
|
||||||
Assert.assertTrue(edgeImitator.getDownlinkMsgs().isEmpty());
|
Assert.assertTrue(edgeImitator.getDownlinkMsgs().isEmpty());
|
||||||
@ -909,6 +910,35 @@ public class EdgeControllerTest extends AbstractControllerTest {
|
|||||||
.andExpect(status().isOk());
|
.andExpect(status().isOk());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void simulateEdgeActivation(Edge edge) throws Exception {
|
||||||
|
ObjectNode attributes = JacksonUtil.newObjectNode();
|
||||||
|
attributes.put("active", true);
|
||||||
|
doPost("/api/plugins/telemetry/EDGE/" + edge.getId() + "/attributes/" + DataConstants.SERVER_SCOPE, attributes);
|
||||||
|
Awaitility.await()
|
||||||
|
.atMost(30, TimeUnit.SECONDS)
|
||||||
|
.until(() -> {
|
||||||
|
List<Map<String, Object>> values = doGetAsyncTyped("/api/plugins/telemetry/EDGE/" + edge.getId() +
|
||||||
|
"/values/attributes/SERVER_SCOPE", new TypeReference<>() {});
|
||||||
|
Optional<Map<String, Object>> activeAttrOpt = values.stream().filter(att -> att.get("key").equals("active")).findFirst();
|
||||||
|
if (activeAttrOpt.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Map<String, Object> activeAttr = activeAttrOpt.get();
|
||||||
|
return "true".equals(activeAttr.get("value").toString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void waitForMessages(EdgeImitator edgeImitator) throws Exception {
|
||||||
|
boolean success = edgeImitator.waitForMessages();
|
||||||
|
if (!success) {
|
||||||
|
List<AbstractMessage> downlinkMsgs = edgeImitator.getDownlinkMsgs();
|
||||||
|
for (AbstractMessage downlinkMsg : downlinkMsgs) {
|
||||||
|
log.error("{}\n{}", downlinkMsg.getClass(), downlinkMsg);
|
||||||
|
}
|
||||||
|
Assert.fail("Await for messages was not successful!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void verifyFetchersMsgs(EdgeImitator edgeImitator) {
|
private void verifyFetchersMsgs(EdgeImitator edgeImitator) {
|
||||||
Assert.assertTrue(popQueueMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Main"));
|
Assert.assertTrue(popQueueMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Main"));
|
||||||
Assert.assertTrue(popRuleChainMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Edge Root Rule Chain"));
|
Assert.assertTrue(popRuleChainMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Edge Root Rule Chain"));
|
||||||
|
|||||||
@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
<cdk-virtual-scroll-viewport #viewport class="tb-scroll-grid-viewport" [itemSize]="itemSize" appendOnly>
|
<cdk-virtual-scroll-viewport #viewport class="tb-scroll-grid-viewport" [itemSize]="itemSize" appendOnly>
|
||||||
<ng-container *cdkVirtualFor="let itemsRow of dataSource">
|
<ng-container *cdkVirtualFor="let itemsRow of dataSource; trackBy: trackByItemsRow">
|
||||||
<div *ngIf="itemsRow" class="tb-scroll-grid-items-row" [style]="{gap: gap+'px'}">
|
<div *ngIf="itemsRow" class="tb-scroll-grid-items-row" [style]="{gap: gap+'px'}">
|
||||||
<div *ngFor="let item of itemsRow" class="tb-scroll-grid-item-container">
|
<div *ngFor="let item of itemsRow; trackBy: trackByItem" class="tb-scroll-grid-item-container">
|
||||||
<ng-container *ngIf="item === 'loadingCell'">
|
<ng-container *ngIf="item === 'loadingCell'">
|
||||||
<ng-container *ngTemplateOutlet="loadingCell ? loadingCell : defaultLoadingCell"></ng-container>
|
<ng-container *ngTemplateOutlet="loadingCell ? loadingCell : defaultLoadingCell"></ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@ -100,4 +100,12 @@ export class ScrollGridComponent<T, F> implements OnInit, AfterViewInit, OnChang
|
|||||||
isObject(value: any): boolean {
|
isObject(value: any): boolean {
|
||||||
return isObject(value);
|
return isObject(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trackByItemsRow(index: number, itemsRow: T[]): number {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
trackByItem(index: number, item: T): T {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -82,7 +82,9 @@ export interface ImageDescriptor {
|
|||||||
previewDescriptor: ImageDescriptor;
|
previewDescriptor: ImageDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ImageResourceInfo = TbResourceInfo<ImageDescriptor>;
|
export interface ImageResourceInfo extends TbResourceInfo<ImageDescriptor> {
|
||||||
|
link?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export type ImageResourceType = 'tenant' | 'system';
|
export type ImageResourceType = 'tenant' | 'system';
|
||||||
|
|
||||||
|
|||||||
@ -17,11 +17,13 @@
|
|||||||
import { Pipe, PipeTransform } from '@angular/core';
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
import { ImageService } from '@core/http/image.service';
|
import { ImageService } from '@core/http/image.service';
|
||||||
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
|
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
|
||||||
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
|
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||||
import { isDefinedAndNotNull } from '@core/utils';
|
import { isDefinedAndNotNull } from '@core/utils';
|
||||||
import { NO_IMAGE_DATA_URI } from '@shared/models/resource.models';
|
import { NO_IMAGE_DATA_URI } from '@shared/models/resource.models';
|
||||||
|
|
||||||
const LOADING_IMAGE_DATA_URI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDIwIDIwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPgo=';
|
const LOADING_IMAGE_DATA_URI = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRG' +
|
||||||
|
'LTgiPz4KPHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAw' +
|
||||||
|
'IDIwIDIwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPgo=';
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'image'
|
name: 'image'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user