Commit b76793fb authored by DMyTryC's avatar DMyTryC Committed by benjaminParisel

Adding a guidance on the main page for having a modal inside another … (#2550)

* Adding a guidance on the main page for having a modal inside another modal error

* Fixing old tests

* Fixing the error in the artifact-list less file

* Adding new tests

* Fixing the small typo
parent 32724587
......@@ -56,6 +56,7 @@ public abstract class AbstractPage extends DesignerArtifact implements Previewab
private Set<Asset> assets = new HashSet<>();
private Set<String> inactiveAssets = new HashSet<>();
private Map<String, Data> data = new HashMap<>();
private boolean hasValidationError = false;
@JsonView({JsonViewLight.class, JsonViewPersistence.class})
public String getId() {
......@@ -199,4 +200,9 @@ public abstract class AbstractPage extends DesignerArtifact implements Previewab
.append("version", getDesignerVersion())
.toString();
}
@JsonView({JsonViewLight.class, JsonViewPersistence.class})
public boolean hasValidationError() { return hasValidationError; }
public void setHasValidationError(boolean hasValidationError) { this.hasValidationError = hasValidationError; }
}
......@@ -19,7 +19,6 @@ import static org.bonitasoft.web.designer.builder.AssetBuilder.anAsset;
import static org.bonitasoft.web.designer.builder.PageBuilder.aPage;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.bonitasoft.web.designer.builder.AssetBuilder;
import org.bonitasoft.web.designer.builder.PageBuilder;
import org.bonitasoft.web.designer.config.DesignerConfig;
import org.bonitasoft.web.designer.model.JsonViewLight;
......@@ -44,7 +43,7 @@ public class PageTest {
}
@Test
public void jsonview_light_should_only_manage_id_name_and_favorite() throws Exception {
public void jsonview_light_should_only_manage_id_name_hasValidationError_and_favorite() throws Exception {
String json = objectMapper.writerWithView(JsonViewLight.class).writeValueAsString(createAFilledPage());
JSONAssert.assertEquals(json, "{"
......@@ -52,7 +51,8 @@ public class PageTest {
+ "\"uuid\":\"UUID\","
+ "\"name\":\"myPage\","
+ "\"type\":\"page\","
+ "\"favorite\": true"
+ "\"favorite\": true,"
+ "\"hasValidationError\": false"
+ "}", false);
}
......
......@@ -14,6 +14,16 @@
*/
package org.bonitasoft.web.designer.model.widget;
import static org.apache.commons.io.IOUtils.toByteArray;
import static org.assertj.core.api.Assertions.assertThat;
import static org.bonitasoft.web.designer.builder.PageBuilder.aFilledPage;
import static org.bonitasoft.web.designer.builder.PageBuilder.aPage;
import static org.bonitasoft.web.designer.builder.WidgetBuilder.aWidget;
import static org.bonitasoft.web.designer.utils.ListUtil.asList;
import static org.skyscreamer.jsonassert.JSONAssert.assertEquals;
import java.util.ArrayList;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.bonitasoft.web.designer.config.DesignerConfig;
import org.bonitasoft.web.designer.model.Identifiable;
......@@ -24,16 +34,6 @@ import org.bonitasoft.web.designer.utils.rule.TestResource;
import org.junit.Rule;
import org.junit.Test;
import java.util.ArrayList;
import static org.apache.commons.io.IOUtils.toByteArray;
import static org.assertj.core.api.Assertions.assertThat;
import static org.bonitasoft.web.designer.builder.PageBuilder.aFilledPage;
import static org.bonitasoft.web.designer.builder.PageBuilder.aPage;
import static org.bonitasoft.web.designer.builder.WidgetBuilder.aWidget;
import static org.bonitasoft.web.designer.utils.ListUtil.asList;
import static org.skyscreamer.jsonassert.JSONAssert.assertEquals;
public class WidgetTest {
@Rule
......@@ -42,7 +42,7 @@ public class WidgetTest {
private ObjectMapper objectMapper = new DesignerConfig().objectMapper();
@Test
public void jsonview_light_should_only_manage_id_name_and_light_page() throws Exception {
public void jsonview_light_should_only_manage_id_name_hasValidationError_and_light_page() throws Exception {
String json = objectMapper.writerWithView(JsonViewLight.class).writeValueAsString(createAFilledWidget());
assertEquals(json, "{"
......@@ -57,7 +57,8 @@ public class WidgetTest {
+ "\"uuid\":\"UUID\","
+ "\"name\":\"myPage\","
+ "\"type\":\"page\","
+ "\"favorite\": false"
+ "\"favorite\": false,"
+ "\"hasValidationError\": false"
+ "}],"
+ "\"widget\":[{"
+ "\"id\":\"ID\","
......
......@@ -22,12 +22,18 @@
.factory('formRepo', pageRepository)
.factory('layoutRepo', pageRepository);
function pageRepository(Repository) {
function pageRepository(Repository, componentUtils) {
class PageRepository extends Repository {
constructor() {
super('page', 'rest/pages');
}
save(artifact) {
artifact.hasValidationError = componentUtils.hasModalContainingModal(artifact);
return super.save(artifact);
}
/**
* Renames a page and returns a promise
* @param id - the page's id
......
......@@ -67,7 +67,7 @@ angular.module('bonitasoft.designer.editor.whiteboard').controller('ContainerDir
// If you are trying to dragAndDrop a widget already defined
if (data.$$widget) {
if (!componentUtils.isMovable(data, $scope.component || $scope.container)) {
if (!componentUtils.isMovable(data, $scope.component || $scope.container)) {
return;
}
$scope.editor.selectRow($scope.container, row);
......@@ -106,8 +106,7 @@ angular.module('bonitasoft.designer.editor.whiteboard').controller('ContainerDir
return container && container.propertyValues && container.propertyValues.repeatedCollection && container.propertyValues.repeatedCollection.value;
};
$scope.hasModalContainingModal = function(container) {
$scope.hasModalContainingModal = function(container) {
return componentUtils.hasModalContainingModal(container) && container.type === 'modalContainer';
};
});
......@@ -15,7 +15,7 @@
</div>
<div ng-repeat="component in row" class="component" ng-class="editor.componentClasses(component)" bo-draggable bo-draggable-data="component" bo-drop-item="dropItem($data, row, rowIndex)">
<i ng-if="hasModalContainingModal(component)" class="fa fa-times-circle Component-marker" style="color:red;" title="{{ 'A modal container cannot contain another modal container.' | translate }}"></i>
<i ng-if="hasModalContainingModal(component)" class="fa fa-times-circle Component-marker error-icon" title="{{ 'A modal container cannot contain another modal container.' | translate }}"></i>
<div ng-include="component.$$templateUrl" ng-class="{'error':hasModalContainingModal(component)}"></div>
</div>
......
......@@ -32,7 +32,8 @@
'Export': this.gettextCatalog.getString('Export'),
'Rename': this.gettextCatalog.getString('Rename'),
'Last Update:': this.gettextCatalog.getString('Last Update:'),
'In folder:': this.gettextCatalog.getString('In folder ')
'In folder:': this.gettextCatalog.getString('In folder:'),
'Validation error. Fix is recommended before export': this.gettextCatalog.getString('Validation error. Fix is recommended before export')
}[key] || key;
}
......
......@@ -9,21 +9,28 @@
<div class="Artifact-info" ng-switch="artifactList.isInEditionMode($index)">
<a ng-switch-default ng-href="{{:: artifact.editionUrl }}"
class="Artifact-link Artifact-link--primary">
<span ng-if="artifact.icon" class="Artifact-icon"><identicon name="{{artifact.id}}" size="25" foreground-color="[198, 199, 228, 255]" background-color="[0,0,0,0]"></identicon></span>
<span ng-if="artifact.icon" class="Artifact-icon"><identicon name="{{artifact.id}}" size="25"
foreground-color="[198, 199, 228, 255]"
background-color="[0,0,0,0]">
</identicon>
<i ng-if="artifact.hasValidationError" class="fa identicon-error-overlay"></i>
</span>
<i ng-if="!artifact.icon" class="ui-icon ui-{{:: artifact.type }}s Artifact-icon"
uib-tooltip="{{:: artifact.type }}"
uib-tooltip="{{::!artifact.hasValidationError ? artifact.type : artifactList.translateKeys('Validation error. Fix is recommended before export')}}"
tooltip-popup-delay="500">
<i ng-if="artifact.hasValidationError" class="fa error-overlay"></i>
</i>
<span class="Artifact-text">
<span class="Artifact-name"
uib-tooltip-template="'js/home/artifact-list/artifact-tooltip-template.html'"
tooltip-popup-delay="500"
tooltip-placement="top-left">{{artifact.name}}</span>
tooltip-placement="top-left">{{artifact.name}}
</span>
<span class="Artifact-metadata"
>{{:: artifactList.translateKeys('Last Update:') }} {{:: artifact.lastUpdate | date:'short' }}</span>
</span>
</a>
<form name="renameArtifact" class="Artifact-form"
ng-switch-when="true"
ng-submit="artifactList.renameItem(artifact)"
......
......@@ -151,3 +151,19 @@
content: "\f005";
}
}
.error-overlay:before {
content: "\f057";
color: @btn-bonita-primary-bg;
position: absolute;
font-size: 15px;
transform: translate(-100%, -180%);
}
.identicon-error-overlay:before {
content: "\f057";
color: @btn-bonita-primary-bg;
position: absolute;
font-size: 15px;
transform: translate(-100%, -95%);
}
@import "theme-colour";
@widget-active-color: #1E90FF;
@widget-hover-color: #87CEFA;
@widget-active-background: #ecf7ff;
......@@ -120,7 +122,7 @@
.error {
.modal-element,
.fragment-element{
border-color: red;
border-color: @btn-bonita-primary-bg;
}
}
......@@ -240,3 +242,7 @@
.component-element--selected .Component-marker {
color: @widget-active-color;
}
.error-icon {
color: @btn-bonita-primary-bg;
}
describe('pageRepo', function() {
var $rootScope, pageRepo, $httpBackend;
var $rootScope, pageRepo, $httpBackend, _componentUtils;
var json = {
id: 'person',
'rows': []
};
beforeEach(angular.mock.module('bonitasoft.designer.common.repositories'));
beforeEach(inject(function(_$rootScope_, $q, _pageRepo_, _$httpBackend_) {
beforeEach(angular.mock.module('bonitasoft.designer.common.repositories', 'bonitasoft.designer.editor.whiteboard'));
beforeEach(inject(function(_$rootScope_, $q, _pageRepo_, _$httpBackend_, componentUtils) {
$rootScope = _$rootScope_;
pageRepo = _pageRepo_;
$httpBackend = _$httpBackend_;
_componentUtils = componentUtils;
}));
it('should list the pages', function() {
......@@ -114,6 +115,96 @@ describe('pageRepo', function() {
$httpBackend.flush();
});
it('should verify if the page is valid on save',function() {
// given a page
let page = {
type: 'page',
name: 'page1',
id: 'page-id-1',
hasValidationError: false,
rows: [[]]
};
// when we save the page
pageRepo.save(page);
// then we should not have a validation error
expect(page.hasValidationError).toBe(false);
// when we add a modal container
page.rows[0].push(
{
$$id: 'pbModalContainer-1',
type: 'modalContainer',
id: 'pbModalContainer',
container: {
$$id: 'pbContainer-1',
rows: [[]]
}
}
);
// when we save the page
pageRepo.save(page);
// then we should not have a validation error
expect(page.hasValidationError).toBe(false);
// when we add a modal container beside the other modal container
page.rows[0].push(
{
$$id: 'pbModalContainer-2',
type: 'modalContainer',
id: 'pbModalContainer',
container: {
$$id: 'pbContainer-2',
rows: [[]]
}
}
);
// when we save the page
pageRepo.save(page);
// then we should not have a validation error
expect(page.hasValidationError).toBe(false);
// when we add a modal container inside a modal container
page.rows[0][0].container.rows[0].push(
{
$$id: 'pbModalContainer-3',
type: 'modalContainer',
id: 'pbModalContainer',
container: {
$$id: 'pbContainer-3',
rows: [[]]
}
}
);
// when we save the page
pageRepo.save(page);
// then we should have a validation error
expect(page.hasValidationError).toBe(true);
// when we add a modal container inside a modal container that is inside a modal container
page.rows[0][0].container.rows[0][0].container.rows[0].push(
{
$$id: 'pbModalContainer-4',
type: 'modalContainer',
id: 'pbModalContainer',
container: {
$$id: 'pbContainer-4',
rows: [[]]
}
}
);
//when we save the page
pageRepo.save(page);
// then the page should stay invalid
expect(page.hasValidationError).toBe(true);
// when we add a remove the modal container that creates the problem
page.rows[0][0].container.rows[0] = [];
//when we save the page
pageRepo.save(page);
// then the page should be valid
expect(page.hasValidationError).toBe(false);
});
it('should compute page export url', function() {
var page = { id: 'aPageId' };
......
......@@ -2,7 +2,7 @@ describe('repositories service', () => {
var repositories, pageRepo, widgetRepo;
beforeEach(angular.mock.module('bonitasoft.designer.common.repositories'));
beforeEach(angular.mock.module('bonitasoft.designer.common.repositories', 'bonitasoft.designer.editor.whiteboard'));
beforeEach(inject(function(_repositories_, _pageRepo_, _widgetRepo_) {
repositories = _repositories_;
......
......@@ -4,7 +4,7 @@
var $scope, repository, $q, $location, $uibModal, gettextCatalog;
beforeEach(angular.mock.module('bonitasoft.designer.editor.bottom-panel.data-panel'));
beforeEach(angular.mock.module('bonitasoft.designer.editor.bottom-panel.data-panel', 'bonitasoft.designer.editor.whiteboard'));
beforeEach(inject(function($rootScope, $controller, _$location_, _pageRepo_, _$q_, _$uibModal_, _gettextCatalog_) {
$scope = $rootScope.$new();
......
......@@ -5,7 +5,7 @@
describe('Menu bar controller', function() {
var pageRepo, scope, controller, $q, $window, $uibModal, modalInstance, $stateParams, $state, $localStorage, browserHistoryService;
beforeEach(angular.mock.module('bonitasoft.designer.editor.header', 'mock.modal'));
beforeEach(angular.mock.module('bonitasoft.designer.editor.header', 'mock.modal', 'bonitasoft.designer.editor.whiteboard'));
beforeEach(inject(function($rootScope, $controller, _pageRepo_, _$q_, _$uibModal_, _$localStorage_, $uibModalInstance, _$state_, _browserHistoryService_) {
pageRepo = _pageRepo_;
......
describe('artifactListController', function() {
beforeEach(angular.mock.module('bonitasoft.designer.common.repositories', 'bonitasoft.designer.home'));
beforeEach(angular.mock.module('bonitasoft.designer.common.repositories', 'bonitasoft.designer.home', 'bonitasoft.designer.editor.whiteboard'));
var $scope, $q, $uibModal, $localStorage, pageRepo, widgetRepo, $state, $timeout, $httpBackend, element;
......
......@@ -3,7 +3,7 @@ describe('HomeCtrl', function() {
var pages = [{ id: 'page1', name: 'Page 1' }];
var widgets = [{ id: 'widget1', name: 'Widget 1', custom: true }];
beforeEach(angular.mock.module('bonitasoft.designer.home'));
beforeEach(angular.mock.module('bonitasoft.designer.home', 'bonitasoft.designer.editor.whiteboard'));
beforeEach(inject(function($injector) {
$q = $injector.get('$q');
......
......@@ -2,7 +2,7 @@ describe('favorite button', function() {
var $scope, element, artifact, controller, pageRepo;
beforeEach(angular.mock.module('bonitasoft.designer.home'));
beforeEach(angular.mock.module('bonitasoft.designer.home', 'bonitasoft.designer.editor.whiteboard'));
beforeEach(inject(function($compile, $rootScope, _pageRepo_) {
$scope = $rootScope.$new();
......
......@@ -12,7 +12,7 @@ describe('HomeCtrl', function() {
var artifacts = [...pages, ...widgets];
beforeEach(angular.mock.module('bonitasoft.designer.home'));
beforeEach(angular.mock.module('bonitasoft.designer.home', 'bonitasoft.designer.editor.whiteboard'));
beforeEach(inject(function($controller, $rootScope, $injector, $state) {
$scope = $rootScope.$new();
$q = $injector.get('$q');
......
describe('PreviewCtrl', function() {
var ctrl, $scope, $q, $location, iframeParameters, webSocket, pageRequest, pageRepo, clock, $timeout, $log, $window;
beforeEach(angular.mock.module('bonitasoft.designer.preview', 'mock.webSocket'));
beforeEach(angular.mock.module('bonitasoft.designer.preview', 'mock.webSocket', 'bonitasoft.designer.editor.whiteboard'));
beforeEach(inject(function($injector, _webSocket_) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment