Remove dependency to Vaadin addon tokenfield (#875)

* Removed vaadin Tokenfield dependency

Implemented own Tokenfield, but not finished yet. This branch is not
intended to be merged!!!

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* added Combobox and get it running

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* Fixed remaining problems, added Combobox for tag selection

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* fixed permission check

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* fixed tag update

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* Changed Tag assignment in details tab

Removed assign button and assign a tag when it is selected. In tables
only refreshFilter when necessary.

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* fixed Bulkupload

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* Making Sonar happy

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* Making Sonar happy

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* Fixed Bug in DistTokenfield and sorted Tags in Tag list

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* Making Sonar happy

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* Fixed Sonar issues

Signed-off-by: Markus Block <markus.block@bosch-si.com>

* Implemented code review remarks

Signed-off-by: Markus Block <markus.block@bosch-si.com>
This commit is contained in:
Markus Block
2019-08-13 11:19:19 +02:00
committed by Dominic Schabel
parent 275c6a5b2e
commit 2b5b8b4a63
33 changed files with 887 additions and 538 deletions

View File

@@ -214,10 +214,6 @@
<groupId>org.vaadin.addons</groupId> <groupId>org.vaadin.addons</groupId>
<artifactId>flexibleoptiongroup</artifactId> <artifactId>flexibleoptiongroup</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.vaadin.addons</groupId>
<artifactId>tokenfield</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.vaadin.alump.distributionbar</groupId> <groupId>org.vaadin.alump.distributionbar</groupId>
<artifactId>dbar-addon</artifactId> <artifactId>dbar-addon</artifactId>

View File

@@ -18,7 +18,7 @@
<inherits name="org.vaadin.hene.flexibleoptiongroup.widgetset.FlexibleOptionGroupWidgetset" /> <inherits name="org.vaadin.hene.flexibleoptiongroup.widgetset.FlexibleOptionGroupWidgetset" />
<inherits name="org.vaadin.tokenfield.TokenfieldWidgetset" />
<inherits name="org.vaadin.alump.distributionbar.gwt.DistributionBarWidgetset" /> <inherits name="org.vaadin.alump.distributionbar.gwt.DistributionBarWidgetset" />

View File

@@ -158,7 +158,7 @@ public abstract class AbstractTableDetailsLayout<T extends NamedEntity> extends
if (getSelectedBaseEntity() == null) { if (getSelectedBaseEntity() == null) {
return; return;
} }
getTagsLayout().addComponent(tagToken.getTokenField()); getTagsLayout().addComponent(tagToken.getTagPanel());
} }
protected void populateLog() { protected void populateLog() {

View File

@@ -9,34 +9,25 @@
package org.eclipse.hawkbit.ui.common.tagdetails; package org.eclipse.hawkbit.ui.common.tagdetails;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.model.BaseEntity; import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.ui.SpPermissionChecker; import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType; import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType;
import org.eclipse.hawkbit.ui.common.table.BaseUIEntityEvent; import org.eclipse.hawkbit.ui.common.table.BaseUIEntityEvent;
import org.eclipse.hawkbit.ui.common.tagdetails.TagPanelLayout.TagAssignmentListener;
import org.eclipse.hawkbit.ui.management.state.ManagementUIState; import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UINotification; import org.eclipse.hawkbit.ui.utils.UINotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.hateoas.Identifiable;
import org.springframework.util.CollectionUtils;
import org.vaadin.spring.events.EventBus; import org.vaadin.spring.events.EventBus;
import org.vaadin.spring.events.EventBus.UIEventBus; import org.vaadin.spring.events.EventBus.UIEventBus;
import org.vaadin.tokenfield.TokenField;
import org.vaadin.tokenfield.TokenField.InsertPosition;
import com.vaadin.data.Container;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.server.FontAwesome;
import com.vaadin.shared.ui.combobox.FilteringMode;
import com.vaadin.ui.Button;
import com.vaadin.ui.CssLayout;
import com.vaadin.ui.UI; import com.vaadin.ui.UI;
import com.vaadin.ui.themes.ValoTheme;
/** /**
* Abstract class for target/ds tag token layout. * Abstract class for target/ds tag token layout.
@@ -44,25 +35,16 @@ import com.vaadin.ui.themes.ValoTheme;
* @param <T> * @param <T>
* the special entity * the special entity
*/ */
public abstract class AbstractTagToken<T extends BaseEntity> implements Serializable { public abstract class AbstractTagToken<T extends BaseEntity> implements Serializable, TagAssignmentListener {
private static final String ID_PROPERTY = "id"; protected static final int MAX_TAG_QUERY = 1000;
private static final String NAME_PROPERTY = "name";
private static final String COLOR_PROPERTY = "color";
protected static final int MAX_TAG_QUERY = 500;
private static final long serialVersionUID = 6599386705285184783L; private static final long serialVersionUID = 6599386705285184783L;
protected TokenField tokenField; protected TagPanelLayout tagPanelLayout;
protected IndexedContainer container; protected final transient Map<Long, TagData> tagDetailsById = new ConcurrentHashMap<>();
protected final transient Map<String, TagData> tagDetailsByName = new ConcurrentHashMap<>();
protected final transient Map<Long, TagData> tagDetails = new ConcurrentHashMap<>();
protected final transient Map<Long, TagData> tokensAdded = new HashMap<>();
protected CssLayout tokenLayout = new CssLayout();
protected SpPermissionChecker checker; protected SpPermissionChecker checker;
@@ -86,8 +68,7 @@ public abstract class AbstractTagToken<T extends BaseEntity> implements Serializ
this.uinotification = uinotification; this.uinotification = uinotification;
this.eventBus = eventBus; this.eventBus = eventBus;
this.managementUIState = managementUIState; this.managementUIState = managementUIState;
createTokenField(); createTagPanel();
checkIfTagAssignedIsAllowed();
if (doSubscribeToEventBus()) { if (doSubscribeToEventBus()) {
eventBus.subscribe(this); eventBus.subscribe(this);
} }
@@ -110,267 +91,91 @@ public abstract class AbstractTagToken<T extends BaseEntity> implements Serializ
final T entity = baseEntityEvent.getEntity(); final T entity = baseEntityEvent.getEntity();
if (entity != null) { if (entity != null) {
selectedEntity = entity; selectedEntity = entity;
repopulateToken(); repopulateTags();
} }
}); });
} }
private void createTokenField() { private void createTagPanel() {
final Container tokenContainer = createContainer(); tagPanelLayout = new TagPanelLayout(i18n, !isToggleTagAssignmentAllowed());
tokenField = createTokenField(tokenContainer); tagPanelLayout.addTagAssignmentListener(this);
tokenField.setContainerDataSource(tokenContainer); tagPanelLayout.setSizeFull();
tokenField.setNewTokensAllowed(false);
tokenField.setFilteringMode(FilteringMode.CONTAINS);
tokenField.setInputPrompt(getTokenInputPrompt());
tokenField.setTokenInsertPosition(InsertPosition.AFTER);
tokenField.setImmediate(true);
tokenField.addStyleName(ValoTheme.COMBOBOX_TINY);
tokenField.setSizeFull();
tokenField.setTokenCaptionPropertyId(NAME_PROPERTY);
} }
protected void repopulateToken() { protected void repopulateTags() {
populateContainer(); tagDetailsById.clear();
displayAlreadyAssignedTags(); tagDetailsByName.clear();
final List<TagData> allAssignableTags = getAllTags();
allAssignableTags.forEach(tagData -> {
tagDetailsByName.put(tagData.getName(), tagData);
tagDetailsById.put(tagData.getId(), tagData);
});
tagPanelLayout.initializeTags(allAssignableTags, getAssignedTags());
} }
private Container createContainer() { protected void tagCreated(final TagData tagData) {
container = new IndexedContainer(); tagDetailsByName.put(tagData.getName(), tagData);
container.addContainerProperty(NAME_PROPERTY, String.class, ""); tagDetailsById.put(tagData.getId(), tagData);
container.addContainerProperty(ID_PROPERTY, Long.class, "");
container.addContainerProperty(COLOR_PROPERTY, String.class, ""); tagPanelLayout.tagCreated(tagData);
return container;
} }
protected void addNewToken(final Long tagId) { protected void tagDeleted(final Long id) {
tokenField.addToken(tagId); final TagData tagData = tagDetailsById.get(id);
removeTagAssignedFromCombo(tagId); if (tagData != null) {
} tagPanelLayout.tagDeleted(tagData);
private void removeTagAssignedFromCombo(final Long tagId) { tagDetailsByName.remove(tagData.getName());
// might not yet exist or not anymore due to unprocessed events tagDetailsById.remove(id);
final Item item = tokenField.getContainerDataSource().getItem(tagId);
if (item == null) {
return;
}
tokensAdded.put(tagId, new TagData(tagId, getTagName(item), getColor(item)));
container.removeItem(tagId);
}
protected void setContainerPropertValues(final Long tagId, final String tagName, final String tagColor) {
final TagData tagData = tagDetails.putIfAbsent(tagId, new TagData(tagId, tagName, tagColor));
if (tagData == null) {
final Item item = container.addItem(tagId);
if (item == null) {
return;
}
item.getItemProperty(ID_PROPERTY).setValue(tagId);
updateItem(tagName, tagColor, item);
} }
} }
protected void updateItem(final String tagName, final String tagColor, final Item item) { @Override
item.getItemProperty(NAME_PROPERTY).setValue(tagName); public void assignTag(final String tagName) {
item.getItemProperty(COLOR_PROPERTY).setValue(tagColor); final TagData tagData = tagDetailsByName.get(tagName);
} if (tagData != null) {
assignTag(tagData);
protected void checkIfTagAssignedIsAllowed() {
if (!isToggleTagAssignmentAllowed()) {
tokenField.addStyleName("hideTokenFieldcombo");
} }
} }
private TokenField createTokenField(final Container tokenContainer) { @Override
return new CustomTokenField(tokenLayout, tokenContainer); public void unassignTag(final String tagName) {
final TagData tagData = tagDetailsByName.get(tagName);
if (tagData != null) {
unassignTag(tagData);
}
} }
class CustomTokenField extends TokenField { protected abstract void assignTag(TagData tagData);
private static final long serialVersionUID = 694216966472937436L;
Container tokenContainer; protected abstract void unassignTag(TagData tagData);
CustomTokenField(final CssLayout cssLayout, final Container tokenContainer) { protected boolean checkAssignmentResult(final List<? extends Identifiable<Long>> assignedEntities,
super(cssLayout); final Long expectedAssignedEntityId) {
this.tokenContainer = tokenContainer; if (!CollectionUtils.isEmpty(assignedEntities) && expectedAssignedEntityId != null) {
} final List<Long> assignedDsIds = assignedEntities.stream().map(Identifiable::getId)
.collect(Collectors.toList());
@Override if (assignedDsIds.contains(expectedAssignedEntityId)) {
protected void configureTokenButton(final Object tokenId, final Button button) { return true;
super.configureTokenButton(tokenId, button);
updateTokenStyle(tokenId, button);
button.addStyleName(SPUIDefinitions.TEXT_STYLE + " " + SPUIStyleDefinitions.DETAILS_LAYOUT_STYLE);
}
@Override
protected void onTokenInput(final Object tokenId) {
super.addToken(tokenId);
onTokenSearch(tokenId);
}
@Override
protected void onTokenClick(final Object tokenId) {
if (isToggleTagAssignmentAllowed()) {
super.onTokenClick(tokenId);
tokenClick(tokenId);
} }
} }
return false;
private void updateTokenStyle(final Object tokenId, final Button button) {
final Item item = tokenField.getContainerDataSource().getItem(tokenId);
if (item == null) {
return;
}
final String color = getColor(item);
button.setCaption("<span style=\"color:" + color + " !important;\">" + FontAwesome.CIRCLE.getHtml()
+ "</span>" + " " + getItemNameProperty(tokenId).getValue().toString().concat(" ×"));
button.setCaptionAsHtml(true);
}
private void onTokenSearch(final Object tokenId) {
assignTag(getItemNameProperty(tokenId).getValue().toString());
removeTagAssignedFromCombo((Long) tokenId);
}
private void tokenClick(final Object tokenId) {
final Item item = tokenField.getContainerDataSource().addItem(tokenId);
item.getItemProperty(NAME_PROPERTY).setValue(tagDetails.get(tokenId).getName());
item.getItemProperty(COLOR_PROPERTY).setValue(tagDetails.get(tokenId).getColor());
unassignTag(tagDetails.get(tokenId).getName());
}
private Property getItemNameProperty(final Object tokenId) {
final Item item = tokenField.getContainerDataSource().getItem(tokenId);
return item.getItemProperty(NAME_PROPERTY);
}
} }
private static String getColor(final Item item) { protected boolean checkUnassignmentResult(final Identifiable<Long> unAssignedEntity,
if (item.getItemProperty(COLOR_PROPERTY).getValue() != null) { final Long expectedUnAssignedEntityId) {
return (String) item.getItemProperty(COLOR_PROPERTY).getValue(); return unAssignedEntity != null && expectedUnAssignedEntityId != null
} else { && unAssignedEntity.getId().equals(expectedUnAssignedEntityId);
return SPUIDefinitions.DEFAULT_COLOR;
}
} }
private static String getTagName(final Item item) {
return (String) item.getItemProperty(NAME_PROPERTY).getValue();
}
protected void removePreviouslyAddedTokens() {
tokensAdded.keySet().forEach(previouslyAddedToken -> tokenField.removeToken(previouslyAddedToken));
}
protected Long getTagIdByTagName(final Long tagId) {
return tagDetails.entrySet().stream().filter(entry -> entry.getValue().getId().equals(tagId)).findAny()
.map(entry -> entry.getKey()).orElse(null);
}
protected void removeTokenItem(final Long tokenId, final String name) {
tokenField.removeToken(tokenId);
tagDetails.remove(tokenId);
setContainerPropertValues(tokenId, name, tokensAdded.get(tokenId).getColor());
}
protected void removeTagFromCombo(final Long deletedTagId) {
if (deletedTagId != null) {
container.removeItem(deletedTagId);
}
}
protected abstract String getTagStyleName();
protected abstract String getTokenInputPrompt();
protected abstract void assignTag(final String tagNameSelected);
protected abstract void unassignTag(final String tagName);
protected abstract Boolean isToggleTagAssignmentAllowed(); protected abstract Boolean isToggleTagAssignmentAllowed();
protected abstract void displayAlreadyAssignedTags(); protected abstract List<TagData> getAllTags();
protected abstract void populateContainer(); protected abstract List<TagData> getAssignedTags();
public TokenField getTokenField() {
return tokenField;
}
/**
* Tag details.
*
*/
public static class TagData implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private Long id;
private String color;
/**
* Tag data constructor.
*
* @param id
* @param name
* @param color
*/
public TagData(final Long id, final String name, final String color) {
this.color = color;
this.id = id;
this.name = name;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name
* the name to set
*/
public void setName(final String name) {
this.name = name;
}
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @param id
* the id to set
*/
public void setId(final Long id) {
this.id = id;
}
/**
* @return the color
*/
public String getColor() {
return color;
}
/**
* @param color
* the color to set
*/
public void setColor(final String color) {
this.color = color;
}
public TagPanelLayout getTagPanel() {
return tagPanelLayout;
} }
} }

View File

@@ -12,10 +12,12 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
import org.eclipse.hawkbit.repository.TargetTagManagement; import org.eclipse.hawkbit.repository.TargetTagManagement;
import org.eclipse.hawkbit.repository.event.remote.TargetTagDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagCreatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagUpdatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.TargetTagUpdatedEvent;
import org.eclipse.hawkbit.repository.model.BaseEntity; import org.eclipse.hawkbit.repository.model.BaseEntity;
import org.eclipse.hawkbit.ui.SpPermissionChecker; import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.management.event.TargetTagTableEvent;
import org.eclipse.hawkbit.ui.management.state.ManagementUIState; import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
import org.eclipse.hawkbit.ui.push.TargetTagCreatedEventContainer; import org.eclipse.hawkbit.ui.push.TargetTagCreatedEventContainer;
import org.eclipse.hawkbit.ui.push.TargetTagDeletedEventContainer; import org.eclipse.hawkbit.ui.push.TargetTagDeletedEventContainer;
@@ -25,8 +27,6 @@ import org.vaadin.spring.events.EventBus.UIEventBus;
import org.vaadin.spring.events.EventScope; import org.vaadin.spring.events.EventScope;
import org.vaadin.spring.events.annotation.EventBusListenerMethod; import org.vaadin.spring.events.annotation.EventBusListenerMethod;
import com.vaadin.data.Item;
/** /**
* /** Abstract class for target tag token layout. * /** Abstract class for target tag token layout.
* *
@@ -49,23 +49,24 @@ public abstract class AbstractTargetTagToken<T extends BaseEntity> extends Abstr
@EventBusListenerMethod(scope = EventScope.UI) @EventBusListenerMethod(scope = EventScope.UI)
void onEventTargetTagCreated(final TargetTagCreatedEventContainer container) { void onEventTargetTagCreated(final TargetTagCreatedEventContainer container) {
container.getEvents().stream().filter(Objects::nonNull).map(TargetTagCreatedEvent::getEntity) container.getEvents().stream().filter(Objects::nonNull).map(TargetTagCreatedEvent::getEntity)
.forEach(tag -> setContainerPropertValues(tag.getId(), tag.getName(), tag.getColour())); .forEach(tag -> tagCreated(new TagData(tag.getId(), tag.getName(), tag.getColour())));
} }
@EventBusListenerMethod(scope = EventScope.UI) @EventBusListenerMethod(scope = EventScope.UI)
void onTargetTagDeletedEvent(final TargetTagDeletedEventContainer container) { void onTargetTagDeletedEvent(final TargetTagDeletedEventContainer container) {
container.getEvents().stream().map(event -> getTagIdByTagName(event.getEntityId())) container.getEvents().stream().filter(Objects::nonNull).map(TargetTagDeletedEvent::getEntityId)
.forEach(this::removeTagFromCombo); .forEach(this::tagDeleted);
} }
@EventBusListenerMethod(scope = EventScope.UI) @EventBusListenerMethod(scope = EventScope.UI)
void onTargetTagUpdateEvent(final List<TargetTagUpdatedEvent> events) { void onTargetTagUpdateEvent(final List<TargetTagUpdatedEvent> events) {
events.stream().map(TargetTagUpdatedEvent::getEntity).forEach(entity -> { repopulateTags();
final Item item = container.getItem(entity.getId());
if (item != null) { }
updateItem(entity.getName(), entity.getColour(), item);
} @EventBusListenerMethod(scope = EventScope.UI)
}); void onTargetTagUpdateEvent(final TargetTagTableEvent event) {
repopulateTags();
} }
} }

View File

@@ -8,6 +8,7 @@
*/ */
package org.eclipse.hawkbit.ui.common.tagdetails; package org.eclipse.hawkbit.ui.common.tagdetails;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -15,18 +16,15 @@ import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.DistributionSetManagement; import org.eclipse.hawkbit.repository.DistributionSetManagement;
import org.eclipse.hawkbit.repository.DistributionSetTagManagement; import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagCreatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetTagUpdatedEvent;
import org.eclipse.hawkbit.repository.model.DistributionSet; import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult;
import org.eclipse.hawkbit.ui.SpPermissionChecker; import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.management.event.DistributionSetTagTableEvent;
import org.eclipse.hawkbit.ui.management.event.DistributionTableEvent; import org.eclipse.hawkbit.ui.management.event.DistributionTableEvent;
import org.eclipse.hawkbit.ui.management.event.ManagementUIEvent; import org.eclipse.hawkbit.ui.management.event.ManagementUIEvent;
import org.eclipse.hawkbit.ui.management.state.ManagementUIState; import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
import org.eclipse.hawkbit.ui.push.DistributionSetTagCreatedEventContainer; import org.eclipse.hawkbit.ui.push.DistributionSetTagCreatedEventContainer;
import org.eclipse.hawkbit.ui.push.DistributionSetTagDeletedEventContainer; import org.eclipse.hawkbit.ui.push.DistributionSetTagDeletedEventContainer;
import org.eclipse.hawkbit.ui.push.DistributionSetTagUpdatedEventContainer; import org.eclipse.hawkbit.ui.push.DistributionSetTagUpdatedEventContainer;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.UINotification; import org.eclipse.hawkbit.ui.utils.UINotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
@@ -35,7 +33,6 @@ import org.vaadin.spring.events.EventScope;
import org.vaadin.spring.events.annotation.EventBusListenerMethod; import org.vaadin.spring.events.annotation.EventBusListenerMethod;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.vaadin.data.Item;
/** /**
* Implementation of target/ds tag token layout. * Implementation of target/ds tag token layout.
@@ -49,9 +46,6 @@ public class DistributionTagToken extends AbstractTagToken<DistributionSet> {
private final transient DistributionSetManagement distributionSetManagement; private final transient DistributionSetManagement distributionSetManagement;
// To Be Done : have to set this value based on view???
private static final Boolean NOTAGS_SELECTED = Boolean.FALSE;
public DistributionTagToken(final SpPermissionChecker checker, final VaadinMessageSource i18n, public DistributionTagToken(final SpPermissionChecker checker, final VaadinMessageSource i18n,
final UINotification uinotification, final UIEventBus eventBus, final ManagementUIState managementUIState, final UINotification uinotification, final UIEventBus eventBus, final ManagementUIState managementUIState,
final DistributionSetTagManagement distributionSetTagManagement, final DistributionSetTagManagement distributionSetTagManagement,
@@ -62,40 +56,26 @@ public class DistributionTagToken extends AbstractTagToken<DistributionSet> {
} }
@Override @Override
protected String getTagStyleName() { protected void assignTag(final TagData tagData) {
return "distribution-tag-"; final List<DistributionSet> assignedDistributionSets = distributionSetManagement
} .assignTag(Sets.newHashSet(selectedEntity.getId()), tagData.getId());
if (checkAssignmentResult(assignedDistributionSets, managementUIState.getLastSelectedDsIdName())) {
@Override uinotification.displaySuccess(
protected String getTokenInputPrompt() { i18n.getMessage("message.target.assigned.one", selectedEntity.getName(), tagData.getName()));
return i18n.getMessage("combo.type.tag.name"); eventBus.publish(this, ManagementUIEvent.ASSIGN_DISTRIBUTION_TAG);
} tagPanelLayout.setAssignedTag(tagData);
@Override
protected void assignTag(final String tagNameSelected) {
if (tagNameSelected != null) {
final DistributionSetTagAssignmentResult result = toggleAssignment(tagNameSelected);
if (result.getAssigned() >= 1 && NOTAGS_SELECTED) {
eventBus.publish(this, ManagementUIEvent.ASSIGN_DISTRIBUTION_TAG);
}
} else {
uinotification.displayValidationError(i18n.getMessage("message.error.missing.tagname"));
} }
} }
private DistributionSetTagAssignmentResult toggleAssignment(final String tagNameSelected) {
final DistributionSetTagAssignmentResult result = distributionSetManagement
.toggleTagAssignment(Sets.newHashSet(selectedEntity.getId()), tagNameSelected);
processTargetTagAssigmentResult(result);
uinotification.displaySuccess(HawkbitCommonUtil.createAssignmentMessage(tagNameSelected, result, i18n));
return result;
}
@Override @Override
protected void unassignTag(final String tagName) { protected void unassignTag(final TagData tagData) {
final DistributionSetTagAssignmentResult result = toggleAssignment(tagName); final DistributionSet unAssignedDistributionSet = distributionSetManagement.unAssignTag(selectedEntity.getId(),
if (result.getUnassigned() >= 1) { tagData.getId());
if (checkUnassignmentResult(unAssignedDistributionSet, managementUIState.getLastSelectedDsIdName())) {
uinotification.displaySuccess(
i18n.getMessage("message.target.unassigned.one", selectedEntity.getName(), tagData.getName()));
eventBus.publish(this, ManagementUIEvent.UNASSIGN_DISTRIBUTION_TAG); eventBus.publish(this, ManagementUIEvent.UNASSIGN_DISTRIBUTION_TAG);
tagPanelLayout.removeAssignedTag(tagData);
} }
} }
@@ -105,21 +85,21 @@ public class DistributionTagToken extends AbstractTagToken<DistributionSet> {
} }
@Override @Override
public void displayAlreadyAssignedTags() { protected List<TagData> getAllTags() {
removePreviouslyAddedTokens(); return distributionSetTagManagement.findAll(PageRequest.of(0, MAX_TAG_QUERY)).getContent().stream()
if (selectedEntity != null) { .map(tag -> new TagData(tag.getId(), tag.getName(), tag.getColour())).collect(Collectors.toList());
distributionSetTagManagement.findByDistributionSet(PageRequest.of(0, MAX_TAG_QUERY), selectedEntity.getId())
.getContent().stream().forEach(tag -> addNewToken(tag.getId()));
}
} }
@Override @Override
protected void populateContainer() { protected List<TagData> getAssignedTags() {
container.removeAllItems(); if (selectedEntity != null) {
tagDetails.clear(); return distributionSetTagManagement
distributionSetTagManagement.findAll(PageRequest.of(0, MAX_TAG_QUERY)).getContent().stream() .findByDistributionSet(PageRequest.of(0, MAX_TAG_QUERY), selectedEntity.getId()).getContent()
.forEach(tag -> setContainerPropertValues(tag.getId(), tag.getName(), tag.getColour())); .stream().map(tag -> new TagData(tag.getId(), tag.getName(), tag.getColour()))
.collect(Collectors.toList());
}
return Collections.emptyList();
} }
@EventBusListenerMethod(scope = EventScope.UI) @EventBusListenerMethod(scope = EventScope.UI)
@@ -128,58 +108,23 @@ public class DistributionTagToken extends AbstractTagToken<DistributionSet> {
} }
@EventBusListenerMethod(scope = EventScope.UI) @EventBusListenerMethod(scope = EventScope.UI)
void onDistributionSetTagCreatedBulkEvent(final DistributionSetTagCreatedEventContainer eventContainer) { void onDistributionSetTagCreatedEvent(final DistributionSetTagCreatedEventContainer eventContainer) {
eventContainer.getEvents().stream().filter(Objects::nonNull).map(DistributionSetTagCreatedEvent::getEntity) eventContainer.getEvents().stream().filter(Objects::nonNull).map(DistributionSetTagCreatedEvent::getEntity)
.forEach(distributionSetTag -> setContainerPropertValues(distributionSetTag.getId(), .forEach(tag -> tagCreated(new TagData(tag.getId(), tag.getName(), tag.getColour())));
distributionSetTag.getName(), distributionSetTag.getColour()));
} }
@EventBusListenerMethod(scope = EventScope.UI) @EventBusListenerMethod(scope = EventScope.UI)
void onDistributionSetTagDeletedEvent(final DistributionSetTagDeletedEventContainer eventContainer) { void onDistributionSetTagDeletedEvent(final DistributionSetTagDeletedEventContainer eventContainer) {
eventContainer.getEvents().stream().map(event -> getTagIdByTagName(event.getEntityId())) eventContainer.getEvents().forEach(event -> tagDeleted(event.getEntityId()));
.forEach(this::removeTagFromCombo);
} }
@EventBusListenerMethod(scope = EventScope.UI) @EventBusListenerMethod(scope = EventScope.UI)
void onDistributionSetTagUpdateEvent(final DistributionSetTagUpdatedEventContainer eventContainer) { void onDistributionSetTagUpdateEvent(final DistributionSetTagUpdatedEventContainer eventContainer) {
eventContainer.getEvents().stream().filter(Objects::nonNull).map(DistributionSetTagUpdatedEvent::getEntity) repopulateTags();
.forEach(entity -> {
final Item item = container.getItem(entity.getId());
if (item != null) {
updateItem(entity.getName(), entity.getColour(), item);
}
});
} }
private void processTargetTagAssigmentResult(final DistributionSetTagAssignmentResult assignmentResult) { @EventBusListenerMethod(scope = EventScope.UI)
final DistributionSetTag tag = assignmentResult.getDistributionSetTag(); void onDistributionSetTagUpdateEvent(final DistributionSetTagTableEvent event) {
if (isAssign(assignmentResult)) { repopulateTags();
addNewToken(tag.getId());
} else if (isUnassign(assignmentResult)) {
removeTokenItem(tag.getId(), tag.getName());
}
} }
protected boolean isAssign(final DistributionSetTagAssignmentResult assignmentResult) {
if (assignmentResult.getAssigned() > 0 && managementUIState.getLastSelectedDsIdName() != null) {
final List<Long> assignedDsNames = assignmentResult.getAssignedEntity().stream().map(t -> t.getId())
.collect(Collectors.toList());
if (assignedDsNames.contains(managementUIState.getLastSelectedDsIdName())) {
return true;
}
}
return false;
}
protected boolean isUnassign(final DistributionSetTagAssignmentResult assignmentResult) {
if (assignmentResult.getUnassigned() > 0 && managementUIState.getLastSelectedDsIdName() != null) {
final List<Long> assignedDsNames = assignmentResult.getUnassignedEntity().stream().map(t -> t.getId())
.collect(Collectors.toList());
if (assignedDsNames.contains(managementUIState.getLastSelectedDsIdName())) {
return true;
}
}
return false;
}
} }

View File

@@ -0,0 +1,170 @@
/**
* Copyright (c) 2019 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.common.tagdetails;
import java.util.List;
import java.util.Set;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.ui.common.builder.ComboBoxBuilder;
import org.eclipse.hawkbit.ui.common.tagdetails.TagPanelLayout.TagAssignmentListener;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.google.common.collect.Sets;
import com.vaadin.data.Item;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.themes.ValoTheme;
/**
* Combobox that lists all available Tags that can be assigned to a
* {@link Target} or {@link DistributionSet}.
*/
public class TagAssignementComboBox extends HorizontalLayout {
private static final long serialVersionUID = 1L;
private static final String NAME_PROPERTY = "name";
private static final String COLOR_PROPERTY = "color";
private final IndexedContainer allAssignableTags;
private final transient Set<TagAssignmentListener> listeners = Sets.newConcurrentHashSet();
private final ComboBox assignableTagsComboBox;
private final boolean readOnlyMode;
/**
* Constructor.
*
* @param i18n
* the i18n
* @param readOnlyMode
* if true the combobox will be disabled so no assignment can be
* done.
*/
TagAssignementComboBox(final VaadinMessageSource i18n, final boolean readOnlyMode) {
this.readOnlyMode = readOnlyMode;
setWidth("100%");
allAssignableTags = new IndexedContainer();
allAssignableTags.addContainerProperty(NAME_PROPERTY, String.class, "");
allAssignableTags.addContainerProperty(COLOR_PROPERTY, String.class, "");
assignableTagsComboBox = new ComboBoxBuilder().setId(UIComponentIdProvider.TAG_SELECTION_ID)
.setPrompt(i18n.getMessage(UIMessageIdProvider.TOOLTIP_SELECT_TAG))
.setValueChangeListener(this::onSelectionChanged).buildCombBox();
addComponent(assignableTagsComboBox);
assignableTagsComboBox.setContainerDataSource(allAssignableTags);
assignableTagsComboBox.setNullSelectionAllowed(true);
assignableTagsComboBox.addStyleName(SPUIStyleDefinitions.DETAILS_LAYOUT_STYLE);
assignableTagsComboBox.addStyleName(ValoTheme.COMBOBOX_TINY);
assignableTagsComboBox.setEnabled(!readOnlyMode);
assignableTagsComboBox.setWidth("100%");
clearComboBoxSelection();
}
/**
* Initializes the Combobox with all assignable tags.
*
* @param assignableTags
* assignable tags
*/
void initializeAssignableTags(final List<TagData> assignableTags) {
assignableTags.forEach(this::addAssignableTag);
}
private void onSelectionChanged(final ValueChangeEvent event) {
final Object selectedValue = event.getProperty().getValue();
if (!isValidTagSelection(selectedValue) || readOnlyMode) {
return;
}
assignTag((String) selectedValue);
}
private void assignTag(final String tagName) {
allAssignableTags.removeItem(tagName);
notifyListenersTagAssigned(tagName);
clearComboBoxSelection();
}
private boolean isValidTagSelection(final Object selectedValue) {
return selectedValue != null && selectedValue != assignableTagsComboBox.getNullSelectionItemId()
&& selectedValue instanceof String;
}
/**
* Removes all Tags from Combobox.
*/
void removeAllTags() {
allAssignableTags.removeAllItems();
clearComboBoxSelection();
}
/**
* Adds an assignable Tag to the combobox.
*
* @param tagData
* the data of the Tag
*/
void addAssignableTag(final TagData tagData) {
final Item item = allAssignableTags.addItem(tagData.getName());
if (item == null) {
return;
}
item.getItemProperty(NAME_PROPERTY).setValue(tagData.getName());
item.getItemProperty(COLOR_PROPERTY).setValue(tagData.getColor());
}
/**
* Removes an assignable tag from the combobox.
*
* @param tagData
* the {@link TagData} of the Tag that should be removed.
*/
void removeAssignableTag(final TagData tagData) {
allAssignableTags.removeItem(tagData.getName());
}
/**
* Registers an {@link TagAssignmentListener} on the combobox.
*
* @param listener
* the listener to register
*/
void addTagAssignmentListener(final TagAssignmentListener listener) {
listeners.add(listener);
}
/**
* Removes a {@link TagAssignmentListener} from the combobox,
*
* @param listener
* the listener that should be removed.
*/
void removeTagAssignmentListener(final TagAssignmentListener listener) {
listeners.remove(listener);
}
private void notifyListenersTagAssigned(final String tagName) {
listeners.forEach(listener -> listener.assignTag(tagName));
}
private void clearComboBoxSelection() {
assignableTagsComboBox.select(assignableTagsComboBox.getNullSelectionItemId());
}
}

View File

@@ -0,0 +1,90 @@
/**
* Copyright (c) 2019 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.common.tagdetails;
import java.io.Serializable;
import java.util.Objects;
import org.eclipse.hawkbit.repository.model.Tag;
import com.google.common.base.MoreObjects;
/**
* Tag details. Represents the ui data for {@link Tag} entity.
*/
public class TagData implements Serializable {
private static final long serialVersionUID = 1L;
private final String name;
private final Long id;
private final String color;
/**
* Tag data constructor.
*
* @param id
* the id of the {@link Tag}
* @param name
* the name of the {@link Tag}
* @param color
* the color of the {@link Tag}
*/
public TagData(final Long id, final String name, final String color) {
this.color = color;
this.id = id;
this.name = name;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @return the color
*/
public String getColor() {
return color;
}
@Override
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final TagData other = (TagData) obj;
return Objects.equals(this.id, other.id) && Objects.equals(this.name, other.name)
&& Objects.equals(this.color, other.color);
}
@Override
public int hashCode() {
return Objects.hash(id, name, color);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("id", id).add("name", name).add("color", color).toString();
}
}

View File

@@ -0,0 +1,170 @@
/**
* Copyright (c) 2019 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.common.tagdetails;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.ui.common.tagdetails.TagPanelLayout.TagAssignmentListener;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.decorators.SPUITagButtonStyle;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.vaadin.server.FontAwesome;
import com.vaadin.ui.Button;
import com.vaadin.ui.CssLayout;
/**
* A panel that shows the assigned tags. A click on a tag unsassigns the tag
* from the {@link Target} or {@link DistributionSet}.
*/
public class TagListField extends CssLayout {
private static final long serialVersionUID = 1L;
private final transient Map<String, Button> tagButtons = Maps.newTreeMap(Ordering.natural());
private final transient Set<TagAssignmentListener> listeners = Sets.newConcurrentHashSet();
private final VaadinMessageSource i18n;
private final boolean readOnlyMode;
/**
* Constructor.
*
* @param i18n
* @param readOnlyMode
* if <code>true</code> no unassignment can be done
*/
TagListField(final VaadinMessageSource i18n, final boolean readOnlyMode) {
this.i18n = i18n;
this.readOnlyMode = readOnlyMode;
setSizeFull();
}
/**
* Initializes the Tag panel with all assigned tags.
*
* @param assignedTags
* assigned tags
*/
void initializeAssignedTags(final List<TagData> assignedTags) {
removeAllComponents();
assignedTags.forEach(tag -> {
final Button tagButton = createButton(tag.getName(), tag.getColor());
tagButtons.put(tag.getName(), tagButton);
});
addTagButtonsAsComponents();
}
/**
* Adds a tag
*
* @param tagName
* @param tagColor
*/
void addTag(final String tagName, final String tagColor) {
if (!tagButtons.containsKey(tagName)) {
removeAllComponents();
final Button tagButton = createButton(tagName, tagColor);
tagButtons.put(tagName, tagButton);
addTagButtonsAsComponents();
}
}
private void addTagButtonsAsComponents() {
tagButtons.keySet().forEach(sortedTagName -> addComponent(tagButtons.get(sortedTagName)));
}
private Button createButton(final String tagName, final String tagColor) {
final Button button = SPUIComponentProvider.getButton(UIComponentIdProvider.ASSIGNED_TAG_ID_PREFIX + tagName,
tagName, i18n.getMessage(UIMessageIdProvider.TOOLTIP_CLICK_TO_REMOVE), null, false, null,
SPUITagButtonStyle.class);
button.addClickListener(e -> removeTagAssignment(tagName));
button.addStyleName(SPUIStyleDefinitions.TAG_BUTTON_WITH_BACKGROUND);
button.addStyleName(SPUIDefinitions.TEXT_STYLE + " " + SPUIStyleDefinitions.DETAILS_LAYOUT_STYLE);
button.setEnabled(!readOnlyMode);
button.setCaption("<span style=\" color:" + tagColor + " !important;\">" + FontAwesome.CIRCLE.getHtml()
+ "</span>" + " " + tagName.concat(" ×"));
button.setCaptionAsHtml(true);
return button;
}
private void removeTagAssignment(final String tagName) {
removeTag(tagName);
notifyListenersTagAssignmentRemoved(tagName);
}
/**
* Removes a tag from the field.
*
* @param tagName
*/
void removeTag(final String tagName) {
final Button button = tagButtons.get(tagName);
if (button != null) {
tagButtons.remove(tagName);
removeComponent(button);
}
}
/**
* Removes all tags from the field.
*/
void removeAllTags() {
removeAllComponents();
tagButtons.clear();
}
/**
* Registers a {@link TagAssignmentListener}.
*
* @param listener
* the listener to register
*/
void addTagAssignmentListener(final TagAssignmentListener listener) {
listeners.add(listener);
}
/**
* Removes a {@link TagAssignmentListener}.
*
* @param listener
* the listener to remove
*/
void removeTagAssignmentListener(final TagAssignmentListener listener) {
listeners.remove(listener);
}
private void notifyListenersTagAssignmentRemoved(final String tagName) {
listeners.forEach(listener -> listener.unassignTag(tagName));
}
/**
* Returns all assigned tags shown in the field.
*
* @return a {@link List} with tags
*/
List<String> getTags() {
return Lists.newArrayList(tagButtons.keySet());
}
}

View File

@@ -0,0 +1,173 @@
/**
* Copyright (c) 2019 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.common.tagdetails;
import java.util.List;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import com.google.common.collect.Lists;
import com.vaadin.ui.VerticalLayout;
/**
* A layout that shows a combobox with available tags that can be assigned to a
* {@link Target} or {@link DistributionSet}. The layout also shows all already
* assigned tags. This tags can also be removed.
*/
public class TagPanelLayout extends VerticalLayout {
private static final long serialVersionUID = 1L;
private final TagListField assignedTagField;
private final TagAssignementComboBox assignableTagsComboBox;
/**
* Constructor.
*
* @param i18n
* i18n
* @param readOnlyMode
* if <code>true</code> no assignments and unassignements can be
* done.
*/
TagPanelLayout(final VaadinMessageSource i18n, final boolean readOnlyMode) {
assignableTagsComboBox = new TagAssignementComboBox(i18n, readOnlyMode);
addComponent(assignableTagsComboBox);
assignedTagField = new TagListField(i18n, readOnlyMode);
addComponent(assignedTagField);
setExpandRatio(assignedTagField, 1.0F);
setExpandRatio(assignableTagsComboBox, 0.0F);
}
/**
* Initializes the panel with all available tags and all assigned tags.
*
* @param allTags
* all tags
* @param assignedTags
* assigned tags
*/
void initializeTags(final List<TagData> allTags, final List<TagData> assignedTags) {
assignableTagsComboBox.removeAllTags();
assignedTagField.removeAllTags();
final List<TagData> assignableTags = Lists.newArrayList(allTags);
assignableTags.removeAll(assignedTags);
assignableTagsComboBox.initializeAssignableTags(assignableTags);
assignedTagField.initializeAssignedTags(assignedTags);
}
/**
* Sets a tag that is assigned.
*
* @param tagData
* the {@link TagData}
*/
public void setAssignedTag(final TagData tagData) {
// the assigned tag is no longer assignable
assignableTagsComboBox.removeAssignableTag(tagData);
// show it as an assigned tag
assignedTagField.addTag(tagData.getName(), tagData.getColor());
}
/**
* Removes an assigned tag.
*
* @param tagData
* the {@link TagData}
*/
public void removeAssignedTag(final TagData tagData) {
// the un-assigned tag is now assignable
assignableTagsComboBox.addAssignableTag(tagData);
// remove ot from the assigned tags
assignedTagField.removeTag(tagData.getName());
}
/**
* Informs the panel that a new tag was created.
*
* @param tagData
* the {@link TagData}
*/
void tagCreated(final TagData tagData) {
assignableTagsComboBox.addAssignableTag(tagData);
}
/**
* Informs the panel that a tag was deleted.
*
* @param tagData
* the {@link TagData}
*/
void tagDeleted(final TagData tagData) {
assignableTagsComboBox.removeAssignableTag(tagData);
assignedTagField.removeTag(tagData.getName());
}
/**
* Callback interface if user triggers a tag assignment or tag unassignment
* via UI controls.
*
*/
interface TagAssignmentListener {
/**
* User triggers a tag assignment.
*
* @param tagName
* the name of the tag that should be assigned.
*/
void assignTag(String tagName);
/**
* User triggers a tag unassignment.
*
* @param tagName
* the name of the tag that should be unassigned.
*/
void unassignTag(String tagName);
}
/**
* Registers a {@link TagAssignmentListener}.
*
* @param listener
* the listener
*/
void addTagAssignmentListener(final TagAssignmentListener listener) {
assignableTagsComboBox.addTagAssignmentListener(listener);
assignedTagField.addTagAssignmentListener(listener);
}
/**
* Removes a {@link TagAssignmentListener}.
*
* @param listener
* the listener
*/
void removeTagAssignmentListener(final TagAssignmentListener listener) {
assignableTagsComboBox.removeTagAssignmentListener(listener);
assignedTagField.removeTagAssignmentListener(listener);
}
/**
* Returns all assigned tags.
*
* @return {@link List} with tags.
*/
public List<String> getAssignedTags() {
return assignedTagField.getTags();
}
}

View File

@@ -9,18 +9,16 @@
package org.eclipse.hawkbit.ui.common.tagdetails; package org.eclipse.hawkbit.ui.common.tagdetails;
import java.util.Arrays; import java.util.Arrays;
import java.util.Optional; import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TargetTagManagement; import org.eclipse.hawkbit.repository.TargetTagManagement;
import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.hawkbit.repository.model.TargetTagAssignmentResult;
import org.eclipse.hawkbit.ui.SpPermissionChecker; import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.management.event.ManagementUIEvent; import org.eclipse.hawkbit.ui.management.event.ManagementUIEvent;
import org.eclipse.hawkbit.ui.management.event.TargetTableEvent; import org.eclipse.hawkbit.ui.management.event.TargetTableEvent;
import org.eclipse.hawkbit.ui.management.state.ManagementUIState; import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
import org.eclipse.hawkbit.ui.utils.UINotification; import org.eclipse.hawkbit.ui.utils.UINotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
@@ -28,6 +26,8 @@ import org.vaadin.spring.events.EventBus.UIEventBus;
import org.vaadin.spring.events.EventScope; import org.vaadin.spring.events.EventScope;
import org.vaadin.spring.events.annotation.EventBusListenerMethod; import org.vaadin.spring.events.annotation.EventBusListenerMethod;
import com.google.common.collect.Lists;
/** /**
* Implementation of Target tag token. * Implementation of Target tag token.
* *
@@ -37,11 +37,6 @@ public class TargetTagToken extends AbstractTargetTagToken<Target> {
private static final long serialVersionUID = 7124887018280196721L; private static final long serialVersionUID = 7124887018280196721L;
private static final int MAX_TAGS = 500;
// To Be Done : have to set this value based on view???
private static final Boolean NOTAGS_SELECTED = Boolean.FALSE;
private final transient TargetManagement targetManagement; private final transient TargetManagement targetManagement;
public TargetTagToken(final SpPermissionChecker checker, final VaadinMessageSource i18n, public TargetTagToken(final SpPermissionChecker checker, final VaadinMessageSource i18n,
@@ -52,40 +47,25 @@ public class TargetTagToken extends AbstractTargetTagToken<Target> {
} }
@Override @Override
protected String getTagStyleName() { protected void assignTag(final TagData tagData) {
return "target-tag-"; final List<Target> assignedTargets = targetManagement.assignTag(Arrays.asList(selectedEntity.getControllerId()),
} tagData.getId());
if (checkAssignmentResult(assignedTargets, selectedEntity.getId())) {
@Override uinotification.displaySuccess(
protected String getTokenInputPrompt() { i18n.getMessage("message.target.assigned.one", selectedEntity.getName(), tagData.getName()));
return i18n.getMessage("combo.type.tag.name"); eventBus.publish(this, ManagementUIEvent.ASSIGN_TARGET_TAG);
} tagPanelLayout.setAssignedTag(tagData);
@Override
protected void assignTag(final String tagNameSelected) {
if (tagNameSelected != null) {
final TargetTagAssignmentResult result = toggleAssignment(tagNameSelected);
if (result.getAssigned() >= 1 && NOTAGS_SELECTED) {
eventBus.publish(this, ManagementUIEvent.ASSIGN_TARGET_TAG);
}
} else {
uinotification.displayValidationError(i18n.getMessage("message.error.missing.tagname"));
} }
} }
private TargetTagAssignmentResult toggleAssignment(final String tagNameSelected) {
final TargetTagAssignmentResult result = targetManagement
.toggleTagAssignment(Arrays.asList(selectedEntity.getControllerId()), tagNameSelected);
processTargetTagAssigmentResult(result);
uinotification.displaySuccess(HawkbitCommonUtil.createAssignmentMessage(tagNameSelected, result, i18n));
return result;
}
@Override @Override
protected void unassignTag(final String tagName) { protected void unassignTag(final TagData tagData) {
final TargetTagAssignmentResult result = toggleAssignment(tagName); final Target unassignedTarget = targetManagement.unAssignTag(selectedEntity.getControllerId(), tagData.getId());
if (result.getUnassigned() >= 1) { if (checkUnassignmentResult(unassignedTarget, selectedEntity.getId())) {
uinotification.displaySuccess(
i18n.getMessage("message.target.unassigned.one", selectedEntity.getName(), tagData.getName()));
eventBus.publish(this, ManagementUIEvent.UNASSIGN_TARGET_TAG); eventBus.publish(this, ManagementUIEvent.UNASSIGN_TARGET_TAG);
tagPanelLayout.removeAssignedTag(tagData);
} }
} }
@@ -95,50 +75,19 @@ public class TargetTagToken extends AbstractTargetTagToken<Target> {
} }
@Override @Override
protected void displayAlreadyAssignedTags() { protected List<TagData> getAllTags() {
removePreviouslyAddedTokens(); return tagManagement.findAll(PageRequest.of(0, MAX_TAG_QUERY)).stream()
if (selectedEntity != null) { .map(tag -> new TagData(tag.getId(), tag.getName(), tag.getColour())).collect(Collectors.toList());
for (final TargetTag tag : tagManagement.findByTarget(PageRequest.of(0, MAX_TAGS),
selectedEntity.getControllerId())) {
addNewToken(tag.getId());
}
}
} }
@Override @Override
protected void populateContainer() { protected List<TagData> getAssignedTags() {
container.removeAllItems(); if (selectedEntity != null) {
tagDetails.clear(); return tagManagement.findByTarget(PageRequest.of(0, MAX_TAG_QUERY), selectedEntity.getControllerId())
for (final TargetTag tag : tagManagement.findAll(PageRequest.of(0, MAX_TAGS))) { .stream().map(tag -> new TagData(tag.getId(), tag.getName(), tag.getColour()))
setContainerPropertValues(tag.getId(), tag.getName(), tag.getColour()); .collect(Collectors.toList());
} }
} return Lists.newArrayList();
public void processTargetTagAssigmentResult(final TargetTagAssignmentResult assignmentResult) {
final TargetTag targetTag = assignmentResult.getTargetTag();
if (isAssign(assignmentResult)) {
addNewToken(targetTag.getId());
} else if (isUnassign(assignmentResult)) {
removeTokenItem(targetTag.getId(), targetTag.getName());
}
}
protected boolean isAssign(final TargetTagAssignmentResult assignmentResult) {
final Optional<Long> targetId = managementUIState.getLastSelectedTargetId();
if (assignmentResult.getAssigned() > 0 && targetId.isPresent()) {
return assignmentResult.getAssignedEntity().stream().map(Target::getId)
.anyMatch(controllerId -> controllerId.equals(targetId.get()));
}
return false;
}
protected boolean isUnassign(final TargetTagAssignmentResult assignmentResult) {
final Optional<Long> targetId = managementUIState.getLastSelectedTargetId();
if (assignmentResult.getUnassigned() > 0 && targetId.isPresent()) {
return assignmentResult.getUnassignedEntity().stream().map(Target::getId)
.anyMatch(controllerId -> controllerId.equals(targetId.get()));
}
return false;
} }
@EventBusListenerMethod(scope = EventScope.UI) @EventBusListenerMethod(scope = EventScope.UI)

View File

@@ -20,7 +20,7 @@
<inherits name="org.vaadin.tokenfield.TokenfieldWidgetset" />
<inherits name="org.vaadin.hene.flexibleoptiongroup.widgetset.FlexibleOptionGroupWidgetset" /> <inherits name="org.vaadin.hene.flexibleoptiongroup.widgetset.FlexibleOptionGroupWidgetset" />

View File

@@ -22,7 +22,7 @@
<inherits name="org.vaadin.tokenfield.TokenfieldWidgetset" />
<inherits name="org.eclipse.hawkbit.ui.customrenderers.CustomRendererWidgetSet" /> <inherits name="org.eclipse.hawkbit.ui.customrenderers.CustomRendererWidgetSet" />

View File

@@ -40,6 +40,7 @@ import org.eclipse.hawkbit.ui.distributions.smtype.filter.DistSMTypeFilterButton
import org.eclipse.hawkbit.ui.distributions.smtype.filter.DistSMTypeFilterLayout; import org.eclipse.hawkbit.ui.distributions.smtype.filter.DistSMTypeFilterLayout;
import org.eclipse.hawkbit.ui.distributions.state.ManageDistUIState; import org.eclipse.hawkbit.ui.distributions.state.ManageDistUIState;
import org.eclipse.hawkbit.ui.management.event.DistributionTableEvent; import org.eclipse.hawkbit.ui.management.event.DistributionTableEvent;
import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
import org.eclipse.hawkbit.ui.menu.DashboardMenuItem; import org.eclipse.hawkbit.ui.menu.DashboardMenuItem;
import org.eclipse.hawkbit.ui.push.DistributionSetCreatedEventContainer; import org.eclipse.hawkbit.ui.push.DistributionSetCreatedEventContainer;
import org.eclipse.hawkbit.ui.push.DistributionSetDeletedEventContainer; import org.eclipse.hawkbit.ui.push.DistributionSetDeletedEventContainer;
@@ -95,8 +96,8 @@ public class DistributionsView extends AbstractNotificationView implements Brows
@Autowired @Autowired
DistributionsView(final SpPermissionChecker permChecker, final UIEventBus eventBus, final VaadinMessageSource i18n, DistributionsView(final SpPermissionChecker permChecker, final UIEventBus eventBus, final VaadinMessageSource i18n,
final UINotification uiNotification, final ManageDistUIState manageDistUIState, final UINotification uiNotification, final ManagementUIState managementUIState,
final SoftwareModuleManagement softwareModuleManagement, final ManageDistUIState manageDistUIState, final SoftwareModuleManagement softwareModuleManagement,
final SoftwareModuleTypeManagement softwareModuleTypeManagement, final SoftwareModuleTypeManagement softwareModuleTypeManagement,
final DistributionSetManagement distributionSetManagement, final DistributionSetManagement distributionSetManagement,
final DistributionSetTypeManagement distributionSetTypeManagement, final TargetManagement targetManagement, final DistributionSetTypeManagement distributionSetTypeManagement, final TargetManagement targetManagement,
@@ -117,10 +118,10 @@ public class DistributionsView extends AbstractNotificationView implements Brows
this.filterByDSTypeLayout = new DSTypeFilterLayout(manageDistUIState, i18n, permChecker, eventBus, this.filterByDSTypeLayout = new DSTypeFilterLayout(manageDistUIState, i18n, permChecker, eventBus,
entityFactory, uiNotification, softwareModuleTypeManagement, distributionSetTypeManagement, entityFactory, uiNotification, softwareModuleTypeManagement, distributionSetTypeManagement,
dsTypeFilterButtons); dsTypeFilterButtons);
this.distributionTableLayout = new DistributionSetTableLayout(i18n, eventBus, permChecker, manageDistUIState, this.distributionTableLayout = new DistributionSetTableLayout(i18n, eventBus, permChecker, managementUIState,
softwareModuleManagement, distributionSetManagement, distributionSetTypeManagement, targetManagement, manageDistUIState, softwareModuleManagement, distributionSetManagement, distributionSetTypeManagement,
entityFactory, uiNotification, distributionSetTagManagement, distributionsViewClientCriterion, targetManagement, entityFactory, uiNotification, distributionSetTagManagement,
systemManagement, configManagement, systemSecurityContext); distributionsViewClientCriterion, systemManagement, configManagement, systemSecurityContext);
this.softwareModuleTableLayout = new SwModuleTableLayout(i18n, uiNotification, eventBus, this.softwareModuleTableLayout = new SwModuleTableLayout(i18n, uiNotification, eventBus,
softwareModuleManagement, softwareModuleTypeManagement, entityFactory, manageDistUIState, permChecker, softwareModuleManagement, softwareModuleTypeManagement, entityFactory, manageDistUIState, permChecker,
distributionsViewClientCriterion, artifactUploadState, artifactManagement); distributionsViewClientCriterion, artifactUploadState, artifactManagement);

View File

@@ -22,6 +22,7 @@ import org.eclipse.hawkbit.ui.common.table.AbstractTableLayout;
import org.eclipse.hawkbit.ui.dd.criteria.DistributionsViewClientCriterion; import org.eclipse.hawkbit.ui.dd.criteria.DistributionsViewClientCriterion;
import org.eclipse.hawkbit.ui.distributions.state.ManageDistUIState; import org.eclipse.hawkbit.ui.distributions.state.ManageDistUIState;
import org.eclipse.hawkbit.ui.management.dstable.DistributionAddUpdateWindowLayout; import org.eclipse.hawkbit.ui.management.dstable.DistributionAddUpdateWindowLayout;
import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
import org.eclipse.hawkbit.ui.utils.UINotification; import org.eclipse.hawkbit.ui.utils.UINotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
import org.vaadin.spring.events.EventBus.UIEventBus; import org.vaadin.spring.events.EventBus.UIEventBus;
@@ -36,8 +37,8 @@ public class DistributionSetTableLayout extends AbstractTableLayout<Distribution
private final DistributionSetTable distributionSetTable; private final DistributionSetTable distributionSetTable;
public DistributionSetTableLayout(final VaadinMessageSource i18n, final UIEventBus eventBus, public DistributionSetTableLayout(final VaadinMessageSource i18n, final UIEventBus eventBus,
final SpPermissionChecker permissionChecker, final ManageDistUIState manageDistUIState, final SpPermissionChecker permissionChecker, final ManagementUIState managementUIState,
final SoftwareModuleManagement softwareManagement, final ManageDistUIState manageDistUIState, final SoftwareModuleManagement softwareManagement,
final DistributionSetManagement distributionSetManagement, final DistributionSetManagement distributionSetManagement,
final DistributionSetTypeManagement distributionSetTypeManagement, final TargetManagement targetManagement, final DistributionSetTypeManagement distributionSetTypeManagement, final TargetManagement targetManagement,
final EntityFactory entityFactory, final UINotification uiNotification, final EntityFactory entityFactory, final UINotification uiNotification,
@@ -61,7 +62,7 @@ public class DistributionSetTableLayout extends AbstractTableLayout<Distribution
new DistributionSetTableHeader( new DistributionSetTableHeader(
i18n, permissionChecker, eventBus, manageDistUIState, distributionAddUpdateWindowLayout), i18n, permissionChecker, eventBus, manageDistUIState, distributionAddUpdateWindowLayout),
distributionSetTable, distributionSetTable,
new DistributionSetDetails(i18n, eventBus, permissionChecker, manageDistUIState, null, new DistributionSetDetails(i18n, eventBus, permissionChecker, manageDistUIState, managementUIState,
distributionAddUpdateWindowLayout, distributionSetManagement, uiNotification, distributionAddUpdateWindowLayout, distributionSetManagement, uiNotification,
distributionSetTagManagement, popupLayout, configManagement, systemSecurityContext)); distributionSetTagManagement, popupLayout, configManagement, systemSecurityContext));
} }

View File

@@ -17,7 +17,7 @@
<inherits name="org.vaadin.tokenfield.TokenfieldWidgetset" />
<inherits name="org.eclipse.hawkbit.ui.customrenderers.CustomRendererWidgetSet" /> <inherits name="org.eclipse.hawkbit.ui.customrenderers.CustomRendererWidgetSet" />

View File

@@ -227,11 +227,27 @@ public class DistributionTable extends AbstractNamedVersionTable<DistributionSet
}); });
} }
private boolean isFilteredByTags() {
return !managementUIState.getDistributionTableFilters().getClickedDistSetTags().isEmpty();
}
private boolean isFilteredByNoTag() {
return managementUIState.getDistributionTableFilters().isNoTagSelected();
}
private boolean tableIsFilteredByTagsAndTagWasUnassignedFromDistSet(final ManagementUIEvent managementUIEvent) {
return managementUIEvent == ManagementUIEvent.UNASSIGN_DISTRIBUTION_TAG && isFilteredByTags();
}
private boolean tableIsFilteredByNoTagAndTagWasAssignedToDistSet(final ManagementUIEvent managementUIEvent) {
return managementUIEvent == ManagementUIEvent.ASSIGN_DISTRIBUTION_TAG && isFilteredByNoTag();
}
@EventBusListenerMethod(scope = EventScope.UI) @EventBusListenerMethod(scope = EventScope.UI)
void onEvent(final ManagementUIEvent managementUIEvent) { void onEvent(final ManagementUIEvent managementUIEvent) {
UI.getCurrent().access(() -> { UI.getCurrent().access(() -> {
if (managementUIEvent == ManagementUIEvent.UNASSIGN_DISTRIBUTION_TAG if (tableIsFilteredByTagsAndTagWasUnassignedFromDistSet(managementUIEvent)
|| managementUIEvent == ManagementUIEvent.ASSIGN_DISTRIBUTION_TAG) { || tableIsFilteredByNoTagAndTagWasAssignedToDistSet(managementUIEvent)) {
refreshFilter(); refreshFilter();
} }
}); });
@@ -263,8 +279,8 @@ public class DistributionTable extends AbstractNamedVersionTable<DistributionSet
final List<String> list = new ArrayList<>(); final List<String> list = new ArrayList<>();
queryConfig.put(SPUIDefinitions.FILTER_BY_NO_TAG, queryConfig.put(SPUIDefinitions.FILTER_BY_NO_TAG,
managementUIState.getDistributionTableFilters().isNoTagSelected()); managementUIState.getDistributionTableFilters().isNoTagSelected());
if (!managementUIState.getDistributionTableFilters().getDistSetTags().isEmpty()) { if (!managementUIState.getDistributionTableFilters().getClickedDistSetTags().isEmpty()) {
list.addAll(managementUIState.getDistributionTableFilters().getDistSetTags()); list.addAll(managementUIState.getDistributionTableFilters().getClickedDistSetTags());
} }
queryConfig.put(SPUIDefinitions.FILTER_BY_TAG, list); queryConfig.put(SPUIDefinitions.FILTER_BY_TAG, list);
return queryConfig; return queryConfig;

View File

@@ -39,7 +39,7 @@ public class DistributionTagButtonClick extends AbstractFilterMultiButtonClick {
if (clickedButton.getData().equals(SPUIDefinitions.NO_TAG_BUTTON_ID)) { if (clickedButton.getData().equals(SPUIDefinitions.NO_TAG_BUTTON_ID)) {
managementUIState.getDistributionTableFilters().setNoTagSelected(false); managementUIState.getDistributionTableFilters().setNoTagSelected(false);
} else { } else {
managementUIState.getDistributionTableFilters().getDistSetTags().remove(clickedButton.getId()); managementUIState.getDistributionTableFilters().getClickedDistSetTags().remove(clickedButton.getId());
} }
eventBus.publish(this, new RefreshDistributionTableByFilterEvent()); eventBus.publish(this, new RefreshDistributionTableByFilterEvent());
} }
@@ -49,7 +49,7 @@ public class DistributionTagButtonClick extends AbstractFilterMultiButtonClick {
if (clickedButton.getData().equals(SPUIDefinitions.NO_TAG_BUTTON_ID)) { if (clickedButton.getData().equals(SPUIDefinitions.NO_TAG_BUTTON_ID)) {
managementUIState.getDistributionTableFilters().setNoTagSelected(true); managementUIState.getDistributionTableFilters().setNoTagSelected(true);
} else { } else {
managementUIState.getDistributionTableFilters().getDistSetTags().add(clickedButton.getId()); managementUIState.getDistributionTableFilters().getClickedDistSetTags().add(clickedButton.getId());
} }
eventBus.publish(this, new RefreshDistributionTableByFilterEvent()); eventBus.publish(this, new RefreshDistributionTableByFilterEvent());
} }

View File

@@ -107,8 +107,8 @@ public class DistributionTagButtons extends AbstractFilterButtons {
@Override @Override
protected boolean isClickedByDefault(final String tagName) { protected boolean isClickedByDefault(final String tagName) {
return null != managementUIState.getDistributionTableFilters().getDistSetTags() return null != managementUIState.getDistributionTableFilters().getClickedDistSetTags()
&& managementUIState.getDistributionTableFilters().getDistSetTags().contains(tagName); && managementUIState.getDistributionTableFilters().getClickedDistSetTags().contains(tagName);
} }
@Override @Override
@@ -173,7 +173,7 @@ public class DistributionTagButtons extends AbstractFilterButtons {
protected void deleteEntity(final String entityToDelete) { protected void deleteEntity(final String entityToDelete) {
final Optional<DistributionSetTag> tagToDelete = distributionSetTagManagement.getByName(entityToDelete); final Optional<DistributionSetTag> tagToDelete = distributionSetTagManagement.getByName(entityToDelete);
tagToDelete.ifPresent(tag -> { tagToDelete.ifPresent(tag -> {
if (managementUIState.getDistributionTableFilters().getDistSetTags().contains(entityToDelete)) { if (managementUIState.getDistributionTableFilters().getClickedDistSetTags().contains(entityToDelete)) {
uiNotification.displayValidationError(getI18n().getMessage("message.tag.delete", entityToDelete)); uiNotification.displayValidationError(getI18n().getMessage("message.tag.delete", entityToDelete));
removeUpdateAndDeleteColumn(); removeUpdateAndDeleteColumn();
} else { } else {

View File

@@ -139,7 +139,7 @@ public class DistributionTagDropEvent implements DropHandler {
final String distTagName = HawkbitCommonUtil.removePrefix(targetDetails.getTarget().getId(), final String distTagName = HawkbitCommonUtil.removePrefix(targetDetails.getTarget().getId(),
SPUIDefinitions.DISTRIBUTION_TAG_ID_PREFIXS); SPUIDefinitions.DISTRIBUTION_TAG_ID_PREFIXS);
final List<String> tagsClickedList = distFilterParameters.getDistSetTags(); final List<String> tagsClickedList = distFilterParameters.getClickedDistSetTags();
final DistributionSetTagAssignmentResult result = distributionSetManagement.toggleTagAssignment(distSelected, final DistributionSetTagAssignmentResult result = distributionSetManagement.toggleTagAssignment(distSelected,
distTagName); distTagName);

View File

@@ -35,7 +35,7 @@ public class DistributionTableFilters implements Serializable {
private TargetIdName pinnedTarget; private TargetIdName pinnedTarget;
private final List<String> distSetTags = new ArrayList<>(); private final List<String> clickedDistSetTags = new ArrayList<>();
private Boolean noTagSelected = Boolean.FALSE; private Boolean noTagSelected = Boolean.FALSE;
@@ -47,8 +47,8 @@ public class DistributionTableFilters implements Serializable {
return noTagSelected; return noTagSelected;
} }
public List<String> getDistSetTags() { public List<String> getClickedDistSetTags() {
return distSetTags; return clickedDistSetTags;
} }
public Optional<Long> getDistId() { public Optional<Long> getDistId() {
@@ -74,5 +74,4 @@ public class DistributionTableFilters implements Serializable {
public void setSearchText(final String searchText) { public void setSearchText(final String searchText) {
this.searchText = searchText; this.searchText = searchText;
} }
} }

View File

@@ -23,7 +23,6 @@ import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import org.eclipse.hawkbit.repository.DeploymentManagement; import org.eclipse.hawkbit.repository.DeploymentManagement;
@@ -33,7 +32,7 @@ import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.TargetTagManagement; import org.eclipse.hawkbit.repository.TargetTagManagement;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException; import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.model.Action.ActionType; import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.ui.common.tagdetails.AbstractTagToken.TagData; import org.eclipse.hawkbit.ui.common.tagdetails.TagData;
import org.eclipse.hawkbit.ui.components.HawkbitErrorNotificationMessage; import org.eclipse.hawkbit.ui.components.HawkbitErrorNotificationMessage;
import org.eclipse.hawkbit.ui.management.event.BulkUploadValidationMessageEvent; import org.eclipse.hawkbit.ui.management.event.BulkUploadValidationMessageEvent;
import org.eclipse.hawkbit.ui.management.event.TargetTableEvent; import org.eclipse.hawkbit.ui.management.event.TargetTableEvent;
@@ -287,7 +286,7 @@ public class BulkUploadHandler extends CustomComponent
String dsAssignmentFailedMsg = null; String dsAssignmentFailedMsg = null;
String tagAssignmentFailedMsg = null; String tagAssignmentFailedMsg = null;
if (ifTargetsCreatedSuccessfully()) { if (ifTargetsCreatedSuccessfully()) {
if (ifTagsSelected()) { if (targetBulkTokenTags.isTagSelectedForAssignment()) {
tagAssignmentFailedMsg = tagAssignment(); tagAssignmentFailedMsg = tagAssignment();
} }
if (ifDsSelected()) { if (ifDsSelected()) {
@@ -312,9 +311,8 @@ public class BulkUploadHandler extends CustomComponent
} }
private String tagAssignment() { private String tagAssignment() {
final Map<Long, TagData> tokensSelected = targetBulkTokenTags.getTokensAdded();
final List<String> deletedTags = new ArrayList<>(); final List<String> deletedTags = new ArrayList<>();
for (final TagData tagData : tokensSelected.values()) { for (final TagData tagData : targetBulkTokenTags.getSelectedTagsForAssignment()) {
if (!tagManagement.get(tagData.getId()).isPresent()) { if (!tagManagement.get(tagData.getId()).isPresent()) {
deletedTags.add(tagData.getName()); deletedTags.add(tagData.getName());
} else { } else {
@@ -332,10 +330,6 @@ public class BulkUploadHandler extends CustomComponent
return i18n.getMessage("message.bulk.upload.tag.assignments.failed"); return i18n.getMessage("message.bulk.upload.tag.assignments.failed");
} }
private boolean ifTagsSelected() {
return targetBulkTokenTags.getTokenField().getValue() != null;
}
private boolean ifDsSelected() { private boolean ifDsSelected() {
return comboBox.getValue() != null; return comboBox.getValue() != null;
} }
@@ -375,6 +369,7 @@ public class BulkUploadHandler extends CustomComponent
} catch (final EntityAlreadyExistsException ex) { } catch (final EntityAlreadyExistsException ex) {
// Targets that exist already are simply ignored // Targets that exist already are simply ignored
LOG.info("Entity {} - {} already exists and will be ignored", newControllerId, name);
} }
} }
} }

View File

@@ -8,12 +8,15 @@
*/ */
package org.eclipse.hawkbit.ui.management.targettable; package org.eclipse.hawkbit.ui.management.targettable;
import java.util.Map; import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.TargetTagManagement; import org.eclipse.hawkbit.repository.TargetTagManagement;
import org.eclipse.hawkbit.repository.model.TargetTag; import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.ui.SpPermissionChecker; import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.common.tagdetails.AbstractTargetTagToken; import org.eclipse.hawkbit.ui.common.tagdetails.AbstractTargetTagToken;
import org.eclipse.hawkbit.ui.common.tagdetails.TagData;
import org.eclipse.hawkbit.ui.management.state.ManagementUIState; import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
import org.eclipse.hawkbit.ui.utils.UINotification; import org.eclipse.hawkbit.ui.utils.UINotification;
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
@@ -24,11 +27,9 @@ import org.vaadin.spring.events.EventBus.UIEventBus;
* Target tag layout in bulk upload popup. * Target tag layout in bulk upload popup.
* *
*/ */
public class TargetBulkTokenTags extends AbstractTargetTagToken { public class TargetBulkTokenTags extends AbstractTargetTagToken<Target> {
private static final long serialVersionUID = 4159616629565523717L; private static final long serialVersionUID = 4159616629565523717L;
private static final int MAX_TAGS = 500;
TargetBulkTokenTags(final SpPermissionChecker checker, final VaadinMessageSource i18n, TargetBulkTokenTags(final SpPermissionChecker checker, final VaadinMessageSource i18n,
final UINotification uinotification, final UIEventBus eventBus, final ManagementUIState managementUIState, final UINotification uinotification, final UIEventBus eventBus, final ManagementUIState managementUIState,
final TargetTagManagement tagManagement) { final TargetTagManagement tagManagement) {
@@ -36,24 +37,15 @@ public class TargetBulkTokenTags extends AbstractTargetTagToken {
} }
@Override @Override
protected void assignTag(final String tagNameSelected) { protected void assignTag(final TagData tagData) {
managementUIState.getTargetTableFilters().getBulkUpload().getAssignedTagNames().add(tagNameSelected); managementUIState.getTargetTableFilters().getBulkUpload().getAssignedTagNames().add(tagData.getName());
tagPanelLayout.setAssignedTag(tagData);
} }
@Override @Override
protected void unassignTag(final String tagName) { protected void unassignTag(final TagData tagData) {
managementUIState.getTargetTableFilters().getBulkUpload().getAssignedTagNames().remove(tagName); managementUIState.getTargetTableFilters().getBulkUpload().getAssignedTagNames().remove(tagData.getName());
} tagPanelLayout.removeAssignedTag(tagData);
@Override
protected String getTagStyleName() {
return "target-tag-";
}
@Override
protected String getTokenInputPrompt() {
return i18n.getMessage("combo.type.tag.name");
} }
@Override @Override
@@ -61,29 +53,32 @@ public class TargetBulkTokenTags extends AbstractTargetTagToken {
return checker.hasCreateTargetPermission(); return checker.hasCreateTargetPermission();
} }
@Override /**
public void displayAlreadyAssignedTags() { * Initializes the Tags
removePreviouslyAddedTokens(); */
addAlreadySelectedTags(); public void initializeTags() {
repopulateTags();
} }
protected void addAlreadySelectedTags() { public boolean isTagSelectedForAssignment() {
for (final String tagName : managementUIState.getTargetTableFilters().getBulkUpload().getAssignedTagNames()) { return !tagPanelLayout.getAssignedTags().isEmpty();
tagManagement.getByName(tagName).map(TargetTag::getId).ifPresent(this::addNewToken);
}
} }
@Override @Override
protected void populateContainer() { protected List<TagData> getAllTags() {
container.removeAllItems(); return tagManagement.findAll(PageRequest.of(0, MAX_TAG_QUERY)).stream()
tagDetails.clear(); .map(tag -> new TagData(tag.getId(), tag.getName(), tag.getColour())).collect(Collectors.toList());
for (final TargetTag tag : tagManagement.findAll(PageRequest.of(0, MAX_TAGS))) {
setContainerPropertValues(tag.getId(), tag.getName(), tag.getColour());
}
} }
public Map<Long, TagData> getTokensAdded() { @Override
return tokensAdded; protected List<TagData> getAssignedTags() {
// this view doesn't belong to a specific target, so the current
// selected target in the target table is ignored and therefore there
// are no assigned tags
return Collections.emptyList();
}
public List<TagData> getSelectedTagsForAssignment() {
return tagPanelLayout.getAssignedTags().stream().map(tagDetailsByName::get).collect(Collectors.toList());
} }
} }

View File

@@ -21,6 +21,7 @@ import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.UiProperties; import org.eclipse.hawkbit.ui.UiProperties;
import org.eclipse.hawkbit.ui.common.builder.TextAreaBuilder; import org.eclipse.hawkbit.ui.common.builder.TextAreaBuilder;
import org.eclipse.hawkbit.ui.common.builder.WindowBuilder; import org.eclipse.hawkbit.ui.common.builder.WindowBuilder;
import org.eclipse.hawkbit.ui.common.tagdetails.TagPanelLayout;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorder; import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorder;
import org.eclipse.hawkbit.ui.management.dstable.DistributionBeanQuery; import org.eclipse.hawkbit.ui.management.dstable.DistributionBeanQuery;
@@ -39,7 +40,6 @@ import org.vaadin.addons.lazyquerycontainer.LazyQueryContainer;
import org.vaadin.addons.lazyquerycontainer.LazyQueryDefinition; import org.vaadin.addons.lazyquerycontainer.LazyQueryDefinition;
import org.vaadin.spring.events.EventBus; import org.vaadin.spring.events.EventBus;
import org.vaadin.spring.events.EventBus.UIEventBus; import org.vaadin.spring.events.EventBus.UIEventBus;
import org.vaadin.tokenfield.TokenField;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.vaadin.data.Container; import com.vaadin.data.Container;
@@ -220,10 +220,11 @@ public class TargetBulkUpdateWindowLayout extends CustomComponent {
} }
private VerticalLayout getTokenFieldLayout() { private VerticalLayout getTokenFieldLayout() {
final TokenField tokenField = targetBulkTokenTags.getTokenField(); final TagPanelLayout tagPanelLayout = targetBulkTokenTags.getTagPanel();
tagPanelLayout.setMargin(false);
final VerticalLayout tokenLayout = SPUIComponentProvider.getDetailTabLayout(); final VerticalLayout tokenLayout = SPUIComponentProvider.getDetailTabLayout();
tokenLayout.addStyleName("bulk-target-tags-layout"); tokenLayout.addStyleName("bulk-target-tags-layout");
tokenLayout.addComponent(tokenField); tokenLayout.addComponent(tagPanelLayout);
tokenLayout.setSpacing(false); tokenLayout.setSpacing(false);
tokenLayout.setMargin(false); tokenLayout.setMargin(false);
tokenLayout.setSizeFull(); tokenLayout.setSizeFull();
@@ -249,7 +250,7 @@ public class TargetBulkUpdateWindowLayout extends CustomComponent {
managementUIState.getDistributionTableFilters().isNoTagSelected()); managementUIState.getDistributionTableFilters().isNoTagSelected());
queryConfiguration.put(SPUIDefinitions.FILTER_BY_TAG, queryConfiguration.put(SPUIDefinitions.FILTER_BY_TAG,
managementUIState.getDistributionTableFilters().getDistSetTags()); managementUIState.getDistributionTableFilters().getClickedDistSetTags());
final BeanQueryFactory<DistributionBeanQuery> distributionQF = new BeanQueryFactory<>( final BeanQueryFactory<DistributionBeanQuery> distributionQF = new BeanQueryFactory<>(
DistributionBeanQuery.class); DistributionBeanQuery.class);
@@ -286,8 +287,7 @@ public class TargetBulkUpdateWindowLayout extends CustomComponent {
public void resetComponents() { public void resetComponents() {
dsNamecomboBox.clear(); dsNamecomboBox.clear();
descTextArea.clear(); descTextArea.clear();
targetBulkTokenTags.getTokenField().clear(); targetBulkTokenTags.initializeTags();
targetBulkTokenTags.populateContainer();
progressBar.setValue(0F); progressBar.setValue(0F);
progressBar.setVisible(false); progressBar.setVisible(false);
managementUIState.getTargetTableFilters().getBulkUpload().setProgressBarCurrentValue(0F); managementUIState.getTargetTableFilters().getBulkUpload().setProgressBarCurrentValue(0F);
@@ -308,12 +308,11 @@ public class TargetBulkUpdateWindowLayout extends CustomComponent {
* Restore the target bulk upload layout field values. * Restore the target bulk upload layout field values.
*/ */
public void restoreComponentsValue() { public void restoreComponentsValue() {
targetBulkTokenTags.populateContainer();
final TargetBulkUpload targetBulkUpload = managementUIState.getTargetTableFilters().getBulkUpload(); final TargetBulkUpload targetBulkUpload = managementUIState.getTargetTableFilters().getBulkUpload();
progressBar.setValue(targetBulkUpload.getProgressBarCurrentValue()); progressBar.setValue(targetBulkUpload.getProgressBarCurrentValue());
dsNamecomboBox.setValue(targetBulkUpload.getDsNameAndVersion()); dsNamecomboBox.setValue(targetBulkUpload.getDsNameAndVersion());
descTextArea.setValue(targetBulkUpload.getDescription()); descTextArea.setValue(targetBulkUpload.getDescription());
targetBulkTokenTags.addAlreadySelectedTags(); targetBulkTokenTags.initializeTags();
if (targetBulkUpload.getProgressBarCurrentValue() >= 1) { if (targetBulkUpload.getProgressBarCurrentValue() >= 1) {
targetsCountLabel.setVisible(true); targetsCountLabel.setVisible(true);

View File

@@ -221,13 +221,21 @@ public class TargetTable extends AbstractTable<Target> {
@EventBusListenerMethod(scope = EventScope.UI) @EventBusListenerMethod(scope = EventScope.UI)
void onEvent(final ManagementUIEvent managementUIEvent) { void onEvent(final ManagementUIEvent managementUIEvent) {
UI.getCurrent().access(() -> { UI.getCurrent().access(() -> {
if (managementUIEvent == ManagementUIEvent.UNASSIGN_TARGET_TAG if (tableIsFilteredByTagsAndTagWasUnassignedFromTarget(managementUIEvent)
|| managementUIEvent == ManagementUIEvent.ASSIGN_TARGET_TAG) { || tableIsFilteredByNoTagAndTagWasAssignedToTarget(managementUIEvent)) {
refreshFilter(); refreshFilter();
} }
}); });
} }
private boolean tableIsFilteredByTagsAndTagWasUnassignedFromTarget(final ManagementUIEvent managementUIEvent) {
return managementUIEvent == ManagementUIEvent.UNASSIGN_TARGET_TAG && isFilteredByTags();
}
private boolean tableIsFilteredByNoTagAndTagWasAssignedToTarget(final ManagementUIEvent managementUIEvent) {
return managementUIEvent == ManagementUIEvent.ASSIGN_TARGET_TAG && isFilteredByNoTag();
}
@EventBusListenerMethod(scope = EventScope.UI) @EventBusListenerMethod(scope = EventScope.UI)
void onEvent(final SaveActionWindowEvent event) { void onEvent(final SaveActionWindowEvent event) {
if (event == SaveActionWindowEvent.SAVED_ASSIGNMENTS) { if (event == SaveActionWindowEvent.SAVED_ASSIGNMENTS) {
@@ -842,6 +850,10 @@ public class TargetTable extends AbstractTable<Target> {
return !managementUIState.getTargetTableFilters().getClickedTargetTags().isEmpty(); return !managementUIState.getTargetTableFilters().getClickedTargetTags().isEmpty();
} }
private boolean isFilteredByNoTag() {
return managementUIState.getTargetTableFilters().isNoTagSelected();
}
private void assignDsToTarget(final DragAndDropEvent event) { private void assignDsToTarget(final DragAndDropEvent event) {
final TableTransferable transferable = (TableTransferable) event.getTransferable(); final TableTransferable transferable = (TableTransferable) event.getTransferable();
final AbstractTable<?> source = (AbstractTable<?>) transferable.getSourceComponent(); final AbstractTable<?> source = (AbstractTable<?>) transferable.getSourceComponent();

View File

@@ -16,7 +16,7 @@
<inherits name="org.vaadin.tokenfield.TokenfieldWidgetset"/>
<inherits name="org.eclipse.hawkbit.ui.customrenderers.CustomRendererWidgetSet"/> <inherits name="org.eclipse.hawkbit.ui.customrenderers.CustomRendererWidgetSet"/>

View File

@@ -119,6 +119,14 @@ public final class SPUIStyleDefinitions {
*/ */
public static final String SIMPLE_FILTER_HEADER = "simple-tag-filter-header"; public static final String SIMPLE_FILTER_HEADER = "simple-tag-filter-header";
/**
* Simple tag filter header layout.
*/
public static final String TAG_BUTTON_WITH_BACKGROUND = "button-tag-with-background";
/**
* Simple tag filter header layout.
*/
public static final String ASSIGN_TAG_BUTTON = "button-assign-tag";
/** /**
* Style to disable top border. * Style to disable top border.
*/ */

View File

@@ -693,6 +693,16 @@ public final class UIComponentIdProvider {
*/ */
public static final String LINK_USERMANAGEMENT = "link.usermanagement"; public static final String LINK_USERMANAGEMENT = "link.usermanagement";
/**
* Prefix for assigned tag button ids.
*/
public static final String ASSIGNED_TAG_ID_PREFIX = "tag.assigned.";
/**
* Assign tag icon id.
*/
public static final String ASSIGN_TAG = "tag.assign";
/** /**
* New Target tag add icon id. * New Target tag add icon id.
*/ */
@@ -973,7 +983,10 @@ public final class UIComponentIdProvider {
* Rollout group remove button id * Rollout group remove button id
*/ */
public static final String ROLLOUT_GROUP_REMOVE_ID = "rollout.group.remove.id"; public static final String ROLLOUT_GROUP_REMOVE_ID = "rollout.group.remove.id";
/**
* Tag selection combo id.
*/
public static final String TAG_SELECTION_ID = "tag.selection.id";
/** /**
* Rollout distribution set combo id. * Rollout distribution set combo id.
*/ */

View File

@@ -113,6 +113,12 @@ public final class UIMessageIdProvider {
public static final String TOOLTIP_SHOW_TAGS = "tooltip.showTags"; public static final String TOOLTIP_SHOW_TAGS = "tooltip.showTags";
public static final String TOOLTIP_ASSIGN_TAG = "tooltip.assignTag";
public static final String TOOLTIP_SELECT_TAG = "tooltip.selectTag";
public static final String TOOLTIP_CLICK_TO_REMOVE = "tooltip.click.to.remove";
public static final String TOOLTIP_BULK_UPLOAD = "tooltip.bulkUpload"; public static final String TOOLTIP_BULK_UPLOAD = "tooltip.bulkUpload";
public static final String TOOLTIP_CONFIGURE = "tooltip.configure"; public static final String TOOLTIP_CONFIGURE = "tooltip.configure";

View File

@@ -182,6 +182,7 @@
border-right: 1px solid #bfc3c8; border-right: 1px solid #bfc3c8;
border-bottom: 1px solid #bfc3c8; border-bottom: 1px solid #bfc3c8;
border-radius: 4px; border-radius: 4px;
overflow-y: auto;
} }
.bulk-upload-ds-combo{ .bulk-upload-ds-combo{
margin-top: 2px !important; margin-top: 2px !important;

View File

@@ -121,4 +121,12 @@
#target\.tag\.drop\.area .v-slot-icon-only { #target\.tag\.drop\.area .v-slot-icon-only {
height: 32px; height: 32px;
} }
.button-tag-with-background {
background-color: lightgrey !important;
}
.button-assign-tag {
padding-top: 5px;
}
} }

View File

@@ -298,6 +298,7 @@ tooltip.timeforced.forced.since=Auto forced since {0}
tooltip.check.for.mandatory=Check to make Mandatory tooltip.check.for.mandatory=Check to make Mandatory
tooltip.artifact.icon=Show Artifact Details tooltip.artifact.icon=Show Artifact Details
tooltip.click.to.edit = Click to edit tooltip.click.to.edit = Click to edit
tooltip.click.to.remove = Click to remove
tooltip.metadata.icon = Manage Metadata.. tooltip.metadata.icon = Manage Metadata..
tooltip.next.maintenance.window = next on {0} tooltip.next.maintenance.window = next on {0}
tooltip.target.attributes.update.request = Request attributes update tooltip.target.attributes.update.request = Request attributes update
@@ -334,6 +335,8 @@ tooltip.maximize = Maximize
tooltip.minimize = Minimize tooltip.minimize = Minimize
tooltip.bulkUpload = Bulk Upload.. tooltip.bulkUpload = Bulk Upload..
tooltip.showTags = Show Tags tooltip.showTags = Show Tags
tooltip.assignTag = Assign Tag
tooltip.selectTag = Select Tag
tooltip.update = Edit.. tooltip.update = Edit..
tooltip.reset = Reset tooltip.reset = Reset
tooltip.configure = Configure.. tooltip.configure = Configure..
@@ -609,7 +612,6 @@ header.caption.typename = SoftwareModuleType
header.caption.softwaremodule = SoftwareModule header.caption.softwaremodule = SoftwareModule
message.sw.unassigned = Software Module {0} successfully unassigned message.sw.unassigned = Software Module {0} successfully unassigned
header.caption.upload.details = Upload details header.caption.upload.details = Upload details
combo.type.tag.name = Type tag name
label.yes = Yes label.yes = Yes
label.no = No label.no = No

View File

@@ -152,8 +152,7 @@
<vaadin.version>7.7.13</vaadin.version> <vaadin.version>7.7.13</vaadin.version>
<vaadin.plugin.version>${vaadin.version}</vaadin.plugin.version> <vaadin.plugin.version>${vaadin.version}</vaadin.plugin.version>
<vaadin.addon.vaadin-lazyquerycontainer.version>7.6.1.3</vaadin.addon.vaadin-lazyquerycontainer.version> <vaadin.addon.vaadin-lazyquerycontainer.version>7.6.1.3</vaadin.addon.vaadin-lazyquerycontainer.version>
<vaadin.addon.flexibleoptiongroup.version>2.2.0</vaadin.addon.flexibleoptiongroup.version> <vaadin.addon.flexibleoptiongroup.version>2.2.0</vaadin.addon.flexibleoptiongroup.version>
<vaadin.addon.tokenfield.version>7.0.1</vaadin.addon.tokenfield.version>
<vaadin.addon.dbar-addon.version>2.0.0</vaadin.addon.dbar-addon.version> <vaadin.addon.dbar-addon.version>2.0.0</vaadin.addon.dbar-addon.version>
<!-- Vaadin versions - END --> <!-- Vaadin versions - END -->
@@ -594,11 +593,6 @@
<artifactId>flexibleoptiongroup</artifactId> <artifactId>flexibleoptiongroup</artifactId>
<version>${vaadin.addon.flexibleoptiongroup.version}</version> <version>${vaadin.addon.flexibleoptiongroup.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.vaadin.addons</groupId>
<artifactId>tokenfield</artifactId>
<version>${vaadin.addon.tokenfield.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.vaadin.alump.distributionbar</groupId> <groupId>org.vaadin.alump.distributionbar</groupId>
<artifactId>dbar-addon</artifactId> <artifactId>dbar-addon</artifactId>