diff --git a/core/core-backend/src/main/java/io/dataease/chart/server/ChartDataServer.java b/core/core-backend/src/main/java/io/dataease/chart/server/ChartDataServer.java index 734e139dd0..edcd4f7759 100644 --- a/core/core-backend/src/main/java/io/dataease/chart/server/ChartDataServer.java +++ b/core/core-backend/src/main/java/io/dataease/chart/server/ChartDataServer.java @@ -49,7 +49,7 @@ public class ChartDataServer implements ChartDataApi { @Override public ChartViewDTO getData(ChartViewDTO chartViewDTO) throws Exception { try { - // 从模版数据获取 + // 从模板数据获取 if(CommonConstants.VIEW_DATA_FROM.TEMPLATE.equalsIgnoreCase(chartViewDTO.getDataFrom())){ return extendDataManage.getChartDataInfo(chartViewDTO.getId(),chartViewDTO); }else{ diff --git a/core/core-backend/src/main/java/io/dataease/commons/constants/OptConstants.java b/core/core-backend/src/main/java/io/dataease/commons/constants/OptConstants.java index f0f7c95d0d..b917051108 100644 --- a/core/core-backend/src/main/java/io/dataease/commons/constants/OptConstants.java +++ b/core/core-backend/src/main/java/io/dataease/commons/constants/OptConstants.java @@ -26,7 +26,7 @@ public class OptConstants { public static final int DATASET = 4; //数据源 public static final int DATASOURCE = 5; - //模版 + //模板 public static final int TEMPLATE = 6; } diff --git a/core/core-backend/src/main/java/io/dataease/template/dao/auto/entity/VisualizationTemplate.java b/core/core-backend/src/main/java/io/dataease/template/dao/auto/entity/VisualizationTemplate.java index 03baecb4f5..d0315f9262 100644 --- a/core/core-backend/src/main/java/io/dataease/template/dao/auto/entity/VisualizationTemplate.java +++ b/core/core-backend/src/main/java/io/dataease/template/dao/auto/entity/VisualizationTemplate.java @@ -37,7 +37,7 @@ public class VisualizationTemplate implements Serializable { private Integer level; /** - * 模版种类 dataV or dashboard 目录或者文件夹 + * 模板种类 dataV or dashboard 目录或者文件夹 */ private String dvType; @@ -62,7 +62,7 @@ public class VisualizationTemplate implements Serializable { private String snapshot; /** - * 模版类型 system 系统内置 self 用户自建 + * 模板类型 system 系统内置 self 用户自建 */ private String templateType; diff --git a/core/core-backend/src/main/java/io/dataease/template/dao/ext/ExtVisualizationTemplateMapper.java b/core/core-backend/src/main/java/io/dataease/template/dao/ext/ExtVisualizationTemplateMapper.java index 3455251da6..51021a4388 100644 --- a/core/core-backend/src/main/java/io/dataease/template/dao/ext/ExtVisualizationTemplateMapper.java +++ b/core/core-backend/src/main/java/io/dataease/template/dao/ext/ExtVisualizationTemplateMapper.java @@ -3,6 +3,7 @@ package io.dataease.template.dao.ext; import io.dataease.api.template.dto.TemplateManageDTO; import io.dataease.api.template.request.TemplateManageRequest; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import java.util.List; @@ -11,5 +12,6 @@ import java.util.List; public interface ExtVisualizationTemplateMapper{ List findTemplateList(TemplateManageRequest request); + List findBaseTemplateList(@Param("nodeType") String nodeType); } diff --git a/core/core-backend/src/main/java/io/dataease/template/manage/TemplateMarketManage.java b/core/core-backend/src/main/java/io/dataease/template/manage/TemplateCenterManage.java similarity index 64% rename from core/core-backend/src/main/java/io/dataease/template/manage/TemplateMarketManage.java rename to core/core-backend/src/main/java/io/dataease/template/manage/TemplateCenterManage.java index fa8cec10b1..451e4c08d6 100644 --- a/core/core-backend/src/main/java/io/dataease/template/manage/TemplateMarketManage.java +++ b/core/core-backend/src/main/java/io/dataease/template/manage/TemplateCenterManage.java @@ -1,5 +1,6 @@ package io.dataease.template.manage; +import io.dataease.api.template.dto.TemplateManageDTO; import io.dataease.api.template.dto.TemplateManageFileDTO; import io.dataease.api.template.dto.TemplateMarketDTO; import io.dataease.api.template.dto.TemplateMarketPreviewInfoDTO; @@ -10,9 +11,11 @@ import io.dataease.api.template.vo.TemplateCategoryVO; import io.dataease.exception.DEException; import io.dataease.operation.manage.CoreOptRecentManage; import io.dataease.system.manage.SysParameterManage; +import io.dataease.template.dao.ext.ExtVisualizationTemplateMapper; import io.dataease.utils.HttpClientConfig; import io.dataease.utils.HttpClientUtil; import io.dataease.utils.JsonUtil; +import io.dataease.utils.LogUtil; import jakarta.annotation.Resource; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -25,7 +28,7 @@ import java.util.stream.Collectors; * Author: wangjiahao */ @Service -public class TemplateMarketManage { +public class TemplateCenterManage { private final static String POSTS_API = "/api/content/posts?page=0&size=2000"; @@ -40,6 +43,9 @@ public class TemplateMarketManage { @Resource private CoreOptRecentManage coreOptRecentManage; + @Resource + private ExtVisualizationTemplateMapper templateManageMapper; + /** * @param templateUrl template url * @Description Get template file from template market @@ -64,22 +70,45 @@ public class TemplateMarketManage { return HttpClientUtil.get(url, config); } - private MarketTemplateV2BaseResponse templateQuery(Map templateParams){ - String result = marketGet(templateParams.get("template.url") + POSTS_API_V2, null); - MarketTemplateV2BaseResponse postsResult = JsonUtil.parseObject(result, MarketTemplateV2BaseResponse.class); - return postsResult; - } + private MarketTemplateV2BaseResponse templateQuery(Map templateParams) { + String result = marketGet(templateParams.get("template.url") + POSTS_API_V2, null); + MarketTemplateV2BaseResponse postsResult = JsonUtil.parseObject(result, MarketTemplateV2BaseResponse.class); + return postsResult; + } public MarketBaseResponse searchTemplate() { try { Map templateParams = sysParameterManage.groupVal("template."); - return baseResponseV2Trans(templateQuery(templateParams), templateParams.get("template.url")); + return baseResponseV2Trans(templateQuery(templateParams), searchTemplateFromManage(), templateParams.get("template.url")); } catch (Exception e) { DEException.throwException(e); } return null; } + private List searchTemplateFromManage() { + try { + List manageResult = templateManageMapper.findBaseTemplateList("template"); + List categories = templateManageMapper.findBaseTemplateList("folder"); + Map categoryMap = categories.stream() + .collect(Collectors.toMap(TemplateManageDTO::getId, TemplateManageDTO::getName)); + return baseManage2MarketTrans(manageResult, categoryMap); + } catch (Exception e) { + DEException.throwException(e); + } + return null; + } + + private List baseManage2MarketTrans(List manageResult, Map categoryMap) { + List result = new ArrayList<>(); + manageResult.stream().forEach(templateManageDTO -> { + templateManageDTO.setCategoryName(categoryMap.get(templateManageDTO.getPid())); + result.add(new TemplateMarketDTO(templateManageDTO)); + }); + return result; + } + + public MarketBaseResponse searchTemplateRecommend() { try { Map templateParams = sysParameterManage.groupVal("template."); @@ -93,7 +122,7 @@ public class TemplateMarketManage { public MarketPreviewBaseResponse searchTemplatePreview() { try { Map templateParams = sysParameterManage.groupVal("template."); - return basePreviewResponseV2Trans(templateQuery(templateParams), templateParams.get("template.url")); + return basePreviewResponseV2Trans(templateQuery(templateParams), searchTemplateFromManage(), templateParams.get("template.url")); } catch (Exception e) { DEException.throwException(e); } @@ -106,76 +135,57 @@ public class TemplateMarketManage { List contents = new ArrayList<>(); v2BaseResponse.getItems().stream().forEach(marketTemplateV2ItemResult -> { MarketApplicationSpecVO spec = marketTemplateV2ItemResult.getApplication().getSpec(); - if("Y".equalsIgnoreCase(spec.getSuggest())){ - contents.add(new TemplateMarketDTO(spec.getReadmeName(), spec.getDisplayName(), spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(), categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName()),"Y")); + if ("Y".equalsIgnoreCase(spec.getSuggest())) { + contents.add(new TemplateMarketDTO(spec.getReadmeName(), spec.getDisplayName(), spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(), categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName()), "Y")); } }); // 最近使用排序 Collections.sort(contents); - return new MarketBaseResponse(url,contents); + return new MarketBaseResponse(url, contents); } - private MarketBaseResponse baseResponseV2Trans(MarketTemplateV2BaseResponse v2BaseResponse, String url) { + private MarketBaseResponse baseResponseV2Trans(MarketTemplateV2BaseResponse v2BaseResponse, List contents, String url) { Map useTime = coreOptRecentManage.findTemplateRecentUseTime(); Map categoriesMap = getCategoriesBaseV2(); - List contents = new ArrayList<>(); v2BaseResponse.getItems().stream().forEach(marketTemplateV2ItemResult -> { MarketApplicationSpecVO spec = marketTemplateV2ItemResult.getApplication().getSpec(); - contents.add(new TemplateMarketDTO(spec.getReadmeName(), spec.getDisplayName(), spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(), categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName()),spec.getSuggest())); + contents.add(new TemplateMarketDTO(spec.getReadmeName(), spec.getDisplayName(), spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(), categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName()), spec.getSuggest())); }); // 最近使用排序 Collections.sort(contents); - return new MarketBaseResponse(url,contents); + return new MarketBaseResponse(url, contents); } - private MarketPreviewBaseResponse basePreviewResponseV2Trans(MarketTemplateV2BaseResponse v2BaseResponse, String url) { + private MarketPreviewBaseResponse basePreviewResponseV2Trans(MarketTemplateV2BaseResponse v2BaseResponse, List manageContents, String url) { Map useTime = coreOptRecentManage.findTemplateRecentUseTime(); - Map categoriesMap = getCategoriesBaseV2(); - List categories = new ArrayList<>(); + List categoryVO = getCategoriesV2(); + Map categoriesMap = categoryVO.stream() + .collect(Collectors.toMap(MarketMetaDataVO::getSlug, MarketMetaDataVO::getLabel)); + List categories = categoryVO.stream().filter(node -> !"全部".equalsIgnoreCase(node.getLabel())).map(MarketMetaDataVO::getLabel) + .collect(Collectors.toList()); List result = new ArrayList<>(); - categoriesMap.forEach((key,value)->{ - if(!"全部".equalsIgnoreCase(value)){ - categories.add(value); + categoriesMap.forEach((key, value) -> { + if (!"全部".equalsIgnoreCase(value)) { List contents = new ArrayList<>(); v2BaseResponse.getItems().stream().forEach(marketTemplateV2ItemResult -> { MarketApplicationSpecVO spec = marketTemplateV2ItemResult.getApplication().getSpec(); - if(key.equalsIgnoreCase(spec.getLabel())){ - contents.add(new TemplateMarketDTO(spec.getReadmeName(), spec.getDisplayName(), spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(), categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName()),spec.getSuggest())); + if (key.equalsIgnoreCase(spec.getLabel())) { + contents.add(new TemplateMarketDTO(spec.getReadmeName(), spec.getDisplayName(), spec.getScreenshots().get(0).getUrl(), spec.getLinks().get(0).getUrl(), categoriesMap.get(spec.getLabel()), spec.getTemplateType(), useTime.get(spec.getReadmeName()), spec.getSuggest())); + } + }); + manageContents.stream().forEach(templateMarketDTO -> { + if (value.equalsIgnoreCase(templateMarketDTO.getMainCategory())) { + contents.add(templateMarketDTO); } }); Collections.sort(contents); - result.add(new TemplateMarketPreviewInfoDTO(value,contents)); + result.add(new TemplateMarketPreviewInfoDTO(value, contents)); } }); // 最近使用排序 - return new MarketPreviewBaseResponse(url,categories,result); + return new MarketPreviewBaseResponse(url, categories, result); } - public MarketBaseResponse searchTemplateV1() { - try { - Map templateParams = sysParameterManage.groupVal("template."); - String result = marketGet(templateParams.get("template.url") + POSTS_API, templateParams.get("template.accessKey")); - MarketTemplateBaseResponse postsResult = JsonUtil.parseObject(result, MarketTemplateBaseResponse.class); - MarketBaseResponse response = new MarketBaseResponse(templateParams.get("template.url"), postsResult.getData().getContent()); - return response; - } catch (Exception e) { - DEException.throwException(e); - } - return null; - } - - public List getCategoriesV1() { - Map templateParams = sysParameterManage.groupVal("template."); - String resultStr = marketGet(templateParams.get("template.url") + CATEGORIES_API, templateParams.get("template.accessKey")); - MarketCategoryBaseResponse categoryBaseResponse = JsonUtil.parseObject(resultStr, MarketCategoryBaseResponse.class); - List categories = categoryBaseResponse.getData(); - if (CollectionUtils.isNotEmpty(categories)) { - return categories.stream().filter(item -> !"应用系列".equals(item.getName())).sorted(Comparator.comparing(TemplateCategoryVO::getPriority)).map(TemplateCategoryVO::getName).collect(Collectors.toList()); - } else { - return null; - } - - } public List getCategories() { return getCategoriesV2().stream().map(MarketMetaDataVO::getLabel) @@ -196,10 +206,21 @@ public class TemplateMarketManage { } public List getCategoriesV2() { - Map templateParams = sysParameterManage.groupVal("template."); - String resultStr = marketGet(templateParams.get("template.url") + TEMPLATE_META_DATA_URL, null); - MarketMetaDataBaseResponse metaData = JsonUtil.parseObject(resultStr, MarketMetaDataBaseResponse.class); - List categories = metaData.getLabels(); - return categories; + List allCategories = new ArrayList<>(); + List manageCategories = templateManageMapper.findBaseTemplateList("folder"); + List manageCategoriesTrans = manageCategories.stream() + .map(templateCategory -> new MarketMetaDataVO(templateCategory.getId(), templateCategory.getName())) + .collect(Collectors.toList()); + try { + Map templateParams = sysParameterManage.groupVal("template."); + String resultStr = marketGet(templateParams.get("template.url") + TEMPLATE_META_DATA_URL, null); + MarketMetaDataBaseResponse metaData = JsonUtil.parseObject(resultStr, MarketMetaDataBaseResponse.class); + allCategories.addAll(metaData.getLabels()); + } catch (Exception e) { + LogUtil.error("模板市场分类获取错误", e); + } + allCategories.addAll(manageCategoriesTrans); + return allCategories; + } } diff --git a/core/core-backend/src/main/java/io/dataease/template/service/TemplateMarketService.java b/core/core-backend/src/main/java/io/dataease/template/service/TemplateMarketService.java index d3b6ad3f5e..c9a80cc92f 100644 --- a/core/core-backend/src/main/java/io/dataease/template/service/TemplateMarketService.java +++ b/core/core-backend/src/main/java/io/dataease/template/service/TemplateMarketService.java @@ -4,7 +4,7 @@ import io.dataease.api.template.TemplateMarketApi; import io.dataease.api.template.response.MarketBaseResponse; import io.dataease.api.template.response.MarketPreviewBaseResponse; import io.dataease.api.template.vo.MarketMetaDataVO; -import io.dataease.template.manage.TemplateMarketManage; +import io.dataease.template.manage.TemplateCenterManage; import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -20,28 +20,28 @@ import java.util.List; public class TemplateMarketService implements TemplateMarketApi { @Resource - private TemplateMarketManage templateMarketManage; + private TemplateCenterManage templateCenterManage; @Override public MarketBaseResponse searchTemplate() { - return templateMarketManage.searchTemplate(); + return templateCenterManage.searchTemplate(); } @Override public MarketBaseResponse searchTemplateRecommend() { - return templateMarketManage.searchTemplateRecommend(); + return templateCenterManage.searchTemplateRecommend(); } @Override public MarketPreviewBaseResponse searchTemplatePreview() { - return templateMarketManage.searchTemplatePreview(); + return templateCenterManage.searchTemplatePreview(); } @Override public List categories() { - return templateMarketManage.getCategories(); + return templateCenterManage.getCategories(); } @Override public List categoriesObject() { - return templateMarketManage.getCategoriesObject(); + return templateCenterManage.getCategoriesObject(); } } diff --git a/core/core-backend/src/main/java/io/dataease/visualization/server/DataVisualizationServer.java b/core/core-backend/src/main/java/io/dataease/visualization/server/DataVisualizationServer.java index 1f848e0bc5..188a83c7d4 100644 --- a/core/core-backend/src/main/java/io/dataease/visualization/server/DataVisualizationServer.java +++ b/core/core-backend/src/main/java/io/dataease/visualization/server/DataVisualizationServer.java @@ -11,7 +11,6 @@ import io.dataease.api.visualization.request.VisualizationWorkbranchQueryRequest import io.dataease.api.visualization.vo.DataVisualizationVO; import io.dataease.api.visualization.vo.VisualizationResourceVO; import io.dataease.chart.dao.auto.entity.CoreChartView; -import io.dataease.chart.dao.auto.mapper.CoreChartViewMapper; import io.dataease.chart.manage.ChartDataManage; import io.dataease.chart.manage.ChartViewManege; import io.dataease.commons.constants.DataVisualizationConstants; @@ -26,7 +25,7 @@ import io.dataease.template.dao.auto.entity.VisualizationTemplate; import io.dataease.template.dao.auto.entity.VisualizationTemplateExtendData; import io.dataease.template.dao.auto.mapper.VisualizationTemplateExtendDataMapper; import io.dataease.template.dao.auto.mapper.VisualizationTemplateMapper; -import io.dataease.template.manage.TemplateMarketManage; +import io.dataease.template.manage.TemplateCenterManage; import io.dataease.utils.AuthUtils; import io.dataease.utils.BeanUtils; import io.dataease.utils.IDUtils; @@ -73,7 +72,7 @@ public class DataVisualizationServer implements DataVisualizationApi { private VisualizationTemplateMapper templateMapper; @Resource - private TemplateMarketManage templateMarketManage; + private TemplateCenterManage templateCenterManage; @Resource private StaticResourceServer staticResourceServer; @@ -251,7 +250,7 @@ public class DataVisualizationServer implements DataVisualizationApi { name = request.getName(); dvType = request.getType(); } else if (DataVisualizationConstants.NEW_PANEL_FROM.NEW_MARKET_TEMPLATE.equals(newFrom)) { - TemplateManageFileDTO templateFileInfo = templateMarketManage.getTemplateFromMarket(request.getTemplateUrl()); + TemplateManageFileDTO templateFileInfo = templateCenterManage.getTemplateFromMarket(request.getTemplateUrl()); if (templateFileInfo == null) { DEException.throwException("Can't find the template's info from market,please check"); } @@ -261,7 +260,7 @@ public class DataVisualizationServer implements DataVisualizationApi { staticResource = templateFileInfo.getStaticResource(); name = templateFileInfo.getName(); dvType = templateFileInfo.getDvType(); - // 模版市场记录 + // 模板市场记录 coreOptRecentManage.saveOpt(request.getResourceName(), OptConstants.OPT_RESOURCE_TYPE.TEMPLATE,OptConstants.OPT_TYPE.NEW); } // 解析动态数据 @@ -286,7 +285,7 @@ public class DataVisualizationServer implements DataVisualizationApi { extendDataInfo.put(newViewId, extendDataDTO); templateData = templateData.replaceAll(originViewId, newViewId.toString()); canvasViewInfo.put(chartView.getId(), chartView); - //插入模版数据 此处预先插入减少数据交互量 + //插入模板数据 此处预先插入减少数据交互量 VisualizationTemplateExtendData extendData = new VisualizationTemplateExtendData(); templateExtendDataMapper.insert(BeanUtils.copyBean(extendData, extendDataDTO)); } diff --git a/core/core-backend/src/main/resources/db/desktop/V2.1__ddl.sql b/core/core-backend/src/main/resources/db/desktop/V2.1__ddl.sql index 3c819f9ae5..94fd98f6ff 100644 --- a/core/core-backend/src/main/resources/db/desktop/V2.1__ddl.sql +++ b/core/core-backend/src/main/resources/db/desktop/V2.1__ddl.sql @@ -4,12 +4,12 @@ CREATE TABLE `visualization_template` ( `name` varchar(255) DEFAULT NULL COMMENT '名称', `pid` varchar(255) DEFAULT NULL COMMENT '父级id', `level` int(10) DEFAULT NULL COMMENT '层级', - `dv_type` varchar(255) DEFAULT NULL COMMENT '模版种类 dataV or dashboard 目录或者文件夹', + `dv_type` varchar(255) DEFAULT NULL COMMENT '模板种类 dataV or dashboard 目录或者文件夹', `node_type` varchar(255) DEFAULT NULL COMMENT '节点类型 folder or panel 目录或者文件夹', `create_by` varchar(255) DEFAULT NULL COMMENT '创建人', `create_time` bigint(13) DEFAULT NULL COMMENT '创建时间', `snapshot` longtext COMMENT '缩略图', - `template_type` varchar(255) DEFAULT NULL COMMENT '模版类型 system 系统内置 self 用户自建 ', + `template_type` varchar(255) DEFAULT NULL COMMENT '模板类型 system 系统内置 self 用户自建 ', `template_style` longtext COMMENT 'template 样式', `template_data` longtext COMMENT 'template 数据', `dynamic_data` longtext COMMENT '预存数据', diff --git a/core/core-backend/src/main/resources/db/migration/V2.1__ddl.sql b/core/core-backend/src/main/resources/db/migration/V2.1__ddl.sql index 922330bb86..07144d536b 100644 --- a/core/core-backend/src/main/resources/db/migration/V2.1__ddl.sql +++ b/core/core-backend/src/main/resources/db/migration/V2.1__ddl.sql @@ -5,12 +5,12 @@ CREATE TABLE `visualization_template` `name` varchar(255) DEFAULT NULL COMMENT '名称', `pid` varchar(255) DEFAULT NULL COMMENT '父级id', `level` int(10) DEFAULT NULL COMMENT '层级', - `dv_type` varchar(255) DEFAULT NULL COMMENT '模版种类 dataV or dashboard 目录或者文件夹', + `dv_type` varchar(255) DEFAULT NULL COMMENT '模板种类 dataV or dashboard 目录或者文件夹', `node_type` varchar(255) DEFAULT NULL COMMENT '节点类型 folder or panel 目录或者文件夹', `create_by` varchar(255) DEFAULT NULL COMMENT '创建人', `create_time` bigint(13) DEFAULT NULL COMMENT '创建时间', `snapshot` longtext COMMENT '缩略图', - `template_type` varchar(255) DEFAULT NULL COMMENT '模版类型 system 系统内置 self 用户自建 ', + `template_type` varchar(255) DEFAULT NULL COMMENT '模板类型 system 系统内置 self 用户自建 ', `template_style` longtext COMMENT 'template 样式', `template_data` longtext COMMENT 'template 数据', `dynamic_data` longtext COMMENT '预存数据', diff --git a/core/core-backend/src/main/resources/mybatis/ExtVisualizationTemplateMapper.xml b/core/core-backend/src/main/resources/mybatis/ExtVisualizationTemplateMapper.xml index 22e2623b47..05898e3bd6 100644 --- a/core/core-backend/src/main/resources/mybatis/ExtVisualizationTemplateMapper.xml +++ b/core/core-backend/src/main/resources/mybatis/ExtVisualizationTemplateMapper.xml @@ -30,6 +30,19 @@ visualization_template.template_style, visualization_template.template_data, visualization_template.dynamic_data + +