diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AbstractHawkbitUI.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AbstractHawkbitUI.java index 422b3bb89..da6905235 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AbstractHawkbitUI.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AbstractHawkbitUI.java @@ -226,14 +226,19 @@ public abstract class AbstractHawkbitUI extends UI implements DetachListener { private class ManagementViewProvider implements ViewProvider { private static final long serialVersionUID = 1L; + private static final String DEFAULT_PARAMETER_SEPARATOR = "/"; + @Override public String getViewName(final String viewAndParameters) { - return viewProvider.getViewName(getStartView(viewAndParameters)); + final int paramsDelimeterIndex = viewAndParameters.indexOf(DEFAULT_PARAMETER_SEPARATOR); + final String viewName = paramsDelimeterIndex != -1 ? viewAndParameters.substring(0, paramsDelimeterIndex) + : viewAndParameters; + return viewProvider.getViewName(getStartView(viewName)); } @Override public View getView(final String viewName) { - return viewProvider.getView(getStartView(viewName)); + return viewProvider.getView(viewName); } private String getStartView(final String viewName) { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEventListenersAwareView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEventListenersAwareView.java index 8787bfea2..f88e0c962 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEventListenersAwareView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEventListenersAwareView.java @@ -8,13 +8,20 @@ */ package org.eclipse.hawkbit.ui.common; +import java.util.AbstractMap; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; +import org.springframework.util.StringUtils; + import com.vaadin.navigator.View; import com.vaadin.navigator.ViewBeforeLeaveEvent; import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; @@ -27,6 +34,10 @@ import com.vaadin.ui.VerticalLayout; public abstract class AbstractEventListenersAwareView extends VerticalLayout implements View, ViewNameAware { private static final long serialVersionUID = 1L; + // directly taken from Vaadin Navigator for consistency + private static final String DEFAULT_STATE_PARAMETER_SEPARATOR = "&"; + private static final String DEFAULT_STATE_PARAMETER_KEY_VALUE_SEPARATOR = "="; + private final transient List eventAwareLayouts = new ArrayList<>(); private boolean initial; @@ -71,10 +82,24 @@ public abstract class AbstractEventListenersAwareView extends VerticalLayout imp if (initial) { restoreState(); initial = false; - return; + } else { + updateLayoutsOnViewEnter(); } - updateLayoutsOnViewEnter(); + if (StringUtils.hasText(event.getParameters())) { + handleStateParams(parseStateParameters(event.getParameters())); + } + } + + private static Map parseStateParameters(final String urlParams) { + return Arrays.stream(urlParams.split(DEFAULT_STATE_PARAMETER_SEPARATOR)).map(paramPair -> { + final String[] keyValue = paramPair.split(DEFAULT_STATE_PARAMETER_KEY_VALUE_SEPARATOR, 2); + if (keyValue.length == 2) { + return new AbstractMap.SimpleEntry<>(keyValue[0], keyValue[1]); + } + return null; + }).filter(Objects::nonNull) + .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)); } /** @@ -94,8 +119,17 @@ public abstract class AbstractEventListenersAwareView extends VerticalLayout imp } /** - * Called on on view enter for added event aware layouts to update their - * state. + * Handles state url parameters of added event aware layouts. + * + * @param stateParams + * map of view state url parameters + */ + protected void handleStateParams(final Map stateParams) { + eventAwareLayouts.forEach(layout -> layout.handleStateParameters(stateParams)); + } + + /** + * Called on view enter for added event aware layouts to update their state. * */ protected void updateLayoutsOnViewEnter() { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/EventListenersAwareLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/EventListenersAwareLayout.java index b4c351727..d6c63adbe 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/EventListenersAwareLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/EventListenersAwareLayout.java @@ -8,6 +8,8 @@ */ package org.eclipse.hawkbit.ui.common; +import java.util.Map; + /** * Interface for event aware event listeners * @@ -26,6 +28,15 @@ public interface EventListenersAwareLayout { default void onViewEnter() { } + /** + * Set components state based on url parameters + * + * @param stateParameters + * map of state url parameters + */ + default void handleStateParameters(final Map stateParameters) { + } + /** * Subscribe event listeners */ diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/SearchHeaderSupport.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/SearchHeaderSupport.java index db986133a..622bdbe15 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/SearchHeaderSupport.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/SearchHeaderSupport.java @@ -54,7 +54,7 @@ public class SearchHeaderSupport implements HeaderSupport { * @param searchResetIconId * Value supplier for search box * @param searchStateSupplier - * Search state supplier + * Search state supplier * @param searchByCallback * Callback for search event */ @@ -70,8 +70,6 @@ public class SearchHeaderSupport implements HeaderSupport { this.searchField = createSearchField(); this.searchResetIcon = createSearchResetIcon(); - - this.isSearchInputActive = false; } private TextField createSearchField() { @@ -108,7 +106,6 @@ public class SearchHeaderSupport implements HeaderSupport { // Clicked on search icon openSearchTextField(); } - isSearchInputActive = !isSearchInputActive; } private void openSearchTextField() { @@ -118,6 +115,8 @@ public class SearchHeaderSupport implements HeaderSupport { searchField.setVisible(true); searchField.focus(); + + isSearchInputActive = true; } private void closeSearchTextField() { @@ -129,6 +128,22 @@ public class SearchHeaderSupport implements HeaderSupport { searchField.setVisible(false); searchByCallback.accept(null); + + isSearchInputActive = false; + } + + /** + * Update the search and trigger the callback to refresh the grid. + * + * @param searchQuery + * search query + */ + public void setAndTriggerSearch(final String searchQuery) { + if (!StringUtils.isEmpty(searchQuery)) { + openSearchTextField(); + searchField.setValue(searchQuery); + searchByCallback.accept(searchQuery); + } } @Override @@ -138,7 +153,6 @@ public class SearchHeaderSupport implements HeaderSupport { if (!StringUtils.isEmpty(onLoadSearchBoxValue)) { openSearchTextField(); searchField.setValue(onLoadSearchBoxValue); - isSearchInputActive = true; } } @@ -162,7 +176,6 @@ public class SearchHeaderSupport implements HeaderSupport { public void resetSearch() { if (isSearchInputActive) { closeSearchTextField(); - isSearchInputActive = false; } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGrid.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGrid.java index 268748a97..cb3a1b498 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGrid.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGrid.java @@ -197,12 +197,24 @@ public class TargetGrid extends AbstractGrid mapIdToProxyEntity(final long entityId) { return targetManagement.get(entityId).map(targetToProxyTargetMapper::map); } + /** + * Map target controller id to proxy target entity + * + * @param controllerId + * controller id + * + * @return ProxyTarget + */ + public Optional mapControllerIdToProxyEntity(final String controllerId) { + return targetManagement.getByControllerID(controllerId).map(targetToProxyTargetMapper::map); + } + private Long getSelectedEntityIdFromUiState() { return targetGridLayoutUiState.getSelectedEntityId(); } @@ -290,7 +302,7 @@ public class TargetGrid extends AbstractGrid { filter.setDistributionId(null); filter.setNoTagClicked(false); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridHeader.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridHeader.java index 4e85ddf61..149043a89 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridHeader.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridHeader.java @@ -241,14 +241,25 @@ public class TargetGridHeader extends AbstractEntityGridHeader { } } + /** + * Update search programmatically. + * + * @param searchQuery + * search query + */ + public void updateSearch(final String searchQuery) { + getSearchHeaderSupport().setAndTriggerSearch(searchQuery); + } + /** * Enable search icon in the search header */ public void enableSearchIcon() { getSearchHeaderSupport().enableSearch(); } + /** - * Disable search icon in the search header + * Disable search icon in the search header. */ public void disabledSearchIcon() { getSearchHeaderSupport().disableSearch(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridLayout.java index 6a08e5b95..42ef3d1b2 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridLayout.java @@ -11,6 +11,7 @@ package org.eclipse.hawkbit.ui.management.targettable; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.Executor; import org.eclipse.hawkbit.repository.DeploymentManagement; @@ -57,6 +58,8 @@ import org.eclipse.hawkbit.ui.management.targettag.filter.TargetTagFilterLayoutU public class TargetGridLayout extends AbstractGridComponentLayout { private static final long serialVersionUID = 1L; + private static final String TARGET_STATE_PARAM = "target"; + private final TargetGridHeader targetGridHeader; private final TargetGrid targetGrid; private final TargetDetailsHeader targetDetailsHeader; @@ -107,23 +110,23 @@ public class TargetGridLayout extends AbstractGridComponentLayout { * DistributionGridLayoutUiState */ public TargetGridLayout(final CommonUiDependencies uiDependencies, final TargetManagement targetManagement, - final TargetTypeManagement targetTypeManagement, - final DeploymentManagement deploymentManagement, final UiProperties uiProperties, - final TargetTagManagement targetTagManagement, final DistributionSetManagement distributionSetManagement, - final Executor uiExecutor, final TenantConfigurationManagement configManagement, - final TargetManagementStateDataSupplier targetManagementStateDataSupplier, - final SystemSecurityContext systemSecurityContext, - final TargetTagFilterLayoutUiState targetTagFilterLayoutUiState, - final TargetGridLayoutUiState targetGridLayoutUiState, - final TargetBulkUploadUiState targetBulkUploadUiState, - final DistributionGridLayoutUiState distributionGridLayoutUiState) { - final TargetWindowBuilder targetWindowBuilder = new TargetWindowBuilder(uiDependencies, targetManagement, targetTypeManagement, - EventView.DEPLOYMENT); + final TargetTypeManagement targetTypeManagement, final DeploymentManagement deploymentManagement, + final UiProperties uiProperties, final TargetTagManagement targetTagManagement, + final DistributionSetManagement distributionSetManagement, final Executor uiExecutor, + final TenantConfigurationManagement configManagement, + final TargetManagementStateDataSupplier targetManagementStateDataSupplier, + final SystemSecurityContext systemSecurityContext, + final TargetTagFilterLayoutUiState targetTagFilterLayoutUiState, + final TargetGridLayoutUiState targetGridLayoutUiState, + final TargetBulkUploadUiState targetBulkUploadUiState, + final DistributionGridLayoutUiState distributionGridLayoutUiState) { + final TargetWindowBuilder targetWindowBuilder = new TargetWindowBuilder(uiDependencies, targetManagement, + targetTypeManagement, EventView.DEPLOYMENT); final TargetMetaDataWindowBuilder targetMetaDataWindowBuilder = new TargetMetaDataWindowBuilder(uiDependencies, targetManagement); final BulkUploadWindowBuilder bulkUploadWindowBuilder = new BulkUploadWindowBuilder(uiDependencies, - uiProperties, uiExecutor, targetManagement, deploymentManagement, targetTypeManagement, targetTagManagement, - distributionSetManagement, targetBulkUploadUiState); + uiProperties, uiExecutor, targetManagement, deploymentManagement, targetTypeManagement, + targetTagManagement, distributionSetManagement, targetBulkUploadUiState); this.targetGridHeader = new TargetGridHeader(uiDependencies, targetWindowBuilder, bulkUploadWindowBuilder, targetTagFilterLayoutUiState, targetGridLayoutUiState, targetBulkUploadUiState); @@ -211,10 +214,10 @@ public class TargetGridLayout extends AbstractGridComponentLayout { if (isCustomFilterTabSelected) { targetGridHeader.disabledSearchIcon(); } - if(isTargetTypeFilterTabSelected){ + if (isTargetTypeFilterTabSelected) { targetGridHeader.enableSearchIcon(); } - if (isSimpleTypeFilterTabSelected){ + if (isSimpleTypeFilterTabSelected) { targetGridHeader.enableSearchIcon(); } @@ -246,6 +249,16 @@ public class TargetGridLayout extends AbstractGridComponentLayout { countMessageLabel.updatePinningDetails(); } + @Override + public void handleStateParameters(final Map stateParameters) { + if (stateParameters.containsKey(TARGET_STATE_PARAM)) { + final String stateTargetParam = stateParameters.get(TARGET_STATE_PARAM); + targetGridHeader.updateSearch(stateTargetParam); + targetGrid.mapControllerIdToProxyEntity(stateTargetParam) + .ifPresent(t -> targetGrid.getSelectionSupport().select(t)); + } + } + @Override public void onViewEnter() { targetGridHeader.checkBulkUpload();