Merge pull request #9233 from thingsboard/fix/vc
Version control: fix ids replacement in dashboard config
This commit is contained in:
commit
5583446340
@ -48,8 +48,8 @@ public abstract class BaseEntityExportService<I extends EntityId, E extends Expo
|
||||
|
||||
public abstract Set<EntityType> getSupportedEntityTypes();
|
||||
|
||||
protected void replaceUuidsRecursively(EntitiesExportCtx<?> ctx, JsonNode node, Set<String> skipFieldsSet, Pattern includedFieldsPattern) {
|
||||
JacksonUtil.replaceUuidsRecursively(node, skipFieldsSet, includedFieldsPattern, uuid -> getExternalIdOrElseInternalByUuid(ctx, uuid));
|
||||
protected void replaceUuidsRecursively(EntitiesExportCtx<?> ctx, JsonNode node, Set<String> skippedRootFields, Pattern includedFieldsPattern) {
|
||||
JacksonUtil.replaceUuidsRecursively(node, skippedRootFields, includedFieldsPattern, uuid -> getExternalIdOrElseInternalByUuid(ctx, uuid), true);
|
||||
}
|
||||
|
||||
protected Stream<UUID> toExternalIds(Collection<UUID> internalIds, Function<UUID, EntityId> entityIdCreator,
|
||||
|
||||
@ -26,8 +26,11 @@ import org.thingsboard.server.common.data.sync.ie.EntityExportData;
|
||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||
import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.thingsboard.server.service.sync.ie.importing.impl.DashboardImportService.WIDGET_CONFIG_PROCESSED_FIELDS_PATTERN;
|
||||
|
||||
@Service
|
||||
@TbCoreComponent
|
||||
public class DashboardExportService extends BaseEntityExportService<DashboardId, Dashboard, EntityExportData<Dashboard>> {
|
||||
@ -43,7 +46,7 @@ public class DashboardExportService extends BaseEntityExportService<DashboardId,
|
||||
replaceUuidsRecursively(ctx, entityAlias, Set.of("id"), null);
|
||||
}
|
||||
for (JsonNode widgetConfig : dashboard.getWidgetsConfig()) {
|
||||
replaceUuidsRecursively(ctx, JacksonUtil.getSafely(widgetConfig, "config", "actions"), Set.of("id"), null);
|
||||
replaceUuidsRecursively(ctx, JacksonUtil.getSafely(widgetConfig, "config", "actions"), Collections.emptySet(), WIDGET_CONFIG_PROCESSED_FIELDS_PATTERN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -388,11 +388,11 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
|
||||
}
|
||||
|
||||
protected void replaceIdsRecursively(EntitiesImportCtx ctx, IdProvider idProvider, JsonNode json,
|
||||
Set<String> skipFieldsSet, Pattern includedFieldsPattern,
|
||||
Set<String> skippedRootFields, Pattern includedFieldsPattern,
|
||||
LinkedHashSet<EntityType> hints) {
|
||||
JacksonUtil.replaceUuidsRecursively(json, skipFieldsSet, includedFieldsPattern,
|
||||
JacksonUtil.replaceUuidsRecursively(json, skippedRootFields, includedFieldsPattern,
|
||||
uuid -> idProvider.getInternalIdByUuid(uuid, ctx.isFinalImportAttempt(), hints)
|
||||
.map(EntityId::getId).orElse(uuid));
|
||||
.map(EntityId::getId).orElse(uuid), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@ -44,6 +45,7 @@ import java.util.stream.Collectors;
|
||||
public class DashboardImportService extends BaseEntityImportService<DashboardId, Dashboard, EntityExportData<Dashboard>> {
|
||||
|
||||
private static final LinkedHashSet<EntityType> HINTS = new LinkedHashSet<>(Arrays.asList(EntityType.DASHBOARD, EntityType.DEVICE, EntityType.ASSET));
|
||||
public static final Pattern WIDGET_CONFIG_PROCESSED_FIELDS_PATTERN = Pattern.compile(".*Id.*");
|
||||
|
||||
private final DashboardService dashboardService;
|
||||
|
||||
@ -68,7 +70,7 @@ public class DashboardImportService extends BaseEntityImportService<DashboardId,
|
||||
replaceIdsRecursively(ctx, idProvider, entityAlias, Set.of("id"), null, HINTS);
|
||||
}
|
||||
for (JsonNode widgetConfig : dashboard.getWidgetsConfig()) {
|
||||
replaceIdsRecursively(ctx, idProvider, JacksonUtil.getSafely(widgetConfig, "config", "actions"), Set.of("id"), null, HINTS);
|
||||
replaceIdsRecursively(ctx, idProvider, JacksonUtil.getSafely(widgetConfig, "config", "actions"), Collections.emptySet(), WIDGET_CONFIG_PROCESSED_FIELDS_PATTERN, HINTS);
|
||||
}
|
||||
return dashboard;
|
||||
}
|
||||
|
||||
@ -257,6 +257,7 @@ public class ExportImportServiceSqlTest extends BaseExportImportServiceTest {
|
||||
Asset asset1 = createAsset(tenantId1, null, assetProfile.getId(), "Asset 1");
|
||||
Asset asset2 = createAsset(tenantId1, null, assetProfile.getId(), "Asset 2");
|
||||
Dashboard dashboard = createDashboard(tenantId1, null, "Dashboard 1");
|
||||
Dashboard otherDashboard = createDashboard(tenantId1, null, "Dashboard 2");
|
||||
DeviceProfile existingDeviceProfile = createDeviceProfile(tenantId2, null, null, "Existing");
|
||||
|
||||
String aliasId = "23c4185d-1497-9457-30b2-6d91e69a5b2c";
|
||||
@ -265,20 +266,43 @@ public class ExportImportServiceSqlTest extends BaseExportImportServiceTest {
|
||||
"\"" + aliasId + "\": {\n" +
|
||||
"\"alias\": \"assets\",\n" +
|
||||
"\"filter\": {\n" +
|
||||
"\"entityList\": [\n" +
|
||||
"\"" + asset1.getId().toString() + "\",\n" +
|
||||
"\"" + asset2.getId().toString() + "\",\n" +
|
||||
"\"" + tenantId1.getId().toString() + "\",\n" +
|
||||
"\"" + existingDeviceProfile.getId().toString() + "\",\n" +
|
||||
"\"" + unknownUuid + "\"\n" +
|
||||
"],\n" +
|
||||
"\"resolveMultiple\": true\n" +
|
||||
" \"entityList\": [\n" +
|
||||
" \"" + asset1.getId() + "\",\n" +
|
||||
" \"" + asset2.getId() + "\",\n" +
|
||||
" \"" + tenantId1.getId() + "\",\n" +
|
||||
" \"" + existingDeviceProfile.getId() + "\",\n" +
|
||||
" \"" + unknownUuid + "\"\n" +
|
||||
" ],\n" +
|
||||
" \"id\":\"" + asset1.getId() + "\",\n" +
|
||||
" \"resolveMultiple\": true\n" +
|
||||
"},\n" +
|
||||
"\"id\": \"" + aliasId + "\"\n" +
|
||||
"}\n" +
|
||||
"}";
|
||||
String widgetId = "ea8f34a0-264a-f11f-cde3-05201bb4ff4b";
|
||||
String actionId = "4a8e6efa-3e68-fa59-7feb-d83366130cae";
|
||||
String widgets = "{\n" +
|
||||
" \"" + widgetId + "\": {\n" +
|
||||
" \"config\": {\n" +
|
||||
" \"actions\": {\n" +
|
||||
" \"rowClick\": [\n" +
|
||||
" {\n" +
|
||||
" \"name\": \"go to dashboard\",\n" +
|
||||
" \"targetDashboardId\": \"" + otherDashboard.getId() + "\",\n" +
|
||||
" \"id\": \"" + actionId + "\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"row\": 0,\n" +
|
||||
" \"col\": 0,\n" +
|
||||
" \"id\": \"" + widgetId + "\"\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
ObjectNode dashboardConfiguration = JacksonUtil.newObjectNode();
|
||||
dashboardConfiguration.set("entityAliases", JacksonUtil.toJsonNode(entityAliases));
|
||||
dashboardConfiguration.set("widgets", JacksonUtil.toJsonNode(widgets));
|
||||
dashboardConfiguration.set("description", new TextNode("hallo"));
|
||||
dashboard.setConfiguration(dashboardConfiguration);
|
||||
dashboard = dashboardService.saveDashboard(dashboard);
|
||||
@ -288,10 +312,12 @@ public class ExportImportServiceSqlTest extends BaseExportImportServiceTest {
|
||||
EntityExportData<Asset> asset1ExportData = exportEntity(tenantAdmin1, asset1.getId());
|
||||
EntityExportData<Asset> asset2ExportData = exportEntity(tenantAdmin1, asset2.getId());
|
||||
EntityExportData<Dashboard> dashboardExportData = exportEntity(tenantAdmin1, dashboard.getId());
|
||||
EntityExportData<Dashboard> otherDashboardExportData = exportEntity(tenantAdmin1, otherDashboard.getId());
|
||||
|
||||
AssetProfile importedProfile = importEntity(tenantAdmin2, profileExportData).getSavedEntity();
|
||||
Asset importedAsset1 = importEntity(tenantAdmin2, asset1ExportData).getSavedEntity();
|
||||
Asset importedAsset2 = importEntity(tenantAdmin2, asset2ExportData).getSavedEntity();
|
||||
Dashboard importedOtherDashboard = importEntity(tenantAdmin2, otherDashboardExportData).getSavedEntity();
|
||||
Dashboard importedDashboard = importEntity(tenantAdmin2, dashboardExportData).getSavedEntity();
|
||||
|
||||
Map.Entry<String, JsonNode> entityAlias = importedDashboard.getConfiguration().get("entityAliases").fields().next();
|
||||
@ -311,6 +337,17 @@ public class ExportImportServiceSqlTest extends BaseExportImportServiceTest {
|
||||
.isEqualTo(existingDeviceProfile.getId().toString());
|
||||
assertThat(aliasEntitiesIds).element(4).as("unresolved uuid was replaced with tenant id")
|
||||
.isEqualTo(tenantId2.toString());
|
||||
assertThat(entityAlias.getValue().get("filter").get("id").asText()).as("external asset 1 was replaced with imported one")
|
||||
.isEqualTo(importedAsset1.getId().toString());
|
||||
|
||||
ObjectNode widgetConfig = importedDashboard.getWidgetsConfig().get(0);
|
||||
assertThat(widgetConfig.get("id").asText()).as("widget id is not replaced")
|
||||
.isEqualTo(widgetId);
|
||||
JsonNode actionConfig = widgetConfig.get("config").get("actions").get("rowClick").get(0);
|
||||
assertThat(actionConfig.get("id").asText()).as("action id is not replaced")
|
||||
.isEqualTo(actionId);
|
||||
assertThat(actionConfig.get("targetDashboardId").asText()).as("dashboard id is replaced with imported one")
|
||||
.isEqualTo(importedOtherDashboard.getId().toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.thingsboard.server.common.data.kv.DataType;
|
||||
import org.thingsboard.server.common.data.kv.KvEntry;
|
||||
|
||||
@ -35,7 +36,6 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
@ -228,27 +228,24 @@ public class JacksonUtil {
|
||||
return node;
|
||||
}
|
||||
|
||||
public static void replaceUuidsRecursively(JsonNode node, Set<String> skipFieldsSet, Pattern includedFieldsPattern, UnaryOperator<UUID> replacer) {
|
||||
public static void replaceUuidsRecursively(JsonNode node, Set<String> skippedRootFields, Pattern includedFieldsPattern, UnaryOperator<UUID> replacer, boolean root) {
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
if (node.isObject()) {
|
||||
ObjectNode objectNode = (ObjectNode) node;
|
||||
List<String> fieldNames = new ArrayList<>(objectNode.size());
|
||||
objectNode.fieldNames().forEachRemaining(fieldNames::add);
|
||||
List<String> fieldNames = Lists.newArrayList(objectNode.fieldNames());
|
||||
for (String fieldName : fieldNames) {
|
||||
if (skipFieldsSet.contains(fieldName)) {
|
||||
if (root && skippedRootFields.contains(fieldName)) {
|
||||
continue;
|
||||
}
|
||||
if (includedFieldsPattern != null) {
|
||||
if (!RegexUtils.matches(fieldName, includedFieldsPattern)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
var child = objectNode.get(fieldName);
|
||||
if (child.isObject() || child.isArray()) {
|
||||
replaceUuidsRecursively(child, skipFieldsSet, includedFieldsPattern, replacer);
|
||||
replaceUuidsRecursively(child, skippedRootFields, includedFieldsPattern, replacer, false);
|
||||
} else if (child.isTextual()) {
|
||||
if (includedFieldsPattern != null && !RegexUtils.matches(fieldName, includedFieldsPattern)) {
|
||||
continue;
|
||||
}
|
||||
String text = child.asText();
|
||||
String newText = RegexUtils.replace(text, RegexUtils.UUID_PATTERN, uuid -> replacer.apply(UUID.fromString(uuid)).toString());
|
||||
if (!text.equals(newText)) {
|
||||
@ -261,7 +258,7 @@ public class JacksonUtil {
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
JsonNode arrayElement = array.get(i);
|
||||
if (arrayElement.isObject() || arrayElement.isArray()) {
|
||||
replaceUuidsRecursively(arrayElement, skipFieldsSet, includedFieldsPattern, replacer);
|
||||
replaceUuidsRecursively(arrayElement, skippedRootFields, includedFieldsPattern, replacer, false);
|
||||
} else if (arrayElement.isTextual()) {
|
||||
String text = arrayElement.asText();
|
||||
String newText = RegexUtils.replace(text, RegexUtils.UUID_PATTERN, uuid -> replacer.apply(UUID.fromString(uuid)).toString());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user