UI deep-linking for targets (#1230)
* added target deeplinking through url param * populate search irregardless of target existence * adapted view state paramater evaluation flow * fixed review comments Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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<EventListenersAwareLayout> 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<String, String> 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<String, String> stateParams) {
|
||||
eventAwareLayouts.forEach(layout -> layout.handleStateParameters(stateParams));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on view enter for added event aware layouts to update their state.
|
||||
*
|
||||
*/
|
||||
protected void updateLayoutsOnViewEnter() {
|
||||
|
||||
@@ -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<String, String> stateParameters) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe event listeners
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -197,12 +197,24 @@ public class TargetGrid extends AbstractGrid<ProxyTarget, TargetManagementFilter
|
||||
* @param entityId
|
||||
* Entity id
|
||||
*
|
||||
* @return Target
|
||||
* @return ProxyTarget
|
||||
*/
|
||||
public Optional<ProxyTarget> 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<ProxyTarget> 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<ProxyTarget, TargetManagementFilter
|
||||
/**
|
||||
* Update filter on filter tab selection
|
||||
*/
|
||||
public void resetAllFilters(){
|
||||
public void resetAllFilters() {
|
||||
getFilter().ifPresent(filter -> {
|
||||
filter.setDistributionId(null);
|
||||
filter.setNoTagClicked(false);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<String, String> 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();
|
||||
|
||||
Reference in New Issue
Block a user