From 2b5b8b4a63a7bd9e84ab881677384c8d20f799a5 Mon Sep 17 00:00:00 2001 From: Markus Block Date: Tue, 13 Aug 2019 11:19:19 +0200 Subject: [PATCH] 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 * added Combobox and get it running Signed-off-by: Markus Block * Fixed remaining problems, added Combobox for tag selection Signed-off-by: Markus Block * fixed permission check Signed-off-by: Markus Block * fixed tag update Signed-off-by: Markus Block * 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 * fixed Bulkupload Signed-off-by: Markus Block * Making Sonar happy Signed-off-by: Markus Block * Making Sonar happy Signed-off-by: Markus Block * Fixed Bug in DistTokenfield and sorted Tags in Tag list Signed-off-by: Markus Block * Making Sonar happy Signed-off-by: Markus Block * Fixed Sonar issues Signed-off-by: Markus Block * Implemented code review remarks Signed-off-by: Markus Block --- hawkbit-ui/pom.xml | 4 - .../eclipse/hawkbit/ui/AppWidgetSet.gwt.xml | 2 +- .../AbstractTableDetailsLayout.java | 2 +- .../common/tagdetails/AbstractTagToken.java | 327 ++++-------------- .../tagdetails/AbstractTargetTagToken.java | 23 +- .../tagdetails/DistributionTagToken.java | 125 ++----- .../tagdetails/TagAssignementComboBox.java | 170 +++++++++ .../hawkbit/ui/common/tagdetails/TagData.java | 90 +++++ .../ui/common/tagdetails/TagListField.java | 170 +++++++++ .../ui/common/tagdetails/TagPanelLayout.java | 173 +++++++++ .../ui/common/tagdetails/TargetTagToken.java | 105 ++---- .../CustomRendererWidgetSet.gwt.xml | 2 +- .../ui/dd/CustomAcceptCriteria.gwt.xml | 2 +- .../ui/distributions/DistributionsView.java | 13 +- .../dstable/DistributionSetTableLayout.java | 7 +- .../TextFieldSuggestionBox.gwt.xml | 2 +- .../management/dstable/DistributionTable.java | 24 +- .../filter/DistributionTagButtonClick.java | 4 +- .../dstag/filter/DistributionTagButtons.java | 6 +- .../event/DistributionTagDropEvent.java | 2 +- .../state/DistributionTableFilters.java | 7 +- .../targettable/BulkUploadHandler.java | 13 +- .../targettable/TargetBulkTokenTags.java | 69 ++-- .../TargetBulkUpdateWindowLayout.java | 15 +- .../management/targettable/TargetTable.java | 16 +- .../groupschart/GroupsPieChart.gwt.xml | 2 +- .../ui/utils/SPUIStyleDefinitions.java | 8 + .../ui/utils/UIComponentIdProvider.java | 15 +- .../hawkbit/ui/utils/UIMessageIdProvider.java | 6 + .../hawkbit/customstyles/popup-window.scss | 1 + .../themes/hawkbit/customstyles/tags.scss | 8 + .../src/main/resources/messages.properties | 4 +- pom.xml | 8 +- 33 files changed, 887 insertions(+), 538 deletions(-) create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagAssignementComboBox.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagData.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagListField.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagPanelLayout.java diff --git a/hawkbit-ui/pom.xml b/hawkbit-ui/pom.xml index 85aa51085..790188f26 100644 --- a/hawkbit-ui/pom.xml +++ b/hawkbit-ui/pom.xml @@ -214,10 +214,6 @@ org.vaadin.addons flexibleoptiongroup - - org.vaadin.addons - tokenfield - org.vaadin.alump.distributionbar dbar-addon diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AppWidgetSet.gwt.xml b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AppWidgetSet.gwt.xml index 4dd1223d2..ad1e153c2 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AppWidgetSet.gwt.xml +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AppWidgetSet.gwt.xml @@ -18,7 +18,7 @@ - + diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java index 0aa82ff99..ca77b8dfe 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java @@ -158,7 +158,7 @@ public abstract class AbstractTableDetailsLayout extends if (getSelectedBaseEntity() == null) { return; } - getTagsLayout().addComponent(tagToken.getTokenField()); + getTagsLayout().addComponent(tagToken.getTagPanel()); } protected void populateLog() { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/AbstractTagToken.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/AbstractTagToken.java index c0216d94e..6affcb36d 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/AbstractTagToken.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/AbstractTagToken.java @@ -9,34 +9,25 @@ package org.eclipse.hawkbit.ui.common.tagdetails; import java.io.Serializable; -import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; import org.eclipse.hawkbit.repository.model.BaseEntity; import org.eclipse.hawkbit.ui.SpPermissionChecker; import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType; 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.utils.SPUIDefinitions; -import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; import org.eclipse.hawkbit.ui.utils.UINotification; 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.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.themes.ValoTheme; /** * Abstract class for target/ds tag token layout. @@ -44,25 +35,16 @@ import com.vaadin.ui.themes.ValoTheme; * @param * the special entity */ -public abstract class AbstractTagToken implements Serializable { +public abstract class AbstractTagToken implements Serializable, TagAssignmentListener { - private static final String ID_PROPERTY = "id"; - private static final String NAME_PROPERTY = "name"; - private static final String COLOR_PROPERTY = "color"; - - protected static final int MAX_TAG_QUERY = 500; + protected static final int MAX_TAG_QUERY = 1000; private static final long serialVersionUID = 6599386705285184783L; - protected TokenField tokenField; + protected TagPanelLayout tagPanelLayout; - protected IndexedContainer container; - - protected final transient Map tagDetails = new ConcurrentHashMap<>(); - - protected final transient Map tokensAdded = new HashMap<>(); - - protected CssLayout tokenLayout = new CssLayout(); + protected final transient Map tagDetailsById = new ConcurrentHashMap<>(); + protected final transient Map tagDetailsByName = new ConcurrentHashMap<>(); protected SpPermissionChecker checker; @@ -86,8 +68,7 @@ public abstract class AbstractTagToken implements Serializ this.uinotification = uinotification; this.eventBus = eventBus; this.managementUIState = managementUIState; - createTokenField(); - checkIfTagAssignedIsAllowed(); + createTagPanel(); if (doSubscribeToEventBus()) { eventBus.subscribe(this); } @@ -110,267 +91,91 @@ public abstract class AbstractTagToken implements Serializ final T entity = baseEntityEvent.getEntity(); if (entity != null) { selectedEntity = entity; - repopulateToken(); + repopulateTags(); } }); } - private void createTokenField() { - final Container tokenContainer = createContainer(); - tokenField = createTokenField(tokenContainer); - tokenField.setContainerDataSource(tokenContainer); - 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); + private void createTagPanel() { + tagPanelLayout = new TagPanelLayout(i18n, !isToggleTagAssignmentAllowed()); + tagPanelLayout.addTagAssignmentListener(this); + tagPanelLayout.setSizeFull(); } - protected void repopulateToken() { - populateContainer(); - displayAlreadyAssignedTags(); + protected void repopulateTags() { + tagDetailsById.clear(); + tagDetailsByName.clear(); + + final List allAssignableTags = getAllTags(); + allAssignableTags.forEach(tagData -> { + tagDetailsByName.put(tagData.getName(), tagData); + tagDetailsById.put(tagData.getId(), tagData); + }); + tagPanelLayout.initializeTags(allAssignableTags, getAssignedTags()); } - private Container createContainer() { - container = new IndexedContainer(); - container.addContainerProperty(NAME_PROPERTY, String.class, ""); - container.addContainerProperty(ID_PROPERTY, Long.class, ""); - container.addContainerProperty(COLOR_PROPERTY, String.class, ""); - return container; + protected void tagCreated(final TagData tagData) { + tagDetailsByName.put(tagData.getName(), tagData); + tagDetailsById.put(tagData.getId(), tagData); + + tagPanelLayout.tagCreated(tagData); } - protected void addNewToken(final Long tagId) { - tokenField.addToken(tagId); - removeTagAssignedFromCombo(tagId); - } + protected void tagDeleted(final Long id) { + final TagData tagData = tagDetailsById.get(id); + if (tagData != null) { + tagPanelLayout.tagDeleted(tagData); - private void removeTagAssignedFromCombo(final Long tagId) { - // might not yet exist or not anymore due to unprocessed events - 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); + tagDetailsByName.remove(tagData.getName()); + tagDetailsById.remove(id); } } - protected void updateItem(final String tagName, final String tagColor, final Item item) { - item.getItemProperty(NAME_PROPERTY).setValue(tagName); - item.getItemProperty(COLOR_PROPERTY).setValue(tagColor); - } - - protected void checkIfTagAssignedIsAllowed() { - if (!isToggleTagAssignmentAllowed()) { - tokenField.addStyleName("hideTokenFieldcombo"); + @Override + public void assignTag(final String tagName) { + final TagData tagData = tagDetailsByName.get(tagName); + if (tagData != null) { + assignTag(tagData); } } - private TokenField createTokenField(final Container tokenContainer) { - return new CustomTokenField(tokenLayout, tokenContainer); + @Override + public void unassignTag(final String tagName) { + final TagData tagData = tagDetailsByName.get(tagName); + if (tagData != null) { + unassignTag(tagData); + } } - class CustomTokenField extends TokenField { - private static final long serialVersionUID = 694216966472937436L; + protected abstract void assignTag(TagData tagData); - Container tokenContainer; + protected abstract void unassignTag(TagData tagData); - CustomTokenField(final CssLayout cssLayout, final Container tokenContainer) { - super(cssLayout); - this.tokenContainer = tokenContainer; - } - - @Override - protected void configureTokenButton(final Object tokenId, final Button button) { - 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); + protected boolean checkAssignmentResult(final List> assignedEntities, + final Long expectedAssignedEntityId) { + if (!CollectionUtils.isEmpty(assignedEntities) && expectedAssignedEntityId != null) { + final List assignedDsIds = assignedEntities.stream().map(Identifiable::getId) + .collect(Collectors.toList()); + if (assignedDsIds.contains(expectedAssignedEntityId)) { + return true; } } - - 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("" + FontAwesome.CIRCLE.getHtml() - + "" + " " + 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); - } - + return false; } - private static String getColor(final Item item) { - if (item.getItemProperty(COLOR_PROPERTY).getValue() != null) { - return (String) item.getItemProperty(COLOR_PROPERTY).getValue(); - } else { - return SPUIDefinitions.DEFAULT_COLOR; - } + protected boolean checkUnassignmentResult(final Identifiable unAssignedEntity, + final Long expectedUnAssignedEntityId) { + return unAssignedEntity != null && expectedUnAssignedEntityId != null + && unAssignedEntity.getId().equals(expectedUnAssignedEntityId); } - 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 void displayAlreadyAssignedTags(); + protected abstract List getAllTags(); - protected abstract void populateContainer(); - - 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; - } + protected abstract List getAssignedTags(); + public TagPanelLayout getTagPanel() { + return tagPanelLayout; } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/AbstractTargetTagToken.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/AbstractTargetTagToken.java index 6e2a6d35a..5d81bca09 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/AbstractTargetTagToken.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/AbstractTargetTagToken.java @@ -12,10 +12,12 @@ import java.util.List; import java.util.Objects; 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.TargetTagUpdatedEvent; import org.eclipse.hawkbit.repository.model.BaseEntity; 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.push.TargetTagCreatedEventContainer; 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.annotation.EventBusListenerMethod; -import com.vaadin.data.Item; - /** * /** Abstract class for target tag token layout. * @@ -49,23 +49,24 @@ public abstract class AbstractTargetTagToken extends Abstr @EventBusListenerMethod(scope = EventScope.UI) void onEventTargetTagCreated(final TargetTagCreatedEventContainer container) { 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) void onTargetTagDeletedEvent(final TargetTagDeletedEventContainer container) { - container.getEvents().stream().map(event -> getTagIdByTagName(event.getEntityId())) - .forEach(this::removeTagFromCombo); + container.getEvents().stream().filter(Objects::nonNull).map(TargetTagDeletedEvent::getEntityId) + .forEach(this::tagDeleted); } @EventBusListenerMethod(scope = EventScope.UI) void onTargetTagUpdateEvent(final List events) { - events.stream().map(TargetTagUpdatedEvent::getEntity).forEach(entity -> { - final Item item = container.getItem(entity.getId()); - if (item != null) { - updateItem(entity.getName(), entity.getColour(), item); - } - }); + repopulateTags(); + + } + + @EventBusListenerMethod(scope = EventScope.UI) + void onTargetTagUpdateEvent(final TargetTagTableEvent event) { + repopulateTags(); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/DistributionTagToken.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/DistributionTagToken.java index b66e9ca5e..7dc9e60da 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/DistributionTagToken.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/DistributionTagToken.java @@ -8,6 +8,7 @@ */ package org.eclipse.hawkbit.ui.common.tagdetails; +import java.util.Collections; import java.util.List; import java.util.Objects; 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.DistributionSetTagManagement; 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.DistributionSetTag; -import org.eclipse.hawkbit.repository.model.DistributionSetTagAssignmentResult; 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.ManagementUIEvent; import org.eclipse.hawkbit.ui.management.state.ManagementUIState; import org.eclipse.hawkbit.ui.push.DistributionSetTagCreatedEventContainer; import org.eclipse.hawkbit.ui.push.DistributionSetTagDeletedEventContainer; 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.VaadinMessageSource; import org.springframework.data.domain.PageRequest; @@ -35,7 +33,6 @@ import org.vaadin.spring.events.EventScope; import org.vaadin.spring.events.annotation.EventBusListenerMethod; import com.google.common.collect.Sets; -import com.vaadin.data.Item; /** * Implementation of target/ds tag token layout. @@ -49,9 +46,6 @@ public class DistributionTagToken extends AbstractTagToken { 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, final UINotification uinotification, final UIEventBus eventBus, final ManagementUIState managementUIState, final DistributionSetTagManagement distributionSetTagManagement, @@ -62,40 +56,26 @@ public class DistributionTagToken extends AbstractTagToken { } @Override - protected String getTagStyleName() { - return "distribution-tag-"; - } - - @Override - protected String getTokenInputPrompt() { - return i18n.getMessage("combo.type.tag.name"); - } - - @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")); + protected void assignTag(final TagData tagData) { + final List assignedDistributionSets = distributionSetManagement + .assignTag(Sets.newHashSet(selectedEntity.getId()), tagData.getId()); + if (checkAssignmentResult(assignedDistributionSets, managementUIState.getLastSelectedDsIdName())) { + uinotification.displaySuccess( + i18n.getMessage("message.target.assigned.one", selectedEntity.getName(), tagData.getName())); + eventBus.publish(this, ManagementUIEvent.ASSIGN_DISTRIBUTION_TAG); + tagPanelLayout.setAssignedTag(tagData); } } - 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 - protected void unassignTag(final String tagName) { - final DistributionSetTagAssignmentResult result = toggleAssignment(tagName); - if (result.getUnassigned() >= 1) { + protected void unassignTag(final TagData tagData) { + final DistributionSet unAssignedDistributionSet = distributionSetManagement.unAssignTag(selectedEntity.getId(), + 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); + tagPanelLayout.removeAssignedTag(tagData); } } @@ -105,21 +85,21 @@ public class DistributionTagToken extends AbstractTagToken { } @Override - public void displayAlreadyAssignedTags() { - removePreviouslyAddedTokens(); - if (selectedEntity != null) { - distributionSetTagManagement.findByDistributionSet(PageRequest.of(0, MAX_TAG_QUERY), selectedEntity.getId()) - .getContent().stream().forEach(tag -> addNewToken(tag.getId())); - } + protected List getAllTags() { + return distributionSetTagManagement.findAll(PageRequest.of(0, MAX_TAG_QUERY)).getContent().stream() + .map(tag -> new TagData(tag.getId(), tag.getName(), tag.getColour())).collect(Collectors.toList()); } @Override - protected void populateContainer() { - container.removeAllItems(); - tagDetails.clear(); - distributionSetTagManagement.findAll(PageRequest.of(0, MAX_TAG_QUERY)).getContent().stream() - .forEach(tag -> setContainerPropertValues(tag.getId(), tag.getName(), tag.getColour())); + protected List getAssignedTags() { + if (selectedEntity != null) { + return distributionSetTagManagement + .findByDistributionSet(PageRequest.of(0, MAX_TAG_QUERY), selectedEntity.getId()).getContent() + .stream().map(tag -> new TagData(tag.getId(), tag.getName(), tag.getColour())) + .collect(Collectors.toList()); + } + return Collections.emptyList(); } @EventBusListenerMethod(scope = EventScope.UI) @@ -128,58 +108,23 @@ public class DistributionTagToken extends AbstractTagToken { } @EventBusListenerMethod(scope = EventScope.UI) - void onDistributionSetTagCreatedBulkEvent(final DistributionSetTagCreatedEventContainer eventContainer) { + void onDistributionSetTagCreatedEvent(final DistributionSetTagCreatedEventContainer eventContainer) { eventContainer.getEvents().stream().filter(Objects::nonNull).map(DistributionSetTagCreatedEvent::getEntity) - .forEach(distributionSetTag -> setContainerPropertValues(distributionSetTag.getId(), - distributionSetTag.getName(), distributionSetTag.getColour())); + .forEach(tag -> tagCreated(new TagData(tag.getId(), tag.getName(), tag.getColour()))); } @EventBusListenerMethod(scope = EventScope.UI) void onDistributionSetTagDeletedEvent(final DistributionSetTagDeletedEventContainer eventContainer) { - eventContainer.getEvents().stream().map(event -> getTagIdByTagName(event.getEntityId())) - .forEach(this::removeTagFromCombo); + eventContainer.getEvents().forEach(event -> tagDeleted(event.getEntityId())); } @EventBusListenerMethod(scope = EventScope.UI) void onDistributionSetTagUpdateEvent(final DistributionSetTagUpdatedEventContainer eventContainer) { - eventContainer.getEvents().stream().filter(Objects::nonNull).map(DistributionSetTagUpdatedEvent::getEntity) - .forEach(entity -> { - final Item item = container.getItem(entity.getId()); - if (item != null) { - updateItem(entity.getName(), entity.getColour(), item); - } - }); + repopulateTags(); } - private void processTargetTagAssigmentResult(final DistributionSetTagAssignmentResult assignmentResult) { - final DistributionSetTag tag = assignmentResult.getDistributionSetTag(); - if (isAssign(assignmentResult)) { - addNewToken(tag.getId()); - } else if (isUnassign(assignmentResult)) { - removeTokenItem(tag.getId(), tag.getName()); - } + @EventBusListenerMethod(scope = EventScope.UI) + void onDistributionSetTagUpdateEvent(final DistributionSetTagTableEvent event) { + repopulateTags(); } - - protected boolean isAssign(final DistributionSetTagAssignmentResult assignmentResult) { - if (assignmentResult.getAssigned() > 0 && managementUIState.getLastSelectedDsIdName() != null) { - final List 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 assignedDsNames = assignmentResult.getUnassignedEntity().stream().map(t -> t.getId()) - .collect(Collectors.toList()); - if (assignedDsNames.contains(managementUIState.getLastSelectedDsIdName())) { - return true; - } - } - return false; - } - } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagAssignementComboBox.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagAssignementComboBox.java new file mode 100644 index 000000000..cdb3b98b8 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagAssignementComboBox.java @@ -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 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 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()); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagData.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagData.java new file mode 100644 index 000000000..b3c1db33c --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagData.java @@ -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(); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagListField.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagListField.java new file mode 100644 index 000000000..c61c5ec7a --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagListField.java @@ -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 tagButtons = Maps.newTreeMap(Ordering.natural()); + private final transient Set listeners = Sets.newConcurrentHashSet(); + private final VaadinMessageSource i18n; + private final boolean readOnlyMode; + + /** + * Constructor. + * + * @param i18n + * @param readOnlyMode + * if true 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 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("" + FontAwesome.CIRCLE.getHtml() + + "" + " " + 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 getTags() { + return Lists.newArrayList(tagButtons.keySet()); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagPanelLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagPanelLayout.java new file mode 100644 index 000000000..e6d140254 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagPanelLayout.java @@ -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 true 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 allTags, final List assignedTags) { + assignableTagsComboBox.removeAllTags(); + assignedTagField.removeAllTags(); + + final List 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 getAssignedTags() { + return assignedTagField.getTags(); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TargetTagToken.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TargetTagToken.java index f95d39c4a..6448ec35b 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TargetTagToken.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TargetTagToken.java @@ -9,18 +9,16 @@ package org.eclipse.hawkbit.ui.common.tagdetails; 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.TargetTagManagement; 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.management.event.ManagementUIEvent; import org.eclipse.hawkbit.ui.management.event.TargetTableEvent; 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.VaadinMessageSource; 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.annotation.EventBusListenerMethod; +import com.google.common.collect.Lists; + /** * Implementation of Target tag token. * @@ -37,11 +37,6 @@ public class TargetTagToken extends AbstractTargetTagToken { 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; public TargetTagToken(final SpPermissionChecker checker, final VaadinMessageSource i18n, @@ -52,40 +47,25 @@ public class TargetTagToken extends AbstractTargetTagToken { } @Override - protected String getTagStyleName() { - return "target-tag-"; - } - - @Override - protected String getTokenInputPrompt() { - return i18n.getMessage("combo.type.tag.name"); - } - - @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")); + protected void assignTag(final TagData tagData) { + final List assignedTargets = targetManagement.assignTag(Arrays.asList(selectedEntity.getControllerId()), + tagData.getId()); + if (checkAssignmentResult(assignedTargets, selectedEntity.getId())) { + uinotification.displaySuccess( + i18n.getMessage("message.target.assigned.one", selectedEntity.getName(), tagData.getName())); + eventBus.publish(this, ManagementUIEvent.ASSIGN_TARGET_TAG); + tagPanelLayout.setAssignedTag(tagData); } } - 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 - protected void unassignTag(final String tagName) { - final TargetTagAssignmentResult result = toggleAssignment(tagName); - if (result.getUnassigned() >= 1) { + protected void unassignTag(final TagData tagData) { + final Target unassignedTarget = targetManagement.unAssignTag(selectedEntity.getControllerId(), tagData.getId()); + if (checkUnassignmentResult(unassignedTarget, selectedEntity.getId())) { + uinotification.displaySuccess( + i18n.getMessage("message.target.unassigned.one", selectedEntity.getName(), tagData.getName())); eventBus.publish(this, ManagementUIEvent.UNASSIGN_TARGET_TAG); + tagPanelLayout.removeAssignedTag(tagData); } } @@ -95,50 +75,19 @@ public class TargetTagToken extends AbstractTargetTagToken { } @Override - protected void displayAlreadyAssignedTags() { - removePreviouslyAddedTokens(); - if (selectedEntity != null) { - for (final TargetTag tag : tagManagement.findByTarget(PageRequest.of(0, MAX_TAGS), - selectedEntity.getControllerId())) { - addNewToken(tag.getId()); - } - } + protected List getAllTags() { + return tagManagement.findAll(PageRequest.of(0, MAX_TAG_QUERY)).stream() + .map(tag -> new TagData(tag.getId(), tag.getName(), tag.getColour())).collect(Collectors.toList()); } @Override - protected void populateContainer() { - container.removeAllItems(); - tagDetails.clear(); - for (final TargetTag tag : tagManagement.findAll(PageRequest.of(0, MAX_TAGS))) { - setContainerPropertValues(tag.getId(), tag.getName(), tag.getColour()); + protected List getAssignedTags() { + if (selectedEntity != null) { + return tagManagement.findByTarget(PageRequest.of(0, MAX_TAG_QUERY), selectedEntity.getControllerId()) + .stream().map(tag -> new TagData(tag.getId(), tag.getName(), tag.getColour())) + .collect(Collectors.toList()); } - } - - 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 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 targetId = managementUIState.getLastSelectedTargetId(); - if (assignmentResult.getUnassigned() > 0 && targetId.isPresent()) { - return assignmentResult.getUnassignedEntity().stream().map(Target::getId) - .anyMatch(controllerId -> controllerId.equals(targetId.get())); - } - return false; + return Lists.newArrayList(); } @EventBusListenerMethod(scope = EventScope.UI) diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/CustomRendererWidgetSet.gwt.xml b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/CustomRendererWidgetSet.gwt.xml index 04e0de679..8b9a6c66d 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/CustomRendererWidgetSet.gwt.xml +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/CustomRendererWidgetSet.gwt.xml @@ -20,7 +20,7 @@ - + diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/dd/CustomAcceptCriteria.gwt.xml b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/dd/CustomAcceptCriteria.gwt.xml index fe4a19781..475237479 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/dd/CustomAcceptCriteria.gwt.xml +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/dd/CustomAcceptCriteria.gwt.xml @@ -22,7 +22,7 @@ - + diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/DistributionsView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/DistributionsView.java index 0564061ad..f7b3ca531 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/DistributionsView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/DistributionsView.java @@ -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.state.ManageDistUIState; 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.push.DistributionSetCreatedEventContainer; import org.eclipse.hawkbit.ui.push.DistributionSetDeletedEventContainer; @@ -95,8 +96,8 @@ public class DistributionsView extends AbstractNotificationView implements Brows @Autowired DistributionsView(final SpPermissionChecker permChecker, final UIEventBus eventBus, final VaadinMessageSource i18n, - final UINotification uiNotification, final ManageDistUIState manageDistUIState, - final SoftwareModuleManagement softwareModuleManagement, + final UINotification uiNotification, final ManagementUIState managementUIState, + final ManageDistUIState manageDistUIState, final SoftwareModuleManagement softwareModuleManagement, final SoftwareModuleTypeManagement softwareModuleTypeManagement, final DistributionSetManagement distributionSetManagement, 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, entityFactory, uiNotification, softwareModuleTypeManagement, distributionSetTypeManagement, dsTypeFilterButtons); - this.distributionTableLayout = new DistributionSetTableLayout(i18n, eventBus, permChecker, manageDistUIState, - softwareModuleManagement, distributionSetManagement, distributionSetTypeManagement, targetManagement, - entityFactory, uiNotification, distributionSetTagManagement, distributionsViewClientCriterion, - systemManagement, configManagement, systemSecurityContext); + this.distributionTableLayout = new DistributionSetTableLayout(i18n, eventBus, permChecker, managementUIState, + manageDistUIState, softwareModuleManagement, distributionSetManagement, distributionSetTypeManagement, + targetManagement, entityFactory, uiNotification, distributionSetTagManagement, + distributionsViewClientCriterion, systemManagement, configManagement, systemSecurityContext); this.softwareModuleTableLayout = new SwModuleTableLayout(i18n, uiNotification, eventBus, softwareModuleManagement, softwareModuleTypeManagement, entityFactory, manageDistUIState, permChecker, distributionsViewClientCriterion, artifactUploadState, artifactManagement); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTableLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTableLayout.java index 3ee0a78f1..b5a01612a 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTableLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTableLayout.java @@ -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.distributions.state.ManageDistUIState; 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.VaadinMessageSource; import org.vaadin.spring.events.EventBus.UIEventBus; @@ -36,8 +37,8 @@ public class DistributionSetTableLayout extends AbstractTableLayout + diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java index 83ab708a4..cd02aed92 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java @@ -227,11 +227,27 @@ public class DistributionTable extends AbstractNamedVersionTable { - if (managementUIEvent == ManagementUIEvent.UNASSIGN_DISTRIBUTION_TAG - || managementUIEvent == ManagementUIEvent.ASSIGN_DISTRIBUTION_TAG) { + if (tableIsFilteredByTagsAndTagWasUnassignedFromDistSet(managementUIEvent) + || tableIsFilteredByNoTagAndTagWasAssignedToDistSet(managementUIEvent)) { refreshFilter(); } }); @@ -263,8 +279,8 @@ public class DistributionTable extends AbstractNamedVersionTable list = new ArrayList<>(); queryConfig.put(SPUIDefinitions.FILTER_BY_NO_TAG, managementUIState.getDistributionTableFilters().isNoTagSelected()); - if (!managementUIState.getDistributionTableFilters().getDistSetTags().isEmpty()) { - list.addAll(managementUIState.getDistributionTableFilters().getDistSetTags()); + if (!managementUIState.getDistributionTableFilters().getClickedDistSetTags().isEmpty()) { + list.addAll(managementUIState.getDistributionTableFilters().getClickedDistSetTags()); } queryConfig.put(SPUIDefinitions.FILTER_BY_TAG, list); return queryConfig; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagButtonClick.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagButtonClick.java index 9e4e9d26e..9a2aae5d8 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagButtonClick.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagButtonClick.java @@ -39,7 +39,7 @@ public class DistributionTagButtonClick extends AbstractFilterMultiButtonClick { if (clickedButton.getData().equals(SPUIDefinitions.NO_TAG_BUTTON_ID)) { managementUIState.getDistributionTableFilters().setNoTagSelected(false); } else { - managementUIState.getDistributionTableFilters().getDistSetTags().remove(clickedButton.getId()); + managementUIState.getDistributionTableFilters().getClickedDistSetTags().remove(clickedButton.getId()); } eventBus.publish(this, new RefreshDistributionTableByFilterEvent()); } @@ -49,7 +49,7 @@ public class DistributionTagButtonClick extends AbstractFilterMultiButtonClick { if (clickedButton.getData().equals(SPUIDefinitions.NO_TAG_BUTTON_ID)) { managementUIState.getDistributionTableFilters().setNoTagSelected(true); } else { - managementUIState.getDistributionTableFilters().getDistSetTags().add(clickedButton.getId()); + managementUIState.getDistributionTableFilters().getClickedDistSetTags().add(clickedButton.getId()); } eventBus.publish(this, new RefreshDistributionTableByFilterEvent()); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagButtons.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagButtons.java index f9a871edc..78de4cfe0 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagButtons.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagButtons.java @@ -107,8 +107,8 @@ public class DistributionTagButtons extends AbstractFilterButtons { @Override protected boolean isClickedByDefault(final String tagName) { - return null != managementUIState.getDistributionTableFilters().getDistSetTags() - && managementUIState.getDistributionTableFilters().getDistSetTags().contains(tagName); + return null != managementUIState.getDistributionTableFilters().getClickedDistSetTags() + && managementUIState.getDistributionTableFilters().getClickedDistSetTags().contains(tagName); } @Override @@ -173,7 +173,7 @@ public class DistributionTagButtons extends AbstractFilterButtons { protected void deleteEntity(final String entityToDelete) { final Optional tagToDelete = distributionSetTagManagement.getByName(entityToDelete); tagToDelete.ifPresent(tag -> { - if (managementUIState.getDistributionTableFilters().getDistSetTags().contains(entityToDelete)) { + if (managementUIState.getDistributionTableFilters().getClickedDistSetTags().contains(entityToDelete)) { uiNotification.displayValidationError(getI18n().getMessage("message.tag.delete", entityToDelete)); removeUpdateAndDeleteColumn(); } else { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/DistributionTagDropEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/DistributionTagDropEvent.java index bd2f0f6ef..15f4e021c 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/DistributionTagDropEvent.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/DistributionTagDropEvent.java @@ -139,7 +139,7 @@ public class DistributionTagDropEvent implements DropHandler { final String distTagName = HawkbitCommonUtil.removePrefix(targetDetails.getTarget().getId(), SPUIDefinitions.DISTRIBUTION_TAG_ID_PREFIXS); - final List tagsClickedList = distFilterParameters.getDistSetTags(); + final List tagsClickedList = distFilterParameters.getClickedDistSetTags(); final DistributionSetTagAssignmentResult result = distributionSetManagement.toggleTagAssignment(distSelected, distTagName); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/state/DistributionTableFilters.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/state/DistributionTableFilters.java index 1fb45182a..3730f28a7 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/state/DistributionTableFilters.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/state/DistributionTableFilters.java @@ -35,7 +35,7 @@ public class DistributionTableFilters implements Serializable { private TargetIdName pinnedTarget; - private final List distSetTags = new ArrayList<>(); + private final List clickedDistSetTags = new ArrayList<>(); private Boolean noTagSelected = Boolean.FALSE; @@ -47,8 +47,8 @@ public class DistributionTableFilters implements Serializable { return noTagSelected; } - public List getDistSetTags() { - return distSetTags; + public List getClickedDistSetTags() { + return clickedDistSetTags; } public Optional getDistId() { @@ -74,5 +74,4 @@ public class DistributionTableFilters implements Serializable { public void setSearchText(final String searchText) { this.searchText = searchText; } - } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java index 3c7549ab7..627f263d4 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java @@ -23,7 +23,6 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.Map; import java.util.concurrent.Executor; 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.exception.EntityAlreadyExistsException; 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.management.event.BulkUploadValidationMessageEvent; import org.eclipse.hawkbit.ui.management.event.TargetTableEvent; @@ -287,7 +286,7 @@ public class BulkUploadHandler extends CustomComponent String dsAssignmentFailedMsg = null; String tagAssignmentFailedMsg = null; if (ifTargetsCreatedSuccessfully()) { - if (ifTagsSelected()) { + if (targetBulkTokenTags.isTagSelectedForAssignment()) { tagAssignmentFailedMsg = tagAssignment(); } if (ifDsSelected()) { @@ -312,9 +311,8 @@ public class BulkUploadHandler extends CustomComponent } private String tagAssignment() { - final Map tokensSelected = targetBulkTokenTags.getTokensAdded(); final List deletedTags = new ArrayList<>(); - for (final TagData tagData : tokensSelected.values()) { + for (final TagData tagData : targetBulkTokenTags.getSelectedTagsForAssignment()) { if (!tagManagement.get(tagData.getId()).isPresent()) { deletedTags.add(tagData.getName()); } else { @@ -332,10 +330,6 @@ public class BulkUploadHandler extends CustomComponent return i18n.getMessage("message.bulk.upload.tag.assignments.failed"); } - private boolean ifTagsSelected() { - return targetBulkTokenTags.getTokenField().getValue() != null; - } - private boolean ifDsSelected() { return comboBox.getValue() != null; } @@ -375,6 +369,7 @@ public class BulkUploadHandler extends CustomComponent } catch (final EntityAlreadyExistsException ex) { // Targets that exist already are simply ignored + LOG.info("Entity {} - {} already exists and will be ignored", newControllerId, name); } } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBulkTokenTags.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBulkTokenTags.java index 8febaf76e..69b55f84e 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBulkTokenTags.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBulkTokenTags.java @@ -8,12 +8,15 @@ */ 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.model.TargetTag; +import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.ui.SpPermissionChecker; 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.utils.UINotification; 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. * */ -public class TargetBulkTokenTags extends AbstractTargetTagToken { +public class TargetBulkTokenTags extends AbstractTargetTagToken { private static final long serialVersionUID = 4159616629565523717L; - private static final int MAX_TAGS = 500; - TargetBulkTokenTags(final SpPermissionChecker checker, final VaadinMessageSource i18n, final UINotification uinotification, final UIEventBus eventBus, final ManagementUIState managementUIState, final TargetTagManagement tagManagement) { @@ -36,24 +37,15 @@ public class TargetBulkTokenTags extends AbstractTargetTagToken { } @Override - protected void assignTag(final String tagNameSelected) { - managementUIState.getTargetTableFilters().getBulkUpload().getAssignedTagNames().add(tagNameSelected); - + protected void assignTag(final TagData tagData) { + managementUIState.getTargetTableFilters().getBulkUpload().getAssignedTagNames().add(tagData.getName()); + tagPanelLayout.setAssignedTag(tagData); } @Override - protected void unassignTag(final String tagName) { - managementUIState.getTargetTableFilters().getBulkUpload().getAssignedTagNames().remove(tagName); - } - - @Override - protected String getTagStyleName() { - return "target-tag-"; - } - - @Override - protected String getTokenInputPrompt() { - return i18n.getMessage("combo.type.tag.name"); + protected void unassignTag(final TagData tagData) { + managementUIState.getTargetTableFilters().getBulkUpload().getAssignedTagNames().remove(tagData.getName()); + tagPanelLayout.removeAssignedTag(tagData); } @Override @@ -61,29 +53,32 @@ public class TargetBulkTokenTags extends AbstractTargetTagToken { return checker.hasCreateTargetPermission(); } - @Override - public void displayAlreadyAssignedTags() { - removePreviouslyAddedTokens(); - addAlreadySelectedTags(); + /** + * Initializes the Tags + */ + public void initializeTags() { + repopulateTags(); } - protected void addAlreadySelectedTags() { - for (final String tagName : managementUIState.getTargetTableFilters().getBulkUpload().getAssignedTagNames()) { - tagManagement.getByName(tagName).map(TargetTag::getId).ifPresent(this::addNewToken); - } + public boolean isTagSelectedForAssignment() { + return !tagPanelLayout.getAssignedTags().isEmpty(); } @Override - protected void populateContainer() { - container.removeAllItems(); - tagDetails.clear(); - for (final TargetTag tag : tagManagement.findAll(PageRequest.of(0, MAX_TAGS))) { - setContainerPropertValues(tag.getId(), tag.getName(), tag.getColour()); - } - + protected List getAllTags() { + return tagManagement.findAll(PageRequest.of(0, MAX_TAG_QUERY)).stream() + .map(tag -> new TagData(tag.getId(), tag.getName(), tag.getColour())).collect(Collectors.toList()); } - public Map getTokensAdded() { - return tokensAdded; + @Override + protected List 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 getSelectedTagsForAssignment() { + return tagPanelLayout.getAssignedTags().stream().map(tagDetailsByName::get).collect(Collectors.toList()); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBulkUpdateWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBulkUpdateWindowLayout.java index 7f0ab9ae6..93e0a3fe7 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBulkUpdateWindowLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBulkUpdateWindowLayout.java @@ -21,6 +21,7 @@ import org.eclipse.hawkbit.ui.SpPermissionChecker; import org.eclipse.hawkbit.ui.UiProperties; import org.eclipse.hawkbit.ui.common.builder.TextAreaBuilder; 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.decorators.SPUIButtonStyleNoBorder; 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.spring.events.EventBus; import org.vaadin.spring.events.EventBus.UIEventBus; -import org.vaadin.tokenfield.TokenField; import com.google.common.collect.Maps; import com.vaadin.data.Container; @@ -220,10 +220,11 @@ public class TargetBulkUpdateWindowLayout extends CustomComponent { } private VerticalLayout getTokenFieldLayout() { - final TokenField tokenField = targetBulkTokenTags.getTokenField(); + final TagPanelLayout tagPanelLayout = targetBulkTokenTags.getTagPanel(); + tagPanelLayout.setMargin(false); final VerticalLayout tokenLayout = SPUIComponentProvider.getDetailTabLayout(); tokenLayout.addStyleName("bulk-target-tags-layout"); - tokenLayout.addComponent(tokenField); + tokenLayout.addComponent(tagPanelLayout); tokenLayout.setSpacing(false); tokenLayout.setMargin(false); tokenLayout.setSizeFull(); @@ -249,7 +250,7 @@ public class TargetBulkUpdateWindowLayout extends CustomComponent { managementUIState.getDistributionTableFilters().isNoTagSelected()); queryConfiguration.put(SPUIDefinitions.FILTER_BY_TAG, - managementUIState.getDistributionTableFilters().getDistSetTags()); + managementUIState.getDistributionTableFilters().getClickedDistSetTags()); final BeanQueryFactory distributionQF = new BeanQueryFactory<>( DistributionBeanQuery.class); @@ -286,8 +287,7 @@ public class TargetBulkUpdateWindowLayout extends CustomComponent { public void resetComponents() { dsNamecomboBox.clear(); descTextArea.clear(); - targetBulkTokenTags.getTokenField().clear(); - targetBulkTokenTags.populateContainer(); + targetBulkTokenTags.initializeTags(); progressBar.setValue(0F); progressBar.setVisible(false); managementUIState.getTargetTableFilters().getBulkUpload().setProgressBarCurrentValue(0F); @@ -308,12 +308,11 @@ public class TargetBulkUpdateWindowLayout extends CustomComponent { * Restore the target bulk upload layout field values. */ public void restoreComponentsValue() { - targetBulkTokenTags.populateContainer(); final TargetBulkUpload targetBulkUpload = managementUIState.getTargetTableFilters().getBulkUpload(); progressBar.setValue(targetBulkUpload.getProgressBarCurrentValue()); dsNamecomboBox.setValue(targetBulkUpload.getDsNameAndVersion()); descTextArea.setValue(targetBulkUpload.getDescription()); - targetBulkTokenTags.addAlreadySelectedTags(); + targetBulkTokenTags.initializeTags(); if (targetBulkUpload.getProgressBarCurrentValue() >= 1) { targetsCountLabel.setVisible(true); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java index 71189f0a8..982ba28d2 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java @@ -221,13 +221,21 @@ public class TargetTable extends AbstractTable { @EventBusListenerMethod(scope = EventScope.UI) void onEvent(final ManagementUIEvent managementUIEvent) { UI.getCurrent().access(() -> { - if (managementUIEvent == ManagementUIEvent.UNASSIGN_TARGET_TAG - || managementUIEvent == ManagementUIEvent.ASSIGN_TARGET_TAG) { + if (tableIsFilteredByTagsAndTagWasUnassignedFromTarget(managementUIEvent) + || tableIsFilteredByNoTagAndTagWasAssignedToTarget(managementUIEvent)) { 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) void onEvent(final SaveActionWindowEvent event) { if (event == SaveActionWindowEvent.SAVED_ASSIGNMENTS) { @@ -842,6 +850,10 @@ public class TargetTable extends AbstractTable { return !managementUIState.getTargetTableFilters().getClickedTargetTags().isEmpty(); } + private boolean isFilteredByNoTag() { + return managementUIState.getTargetTableFilters().isNoTagSelected(); + } + private void assignDsToTarget(final DragAndDropEvent event) { final TableTransferable transferable = (TableTransferable) event.getTransferable(); final AbstractTable source = (AbstractTable) transferable.getSourceComponent(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/groupschart/GroupsPieChart.gwt.xml b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/groupschart/GroupsPieChart.gwt.xml index bf6f30341..010971890 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/groupschart/GroupsPieChart.gwt.xml +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/groupschart/GroupsPieChart.gwt.xml @@ -16,7 +16,7 @@ - + diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIStyleDefinitions.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIStyleDefinitions.java index 9b5e67a94..a521fb071 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIStyleDefinitions.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/SPUIStyleDefinitions.java @@ -119,6 +119,14 @@ public final class SPUIStyleDefinitions { */ 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. */ diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java index b96e67f48..aa4fbbd35 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIComponentIdProvider.java @@ -693,6 +693,16 @@ public final class UIComponentIdProvider { */ 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. */ @@ -973,7 +983,10 @@ public final class UIComponentIdProvider { * Rollout group remove button 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. */ diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIMessageIdProvider.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIMessageIdProvider.java index 05e874c9f..a810877df 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIMessageIdProvider.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/UIMessageIdProvider.java @@ -113,6 +113,12 @@ public final class UIMessageIdProvider { 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_CONFIGURE = "tooltip.configure"; diff --git a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/popup-window.scss b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/popup-window.scss index cb936685b..809547aa8 100644 --- a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/popup-window.scss +++ b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/popup-window.scss @@ -182,6 +182,7 @@ border-right: 1px solid #bfc3c8; border-bottom: 1px solid #bfc3c8; border-radius: 4px; + overflow-y: auto; } .bulk-upload-ds-combo{ margin-top: 2px !important; diff --git a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/tags.scss b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/tags.scss index c268df035..7a1231e12 100644 --- a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/tags.scss +++ b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/tags.scss @@ -121,4 +121,12 @@ #target\.tag\.drop\.area .v-slot-icon-only { height: 32px; } + + .button-tag-with-background { + background-color: lightgrey !important; + } + + .button-assign-tag { + padding-top: 5px; + } } diff --git a/hawkbit-ui/src/main/resources/messages.properties b/hawkbit-ui/src/main/resources/messages.properties index c67d0959f..613428475 100644 --- a/hawkbit-ui/src/main/resources/messages.properties +++ b/hawkbit-ui/src/main/resources/messages.properties @@ -298,6 +298,7 @@ tooltip.timeforced.forced.since=Auto forced since {0} tooltip.check.for.mandatory=Check to make Mandatory tooltip.artifact.icon=Show Artifact Details tooltip.click.to.edit = Click to edit +tooltip.click.to.remove = Click to remove tooltip.metadata.icon = Manage Metadata.. tooltip.next.maintenance.window = next on {0} tooltip.target.attributes.update.request = Request attributes update @@ -334,6 +335,8 @@ tooltip.maximize = Maximize tooltip.minimize = Minimize tooltip.bulkUpload = Bulk Upload.. tooltip.showTags = Show Tags +tooltip.assignTag = Assign Tag +tooltip.selectTag = Select Tag tooltip.update = Edit.. tooltip.reset = Reset tooltip.configure = Configure.. @@ -609,7 +612,6 @@ header.caption.typename = SoftwareModuleType header.caption.softwaremodule = SoftwareModule message.sw.unassigned = Software Module {0} successfully unassigned header.caption.upload.details = Upload details -combo.type.tag.name = Type tag name label.yes = Yes label.no = No diff --git a/pom.xml b/pom.xml index 7f7e5b66a..9f4dd376a 100644 --- a/pom.xml +++ b/pom.xml @@ -152,8 +152,7 @@ 7.7.13 ${vaadin.version} 7.6.1.3 - 2.2.0 - 7.0.1 + 2.2.0 2.0.0 @@ -594,11 +593,6 @@ flexibleoptiongroup ${vaadin.addon.flexibleoptiongroup.version} - - org.vaadin.addons - tokenfield - ${vaadin.addon.tokenfield.version} - org.vaadin.alump.distributionbar dbar-addon