Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com>
This commit is contained in:
1
hawkbit-ui/src/main/.gitignore
vendored
1
hawkbit-ui/src/main/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
/webapp/
|
||||
@@ -1,271 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui;
|
||||
|
||||
import com.vaadin.shared.ui.ContentMode;
|
||||
import org.eclipse.hawkbit.ui.components.NotificationUnreadButton;
|
||||
import org.eclipse.hawkbit.ui.error.ErrorView;
|
||||
import org.eclipse.hawkbit.ui.menu.DashboardEvent.PostViewChangeEvent;
|
||||
import org.eclipse.hawkbit.ui.menu.DashboardMenu;
|
||||
import org.eclipse.hawkbit.ui.menu.DashboardMenuItem;
|
||||
import org.eclipse.hawkbit.ui.push.EventPushStrategy;
|
||||
import org.eclipse.hawkbit.ui.push.UIEventProvider;
|
||||
import org.eclipse.hawkbit.ui.themes.HawkbitTheme;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.annotations.Theme;
|
||||
import com.vaadin.annotations.Title;
|
||||
import com.vaadin.annotations.Widgetset;
|
||||
import com.vaadin.navigator.Navigator;
|
||||
import com.vaadin.navigator.View;
|
||||
import com.vaadin.navigator.ViewChangeListener;
|
||||
import com.vaadin.navigator.ViewProvider;
|
||||
import com.vaadin.server.ClientConnector.DetachListener;
|
||||
import com.vaadin.server.ErrorHandler;
|
||||
import com.vaadin.server.Responsive;
|
||||
import com.vaadin.server.VaadinRequest;
|
||||
import com.vaadin.spring.navigator.SpringViewProvider;
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.Component;
|
||||
import com.vaadin.ui.CssLayout;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.Panel;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
/**
|
||||
* Vaadin management UI.
|
||||
*
|
||||
*/
|
||||
@Title("hawkBit Update Server")
|
||||
@Widgetset(value = HawkbitTheme.WIDGET_SET_NAME)
|
||||
@Theme(HawkbitTheme.THEME_NAME)
|
||||
public abstract class AbstractHawkbitUI extends UI implements DetachListener {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractHawkbitUI.class);
|
||||
|
||||
private static final String EMPTY_VIEW = "";
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
private final UiProperties uiProperties;
|
||||
|
||||
private Label viewTitle;
|
||||
|
||||
private final DashboardMenu dashboardMenu;
|
||||
private final ErrorView errorview;
|
||||
private final NotificationUnreadButton notificationUnreadButton;
|
||||
|
||||
private final SpringViewProvider viewProvider;
|
||||
private final transient ApplicationContext context;
|
||||
private final transient EventPushStrategy pushStrategy;
|
||||
private final transient ErrorHandler uiErrorHandler;
|
||||
|
||||
private final transient HawkbitEntityEventListener entityEventsListener;
|
||||
|
||||
protected AbstractHawkbitUI(final EventPushStrategy pushStrategy, final UIEventBus eventBus,
|
||||
final UIEventProvider eventProvider, final SpringViewProvider viewProvider,
|
||||
final ApplicationContext context, final DashboardMenu dashboardMenu, final ErrorView errorview,
|
||||
final NotificationUnreadButton notificationUnreadButton, final UiProperties uiProperties,
|
||||
final VaadinMessageSource i18n, final ErrorHandler uiErrorHandler) {
|
||||
this.pushStrategy = pushStrategy;
|
||||
this.viewProvider = viewProvider;
|
||||
this.context = context;
|
||||
this.dashboardMenu = dashboardMenu;
|
||||
this.errorview = errorview;
|
||||
this.notificationUnreadButton = notificationUnreadButton;
|
||||
this.uiProperties = uiProperties;
|
||||
this.i18n = i18n;
|
||||
this.uiErrorHandler = uiErrorHandler;
|
||||
|
||||
this.entityEventsListener = new HawkbitEntityEventListener(eventBus, eventProvider, notificationUnreadButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach(final DetachEvent event) {
|
||||
LOG.debug("ManagementUI is detached uiid - {}", getUIId());
|
||||
|
||||
entityEventsListener.unsubscribeListeners();
|
||||
|
||||
if (pushStrategy != null) {
|
||||
pushStrategy.clean();
|
||||
clearContextListener();
|
||||
}
|
||||
}
|
||||
|
||||
private void clearContextListener() {
|
||||
if (pushStrategy instanceof ApplicationListener && context instanceof AbstractApplicationContext) {
|
||||
final ApplicationListener<?> listener = (ApplicationListener<?>) pushStrategy;
|
||||
((AbstractApplicationContext) context).getApplicationListeners().remove(listener);
|
||||
|
||||
// we do not need to explicitly remove the listener from
|
||||
// ApplicationEventMulticaster because it is done by
|
||||
// UIBeanStore#destroy delegating to
|
||||
// ApplicationListenerDetector#postProcessBeforeDestruction
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init(final VaadinRequest vaadinRequest) {
|
||||
LOG.debug("ManagementUI init starts uiid - {}", getUI().getUIId());
|
||||
if (pushStrategy != null) {
|
||||
pushStrategy.init(getUI());
|
||||
}
|
||||
addDetachListener(this);
|
||||
|
||||
Responsive.makeResponsive(this);
|
||||
addStyleName(ValoTheme.UI_WITH_MENU);
|
||||
setResponsive(Boolean.TRUE);
|
||||
|
||||
final HorizontalLayout rootLayout = new HorizontalLayout();
|
||||
rootLayout.setMargin(false);
|
||||
rootLayout.setSpacing(false);
|
||||
rootLayout.setSizeFull();
|
||||
|
||||
HawkbitCommonUtil.initLocalization(this, uiProperties.getLocalization(), i18n);
|
||||
SPDateTimeUtil.initializeFixedTimeZoneProperty(uiProperties.getFixedTimeZone());
|
||||
|
||||
dashboardMenu.init();
|
||||
dashboardMenu.setResponsive(true);
|
||||
|
||||
final VerticalLayout contentVerticalLayout = new VerticalLayout();
|
||||
contentVerticalLayout.setMargin(false);
|
||||
contentVerticalLayout.setSpacing(false);
|
||||
contentVerticalLayout.setSizeFull();
|
||||
contentVerticalLayout.setStyleName("main-content");
|
||||
contentVerticalLayout.addComponent(buildHeader());
|
||||
contentVerticalLayout.addComponent(buildViewTitle());
|
||||
|
||||
final Panel content = buildContent();
|
||||
contentVerticalLayout.addComponent(content);
|
||||
contentVerticalLayout.setExpandRatio(content, 1.0F);
|
||||
|
||||
String footerNotification = uiProperties.getNotification().getText();
|
||||
if (!ObjectUtils.isEmpty(footerNotification)) {
|
||||
contentVerticalLayout.addComponent(buildFooterNotification(footerNotification));
|
||||
}
|
||||
|
||||
rootLayout.addComponent(dashboardMenu);
|
||||
rootLayout.addComponent(contentVerticalLayout);
|
||||
rootLayout.setExpandRatio(contentVerticalLayout, 1.0F);
|
||||
setContent(rootLayout);
|
||||
|
||||
final Navigator navigator = new Navigator(this, content);
|
||||
navigator.addViewChangeListener(new ViewChangeListener() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public boolean beforeViewChange(final ViewChangeEvent event) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterViewChange(final ViewChangeEvent event) {
|
||||
final DashboardMenuItem view = dashboardMenu.getByViewName(event.getViewName());
|
||||
dashboardMenu.postViewChange(new PostViewChangeEvent(view));
|
||||
if (view == null) {
|
||||
viewTitle.setCaption(null);
|
||||
return;
|
||||
}
|
||||
viewTitle.setCaption(view.getDashboardCaptionLong());
|
||||
}
|
||||
});
|
||||
|
||||
navigator.setErrorView(errorview);
|
||||
navigator.addView(EMPTY_VIEW, new Navigator.EmptyView());
|
||||
navigator.addProvider(new ManagementViewProvider());
|
||||
setNavigator(navigator);
|
||||
|
||||
if (UI.getCurrent().getErrorHandler() == null) {
|
||||
UI.getCurrent().setErrorHandler(uiErrorHandler);
|
||||
}
|
||||
|
||||
LOG.debug("Current locale of the application is : {}", getLocale());
|
||||
}
|
||||
|
||||
private static Component buildFooterNotification(String text) {
|
||||
Label notification = new Label();
|
||||
notification.setValue(text);
|
||||
notification.setWidth("100%");
|
||||
notification.setContentMode(ContentMode.HTML);
|
||||
return notification;
|
||||
}
|
||||
|
||||
private static Panel buildContent() {
|
||||
final Panel content = new Panel();
|
||||
content.setSizeFull();
|
||||
content.setStyleName("view-content");
|
||||
return content;
|
||||
}
|
||||
|
||||
private HorizontalLayout buildViewTitle() {
|
||||
final HorizontalLayout viewHeadercontent = new HorizontalLayout();
|
||||
viewHeadercontent.setMargin(false);
|
||||
viewHeadercontent.setSpacing(false);
|
||||
viewHeadercontent.setWidth("100%");
|
||||
viewHeadercontent.addStyleName("view-header-layout");
|
||||
|
||||
viewTitle = new Label();
|
||||
viewTitle.setWidth("100%");
|
||||
viewTitle.setStyleName("header-content");
|
||||
viewHeadercontent.addComponent(viewTitle);
|
||||
|
||||
viewHeadercontent.addComponent(notificationUnreadButton);
|
||||
viewHeadercontent.setComponentAlignment(notificationUnreadButton, Alignment.MIDDLE_RIGHT);
|
||||
return viewHeadercontent;
|
||||
}
|
||||
|
||||
private static Component buildHeader() {
|
||||
final CssLayout cssLayout = new CssLayout();
|
||||
cssLayout.setStyleName("view-header");
|
||||
return cssLayout;
|
||||
}
|
||||
|
||||
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) {
|
||||
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(viewName);
|
||||
}
|
||||
|
||||
private String getStartView(final String viewName) {
|
||||
final DashboardMenuItem view = dashboardMenu.getByViewName(viewName);
|
||||
if ("".equals(viewName) && !dashboardMenu.isAccessibleViewsEmpty()) {
|
||||
return dashboardMenu.getInitialViewName();
|
||||
}
|
||||
if (view == null || dashboardMenu.isAccessDenied(viewName)) {
|
||||
return " ";
|
||||
}
|
||||
return viewName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
|
||||
This program and the accompanying materials are made
|
||||
available under the terms of the Eclipse Public License 2.0
|
||||
which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
|
||||
SPDX-License-Identifier: EPL-2.0
|
||||
|
||||
-->
|
||||
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.5.1//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.5.1/distro-source/core/src/gwt-module.dtd">
|
||||
<module>
|
||||
<!-- This file is automatically updated based on new dependencies by the goal "vaadin:update-widgetset". -->
|
||||
|
||||
<inherits name="com.vaadin.DefaultWidgetSet" />
|
||||
<inherits name="org.vaadin.alump.distributionbar.gwt.DistributionBarWidgetset" />
|
||||
<inherits name="org.eclipse.hawkbit.ui.filtermanagement.TextFieldSuggestionBox" />
|
||||
<inherits name="org.eclipse.hawkbit.ui.rollout.groupschart.GroupsPieChart" />
|
||||
<inherits
|
||||
name="org.eclipse.hawkbit.ui.common.grid.selection.RangeSelectionWidgetset" />
|
||||
<inherits
|
||||
name="org.eclipse.hawkbit.ui.common.notification.ParallelNotificationWidgetset" />
|
||||
</module>
|
||||
@@ -1,177 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
|
||||
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayloadIdentifier;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventTopics;
|
||||
import org.eclipse.hawkbit.ui.components.NotificationUnreadButton;
|
||||
import org.eclipse.hawkbit.ui.push.UIEventProvider;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.vaadin.spring.events.Event;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
import org.vaadin.spring.events.EventBusListenerMethodFilter;
|
||||
import org.vaadin.spring.events.EventScope;
|
||||
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.vaadin.ui.UI;
|
||||
|
||||
/**
|
||||
* Listener for internal and remote entity modified events. Keeps a cache of the
|
||||
* events coming from UI in order to suppress the corresponding remote events.
|
||||
*/
|
||||
public class HawkbitEntityEventListener {
|
||||
private final UIEventBus eventBus;
|
||||
private final UIEventProvider eventProvider;
|
||||
private final NotificationUnreadButton notificationUnreadButton;
|
||||
|
||||
private final Cache<EntityModifiedEventPayloadIdentifier, Collection<Long>> uiOriginatedEventsCache;
|
||||
private final List<Object> eventListeners;
|
||||
|
||||
HawkbitEntityEventListener(final UIEventBus eventBus, final UIEventProvider eventProvider,
|
||||
final NotificationUnreadButton notificationUnreadButton) {
|
||||
this.eventBus = eventBus;
|
||||
this.eventProvider = eventProvider;
|
||||
this.notificationUnreadButton = notificationUnreadButton;
|
||||
|
||||
this.uiOriginatedEventsCache = Caffeine.newBuilder().expireAfterWrite(10, SECONDS).build();
|
||||
|
||||
this.eventListeners = new ArrayList<>();
|
||||
registerEventListeners();
|
||||
}
|
||||
|
||||
private void registerEventListeners() {
|
||||
eventListeners.add(new EntityModifiedListener());
|
||||
eventListeners.add(new RemoteEventListener());
|
||||
}
|
||||
|
||||
private class EntityModifiedListener {
|
||||
|
||||
/**
|
||||
* Constructor for EntityModifiedListener
|
||||
*/
|
||||
public EntityModifiedListener() {
|
||||
eventBus.subscribe(this, EventTopics.ENTITY_MODIFIED);
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI, filter = IgnoreRemoteEventsFilter.class)
|
||||
private void onEntityModifiedEvent(final EntityModifiedEventPayload eventPayload) {
|
||||
// parentId is ignored here because entityIds should be unique
|
||||
uiOriginatedEventsCache.asMap().merge(EntityModifiedEventPayloadIdentifier.of(eventPayload),
|
||||
eventPayload.getEntityIds(), (oldEntityIds, newEntityIds) -> Stream
|
||||
.concat(oldEntityIds.stream(), newEntityIds.stream()).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore remote events filter
|
||||
*/
|
||||
public static class IgnoreRemoteEventsFilter implements EventBusListenerMethodFilter {
|
||||
|
||||
@Override
|
||||
public boolean filter(final Event<?> event) {
|
||||
return !event.getSource().equals(UI.getCurrent());
|
||||
}
|
||||
}
|
||||
|
||||
private class RemoteEventListener {
|
||||
|
||||
/**
|
||||
* Constructor for RemoteEventListener
|
||||
*/
|
||||
public RemoteEventListener() {
|
||||
eventBus.subscribe(this, EventTopics.REMOTE_EVENT_RECEIVED);
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
private void onRemoteEventReceived(final EntityModifiedEventPayload eventPayload) {
|
||||
if (eventPayload.getEntityType() == null || eventPayload.getEntityModifiedEventType() == null
|
||||
|| CollectionUtils.isEmpty(eventPayload.getEntityIds())) {
|
||||
return;
|
||||
}
|
||||
|
||||
getEventPayloadIdentifierFromProvider(eventPayload).ifPresent(eventPayloadIdentifier -> {
|
||||
final Collection<Long> remotelyModifiedEntityIds = getRemotelyModifiedEntityIds(eventPayloadIdentifier,
|
||||
eventPayload.getEntityIds());
|
||||
|
||||
if (!remotelyModifiedEntityIds.isEmpty()) {
|
||||
final EntityModifiedEventPayload remoteEventPayload = EntityModifiedEventPayload
|
||||
.of(eventPayloadIdentifier, eventPayload.getParentId(), remotelyModifiedEntityIds);
|
||||
|
||||
if (eventPayloadIdentifier.shouldBeDeffered()) {
|
||||
notificationUnreadButton.incrementUnreadNotification(
|
||||
eventPayloadIdentifier.getNotificationType(), remoteEventPayload);
|
||||
} else {
|
||||
eventBus.publish(EventTopics.ENTITY_MODIFIED, UI.getCurrent(), remoteEventPayload);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Optional<EntityModifiedEventPayloadIdentifier> getEventPayloadIdentifierFromProvider(
|
||||
final EntityModifiedEventPayload eventPayload) {
|
||||
return eventProvider.getEvents().values().stream().filter(providedIdentifier -> providedIdentifier
|
||||
.equals(EntityModifiedEventPayloadIdentifier.of(eventPayload))).findAny();
|
||||
}
|
||||
|
||||
private Collection<Long> getRemotelyModifiedEntityIds(
|
||||
final EntityModifiedEventPayloadIdentifier eventPayloadIdentifier,
|
||||
final Collection<Long> remoteEventEntityIds) {
|
||||
final Collection<Long> cachedEventEntityIds = uiOriginatedEventsCache.getIfPresent(eventPayloadIdentifier);
|
||||
|
||||
if (CollectionUtils.isEmpty(cachedEventEntityIds)) {
|
||||
return remoteEventEntityIds;
|
||||
}
|
||||
|
||||
final Collection<Long> commonEntityIds = getCommonEntityIds(cachedEventEntityIds, remoteEventEntityIds);
|
||||
if (!commonEntityIds.isEmpty()) {
|
||||
updateCache(eventPayloadIdentifier, cachedEventEntityIds, commonEntityIds);
|
||||
remoteEventEntityIds.removeAll(commonEntityIds);
|
||||
}
|
||||
|
||||
return remoteEventEntityIds;
|
||||
}
|
||||
|
||||
private Collection<Long> getCommonEntityIds(final Collection<Long> cachedEventEntityIds,
|
||||
final Collection<Long> remoteEventEntityIds) {
|
||||
final List<Long> commonEntityIds = new ArrayList<>(cachedEventEntityIds);
|
||||
commonEntityIds.retainAll(remoteEventEntityIds);
|
||||
|
||||
return commonEntityIds;
|
||||
}
|
||||
|
||||
private void updateCache(final EntityModifiedEventPayloadIdentifier eventPayloadIdentifier,
|
||||
final Collection<Long> cachedEventEntityIds, final Collection<Long> commonEntityIds) {
|
||||
final List<Long> updatedCachedEventEntityIds = new ArrayList<>(cachedEventEntityIds);
|
||||
updatedCachedEventEntityIds.removeAll(commonEntityIds);
|
||||
|
||||
if (updatedCachedEventEntityIds.isEmpty()) {
|
||||
uiOriginatedEventsCache.invalidate(eventPayloadIdentifier);
|
||||
} else {
|
||||
uiOriginatedEventsCache.put(eventPayloadIdentifier, updatedCachedEventEntityIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unsubscribeListeners() {
|
||||
eventListeners.forEach(eventBus::unsubscribe);
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
import com.vaadin.server.CustomizedSystemMessages;
|
||||
import com.vaadin.server.SystemMessages;
|
||||
import com.vaadin.server.SystemMessagesInfo;
|
||||
import com.vaadin.server.SystemMessagesProvider;
|
||||
|
||||
/**
|
||||
* {@link SystemMessagesProvider} that localizes Vaadin system messages.
|
||||
*
|
||||
*/
|
||||
public class LocalizedSystemMessagesProvider implements SystemMessagesProvider {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
private final UiProperties uiProperties;
|
||||
|
||||
/**
|
||||
* Constructor for LocalizedSystemMessagesProvider
|
||||
*
|
||||
* @param uiProperties
|
||||
* Properties to determine the available Locales
|
||||
* @param i18n
|
||||
* Message source used for localization
|
||||
*/
|
||||
public LocalizedSystemMessagesProvider(final UiProperties uiProperties, final VaadinMessageSource i18n) {
|
||||
this.i18n = i18n;
|
||||
this.uiProperties = uiProperties;
|
||||
}
|
||||
|
||||
private SystemMessages getLocalizedSystemMessages(final VaadinMessageSource i18n, final Locale local) {
|
||||
final CustomizedSystemMessages messages = new CustomizedSystemMessages();
|
||||
final Locale desiredLocale = HawkbitCommonUtil.getLocaleToBeUsed(uiProperties.getLocalization(), local);
|
||||
|
||||
messages.setSessionExpiredCaption(
|
||||
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_SESSIONEXPIRED_CAPTION));
|
||||
messages.setSessionExpiredMessage(
|
||||
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_SESSIONEXPIRED_MESSAGE));
|
||||
messages.setCommunicationErrorCaption(
|
||||
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_COMMUNICATIONERROR_CAPTION));
|
||||
messages.setCommunicationErrorMessage(
|
||||
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_COMMUNICATIONERROR_MESSAGE));
|
||||
messages.setInternalErrorCaption(
|
||||
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_INTERNALERROR_CAPTION));
|
||||
messages.setInternalErrorMessage(
|
||||
i18n.getMessage(desiredLocale, UIMessageIdProvider.VAADIN_SYSTEM_INTERNALERROR_MESSAGE));
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemMessages getSystemMessages(final SystemMessagesInfo systemMessagesInfo) {
|
||||
return getLocalizedSystemMessages(i18n, systemMessagesInfo.getLocale());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.PermissionService;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.ui.common.data.mappers.TargetToProxyTargetMapper;
|
||||
import org.eclipse.hawkbit.ui.common.data.suppliers.TargetFilterStateDataSupplier;
|
||||
import org.eclipse.hawkbit.ui.common.data.suppliers.TargetFilterStateDataSupplierImpl;
|
||||
import org.eclipse.hawkbit.ui.common.data.suppliers.TargetManagementStateDataSupplier;
|
||||
import org.eclipse.hawkbit.ui.common.data.suppliers.TargetManagementStateDataSupplierImpl;
|
||||
import org.eclipse.hawkbit.ui.error.HawkbitUIErrorHandler;
|
||||
import org.eclipse.hawkbit.ui.error.extractors.ArtifactEncryptionErrorExtractor;
|
||||
import org.eclipse.hawkbit.ui.error.extractors.ConstraintViolationErrorExtractor;
|
||||
import org.eclipse.hawkbit.ui.error.extractors.EntityNotFoundErrorExtractor;
|
||||
import org.eclipse.hawkbit.ui.error.extractors.IncompatibleTargetTypeErrorExtractor;
|
||||
import org.eclipse.hawkbit.ui.error.extractors.InsufficientPermissionErrorExtractor;
|
||||
import org.eclipse.hawkbit.ui.error.extractors.InvalidDistributionSetErrorExtractor;
|
||||
import org.eclipse.hawkbit.ui.error.extractors.AssignmentQuotaExceededErrorExtractor;
|
||||
import org.eclipse.hawkbit.ui.error.extractors.UiErrorDetailsExtractor;
|
||||
import org.eclipse.hawkbit.ui.error.extractors.UploadErrorExtractor;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.vaadin.spring.servlet.Vaadin4SpringServlet;
|
||||
|
||||
import com.vaadin.server.ErrorHandler;
|
||||
import com.vaadin.server.SystemMessagesProvider;
|
||||
import com.vaadin.server.VaadinServlet;
|
||||
import com.vaadin.spring.annotation.UIScope;
|
||||
|
||||
/**
|
||||
* Enables UI components for the Management UI.
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
@ComponentScan
|
||||
@EnableConfigurationProperties(UiProperties.class)
|
||||
@PropertySource("classpath:/hawkbit-ui-defaults.properties")
|
||||
public class MgmtUiConfiguration {
|
||||
|
||||
/**
|
||||
* Permission checker for UI.
|
||||
*
|
||||
* @param permissionService
|
||||
* PermissionService
|
||||
*
|
||||
* @return Permission checker for UI
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
SpPermissionChecker spPermissionChecker(final PermissionService permissionService) {
|
||||
return new SpPermissionChecker(permissionService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility for Vaadin messages source.
|
||||
*
|
||||
* @param source
|
||||
* Delegate MessageSource
|
||||
*
|
||||
* @return Vaadin messages source utility
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
VaadinMessageSource messageSourceVaadin(final MessageSource source) {
|
||||
return new VaadinMessageSource(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Localized system message provider bean.
|
||||
*
|
||||
* @param uiProperties
|
||||
* UiProperties
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
*
|
||||
* @return Localized system message provider
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
SystemMessagesProvider systemMessagesProvider(final UiProperties uiProperties, final VaadinMessageSource i18n) {
|
||||
return new LocalizedSystemMessagesProvider(uiProperties, i18n);
|
||||
}
|
||||
|
||||
/**
|
||||
* UI Error handler bean.
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param uiErrorDetailsExtractor
|
||||
* ui error details extractors
|
||||
*
|
||||
* @return UI Error handler
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ErrorHandler uiErrorHandler(final VaadinMessageSource i18n,
|
||||
final List<UiErrorDetailsExtractor> uiErrorDetailsExtractors) {
|
||||
return new HawkbitUIErrorHandler(i18n, uiErrorDetailsExtractors);
|
||||
}
|
||||
|
||||
/**
|
||||
* UI Upload Error details extractor bean.
|
||||
*
|
||||
* @return UI Upload Error details extractor
|
||||
*/
|
||||
@Bean
|
||||
UiErrorDetailsExtractor uploadErrorExtractor() {
|
||||
return new UploadErrorExtractor();
|
||||
}
|
||||
|
||||
/**
|
||||
* UI ConstraintViolation Error details extractor bean.
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @return UI ConstraintViolation Error details extractor
|
||||
*/
|
||||
@Bean
|
||||
UiErrorDetailsExtractor constraintViolationErrorExtractor(final VaadinMessageSource i18n) {
|
||||
return new ConstraintViolationErrorExtractor(i18n);
|
||||
}
|
||||
|
||||
/**
|
||||
* UI Entity not found Error details extractor bean.
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @return UI EntityNotFound Error details extractor
|
||||
*/
|
||||
@Bean
|
||||
UiErrorDetailsExtractor entityNotFoundErrorExtractor(final VaadinMessageSource i18n) {
|
||||
return new EntityNotFoundErrorExtractor(i18n);
|
||||
}
|
||||
|
||||
/**
|
||||
* UI incompatible Target Type error details extractor bean.
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @return UI IncompatibleTargetType Error details extractor
|
||||
*/
|
||||
@Bean
|
||||
UiErrorDetailsExtractor incompatibleTargetTypeErrorExtractor(final VaadinMessageSource i18n) {
|
||||
return new IncompatibleTargetTypeErrorExtractor(i18n);
|
||||
}
|
||||
|
||||
/**
|
||||
* UI Insufficient Permission Error details extractor bean.
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @return UI InsufficientPermission Error details extractor
|
||||
*/
|
||||
@Bean
|
||||
UiErrorDetailsExtractor insufficientPermissionErrorExtractor(final VaadinMessageSource i18n) {
|
||||
return new InsufficientPermissionErrorExtractor(i18n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Details extractor bean for action not possible because of distribution
|
||||
* set is invalid.
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @return UI invalid distributionset Error details extractor
|
||||
*/
|
||||
@Bean
|
||||
UiErrorDetailsExtractor invalidDistributionSetErrorExtractor(final VaadinMessageSource i18n) {
|
||||
return new InvalidDistributionSetErrorExtractor(i18n);
|
||||
}
|
||||
|
||||
/**
|
||||
* UI Artifact ecnryption operations Error details extractor bean.
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @return UI Artifact ecnryption operations Error details extractor
|
||||
*/
|
||||
@Bean
|
||||
UiErrorDetailsExtractor artifactEncryptionErrorExtractor(final VaadinMessageSource i18n) {
|
||||
return new ArtifactEncryptionErrorExtractor(i18n);
|
||||
}
|
||||
|
||||
/**
|
||||
* UI Assignment Quota exceeded Error details extractor bean.
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @return UI Assignment Quota exceeded Error details extractor
|
||||
*/
|
||||
@Bean
|
||||
UiErrorDetailsExtractor assignmentQuotaExceededErrorExtractor(final VaadinMessageSource i18n) {
|
||||
return new AssignmentQuotaExceededErrorExtractor(i18n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vaadin4Spring servlet bean.
|
||||
*
|
||||
* @return Vaadin servlet for Spring
|
||||
*/
|
||||
@Bean
|
||||
public VaadinServlet vaadinServlet() {
|
||||
return new Vaadin4SpringServlet();
|
||||
}
|
||||
|
||||
/**
|
||||
* UI target entity mapper bean.
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @return UI target entity mapper
|
||||
*/
|
||||
@Bean
|
||||
public TargetToProxyTargetMapper targetToProxyTargetMapper(final VaadinMessageSource i18n) {
|
||||
return new TargetToProxyTargetMapper(i18n);
|
||||
}
|
||||
|
||||
/**
|
||||
* UI Management target data supplier bean.
|
||||
*
|
||||
* @param targetManagement
|
||||
* TargetManagement
|
||||
* @param targetToProxyTargetMapper
|
||||
* UI target entity mapper
|
||||
* @return UI target data supplier for Management view
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@UIScope
|
||||
public TargetManagementStateDataSupplier targetManagementStateDataSupplier(final TargetManagement targetManagement,
|
||||
final TargetToProxyTargetMapper targetToProxyTargetMapper) {
|
||||
return new TargetManagementStateDataSupplierImpl(targetManagement, targetToProxyTargetMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* UI Filter target data supplier bean.
|
||||
*
|
||||
* @param targetManagement
|
||||
* TargetManagement
|
||||
* @param targetToProxyTargetMapper
|
||||
* UI target entity mapper
|
||||
* @return UI target data supplier for Filter view
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@UIScope
|
||||
public TargetFilterStateDataSupplier targetFilterStateDataSupplier(final TargetManagement targetManagement,
|
||||
final TargetToProxyTargetMapper targetToProxyTargetMapper) {
|
||||
return new TargetFilterStateDataSupplierImpl(targetManagement, targetToProxyTargetMapper);
|
||||
}
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.PermissionService;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
|
||||
/**
|
||||
* Bean which contains all permissions.
|
||||
*
|
||||
*/
|
||||
public class SpPermissionChecker implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected transient PermissionService permissionService;
|
||||
|
||||
protected SpPermissionChecker(final PermissionService permissionService) {
|
||||
this.permissionService = permissionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the read Target and repository Permission.
|
||||
*
|
||||
* @return TARGET_REPOSITORY_READ boolean value
|
||||
*/
|
||||
public boolean hasTargetAndRepositoryReadPermission() {
|
||||
return hasTargetReadPermission() && hasReadRepositoryPermission();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the read Target Permission.
|
||||
*
|
||||
* @return READ_TARGET boolean value
|
||||
*/
|
||||
public boolean hasTargetReadPermission() {
|
||||
return permissionService.hasPermission(SpPermission.READ_TARGET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the create Target Permission.
|
||||
*
|
||||
* @return READ_TARGET boolean value
|
||||
*/
|
||||
public boolean hasCreateTargetPermission() {
|
||||
return hasTargetReadPermission() && permissionService.hasPermission(SpPermission.CREATE_TARGET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the update Target Permission.
|
||||
*
|
||||
* @return READ_TARGET boolean value
|
||||
*/
|
||||
public boolean hasUpdateTargetPermission() {
|
||||
return hasTargetReadPermission() && permissionService.hasPermission(SpPermission.UPDATE_TARGET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the delete Target Permission.
|
||||
*
|
||||
* @return READ_TARGET boolean value
|
||||
*/
|
||||
public boolean hasDeleteTargetPermission() {
|
||||
return hasTargetReadPermission() && permissionService.hasPermission(SpPermission.DELETE_TARGET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the READ Repository Permission.
|
||||
*
|
||||
* @return READ_REPOSITORY boolean value
|
||||
*/
|
||||
public boolean hasReadRepositoryPermission() {
|
||||
return permissionService.hasPermission(SpPermission.READ_REPOSITORY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the download Repository Artifact Permission.
|
||||
*
|
||||
* @return DOWNLOAD_REPOSITORY_ARTIFACT boolean value
|
||||
*/
|
||||
public boolean hasDownloadRepositoryPermission() {
|
||||
return permissionService.hasPermission(SpPermission.DOWNLOAD_REPOSITORY_ARTIFACT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the create Repository Permission.
|
||||
*
|
||||
* @return CREATE_REPOSITORY boolean value
|
||||
*/
|
||||
public boolean hasCreateRepositoryPermission() {
|
||||
return hasReadRepositoryPermission() && permissionService.hasPermission(SpPermission.CREATE_REPOSITORY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the update Repository Permission.
|
||||
*
|
||||
* @return UPDATE_REPOSITORY boolean value
|
||||
*/
|
||||
public boolean hasUpdateRepositoryPermission() {
|
||||
return hasReadRepositoryPermission() && permissionService.hasPermission(SpPermission.UPDATE_REPOSITORY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the delete Repository Permission.
|
||||
*
|
||||
* @return DELETE_REPOSITORY boolean value
|
||||
*/
|
||||
public boolean hasDeleteRepositoryPermission() {
|
||||
return hasReadRepositoryPermission() && permissionService.hasPermission(SpPermission.DELETE_REPOSITORY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the rollout update permission.
|
||||
*
|
||||
* @return permission for rollout update
|
||||
*/
|
||||
public boolean hasRolloutUpdatePermission() {
|
||||
return hasRolloutReadPermission() && permissionService.hasPermission(SpPermission.UPDATE_ROLLOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if rollout create permission
|
||||
*/
|
||||
public boolean hasRolloutCreatePermission() {
|
||||
return hasTargetReadPermission() && hasReadRepositoryPermission()
|
||||
&& permissionService.hasPermission(SpPermission.CREATE_ROLLOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if rollout read permission
|
||||
*/
|
||||
public boolean hasRolloutReadPermission() {
|
||||
return permissionService.hasPermission(SpPermission.READ_ROLLOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if rollout delete permission
|
||||
*/
|
||||
public boolean hasRolloutDeletePermission() {
|
||||
return hasRolloutReadPermission() && permissionService.hasPermission(SpPermission.DELETE_ROLLOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if rollout handle permission.
|
||||
*/
|
||||
public boolean hasRolloutHandlePermission() {
|
||||
return hasRolloutReadPermission() && permissionService.hasPermission(SpPermission.HANDLE_ROLLOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return permission to read rollout targets
|
||||
*/
|
||||
public boolean hasRolloutTargetsReadPermission() {
|
||||
return hasTargetReadPermission() && permissionService.hasPermission(SpPermission.READ_ROLLOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <code>true</code> if rollout can be approved by the user.
|
||||
*/
|
||||
public boolean hasRolloutApprovalPermission() {
|
||||
return hasRolloutReadPermission() && permissionService.hasPermission(SpPermission.APPROVE_ROLLOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <code>true</code> if auto assignment can be added/updated to target filter
|
||||
*/
|
||||
public boolean hasAutoAssignmentUpdatePermission() {
|
||||
return hasUpdateTargetPermission() && hasReadRepositoryPermission();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <code>true</code> if default invalidation of distribution set is
|
||||
* allowed
|
||||
*/
|
||||
public boolean hasDistributionSetInvalidatePermission() {
|
||||
return hasUpdateRepositoryPermission() && hasUpdateTargetPermission();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,627 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Properties for Management UI customization.
|
||||
*
|
||||
*/
|
||||
@ConfigurationProperties("hawkbit.server.ui")
|
||||
public class UiProperties implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private boolean gravatar;
|
||||
|
||||
private String fixedTimeZone;
|
||||
|
||||
private final Localization localization = new Localization();
|
||||
|
||||
private final Links links = new Links();
|
||||
|
||||
private final Demo demo = new Demo();
|
||||
|
||||
private final Event event = new Event();
|
||||
|
||||
private final Notification notification = new Notification();
|
||||
|
||||
/**
|
||||
* @return True if menu item has gravatar else false
|
||||
*/
|
||||
public boolean isGravatar() {
|
||||
return gravatar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the gravatar
|
||||
*
|
||||
* @param gravatar
|
||||
* Menu icon
|
||||
*/
|
||||
public void setGravatar(final boolean gravatar) {
|
||||
this.gravatar = gravatar;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Fixed time zone if unknown then GMT
|
||||
*/
|
||||
public String getFixedTimeZone() {
|
||||
return fixedTimeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the fixed time zone
|
||||
*
|
||||
* @param fixedTimeZone
|
||||
* Date time zone
|
||||
*/
|
||||
public void setFixedTimeZone(final String fixedTimeZone) {
|
||||
this.fixedTimeZone = fixedTimeZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Localization information
|
||||
*/
|
||||
public static class Localization implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Default localization
|
||||
*/
|
||||
private Locale defaultLocal = Locale.ENGLISH;
|
||||
|
||||
/**
|
||||
* List of available localizations
|
||||
*/
|
||||
private List<Locale> availableLocals = Collections.singletonList(Locale.ENGLISH);
|
||||
|
||||
/**
|
||||
* @return Default locale
|
||||
*/
|
||||
public Locale getDefaultLocal() {
|
||||
return defaultLocal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of available locale
|
||||
*/
|
||||
public List<Locale> getAvailableLocals() {
|
||||
return availableLocals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default locale
|
||||
*
|
||||
* @param defaultLocal
|
||||
* Locale
|
||||
*/
|
||||
public void setDefaultLocal(final Locale defaultLocal) {
|
||||
this.defaultLocal = defaultLocal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the all available locale
|
||||
*
|
||||
* @param availableLocals
|
||||
* List of locale
|
||||
*/
|
||||
public void setAvailableLocals(final List<Locale> availableLocals) {
|
||||
this.availableLocals = availableLocals;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Demo account login information.
|
||||
*
|
||||
*/
|
||||
public static class Demo implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Demo tenant.
|
||||
*/
|
||||
private String tenant = "";
|
||||
/**
|
||||
* Demo user name.
|
||||
*/
|
||||
private String user = "";
|
||||
|
||||
/**
|
||||
* Demo user password.
|
||||
*/
|
||||
// Exception squid:S2068 - Empty password
|
||||
@SuppressWarnings({ "squid:S2068" })
|
||||
private String password = "";
|
||||
|
||||
private String disclaimer = "";
|
||||
|
||||
/**
|
||||
* @return password
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return tenant
|
||||
*/
|
||||
public String getTenant() {
|
||||
return tenant;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return username
|
||||
*/
|
||||
public String getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the login password
|
||||
*
|
||||
* @param password
|
||||
* Password value
|
||||
*/
|
||||
public void setPassword(final String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tenant
|
||||
*
|
||||
* @param tenant
|
||||
* Tenant value
|
||||
*/
|
||||
public void setTenant(final String tenant) {
|
||||
this.tenant = tenant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the login user
|
||||
*
|
||||
* @param user
|
||||
* username
|
||||
*/
|
||||
public void setUser(final String user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return disclaimer
|
||||
*/
|
||||
public String getDisclaimer() {
|
||||
return disclaimer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the disclaimer
|
||||
*
|
||||
* @param disclaimer
|
||||
* Disclaimer value
|
||||
*/
|
||||
public void setDisclaimer(final String disclaimer) {
|
||||
this.disclaimer = disclaimer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Links to potentially other systems (e.g. support, user management,
|
||||
* documentation etc.).
|
||||
*
|
||||
*/
|
||||
public static class Links implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Configuration of UI documentation links.
|
||||
*
|
||||
*/
|
||||
public static class Documentation implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* Link to root of documentation and user guides.
|
||||
*/
|
||||
private String root = "";
|
||||
|
||||
/**
|
||||
* Link to documentation of deployment view.
|
||||
*/
|
||||
private String deploymentView = "";
|
||||
|
||||
/**
|
||||
* Link to documentation of distribution view.
|
||||
*/
|
||||
private String distributionView = "";
|
||||
|
||||
/**
|
||||
* Link to documentation of upload view.
|
||||
*/
|
||||
private String uploadView = "";
|
||||
|
||||
/**
|
||||
* Link to documentation of maintenance window view.
|
||||
*/
|
||||
private String maintenanceWindowView = "";
|
||||
|
||||
/**
|
||||
* Link to documentation of the user consent and confirmation flow.
|
||||
*/
|
||||
private String userConsentAndConfirmationGuide = "";
|
||||
|
||||
public String getAutoConfirmationView() {
|
||||
return autoConfirmationView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Link to documentation of system configuration view.
|
||||
*/
|
||||
private String systemConfigurationView = "";
|
||||
|
||||
/**
|
||||
* Link to security related documentation.
|
||||
*/
|
||||
private String security = "";
|
||||
|
||||
/**
|
||||
* Link to rollout related documentation.
|
||||
*/
|
||||
private String rollout = "";
|
||||
|
||||
/**
|
||||
* Link to target filter view.
|
||||
*/
|
||||
private String targetfilterView = "";
|
||||
|
||||
/**
|
||||
* Link to documentation of rollout view.
|
||||
*/
|
||||
private String rolloutView = "";
|
||||
|
||||
/**
|
||||
* Link to documentation of auto confirmation view.
|
||||
*/
|
||||
private String autoConfirmationView = "";
|
||||
|
||||
/**
|
||||
* Link to documentation of state machine
|
||||
*/
|
||||
private String provisioningStateMachine = "";
|
||||
|
||||
/**
|
||||
* Link to documentation of distribution set invalidation
|
||||
*/
|
||||
private String distributionSetInvalidation = "";
|
||||
|
||||
/**
|
||||
* @return Link to documentation of deployment view
|
||||
*/
|
||||
public String getDeploymentView() {
|
||||
return deploymentView;
|
||||
}
|
||||
|
||||
public String getDistributionView() {
|
||||
return distributionView;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to documentation of rollout view
|
||||
*/
|
||||
public String getRolloutView() {
|
||||
return rolloutView;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to documentation of root
|
||||
*/
|
||||
public String getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to documentation of security
|
||||
*/
|
||||
public String getSecurity() {
|
||||
return security;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to documentation of rollout
|
||||
*/
|
||||
public String getRollout() {
|
||||
return rollout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to documentation of system config
|
||||
*/
|
||||
public String getSystemConfigurationView() {
|
||||
return systemConfigurationView;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to documentation of target filter
|
||||
*/
|
||||
public String getTargetfilterView() {
|
||||
return targetfilterView;
|
||||
}
|
||||
|
||||
public String getUploadView() {
|
||||
return uploadView;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to documentation of maintenance window
|
||||
*/
|
||||
public String getMaintenanceWindowView() {
|
||||
return maintenanceWindowView;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to documentation of the user consent and confirmation flow.
|
||||
*/
|
||||
public String getUserConsentAndConfirmationGuide() {
|
||||
return userConsentAndConfirmationGuide;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to documentation of provisioning state machine
|
||||
*/
|
||||
public String getProvisioningStateMachine() {
|
||||
return provisioningStateMachine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to documentation of distribution set invalidation
|
||||
*/
|
||||
public String getDistributionSetInvalidation() {
|
||||
return distributionSetInvalidation;
|
||||
}
|
||||
|
||||
public void setDeploymentView(final String deploymentView) {
|
||||
this.deploymentView = deploymentView;
|
||||
}
|
||||
|
||||
public void setDistributionView(final String distributionView) {
|
||||
this.distributionView = distributionView;
|
||||
}
|
||||
|
||||
public void setRolloutView(final String rolloutView) {
|
||||
this.rolloutView = rolloutView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the root documentation link
|
||||
*
|
||||
* @param root
|
||||
* link
|
||||
*/
|
||||
public void setRoot(final String root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the security documentation link
|
||||
*
|
||||
* @param security
|
||||
* link
|
||||
*/
|
||||
public void setSecurity(final String security) {
|
||||
this.security = security;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rollout documentation link
|
||||
*
|
||||
* @param rollout
|
||||
* link
|
||||
*/
|
||||
public void setRollout(final String rollout) {
|
||||
this.rollout = rollout;
|
||||
}
|
||||
|
||||
public void setSystemConfigurationView(final String systemConfigurationView) {
|
||||
this.systemConfigurationView = systemConfigurationView;
|
||||
}
|
||||
|
||||
public void setTargetfilterView(final String targetfilterView) {
|
||||
this.targetfilterView = targetfilterView;
|
||||
}
|
||||
|
||||
public void setUploadView(final String uploadView) {
|
||||
this.uploadView = uploadView;
|
||||
}
|
||||
|
||||
public void setMaintenanceWindowView(final String maintenanceWindowView) {
|
||||
this.maintenanceWindowView = maintenanceWindowView;
|
||||
}
|
||||
|
||||
public void setUserConsentAndConfirmationGuide(final String userConsentAndConfirmationGuide) {
|
||||
this.userConsentAndConfirmationGuide = userConsentAndConfirmationGuide;
|
||||
}
|
||||
|
||||
public void setProvisioningStateMachine(final String provisioningStateMachine) {
|
||||
this.provisioningStateMachine = provisioningStateMachine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the link to the distribution set invalidation documentation
|
||||
*
|
||||
* @param distributionSetInvalidation
|
||||
* Link
|
||||
*/
|
||||
public void setDistributionSetInvalidation(String distributionSetInvalidation) {
|
||||
this.distributionSetInvalidation = distributionSetInvalidation;
|
||||
}
|
||||
}
|
||||
|
||||
private final Documentation documentation = new Documentation();
|
||||
|
||||
/**
|
||||
* Link to product support.
|
||||
*/
|
||||
private String support = "";
|
||||
|
||||
/**
|
||||
* Link to request a system account, access.
|
||||
*/
|
||||
private String requestAccount = "";
|
||||
|
||||
/**
|
||||
* Link to user management.
|
||||
*/
|
||||
private String userManagement = "";
|
||||
|
||||
/**
|
||||
* @return Link to documentation
|
||||
*/
|
||||
public Documentation getDocumentation() {
|
||||
return documentation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to request a system account, access
|
||||
*/
|
||||
public String getRequestAccount() {
|
||||
return requestAccount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to product support
|
||||
*/
|
||||
public String getSupport() {
|
||||
return support;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to user management
|
||||
*/
|
||||
public String getUserManagement() {
|
||||
return userManagement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the link to request a system account, access
|
||||
*
|
||||
* @param requestAccount
|
||||
* Link
|
||||
*/
|
||||
public void setRequestAccount(final String requestAccount) {
|
||||
this.requestAccount = requestAccount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the link to product support
|
||||
*
|
||||
* @param support
|
||||
* Link
|
||||
*/
|
||||
public void setSupport(final String support) {
|
||||
this.support = support;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the link to user management
|
||||
*
|
||||
* @param userManagement
|
||||
* Link
|
||||
*/
|
||||
public void setUserManagement(final String userManagement) {
|
||||
this.userManagement = userManagement;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration of the UI event bus.
|
||||
*/
|
||||
public static class Event implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
*
|
||||
* Configuration of the UI push.
|
||||
*
|
||||
*/
|
||||
public static class Push implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* The delay for the ui event forwarding.
|
||||
*/
|
||||
private long delay = TimeUnit.SECONDS.toMillis(2);
|
||||
|
||||
public long getDelay() {
|
||||
return delay;
|
||||
}
|
||||
|
||||
public void setDelay(final long delay) {
|
||||
this.delay = delay;
|
||||
}
|
||||
}
|
||||
|
||||
private final Push push = new Push();
|
||||
|
||||
public Push getPush() {
|
||||
return push;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Notification implements Serializable {
|
||||
private String text = "";
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(final String text) {
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Demo account details
|
||||
*/
|
||||
public Demo getDemo() {
|
||||
return demo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Document links
|
||||
*/
|
||||
public Links getLinks() {
|
||||
return links;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Events
|
||||
*/
|
||||
public Event getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Localization
|
||||
*/
|
||||
public Localization getLocalization() {
|
||||
return localization;
|
||||
}
|
||||
|
||||
public Notification getNotification() {
|
||||
return notification;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,320 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.artifacts.details.ArtifactDetailsGridLayoutUiState;
|
||||
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadId;
|
||||
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress;
|
||||
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress.FileUploadStatus;
|
||||
import org.eclipse.hawkbit.ui.common.state.GridLayoutUiState;
|
||||
import org.eclipse.hawkbit.ui.common.state.TypeFilterLayoutUiState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.vaadin.spring.annotation.SpringComponent;
|
||||
import com.vaadin.spring.annotation.VaadinSessionScope;
|
||||
|
||||
/**
|
||||
* User status of Artifact upload.
|
||||
*/
|
||||
@VaadinSessionScope
|
||||
@SpringComponent
|
||||
public class ArtifactUploadState implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ArtifactUploadState.class);
|
||||
|
||||
private final TypeFilterLayoutUiState smTypeFilterLayoutUiState;
|
||||
private final GridLayoutUiState smGridLayoutUiState;
|
||||
private final ArtifactDetailsGridLayoutUiState artifactDetailsGridLayoutUiState;
|
||||
|
||||
private boolean statusPopupMinimized;
|
||||
|
||||
/**
|
||||
* Map that holds all files that were selected for upload. They remain in
|
||||
* the list even if upload fails, succeeds or is aborted by the user.
|
||||
*/
|
||||
private Map<FileUploadId, FileUploadProgress> overallFilesInUploadProcess;
|
||||
|
||||
/**
|
||||
* Constructor for ArtifactUploadState
|
||||
*/
|
||||
public ArtifactUploadState() {
|
||||
this.smTypeFilterLayoutUiState = new TypeFilterLayoutUiState();
|
||||
this.smGridLayoutUiState = new GridLayoutUiState();
|
||||
this.artifactDetailsGridLayoutUiState = new ArtifactDetailsGridLayoutUiState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimize or maximize the status popup view
|
||||
*
|
||||
* @param statusPopupMinimized
|
||||
* boolean
|
||||
*/
|
||||
public void setStatusPopupMinimized(final boolean statusPopupMinimized) {
|
||||
this.statusPopupMinimized = statusPopupMinimized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the status popup view is in minimized state
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isStatusPopupMinimized() {
|
||||
return statusPopupMinimized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Software module type filter UI state
|
||||
*
|
||||
* @return TypeFilterLayoutUiState
|
||||
*/
|
||||
public TypeFilterLayoutUiState getSmTypeFilterLayoutUiState() {
|
||||
return smTypeFilterLayoutUiState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Software module grid UI state
|
||||
*
|
||||
* @return GridLayoutUiState
|
||||
*/
|
||||
public GridLayoutUiState getSmGridLayoutUiState() {
|
||||
return smGridLayoutUiState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Artifact details grid UI state
|
||||
*
|
||||
* @return ArtifactDetailsGridLayoutUiState
|
||||
*/
|
||||
public ArtifactDetailsGridLayoutUiState getArtifactDetailsGridLayoutUiState() {
|
||||
return artifactDetailsGridLayoutUiState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all the files from the upload process list
|
||||
*
|
||||
* @param filesToRemove
|
||||
* Collection of fie upload ID
|
||||
*/
|
||||
public void removeFilesFromOverallUploadProcessList(final Collection<FileUploadId> filesToRemove) {
|
||||
getOverallFilesInUploadProcessMap().keySet().removeAll(filesToRemove);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the IDs of uploaded files from the upload process
|
||||
*
|
||||
* @return List of IDs of uploaded files
|
||||
*/
|
||||
public Set<FileUploadId> getAllFileUploadIdsFromOverallUploadProcessList() {
|
||||
return Collections.unmodifiableSet(getOverallFilesInUploadProcessMap().keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file upload progress values from process list
|
||||
*
|
||||
* @return List of FileUploadProgress
|
||||
*/
|
||||
public Collection<FileUploadProgress> getAllFileUploadProgressValuesFromOverallUploadProcessList() {
|
||||
return Collections.unmodifiableCollection(getOverallFilesInUploadProcessMap().values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the IDs of files from the failed upload
|
||||
*
|
||||
* @return List of IDs of uploaded files
|
||||
*/
|
||||
public Set<FileUploadId> getFilesInFailedState() {
|
||||
return Collections.unmodifiableSet(getFailedUploads());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get upload progress of the file
|
||||
*
|
||||
* @param fileUploadId
|
||||
* FileUploadId
|
||||
*
|
||||
* @return FileUploadProgress
|
||||
*/
|
||||
public FileUploadProgress getFileUploadProgress(final FileUploadId fileUploadId) {
|
||||
return getOverallFilesInUploadProcessMap().get(fileUploadId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all files that were selected for upload
|
||||
*
|
||||
* @param fileUploadId
|
||||
* FileUploadId
|
||||
* @param fileUploadProgress
|
||||
* FileUploadProgress
|
||||
*/
|
||||
public void updateFileUploadProgress(final FileUploadId fileUploadId, final FileUploadProgress fileUploadProgress) {
|
||||
getOverallFilesInUploadProcessMap().put(fileUploadId, fileUploadProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check upload state of the file
|
||||
*
|
||||
* @param fileUploadId
|
||||
* FileUploadId
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isFileInUploadState(final FileUploadId fileUploadId) {
|
||||
return getOverallFilesInUploadProcessMap().containsKey(fileUploadId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check upload state of the file link to the related software module
|
||||
*
|
||||
* @param filename
|
||||
* Name of the file
|
||||
*
|
||||
* @param softwareModule
|
||||
* the {@link SoftwareModule} for which the file is uploaded
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isFileInUploadState(final String filename, final SoftwareModule softwareModule) {
|
||||
return isFileInUploadState(new FileUploadId(filename, softwareModule));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if at least one file upload is in progress
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isAtLeastOneUploadInProgress() {
|
||||
return getInProgressCount() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if all file uploads are finished
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean areAllUploadsFinished() {
|
||||
return getInProgressCount() == 0;
|
||||
}
|
||||
|
||||
private int getInProgressCount() {
|
||||
final int succeededUploadCount = getSucceededUploads().size();
|
||||
final int failedUploadCount = getFailedUploads().size();
|
||||
final int overallUploadCount = getOverallFilesInUploadProcessMap().size();
|
||||
|
||||
final int inProgressCount = overallUploadCount - failedUploadCount - succeededUploadCount;
|
||||
|
||||
assertFileStateConsistency(inProgressCount, overallUploadCount, succeededUploadCount, failedUploadCount);
|
||||
|
||||
return inProgressCount;
|
||||
}
|
||||
|
||||
@SuppressWarnings("java:S2629") // error shall be enable almost every time and evaluation is light
|
||||
private static void assertFileStateConsistency(final int inProgressCount, final int overallUploadCount,
|
||||
final int succeededUploadCount, final int failedUploadCount) {
|
||||
if (inProgressCount < 0) {
|
||||
LOG.error("IllegalState: \n{}",
|
||||
getStateListLogMessage(overallUploadCount, succeededUploadCount, failedUploadCount));
|
||||
}
|
||||
}
|
||||
|
||||
private static String getStateListLogMessage(final int overallUploadCount, final int succeededUploadCount,
|
||||
final int failedUploadCount) {
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
buffer.append("Overall uploads: " + overallUploadCount);
|
||||
buffer.append("| succeeded uploads: " + succeededUploadCount);
|
||||
buffer.append("| Failed Uploads: " + failedUploadCount);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all of the data from this Upload process collection
|
||||
*/
|
||||
public void clearFileStates() {
|
||||
getOverallFilesInUploadProcessMap().clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all temp data collected while uploading files.
|
||||
*/
|
||||
public void clearUploadTempData() {
|
||||
LOG.debug("Cleaning up temp data...");
|
||||
// delete file system zombies
|
||||
for (final FileUploadProgress fileUploadProgress : getAllFileUploadProgressValuesFromOverallUploadProcessList()) {
|
||||
if (StringUtils.hasText(fileUploadProgress.getFilePath())) {
|
||||
final boolean deleted = FileUtils.deleteQuietly(new File(fileUploadProgress.getFilePath()));
|
||||
if (!deleted) {
|
||||
LOG.warn("TempFile was not deleted: {}", fileUploadProgress.getFilePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
clearFileStates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an upload is in progress for the given Software Module
|
||||
*
|
||||
* @param softwareModuleId
|
||||
* id of the software module
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isUploadInProgressForSelectedSoftwareModule(final Long softwareModuleId) {
|
||||
for (final FileUploadId fileUploadId : getAllFileUploadIdsFromOverallUploadProcessList()) {
|
||||
if (fileUploadId.getSoftwareModuleId().equals(softwareModuleId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Map<FileUploadId, FileUploadProgress> getOverallFilesInUploadProcessMap() {
|
||||
if (overallFilesInUploadProcess == null) {
|
||||
overallFilesInUploadProcess = Maps.newConcurrentMap();
|
||||
}
|
||||
return overallFilesInUploadProcess;
|
||||
}
|
||||
|
||||
private Set<FileUploadId> getFailedUploads() {
|
||||
final Collection<FileUploadProgress> allFileUploadProgressObjects = getOverallFilesInUploadProcessMap()
|
||||
.values();
|
||||
final Set<FileUploadId> failedFileUploads = Sets.newHashSet();
|
||||
for (final FileUploadProgress fileUploadProgress : allFileUploadProgressObjects) {
|
||||
if (fileUploadProgress.getFileUploadStatus() == FileUploadStatus.UPLOAD_FAILED) {
|
||||
failedFileUploads.add(fileUploadProgress.getFileUploadId());
|
||||
}
|
||||
}
|
||||
return failedFileUploads;
|
||||
}
|
||||
|
||||
private Set<FileUploadId> getSucceededUploads() {
|
||||
final Collection<FileUploadProgress> allFileUploadProgressObjects = getOverallFilesInUploadProcessMap()
|
||||
.values();
|
||||
final Set<FileUploadId> succeededFileUploads = Sets.newHashSet();
|
||||
for (final FileUploadProgress fileUploadProgress : allFileUploadProgressObjects) {
|
||||
if (fileUploadProgress.getFileUploadStatus() == FileUploadStatus.UPLOAD_SUCCESSFUL) {
|
||||
succeededFileUploads.add(fileUploadProgress.getFileUploadId());
|
||||
}
|
||||
}
|
||||
return succeededFileUploads;
|
||||
}
|
||||
}
|
||||
@@ -1,335 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts;
|
||||
|
||||
import static org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress.FileUploadStatus.UPLOAD_STARTED;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.MultipartConfigElement;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.ui.AbstractHawkbitUI;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.artifacts.details.ArtifactDetailsGridLayout;
|
||||
import org.eclipse.hawkbit.ui.artifacts.smtable.SoftwareModuleGridLayout;
|
||||
import org.eclipse.hawkbit.ui.artifacts.smtype.filter.SMTypeFilterLayout;
|
||||
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractEventListenersAwareView;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.ConfirmationDialog;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventLayout;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventView;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventViewAware;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.LayoutResizeListener;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.LayoutResizeListener.ResizeHandler;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.LayoutVisibilityListener;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.LayoutVisibilityListener.VisibilityHandler;
|
||||
import org.eclipse.hawkbit.ui.menu.DashboardEvent;
|
||||
import org.eclipse.hawkbit.ui.menu.DashboardMenu;
|
||||
import org.eclipse.hawkbit.ui.menu.DashboardMenuItem;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.navigator.ViewBeforeLeaveEvent;
|
||||
import com.vaadin.server.Page;
|
||||
import com.vaadin.server.Page.BrowserWindowResizeEvent;
|
||||
import com.vaadin.server.Page.BrowserWindowResizeListener;
|
||||
import com.vaadin.spring.annotation.SpringView;
|
||||
import com.vaadin.spring.annotation.UIScope;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.UI;
|
||||
|
||||
/**
|
||||
* Display artifacts upload view.
|
||||
*/
|
||||
@UIScope
|
||||
@SpringView(name = UploadArtifactView.VIEW_NAME, ui = AbstractHawkbitUI.class)
|
||||
public class UploadArtifactView extends AbstractEventListenersAwareView implements BrowserWindowResizeListener {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String VIEW_NAME = "spUpload";
|
||||
|
||||
private final SpPermissionChecker permChecker;
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
|
||||
private final SMTypeFilterLayout smTypeFilterLayout;
|
||||
private final SoftwareModuleGridLayout smGridLayout;
|
||||
private final ArtifactDetailsGridLayout artifactDetailsGridLayout;
|
||||
private final VaadinMessageSource i18n;
|
||||
private final DashboardMenu dashboardMenu;
|
||||
|
||||
private HorizontalLayout mainLayout;
|
||||
|
||||
private final transient LayoutVisibilityListener layoutVisibilityListener;
|
||||
private final transient LayoutResizeListener layoutResizeListener;
|
||||
|
||||
@Autowired
|
||||
UploadArtifactView(final UIEventBus eventBus, final SpPermissionChecker permChecker, final VaadinMessageSource i18n,
|
||||
final UINotification uiNotification, final ArtifactUploadState artifactUploadState,
|
||||
final EntityFactory entityFactory, final SoftwareModuleManagement softwareModuleManagement,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement,
|
||||
final MultipartConfigElement multipartConfigElement, final ArtifactManagement artifactManagement,
|
||||
final DashboardMenu dashboardMenu) {
|
||||
this.permChecker = permChecker;
|
||||
this.artifactUploadState = artifactUploadState;
|
||||
this.i18n = i18n;
|
||||
this.dashboardMenu = dashboardMenu;
|
||||
|
||||
final CommonUiDependencies uiDependencies = new CommonUiDependencies(i18n, entityFactory, eventBus,
|
||||
uiNotification, permChecker);
|
||||
|
||||
if (permChecker.hasReadRepositoryPermission()) {
|
||||
this.smTypeFilterLayout = new SMTypeFilterLayout(uiDependencies, softwareModuleTypeManagement,
|
||||
artifactUploadState.getSmTypeFilterLayoutUiState(), EventView.UPLOAD);
|
||||
this.smGridLayout = new SoftwareModuleGridLayout(uiDependencies, softwareModuleManagement,
|
||||
softwareModuleTypeManagement, artifactUploadState.getSmTypeFilterLayoutUiState(),
|
||||
artifactUploadState.getSmGridLayoutUiState());
|
||||
this.artifactDetailsGridLayout = new ArtifactDetailsGridLayout(uiDependencies, artifactUploadState,
|
||||
artifactUploadState.getArtifactDetailsGridLayoutUiState(), artifactManagement,
|
||||
softwareModuleManagement, multipartConfigElement);
|
||||
|
||||
addEventAwareLayouts(Arrays.asList(smTypeFilterLayout, smGridLayout, artifactDetailsGridLayout));
|
||||
|
||||
final Map<EventLayout, VisibilityHandler> layoutVisibilityHandlers = new EnumMap<>(EventLayout.class);
|
||||
layoutVisibilityHandlers.put(EventLayout.SM_TYPE_FILTER,
|
||||
new VisibilityHandler(this::showSmTypeLayout, this::hideSmTypeLayout));
|
||||
this.layoutVisibilityListener = new LayoutVisibilityListener(eventBus, new EventViewAware(EventView.UPLOAD),
|
||||
layoutVisibilityHandlers);
|
||||
|
||||
final Map<EventLayout, ResizeHandler> layoutResizeHandlers = new EnumMap<>(EventLayout.class);
|
||||
layoutResizeHandlers.put(EventLayout.SM_LIST,
|
||||
new ResizeHandler(this::maximizeSmGridLayout, this::minimizeSmGridLayout));
|
||||
layoutResizeHandlers.put(EventLayout.ARTIFACT_LIST,
|
||||
new ResizeHandler(this::maximizeArtifactGridLayout, this::minimizeArtifactGridLayout));
|
||||
this.layoutResizeListener = new LayoutResizeListener(eventBus, new EventViewAware(EventView.UPLOAD),
|
||||
layoutResizeHandlers);
|
||||
} else {
|
||||
this.smTypeFilterLayout = null;
|
||||
this.smGridLayout = null;
|
||||
this.artifactDetailsGridLayout = null;
|
||||
this.layoutVisibilityListener = null;
|
||||
this.layoutResizeListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
if (permChecker.hasReadRepositoryPermission()) {
|
||||
super.init();
|
||||
Page.getCurrent().addBrowserWindowResizeListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildLayout() {
|
||||
setMargin(false);
|
||||
setSpacing(false);
|
||||
setSizeFull();
|
||||
|
||||
createMainLayout();
|
||||
|
||||
addComponent(mainLayout);
|
||||
setExpandRatio(mainLayout, 1.0F);
|
||||
}
|
||||
|
||||
private void createMainLayout() {
|
||||
mainLayout = new HorizontalLayout();
|
||||
mainLayout.setSizeFull();
|
||||
mainLayout.setMargin(false);
|
||||
mainLayout.setSpacing(true);
|
||||
|
||||
mainLayout.addComponent(smTypeFilterLayout);
|
||||
mainLayout.addComponent(smGridLayout);
|
||||
mainLayout.addComponent(artifactDetailsGridLayout);
|
||||
|
||||
mainLayout.setExpandRatio(smTypeFilterLayout, 0F);
|
||||
mainLayout.setExpandRatio(smGridLayout, 0.5F);
|
||||
mainLayout.setExpandRatio(artifactDetailsGridLayout, 0.5F);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void restoreState() {
|
||||
if (permChecker.hasReadRepositoryPermission()) {
|
||||
restoreSmWidgetsState();
|
||||
restoreArtifactWidgetsState();
|
||||
}
|
||||
|
||||
super.restoreState();
|
||||
}
|
||||
|
||||
private void restoreSmWidgetsState() {
|
||||
if (artifactUploadState.getSmTypeFilterLayoutUiState().isHidden()
|
||||
|| artifactUploadState.getArtifactDetailsGridLayoutUiState().isMaximized()) {
|
||||
hideSmTypeLayout();
|
||||
} else {
|
||||
showSmTypeLayout();
|
||||
}
|
||||
|
||||
if (artifactUploadState.getSmGridLayoutUiState().isMaximized()) {
|
||||
maximizeSmGridLayout();
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreArtifactWidgetsState() {
|
||||
if (artifactUploadState.getArtifactDetailsGridLayoutUiState().isMaximized()) {
|
||||
maximizeArtifactGridLayout();
|
||||
}
|
||||
}
|
||||
|
||||
private void showSmTypeLayout() {
|
||||
smTypeFilterLayout.setVisible(true);
|
||||
smGridLayout.hideSmTypeHeaderIcon();
|
||||
}
|
||||
|
||||
private void hideSmTypeLayout() {
|
||||
smTypeFilterLayout.setVisible(false);
|
||||
smGridLayout.showSmTypeHeaderIcon();
|
||||
}
|
||||
|
||||
private void maximizeSmGridLayout() {
|
||||
artifactDetailsGridLayout.setVisible(false);
|
||||
|
||||
mainLayout.setExpandRatio(smTypeFilterLayout, 0F);
|
||||
mainLayout.setExpandRatio(smGridLayout, 1.0F);
|
||||
mainLayout.setExpandRatio(artifactDetailsGridLayout, 0F);
|
||||
|
||||
smGridLayout.maximize();
|
||||
}
|
||||
|
||||
private void minimizeSmGridLayout() {
|
||||
artifactDetailsGridLayout.setVisible(true);
|
||||
|
||||
mainLayout.setExpandRatio(smTypeFilterLayout, 0F);
|
||||
mainLayout.setExpandRatio(smGridLayout, 0.5F);
|
||||
mainLayout.setExpandRatio(artifactDetailsGridLayout, 0.5F);
|
||||
|
||||
smGridLayout.minimize();
|
||||
}
|
||||
|
||||
private void maximizeArtifactGridLayout() {
|
||||
smTypeFilterLayout.setVisible(false);
|
||||
smGridLayout.setVisible(false);
|
||||
|
||||
mainLayout.setExpandRatio(smTypeFilterLayout, 0F);
|
||||
mainLayout.setExpandRatio(smGridLayout, 0F);
|
||||
mainLayout.setExpandRatio(artifactDetailsGridLayout, 1.0F);
|
||||
|
||||
artifactDetailsGridLayout.maximize();
|
||||
}
|
||||
|
||||
private void minimizeArtifactGridLayout() {
|
||||
if (!artifactUploadState.getSmTypeFilterLayoutUiState().isHidden()) {
|
||||
smTypeFilterLayout.setVisible(true);
|
||||
}
|
||||
smGridLayout.setVisible(true);
|
||||
|
||||
mainLayout.setExpandRatio(smTypeFilterLayout, 0F);
|
||||
mainLayout.setExpandRatio(smGridLayout, 0.5F);
|
||||
mainLayout.setExpandRatio(artifactDetailsGridLayout, 0.5F);
|
||||
|
||||
artifactDetailsGridLayout.minimize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show or hide the filter button based on the event width
|
||||
*
|
||||
* @param event
|
||||
* BrowserWindowResizeEvent
|
||||
*/
|
||||
@Override
|
||||
public void browserWindowResized(final BrowserWindowResizeEvent event) {
|
||||
showOrHideFilterButtons(event.getWidth());
|
||||
}
|
||||
|
||||
private void showOrHideFilterButtons(final int browserWidth) {
|
||||
if (artifactUploadState.getArtifactDetailsGridLayoutUiState().isMaximized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (browserWidth < SPUIDefinitions.REQ_MIN_BROWSER_WIDTH) {
|
||||
if (!artifactUploadState.getSmTypeFilterLayoutUiState().isHidden()) {
|
||||
hideSmTypeLayout();
|
||||
}
|
||||
} else {
|
||||
if (artifactUploadState.getSmTypeFilterLayoutUiState().isHidden()) {
|
||||
showSmTypeLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getViewName() {
|
||||
return UploadArtifactView.VIEW_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void subscribeListeners() {
|
||||
if (permChecker.hasReadRepositoryPermission()) {
|
||||
layoutVisibilityListener.subscribe();
|
||||
layoutResizeListener.subscribe();
|
||||
}
|
||||
|
||||
super.subscribeListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unsubscribeListeners() {
|
||||
if (permChecker.hasReadRepositoryPermission()) {
|
||||
layoutVisibilityListener.unsubscribe();
|
||||
layoutResizeListener.unsubscribe();
|
||||
}
|
||||
|
||||
super.unsubscribeListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeLeave(final ViewBeforeLeaveEvent event) {
|
||||
if (isAnyUploadInUploadQueue()) {
|
||||
final ConfirmationDialog confirmDeleteDialog = ConfirmationDialog
|
||||
.newBuilder(i18n, UIComponentIdProvider.UPLOAD_QUEUE_CLEAR_CONFIRMATION_DIALOG)
|
||||
.caption(i18n.getMessage(UIMessageIdProvider.CAPTION_CLEAR_FILE_UPLOAD_QUEUE))
|
||||
.question(i18n.getMessage(UIMessageIdProvider.MESSAGE_CLEAR_FILE_UPLOAD_QUEUE))
|
||||
.onSaveOrUpdate(() -> {
|
||||
// Clear all queued file uploads
|
||||
artifactUploadState.clearFileStates();
|
||||
super.beforeLeave(event);
|
||||
}).onCancel(() -> {
|
||||
// Send a PostViewChangeEvent to the DashboardMenu
|
||||
// as if the navigation actually
|
||||
// happened to prevent the DashboardMenu navigation
|
||||
// from getting stuck
|
||||
final DashboardMenuItem dashboardMenuItem = dashboardMenu.getByViewName(VIEW_NAME);
|
||||
dashboardMenu.postViewChange(DashboardEvent.createPostViewChangeEvent(dashboardMenuItem));
|
||||
}).build();
|
||||
UI.getCurrent().addWindow(confirmDeleteDialog.getWindow());
|
||||
confirmDeleteDialog.getWindow().bringToFront();
|
||||
} else {
|
||||
super.beforeLeave(event);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAnyUploadInUploadQueue() {
|
||||
return artifactUploadState.getAllFileUploadProgressValuesFromOverallUploadProcessList().stream()
|
||||
.map(FileUploadProgress::getFileUploadStatus)
|
||||
.anyMatch(fileUploadStatus -> fileUploadStatus == UPLOAD_STARTED);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.ui.menu.AbstractDashboardMenuItemNotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.server.Resource;
|
||||
import com.vaadin.spring.annotation.SpringComponent;
|
||||
import com.vaadin.spring.annotation.UIScope;
|
||||
|
||||
/**
|
||||
* Display artifacts upload view menu item.
|
||||
*
|
||||
*
|
||||
*/
|
||||
@SpringComponent
|
||||
@UIScope
|
||||
@Order(500)
|
||||
public class UploadArtifactViewMenuItem extends AbstractDashboardMenuItemNotification {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Autowired
|
||||
UploadArtifactViewMenuItem(final VaadinMessageSource i18n) {
|
||||
super(i18n);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getViewName() {
|
||||
return UploadArtifactView.VIEW_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getDashboardIcon() {
|
||||
return VaadinIcons.UPLOAD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDashboardCaption() {
|
||||
return i18n.getMessage("dashboard.upload.caption");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDashboardCaptionLong() {
|
||||
return i18n.getMessage("dashboard.upload.caption-long");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPermissions() {
|
||||
return Arrays.asList(SpPermission.READ_REPOSITORY);
|
||||
}
|
||||
}
|
||||
@@ -1,252 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.details;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.builder.GridComponentBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.data.mappers.ArtifactToProxyArtifactMapper;
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.ArtifactDataProvider;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyArtifact;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
|
||||
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload.EntityModifiedEventType;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventTopics;
|
||||
import org.eclipse.hawkbit.ui.common.event.FilterType;
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGrid;
|
||||
import org.eclipse.hawkbit.ui.common.grid.support.DeleteSupport;
|
||||
import org.eclipse.hawkbit.ui.common.grid.support.FilterSupport;
|
||||
import org.eclipse.hawkbit.ui.common.grid.support.MasterEntitySupport;
|
||||
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.UINotification;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.server.FileDownloader;
|
||||
import com.vaadin.server.StreamResource;
|
||||
import com.vaadin.ui.Button;
|
||||
import com.vaadin.ui.UI;
|
||||
|
||||
/**
|
||||
* Artifact Details grid which is shown on the Upload View.
|
||||
*/
|
||||
public class ArtifactDetailsGrid extends AbstractGrid<ProxyArtifact, Long> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ArtifactDetailsGrid.class);
|
||||
|
||||
private static final String ARTIFACT_NAME_ID = "artifactName";
|
||||
private static final String ARTIFACT_SIZE_ID = "artifactSize";
|
||||
private static final String ARTIFACT_MODIFIED_DATE_ID = "artifactModifiedDate";
|
||||
private static final String ARTIFACT_SHA1_ID = "artifactSha1";
|
||||
private static final String ARTIFACT_MD5_ID = "artifactMd5";
|
||||
private static final String ARTIFACT_SHA256_ID = "artifactSha256";
|
||||
private static final String ARTIFACT_DOWNLOAD_BUTTON_ID = "artifactDownloadButton";
|
||||
private static final String ARTIFACT_DELETE_BUTTON_ID = "artifactDeleteButton";
|
||||
|
||||
private final UINotification notification;
|
||||
private final transient ArtifactManagement artifactManagement;
|
||||
|
||||
private final transient DeleteSupport<ProxyArtifact> artifactDeleteSupport;
|
||||
private final transient MasterEntitySupport<ProxySoftwareModule> masterEntitySupport;
|
||||
|
||||
private boolean artifactsEncrypted;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param artifactManagement
|
||||
* ArtifactManagement
|
||||
*/
|
||||
public ArtifactDetailsGrid(final CommonUiDependencies uiDependencies, final ArtifactManagement artifactManagement) {
|
||||
super(uiDependencies.getI18n(), uiDependencies.getEventBus(), uiDependencies.getPermChecker());
|
||||
|
||||
this.notification = uiDependencies.getUiNotification();
|
||||
this.artifactManagement = artifactManagement;
|
||||
|
||||
this.artifactDeleteSupport = new DeleteSupport<>(this, i18n, notification, "artifact.details.header",
|
||||
"caption.artifacts", ProxyArtifact::getFilename, this::artifactsDeletionCallback,
|
||||
UIComponentIdProvider.ARTIFACT_DELETE_CONFIRMATION_DIALOG);
|
||||
|
||||
setFilterSupport(
|
||||
new FilterSupport<>(new ArtifactDataProvider(artifactManagement, new ArtifactToProxyArtifactMapper())));
|
||||
initFilterMappings();
|
||||
|
||||
this.masterEntitySupport = new MasterEntitySupport<>(getFilterSupport(), null,
|
||||
sm -> artifactsEncrypted = sm != null && sm.isEncrypted());
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private void initFilterMappings() {
|
||||
getFilterSupport().<Long> addMapping(FilterType.MASTER,
|
||||
(filter, masterFilter) -> getFilterSupport().setFilter(masterFilter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial method of grid and set style name
|
||||
*/
|
||||
@Override
|
||||
public void init() {
|
||||
super.init();
|
||||
|
||||
addStyleName("grid-row-border");
|
||||
}
|
||||
|
||||
private boolean artifactsDeletionCallback(final Collection<ProxyArtifact> artifactsToBeDeleted) {
|
||||
final Collection<Long> artifactToBeDeletedIds = artifactsToBeDeleted.stream()
|
||||
.map(ProxyIdentifiableEntity::getId).collect(Collectors.toList());
|
||||
artifactToBeDeletedIds.forEach(artifactManagement::delete);
|
||||
|
||||
eventBus.publish(EventTopics.ENTITY_MODIFIED, this, new EntityModifiedEventPayload(
|
||||
EntityModifiedEventType.ENTITY_UPDATED, ProxySoftwareModule.class, masterEntitySupport.getMasterId()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ID for artifact details table
|
||||
*/
|
||||
@Override
|
||||
public String getGridId() {
|
||||
return UIComponentIdProvider.UPLOAD_ARTIFACT_DETAILS_TABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* setting up the columns with their required definition
|
||||
*/
|
||||
@Override
|
||||
public void addColumns() {
|
||||
addFilenameColumn().setExpandRatio(2);
|
||||
|
||||
addSizeColumn();
|
||||
|
||||
addModifiedDateColumn();
|
||||
|
||||
GridComponentBuilder.joinToActionColumn(i18n, getDefaultHeaderRow(),
|
||||
Arrays.asList(addDownloadColumn(), addDeleteColumn()));
|
||||
}
|
||||
|
||||
private Column<ProxyArtifact, String> addFilenameColumn() {
|
||||
return GridComponentBuilder.addColumn(this, ProxyArtifact::getFilename).setId(ARTIFACT_NAME_ID)
|
||||
.setCaption(i18n.getMessage("artifact.filename.caption"));
|
||||
}
|
||||
|
||||
private Column<ProxyArtifact, Long> addSizeColumn() {
|
||||
return GridComponentBuilder.addColumn(this, ProxyArtifact::getSize).setId(ARTIFACT_SIZE_ID)
|
||||
.setCaption(i18n.getMessage("artifact.filesize.bytes.caption"));
|
||||
}
|
||||
|
||||
protected Column<ProxyArtifact, String> addModifiedDateColumn() {
|
||||
return GridComponentBuilder.addColumn(this, ProxyArtifact::getModifiedDate).setId(ARTIFACT_MODIFIED_DATE_ID)
|
||||
.setCaption(i18n.getMessage("upload.last.modified.date"));
|
||||
}
|
||||
|
||||
private Column<ProxyArtifact, Button> addDownloadColumn() {
|
||||
return GridComponentBuilder.addIconColumn(this, this::buildDownloadButton, ARTIFACT_DOWNLOAD_BUTTON_ID,
|
||||
i18n.getMessage("header.action.download"));
|
||||
}
|
||||
|
||||
private Button buildDownloadButton(final ProxyArtifact artifact) {
|
||||
final Button downloadButton = GridComponentBuilder.buildActionButton(i18n, clickEvent -> {
|
||||
}, VaadinIcons.DOWNLOAD, UIMessageIdProvider.TOOLTIP_ARTIFACT_DOWNLOAD,
|
||||
SPUIStyleDefinitions.STATUS_ICON_NEUTRAL,
|
||||
UIComponentIdProvider.ARTIFACT_FILE_DOWNLOAD_ICON + "." + artifact.getId(),
|
||||
permissionChecker.hasDownloadRepositoryPermission());
|
||||
|
||||
attachFileDownloader(artifact, downloadButton);
|
||||
|
||||
return downloadButton;
|
||||
}
|
||||
|
||||
private void attachFileDownloader(final ProxyArtifact artifact, final Button downloadButton) {
|
||||
final StreamResource artifactStreamResource = new StreamResource(() -> artifactManagement
|
||||
.loadArtifactBinary(artifact.getSha1Hash(), masterEntitySupport.getMasterId(), artifactsEncrypted)
|
||||
.map(DbArtifact::getFileInputStream).orElse(null), artifact.getFilename());
|
||||
|
||||
final FileDownloader fileDownloader = new FileDownloader(artifactStreamResource);
|
||||
fileDownloader.setErrorHandler(event -> {
|
||||
LOG.error("Download failed for artifact with id {}, filename {}", artifact.getId(), artifact.getFilename(),
|
||||
event.getThrowable());
|
||||
notification.displayValidationError(i18n.getMessage(UIMessageIdProvider.ARTIFACT_DOWNLOAD_FAILURE_MSG));
|
||||
UI.getCurrent().access(() -> {
|
||||
// give error details extractors a chance to process specific
|
||||
// error
|
||||
throw new DownloadException(event.getThrowable());
|
||||
});
|
||||
});
|
||||
|
||||
fileDownloader.extend(downloadButton);
|
||||
}
|
||||
|
||||
private Column<ProxyArtifact, Button> addDeleteColumn() {
|
||||
return GridComponentBuilder.addDeleteColumn(this, i18n, ARTIFACT_DELETE_BUTTON_ID, artifactDeleteSupport,
|
||||
UIComponentIdProvider.ARTIFACT_DELET_ICON, e -> permissionChecker.hasDeleteRepositoryPermission());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addMaxColumns() {
|
||||
addFilenameColumn().setExpandRatio(2);
|
||||
|
||||
addSizeColumn();
|
||||
|
||||
addSha1Column();
|
||||
addMd5Column();
|
||||
addSha256Column();
|
||||
|
||||
addModifiedDateColumn();
|
||||
|
||||
GridComponentBuilder.joinToActionColumn(i18n, getDefaultHeaderRow(),
|
||||
Arrays.asList(addDownloadColumn(), addDeleteColumn()));
|
||||
|
||||
getColumns().forEach(column -> column.setHidable(true));
|
||||
}
|
||||
|
||||
private Column<ProxyArtifact, String> addSha1Column() {
|
||||
return GridComponentBuilder.addColumn(this, ProxyArtifact::getSha1Hash).setId(ARTIFACT_SHA1_ID)
|
||||
.setCaption(i18n.getMessage("upload.sha1"));
|
||||
}
|
||||
|
||||
private Column<ProxyArtifact, String> addMd5Column() {
|
||||
return GridComponentBuilder.addColumn(this, ProxyArtifact::getMd5Hash).setId(ARTIFACT_MD5_ID)
|
||||
.setCaption(i18n.getMessage("upload.md5"));
|
||||
}
|
||||
|
||||
private Column<ProxyArtifact, String> addSha256Column() {
|
||||
return GridComponentBuilder.addColumn(this, ProxyArtifact::getSha256Hash).setId(ARTIFACT_SHA256_ID)
|
||||
.setCaption(i18n.getMessage("upload.sha256"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return software module entity
|
||||
*/
|
||||
public MasterEntitySupport<ProxySoftwareModule> getMasterEntitySupport() {
|
||||
return masterEntitySupport;
|
||||
}
|
||||
|
||||
private static class DownloadException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public DownloadException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.details;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.event.CommandTopics;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventLayout;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventView;
|
||||
import org.eclipse.hawkbit.ui.common.event.LayoutResizeEventPayload;
|
||||
import org.eclipse.hawkbit.ui.common.event.LayoutResizeEventPayload.ResizeType;
|
||||
import org.eclipse.hawkbit.ui.common.grid.header.AbstractMasterAwareGridHeader;
|
||||
import org.eclipse.hawkbit.ui.common.grid.header.support.ResizeHeaderSupport;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
|
||||
|
||||
/**
|
||||
* Header for ArtifactDetails with maximize-support.
|
||||
*/
|
||||
public class ArtifactDetailsGridHeader extends AbstractMasterAwareGridHeader<ProxySoftwareModule> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final ArtifactDetailsGridLayoutUiState artifactDetailsGridLayoutUiState;
|
||||
|
||||
private final transient ResizeHeaderSupport resizeHeaderSupport;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param artifactDetailsGridLayoutUiState
|
||||
* ArtifactDetailsGridLayoutUiState
|
||||
*/
|
||||
public ArtifactDetailsGridHeader(final CommonUiDependencies uiDependencies,
|
||||
final ArtifactDetailsGridLayoutUiState artifactDetailsGridLayoutUiState) {
|
||||
super(uiDependencies.getI18n(), uiDependencies.getPermChecker(), uiDependencies.getEventBus());
|
||||
|
||||
this.artifactDetailsGridLayoutUiState = artifactDetailsGridLayoutUiState;
|
||||
|
||||
this.resizeHeaderSupport = new ResizeHeaderSupport(i18n, SPUIDefinitions.EXPAND_ARTIFACT_DETAILS,
|
||||
this::maximizeTable, this::minimizeTable, this::onLoadIsTableMaximized);
|
||||
addHeaderSupport(resizeHeaderSupport);
|
||||
|
||||
buildHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getEntityDetailsCaptionMsgKey() {
|
||||
return UIMessageIdProvider.CAPTION_ARTIFACT_DETAILS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMasterEntityDetailsCaptionId() {
|
||||
return UIComponentIdProvider.ARTIFACT_DETAILS_HEADER_LABEL_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMasterEntityName(final ProxySoftwareModule masterEntity) {
|
||||
return masterEntity.getNameAndVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getEntityDetailsCaptionOfMsgKey() {
|
||||
return UIMessageIdProvider.CAPTION_ARTIFACT_DETAILS_OF;
|
||||
}
|
||||
|
||||
private void maximizeTable() {
|
||||
eventBus.publish(CommandTopics.RESIZE_LAYOUT, this,
|
||||
new LayoutResizeEventPayload(ResizeType.MAXIMIZE, EventLayout.ARTIFACT_LIST, EventView.UPLOAD));
|
||||
|
||||
artifactDetailsGridLayoutUiState.setMaximized(true);
|
||||
}
|
||||
|
||||
private void minimizeTable() {
|
||||
eventBus.publish(CommandTopics.RESIZE_LAYOUT, this,
|
||||
new LayoutResizeEventPayload(ResizeType.MINIMIZE, EventLayout.ARTIFACT_LIST, EventView.UPLOAD));
|
||||
|
||||
artifactDetailsGridLayoutUiState.setMaximized(false);
|
||||
}
|
||||
|
||||
private Boolean onLoadIsTableMaximized() {
|
||||
return artifactDetailsGridLayoutUiState.isMaximized();
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.details;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.MultipartConfigElement;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.ui.artifacts.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress;
|
||||
import org.eclipse.hawkbit.ui.artifacts.upload.UploadDropAreaLayout;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventLayout;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventLayoutViewAware;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventTopics;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventView;
|
||||
import org.eclipse.hawkbit.ui.common.layout.AbstractGridComponentLayout;
|
||||
import org.eclipse.hawkbit.ui.common.layout.MasterEntityAwareComponent;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.GenericEventListener;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.SelectionChangedListener;
|
||||
|
||||
/**
|
||||
* Display the details of the artifacts for a selected software module.
|
||||
*/
|
||||
public class ArtifactDetailsGridLayout extends AbstractGridComponentLayout {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final ArtifactDetailsGridHeader artifactDetailsHeader;
|
||||
private final ArtifactDetailsGrid artifactDetailsGrid;
|
||||
private final UploadDropAreaLayout uploadDropAreaLayout;
|
||||
|
||||
private final transient SelectionChangedListener<ProxySoftwareModule> selectionChangedListener;
|
||||
private final transient GenericEventListener<FileUploadProgress> fileUploadChangedListener;
|
||||
|
||||
/**
|
||||
* Constructor for ArtifactDetailsLayout
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param artifactUploadState
|
||||
* ArtifactUploadState
|
||||
* @param artifactDetailsGridLayoutUiState
|
||||
* ArtifactDetailsGridLayoutUiState
|
||||
* @param artifactManagement
|
||||
* ArtifactManagement
|
||||
* @param softwareManagement
|
||||
* SoftwareModuleManagement
|
||||
* @param multipartConfigElement
|
||||
* MultipartConfigElement
|
||||
*/
|
||||
public ArtifactDetailsGridLayout(final CommonUiDependencies uiDependencies,
|
||||
final ArtifactUploadState artifactUploadState,
|
||||
final ArtifactDetailsGridLayoutUiState artifactDetailsGridLayoutUiState,
|
||||
final ArtifactManagement artifactManagement, final SoftwareModuleManagement softwareManagement,
|
||||
final MultipartConfigElement multipartConfigElement) {
|
||||
this.artifactDetailsHeader = new ArtifactDetailsGridHeader(uiDependencies, artifactDetailsGridLayoutUiState);
|
||||
this.artifactDetailsGrid = new ArtifactDetailsGrid(uiDependencies, artifactManagement);
|
||||
|
||||
if (uiDependencies.getPermChecker().hasCreateRepositoryPermission()) {
|
||||
this.uploadDropAreaLayout = new UploadDropAreaLayout(uiDependencies, artifactUploadState,
|
||||
multipartConfigElement, softwareManagement, artifactManagement);
|
||||
|
||||
buildLayout(artifactDetailsHeader, artifactDetailsGrid, uploadDropAreaLayout);
|
||||
} else {
|
||||
this.uploadDropAreaLayout = null;
|
||||
|
||||
buildLayout(artifactDetailsHeader, artifactDetailsGrid);
|
||||
}
|
||||
|
||||
final EventLayoutViewAware masterLayoutView = new EventLayoutViewAware(EventLayout.SM_LIST, EventView.UPLOAD);
|
||||
this.selectionChangedListener = new SelectionChangedListener<>(uiDependencies.getEventBus(), masterLayoutView,
|
||||
getMasterEntityAwareComponents());
|
||||
this.fileUploadChangedListener = new GenericEventListener<>(uiDependencies.getEventBus(),
|
||||
EventTopics.FILE_UPLOAD_CHANGED, this::onUploadChanged);
|
||||
}
|
||||
|
||||
private List<MasterEntityAwareComponent<ProxySoftwareModule>> getMasterEntityAwareComponents() {
|
||||
return Arrays.asList(artifactDetailsHeader, artifactDetailsGrid.getMasterEntitySupport(), uploadDropAreaLayout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks progress on file upload
|
||||
*
|
||||
* @param fileUploadProgress
|
||||
* FileUploadProgress
|
||||
*/
|
||||
public void onUploadChanged(final FileUploadProgress fileUploadProgress) {
|
||||
if (uploadDropAreaLayout != null) {
|
||||
uploadDropAreaLayout.onUploadChanged(fileUploadProgress);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximize the artifact grid
|
||||
*/
|
||||
public void maximize() {
|
||||
artifactDetailsGrid.createMaximizedContent();
|
||||
hideDetailsLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimize the artifact grid
|
||||
*/
|
||||
public void minimize() {
|
||||
artifactDetailsGrid.createMinimizedContent();
|
||||
showDetailsLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreState() {
|
||||
artifactDetailsHeader.restoreState();
|
||||
|
||||
if (uploadDropAreaLayout != null) {
|
||||
uploadDropAreaLayout.restoreState();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribeListeners() {
|
||||
selectionChangedListener.subscribe();
|
||||
fileUploadChangedListener.subscribe();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribeListeners() {
|
||||
selectionChangedListener.unsubscribe();
|
||||
fileUploadChangedListener.unsubscribe();
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.details;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Display and set the current state of the artifacts detail layout
|
||||
*
|
||||
*/
|
||||
public class ArtifactDetailsGridLayoutUiState implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private boolean maximized;
|
||||
|
||||
/**
|
||||
* @return current state artifact detail grid
|
||||
*/
|
||||
public boolean isMaximized() {
|
||||
return maximized;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maximized set artifact detail grid to true or false
|
||||
*/
|
||||
public void setMaximized(final boolean maximized) {
|
||||
this.maximized = maximized;
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ArtifactEncryptionService;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleCreate;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractAddNamedEntityWindowController;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.EntityWindowLayout;
|
||||
import org.eclipse.hawkbit.ui.common.data.mappers.SoftwareModuleToProxyMapper;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventLayout;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventView;
|
||||
import org.eclipse.hawkbit.ui.common.event.SelectionChangedEventPayload;
|
||||
import org.eclipse.hawkbit.ui.common.event.SelectionChangedEventPayload.SelectionChangedEventType;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
|
||||
/**
|
||||
* Controller for populating and saving data in Add Software Module Window.
|
||||
*/
|
||||
public class AddSmWindowController
|
||||
extends AbstractAddNamedEntityWindowController<ProxySoftwareModule, ProxySoftwareModule, SoftwareModule> {
|
||||
|
||||
private final SoftwareModuleManagement smManagement;
|
||||
private final SmWindowLayout layout;
|
||||
private final EventView view;
|
||||
private final ProxySmValidator validator;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param smManagement
|
||||
* SoftwareModuleManagement
|
||||
* @param layout
|
||||
* SoftwareModuleWindowLayout
|
||||
* @param view
|
||||
* EventView
|
||||
*/
|
||||
public AddSmWindowController(final CommonUiDependencies uiDependencies, final SoftwareModuleManagement smManagement,
|
||||
final SmWindowLayout layout, final EventView view) {
|
||||
super(uiDependencies);
|
||||
|
||||
this.smManagement = smManagement;
|
||||
this.layout = layout;
|
||||
this.view = view;
|
||||
this.validator = new ProxySmValidator(uiDependencies);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityWindowLayout<ProxySoftwareModule> getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void adaptLayout(final ProxySoftwareModule proxyEntity) {
|
||||
if (!ArtifactEncryptionService.getInstance().isEncryptionSupported()) {
|
||||
layout.disableEncryptionField();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProxySoftwareModule buildEntityFromProxy(final ProxySoftwareModule proxyEntity) {
|
||||
// We ignore the method parameter, because we are interested in the
|
||||
// empty object, that we can populate with defaults
|
||||
return new ProxySoftwareModule();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SoftwareModule persistEntityInRepository(final ProxySoftwareModule entity) {
|
||||
final SoftwareModuleCreate smCreate = getEntityFactory().softwareModule().create()
|
||||
.type(entity.getTypeInfo().getKey()).name(entity.getName()).version(entity.getVersion())
|
||||
.vendor(entity.getVendor()).description(entity.getDescription()).encrypted(entity.isEncrypted());
|
||||
|
||||
return smManagement.create(smCreate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDisplayableName(final SoftwareModule entity) {
|
||||
return HawkbitCommonUtil.getFormattedNameVersion(entity.getName(), entity.getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDisplayableNameForFailedMessage(final ProxySoftwareModule entity) {
|
||||
return HawkbitCommonUtil.getFormattedNameVersion(entity.getName(), entity.getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends ProxyIdentifiableEntity> getEntityClass() {
|
||||
return ProxySoftwareModule.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void selectPersistedEntity(final SoftwareModule entity) {
|
||||
final ProxySoftwareModule addedItem = new SoftwareModuleToProxyMapper().map(entity);
|
||||
publishSelectionEvent(new SelectionChangedEventPayload<>(SelectionChangedEventType.ENTITY_SELECTED, addedItem,
|
||||
EventLayout.SM_LIST, view));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEntityValid(final ProxySoftwareModule entity) {
|
||||
final String name = entity.getName();
|
||||
final String version = entity.getVersion();
|
||||
final Long typeId = entity.getTypeInfo().getId();
|
||||
return validator.isEntityValid(entity,
|
||||
() -> smManagement.getByNameAndVersionAndType(name, version, typeId).isPresent());
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.EntityValidator;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Validator used in SoftwareModule window controllers to validate
|
||||
* {@link ProxySoftwareModule}.
|
||||
*/
|
||||
public class ProxySmValidator extends EntityValidator {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
*/
|
||||
public ProxySmValidator(final CommonUiDependencies uiDependencies) {
|
||||
super(uiDependencies);
|
||||
}
|
||||
|
||||
boolean isEntityValid(final ProxySoftwareModule entity, final BooleanSupplier duplicateCheck) {
|
||||
if (!StringUtils.hasText(entity.getName()) || !StringUtils.hasText(entity.getVersion())
|
||||
|| entity.getTypeInfo() == null) {
|
||||
displayValidationError("message.error.missing.nameorversionortype");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (duplicateCheck.getAsBoolean()) {
|
||||
displayValidationError("message.duplicate.softwaremodule", entity.getName(), entity.getVersion());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.detailslayout.MetaDataAddUpdateWindowLayout;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
import com.vaadin.ui.CheckBox;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
/**
|
||||
* Class for sm metadata add/update window layout.
|
||||
*/
|
||||
public class SmMetaDataAddUpdateWindowLayout extends MetaDataAddUpdateWindowLayout {
|
||||
protected final CheckBox isVisibleForTarget;
|
||||
|
||||
/**
|
||||
* Constructor for AbstractTagWindowLayout
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param hasMetadataChangePermission
|
||||
* checks the permission allowing to change metadata entities
|
||||
*/
|
||||
public SmMetaDataAddUpdateWindowLayout(final VaadinMessageSource i18n,
|
||||
final BooleanSupplier hasMetadataChangePermission) {
|
||||
super(i18n, hasMetadataChangePermission);
|
||||
|
||||
this.isVisibleForTarget = metaDataComponentBuilder.createVisibleForTargetsField(binder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected VerticalLayout getMetadataAddUpdateLayout() {
|
||||
final VerticalLayout addUpdateLayout = super.getMetadataAddUpdateLayout();
|
||||
addUpdateLayout.addComponent(isVisibleForTarget);
|
||||
|
||||
return addUpdateLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void disableMetadataInputComponents() {
|
||||
super.disableMetadataInputComponents();
|
||||
isVisibleForTarget.setEnabled(false);
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyMetaData;
|
||||
import org.eclipse.hawkbit.ui.common.detailslayout.AbstractMetaDataWindowBuilder;
|
||||
|
||||
import com.vaadin.ui.Window;
|
||||
|
||||
/**
|
||||
* Builder for Software module meta data windows
|
||||
*/
|
||||
public class SmMetaDataWindowBuilder extends AbstractMetaDataWindowBuilder<Long> {
|
||||
|
||||
private final SoftwareModuleManagement smManagement;
|
||||
|
||||
/**
|
||||
* Constructor for SmMetaDataWindowBuilder
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param smManagement
|
||||
* SoftwareModuleManagement
|
||||
*/
|
||||
public SmMetaDataWindowBuilder(final CommonUiDependencies uiDependencies, final SoftwareModuleManagement smManagement) {
|
||||
super(uiDependencies);
|
||||
|
||||
this.smManagement = smManagement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get software module window without proxy meta data
|
||||
*
|
||||
* @param smId
|
||||
* software module ID
|
||||
* @param name
|
||||
* Selected entity name
|
||||
*
|
||||
* @return software module window
|
||||
*/
|
||||
public Window getWindowForShowSmMetaData(final Long smId, final String name) {
|
||||
return getWindowForShowSmMetaData(smId, name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get software module window with proxy meta data
|
||||
*
|
||||
* @param smId
|
||||
* software module ID
|
||||
* @param name
|
||||
* Selected entity name
|
||||
* @param proxyMetaData
|
||||
* ProxyMetaData
|
||||
*
|
||||
* @return software module window
|
||||
*/
|
||||
public Window getWindowForShowSmMetaData(final Long smId, final String name, final ProxyMetaData proxyMetaData) {
|
||||
return getWindowForShowMetaData(new SmMetaDataWindowLayout(uiDependencies, smManagement), smId, name, proxyMetaData);
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.model.MetaData;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.SmMetaDataDataProvider;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyMetaData;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.detailslayout.AbstractMetaDataWindowLayout;
|
||||
import org.eclipse.hawkbit.ui.common.detailslayout.AddMetaDataWindowController;
|
||||
import org.eclipse.hawkbit.ui.common.detailslayout.MetaDataAddUpdateWindowLayout;
|
||||
import org.eclipse.hawkbit.ui.common.detailslayout.MetaDataWindowGrid;
|
||||
import org.eclipse.hawkbit.ui.common.detailslayout.UpdateMetaDataWindowController;
|
||||
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
|
||||
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload.EntityModifiedEventType;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventTopics;
|
||||
|
||||
/**
|
||||
* Class for metadata add/update window layout.
|
||||
*/
|
||||
public class SmMetaDataWindowLayout extends AbstractMetaDataWindowLayout<Long> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final transient SoftwareModuleManagement smManagement;
|
||||
|
||||
private final MetaDataWindowGrid<Long> smMetaDataWindowGrid;
|
||||
|
||||
private final transient SmMetaDataAddUpdateWindowLayout smMetaDataAddUpdateWindowLayout;
|
||||
private final transient AddMetaDataWindowController addSmMetaDataWindowController;
|
||||
private final transient UpdateMetaDataWindowController updateSmMetaDataWindowController;
|
||||
|
||||
/**
|
||||
* Constructor for AbstractTagWindowLayout
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param smManagement
|
||||
* SoftwareModuleManagement
|
||||
*/
|
||||
public SmMetaDataWindowLayout(final CommonUiDependencies uiDependencies,
|
||||
final SoftwareModuleManagement smManagement) {
|
||||
super(uiDependencies);
|
||||
|
||||
this.smManagement = smManagement;
|
||||
|
||||
this.smMetaDataWindowGrid = new MetaDataWindowGrid<>(uiDependencies, new SmMetaDataDataProvider(smManagement),
|
||||
this::hasMetadataChangePermission, this::deleteMetaData);
|
||||
|
||||
this.smMetaDataAddUpdateWindowLayout = new SmMetaDataAddUpdateWindowLayout(i18n,this::hasMetadataChangePermission);
|
||||
this.addSmMetaDataWindowController = new AddMetaDataWindowController(uiDependencies,
|
||||
smMetaDataAddUpdateWindowLayout, this::createMetaData, this::isDuplicate);
|
||||
this.updateSmMetaDataWindowController = new UpdateMetaDataWindowController(uiDependencies,
|
||||
smMetaDataAddUpdateWindowLayout, this::updateMetaData, this::isDuplicate);
|
||||
|
||||
buildLayout();
|
||||
addGridSelectionListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getEntityType() {
|
||||
return i18n.getMessage("caption.software.module");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MetaData doCreateMetaData(final ProxyMetaData entity) {
|
||||
return smManagement
|
||||
.createMetaData(uiDependencies.getEntityFactory().softwareModuleMetadata().create(masterEntityFilter)
|
||||
.key(entity.getKey()).value(entity.getValue()).targetVisible(entity.isVisibleForTargets()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MetaData doUpdateMetaData(final ProxyMetaData entity) {
|
||||
return smManagement.updateMetaData(
|
||||
uiDependencies.getEntityFactory().softwareModuleMetadata().update(masterEntityFilter, entity.getKey())
|
||||
.value(entity.getValue()).targetVisible(entity.isVisibleForTargets()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doDeleteMetaDataByKey(final String metaDataKey) {
|
||||
smManagement.deleteMetaData(masterEntityFilter, metaDataKey);
|
||||
}
|
||||
|
||||
private boolean isDuplicate(final String metaDataKey) {
|
||||
return smManagement.getMetaDataBySoftwareModuleId(masterEntityFilter, metaDataKey).isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MetaDataWindowGrid<Long> getMetaDataWindowGrid() {
|
||||
return smMetaDataWindowGrid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return add widow controller for software module
|
||||
*/
|
||||
@Override
|
||||
public AddMetaDataWindowController getAddMetaDataWindowController() {
|
||||
return addSmMetaDataWindowController;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return update widow controller for software module
|
||||
*/
|
||||
@Override
|
||||
public UpdateMetaDataWindowController getUpdateMetaDataWindowController() {
|
||||
return updateSmMetaDataWindowController;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return add and update widow layout for software module
|
||||
*/
|
||||
@Override
|
||||
public MetaDataAddUpdateWindowLayout getMetaDataAddUpdateWindowLayout() {
|
||||
return smMetaDataAddUpdateWindowLayout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void publishEntityModifiedEvent() {
|
||||
eventBus.publish(EventTopics.ENTITY_MODIFIED, this, new EntityModifiedEventPayload(
|
||||
EntityModifiedEventType.ENTITY_UPDATED, ProxySoftwareModule.class, masterEntityFilter));
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventView;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
|
||||
import com.vaadin.ui.Window;
|
||||
|
||||
/**
|
||||
* Builder for Software module windows
|
||||
*/
|
||||
public class SmWindowBuilder extends AbstractEntityWindowBuilder<ProxySoftwareModule> {
|
||||
|
||||
private final SoftwareModuleManagement smManagement;
|
||||
private final SoftwareModuleTypeManagement smTypeManagement;
|
||||
|
||||
private final EventView view;
|
||||
|
||||
/**
|
||||
* Constructor for SmWindowBuilder
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param smManagement
|
||||
* SoftwareModuleManagement
|
||||
* @param smTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
* @param view
|
||||
* EventView
|
||||
*/
|
||||
public SmWindowBuilder(final CommonUiDependencies uiDependencies, final SoftwareModuleManagement smManagement,
|
||||
final SoftwareModuleTypeManagement smTypeManagement, final EventView view) {
|
||||
super(uiDependencies);
|
||||
|
||||
this.smManagement = smManagement;
|
||||
this.smTypeManagement = smTypeManagement;
|
||||
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getWindowId() {
|
||||
return UIComponentIdProvider.CREATE_POPUP_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return add window for software module
|
||||
*/
|
||||
@Override
|
||||
public Window getWindowForAdd() {
|
||||
return getWindowForNewEntity(new AddSmWindowController(uiDependencies, smManagement,
|
||||
new SmWindowLayout(getI18n(), smTypeManagement), view));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param proxySm
|
||||
* ProxySoftwareModule
|
||||
*
|
||||
* @return update window for software module
|
||||
*/
|
||||
@Override
|
||||
public Window getWindowForUpdate(final ProxySoftwareModule proxySm) {
|
||||
return getWindowForEntity(proxySm, new UpdateSmWindowController(uiDependencies, smManagement,
|
||||
new SmWindowLayout(getI18n(), smTypeManagement)));
|
||||
}
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowLayout;
|
||||
import org.eclipse.hawkbit.ui.common.data.mappers.TypeToTypeInfoMapper;
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.SoftwareModuleTypeDataProvider;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTypeInfo;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
import com.vaadin.ui.CheckBox;
|
||||
import com.vaadin.ui.ComboBox;
|
||||
import com.vaadin.ui.ComponentContainer;
|
||||
import com.vaadin.ui.FormLayout;
|
||||
import com.vaadin.ui.TextArea;
|
||||
import com.vaadin.ui.TextField;
|
||||
|
||||
/**
|
||||
* Target add/update window layout.
|
||||
*/
|
||||
public class SmWindowLayout extends AbstractEntityWindowLayout<ProxySoftwareModule> {
|
||||
private final SmWindowLayoutComponentBuilder smComponentBuilder;
|
||||
|
||||
private final ComboBox<ProxyTypeInfo> smTypeSelect;
|
||||
private final TextField smName;
|
||||
private final TextField smVersion;
|
||||
private final TextField smVendor;
|
||||
private final TextArea smDescription;
|
||||
private final CheckBox artifactEncryption;
|
||||
|
||||
/**
|
||||
* Constructor for AbstractTagWindowLayout
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param smTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
*/
|
||||
public SmWindowLayout(final VaadinMessageSource i18n, final SoftwareModuleTypeManagement smTypeManagement) {
|
||||
super();
|
||||
|
||||
final SoftwareModuleTypeDataProvider<ProxyTypeInfo> smTypeDataProvider = new SoftwareModuleTypeDataProvider<>(
|
||||
smTypeManagement, new TypeToTypeInfoMapper<>());
|
||||
this.smComponentBuilder = new SmWindowLayoutComponentBuilder(i18n, smTypeDataProvider);
|
||||
|
||||
this.smTypeSelect = smComponentBuilder.createSoftwareModuleTypeCombo(binder);
|
||||
this.smName = smComponentBuilder.createNameField(binder);
|
||||
this.smVersion = smComponentBuilder.createVersionField(binder);
|
||||
this.smVendor = smComponentBuilder.createVendorField(binder);
|
||||
this.smDescription = smComponentBuilder.createDescription(binder);
|
||||
this.artifactEncryption = smComponentBuilder.createArtifactEncryptionCheck(binder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return software module window layout
|
||||
*/
|
||||
@Override
|
||||
public ComponentContainer getRootComponent() {
|
||||
final FormLayout smWindowLayout = new FormLayout();
|
||||
|
||||
smWindowLayout.setSpacing(true);
|
||||
smWindowLayout.setMargin(true);
|
||||
smWindowLayout.setSizeUndefined();
|
||||
|
||||
smWindowLayout.addComponent(smTypeSelect);
|
||||
|
||||
smWindowLayout.addComponent(smName);
|
||||
smName.focus();
|
||||
|
||||
smWindowLayout.addComponent(smVersion);
|
||||
|
||||
smWindowLayout.addComponent(smVendor);
|
||||
|
||||
smWindowLayout.addComponent(smDescription);
|
||||
|
||||
smWindowLayout.addComponent(artifactEncryption);
|
||||
|
||||
return smWindowLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the software module type
|
||||
*/
|
||||
public void disableSmTypeSelect() {
|
||||
smTypeSelect.setEnabled(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the software module name
|
||||
*/
|
||||
public void disableNameField() {
|
||||
smName.setEnabled(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the software module version
|
||||
*/
|
||||
public void disableVersionField() {
|
||||
smVersion.setEnabled(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the software module artifact encryption
|
||||
*/
|
||||
public void disableEncryptionField() {
|
||||
artifactEncryption.setEnabled(false);
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.builder.FormComponentBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.builder.TextFieldBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.SoftwareModuleTypeDataProvider;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTypeInfo;
|
||||
import org.eclipse.hawkbit.ui.utils.TrimmingStringConverter;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
import com.vaadin.data.Binder;
|
||||
import com.vaadin.ui.CheckBox;
|
||||
import com.vaadin.ui.ComboBox;
|
||||
import com.vaadin.ui.TextArea;
|
||||
import com.vaadin.ui.TextField;
|
||||
|
||||
/**
|
||||
* Builder for software module window layout
|
||||
*/
|
||||
public class SmWindowLayoutComponentBuilder {
|
||||
|
||||
public static final String TEXTFIELD_VENDOR = "textfield.vendor";
|
||||
public static final String ARTIFACT_ENCRYPTION = "artifact.encryption";
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
private final SoftwareModuleTypeDataProvider<ProxyTypeInfo> smTypeDataProvider;
|
||||
|
||||
/**
|
||||
* Constructor for SmWindowLayoutComponentBuilder
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param smTypeDataProvider
|
||||
* SoftwareModuleTypeDataProvider
|
||||
*/
|
||||
public SmWindowLayoutComponentBuilder(final VaadinMessageSource i18n,
|
||||
final SoftwareModuleTypeDataProvider<ProxyTypeInfo> smTypeDataProvider) {
|
||||
this.i18n = i18n;
|
||||
this.smTypeDataProvider = smTypeDataProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create combo box options for software module types
|
||||
*
|
||||
* @param binder
|
||||
* binder the input will be bound to
|
||||
*
|
||||
* @return input component
|
||||
*/
|
||||
public ComboBox<ProxyTypeInfo> createSoftwareModuleTypeCombo(final Binder<ProxySoftwareModule> binder) {
|
||||
return FormComponentBuilder
|
||||
.createTypeCombo(binder, smTypeDataProvider, i18n, UIComponentIdProvider.SW_MODULE_TYPE, true)
|
||||
.getComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* create name field
|
||||
*
|
||||
* @param binder
|
||||
* binder the input will be bound to
|
||||
* @return input component
|
||||
*/
|
||||
public TextField createNameField(final Binder<ProxySoftwareModule> binder) {
|
||||
return FormComponentBuilder.createNameInput(binder, i18n, UIComponentIdProvider.SOFT_MODULE_NAME)
|
||||
.getComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* create version field
|
||||
*
|
||||
* @param binder
|
||||
* binder the input will be bound to
|
||||
* @return input component
|
||||
*/
|
||||
public TextField createVersionField(final Binder<ProxySoftwareModule> binder) {
|
||||
return FormComponentBuilder.createVersionInput(binder, i18n, UIComponentIdProvider.SOFT_MODULE_VERSION)
|
||||
.getComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create vendor field
|
||||
*
|
||||
* @param binder
|
||||
* binder the input will be bound to
|
||||
*
|
||||
* @return input component
|
||||
*/
|
||||
public TextField createVendorField(final Binder<ProxySoftwareModule> binder) {
|
||||
final TextField smVendor = new TextFieldBuilder(SoftwareModule.VENDOR_MAX_SIZE)
|
||||
.id(UIComponentIdProvider.SOFT_MODULE_VENDOR).caption(i18n.getMessage(TEXTFIELD_VENDOR))
|
||||
.prompt(i18n.getMessage(TEXTFIELD_VENDOR)).buildTextComponent();
|
||||
smVendor.setSizeUndefined();
|
||||
|
||||
binder.forField(smVendor).withConverter(new TrimmingStringConverter()).bind(ProxySoftwareModule::getVendor,
|
||||
ProxySoftwareModule::setVendor);
|
||||
|
||||
return smVendor;
|
||||
}
|
||||
|
||||
/**
|
||||
* create description field
|
||||
*
|
||||
* @param binder
|
||||
* binder the input will be bound to
|
||||
* @return input component
|
||||
*/
|
||||
public TextArea createDescription(final Binder<ProxySoftwareModule> binder) {
|
||||
return FormComponentBuilder
|
||||
.createDescriptionInput(binder, i18n, UIComponentIdProvider.ADD_SW_MODULE_DESCRIPTION).getComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create checkbox for artifact encryption
|
||||
*
|
||||
* @param binder
|
||||
* binder the input will be bound to
|
||||
*
|
||||
* @return input component
|
||||
*/
|
||||
public CheckBox createArtifactEncryptionCheck(final Binder<ProxySoftwareModule> binder) {
|
||||
return FormComponentBuilder.createCheckBox(i18n.getMessage(ARTIFACT_ENCRYPTION),
|
||||
UIComponentIdProvider.ARTIFACT_ENCRYPTION_ID, binder, ProxySoftwareModule::isEncrypted,
|
||||
ProxySoftwareModule::setEncrypted);
|
||||
}
|
||||
}
|
||||
@@ -1,313 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.builder.GridComponentBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.data.filters.SwFilterParams;
|
||||
import org.eclipse.hawkbit.ui.common.data.mappers.AssignedSoftwareModuleToProxyMapper;
|
||||
import org.eclipse.hawkbit.ui.common.data.mappers.SoftwareModuleToProxyMapper;
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.SoftwareModuleDataProvider;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSet;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
|
||||
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload.EntityModifiedEventType;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventLayout;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventTopics;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventView;
|
||||
import org.eclipse.hawkbit.ui.common.event.FilterType;
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGrid;
|
||||
import org.eclipse.hawkbit.ui.common.grid.support.DeleteSupport;
|
||||
import org.eclipse.hawkbit.ui.common.grid.support.DragAndDropSupport;
|
||||
import org.eclipse.hawkbit.ui.common.grid.support.FilterSupport;
|
||||
import org.eclipse.hawkbit.ui.common.grid.support.MasterEntitySupport;
|
||||
import org.eclipse.hawkbit.ui.common.grid.support.SelectionSupport;
|
||||
import org.eclipse.hawkbit.ui.common.state.GridLayoutUiState;
|
||||
import org.eclipse.hawkbit.ui.common.state.TypeFilterLayoutUiState;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
|
||||
import com.vaadin.ui.Button;
|
||||
|
||||
/**
|
||||
* Software Module grid.
|
||||
*/
|
||||
public class SoftwareModuleGrid extends AbstractGrid<ProxySoftwareModule, SwFilterParams> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String SM_NAME_ID = "smName";
|
||||
private static final String SM_VERSION_ID = "smVersion";
|
||||
private static final String SM_DESC_ID = "smDescription";
|
||||
private static final String SM_VENDOR_ID = "smVendor";
|
||||
private static final String SM_DELETE_BUTTON_ID = "smDeleteButton";
|
||||
|
||||
private final UINotification notification;
|
||||
|
||||
private final TypeFilterLayoutUiState smTypeFilterLayoutUiState;
|
||||
private final GridLayoutUiState smGridLayoutUiState;
|
||||
|
||||
private final transient SoftwareModuleManagement softwareModuleManagement;
|
||||
private final transient SoftwareModuleToProxyMapper softwareModuleToProxyMapper;
|
||||
|
||||
private final transient DeleteSupport<ProxySoftwareModule> swModuleDeleteSupport;
|
||||
private transient MasterEntitySupport<ProxyDistributionSet> masterEntitySupport;
|
||||
|
||||
private final Map<Long, Integer> numberOfArtifactUploadsForSm;
|
||||
|
||||
/**
|
||||
* Constructor for SoftwareModuleGrid
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param smTypeFilterLayoutUiState
|
||||
* TypeFilterLayoutUiState
|
||||
* @param smGridLayoutUiState
|
||||
* GridLayoutUiState
|
||||
* @param softwareModuleManagement
|
||||
* SoftwareModuleManagement
|
||||
* @param view
|
||||
* EventView
|
||||
*/
|
||||
public SoftwareModuleGrid(final CommonUiDependencies uiDependencies,
|
||||
final TypeFilterLayoutUiState smTypeFilterLayoutUiState, final GridLayoutUiState smGridLayoutUiState,
|
||||
final SoftwareModuleManagement softwareModuleManagement, final EventView view) {
|
||||
super(uiDependencies.getI18n(), uiDependencies.getEventBus(), uiDependencies.getPermChecker());
|
||||
|
||||
this.smTypeFilterLayoutUiState = smTypeFilterLayoutUiState;
|
||||
this.smGridLayoutUiState = smGridLayoutUiState;
|
||||
this.notification = uiDependencies.getUiNotification();
|
||||
this.softwareModuleManagement = softwareModuleManagement;
|
||||
this.softwareModuleToProxyMapper = new SoftwareModuleToProxyMapper();
|
||||
|
||||
setSelectionSupport(new SelectionSupport<>(this, eventBus, EventLayout.SM_LIST, view, this::mapIdToProxyEntity,
|
||||
this::getSelectedEntityIdFromUiState, this::setSelectedEntityIdToUiState));
|
||||
if (smGridLayoutUiState.isMaximized()) {
|
||||
getSelectionSupport().disableSelection();
|
||||
} else {
|
||||
getSelectionSupport().enableMultiSelection();
|
||||
}
|
||||
|
||||
this.swModuleDeleteSupport = new DeleteSupport<>(this, i18n, notification, "caption.software.module",
|
||||
"caption.softwaremodules", ProxySoftwareModule::getNameAndVersion, this::deleteSoftwareModules,
|
||||
UIComponentIdProvider.SM_DELETE_CONFIRMATION_DIALOG);
|
||||
|
||||
setFilterSupport(new FilterSupport<>(
|
||||
new SoftwareModuleDataProvider(softwareModuleManagement,
|
||||
new AssignedSoftwareModuleToProxyMapper(softwareModuleToProxyMapper)),
|
||||
SwFilterParams::new, this::afterFilterRefresh));
|
||||
initFilterMappings();
|
||||
getFilterSupport().setFilter(new SwFilterParams());
|
||||
|
||||
this.numberOfArtifactUploadsForSm = new HashMap<>();
|
||||
}
|
||||
|
||||
private void afterFilterRefresh() {
|
||||
// keep selection on master distribution set change as it does not
|
||||
// filter out any software module entries, only sorts them
|
||||
if (masterFilterHasNotChanged()) {
|
||||
getSelectionSupport().deselectAll();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean masterFilterHasNotChanged() {
|
||||
final Long filterDsId = getFilter().map(SwFilterParams::getLastSelectedDistributionId).orElse(null);
|
||||
final Long masterDsId = getMasterEntitySupport() != null ? getMasterEntitySupport().getMasterId() : null;
|
||||
|
||||
return Objects.equals(filterDsId, masterDsId);
|
||||
}
|
||||
|
||||
private void initFilterMappings() {
|
||||
getFilterSupport().addMapping(FilterType.SEARCH, SwFilterParams::setSearchText,
|
||||
smGridLayoutUiState.getSearchFilter());
|
||||
getFilterSupport().addMapping(FilterType.TYPE, SwFilterParams::setSoftwareModuleTypeId,
|
||||
smTypeFilterLayoutUiState.getClickedTypeId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial method of grid and set style name
|
||||
*/
|
||||
@Override
|
||||
public void init() {
|
||||
super.init();
|
||||
|
||||
addStyleName("grid-row-border");
|
||||
}
|
||||
|
||||
/**
|
||||
* Map SoftwareModule to Proxy type
|
||||
*
|
||||
* @param entityId
|
||||
* EntityId Long type
|
||||
*
|
||||
* @return ProxySoftwareModule
|
||||
*/
|
||||
public Optional<ProxySoftwareModule> mapIdToProxyEntity(final long entityId) {
|
||||
return softwareModuleManagement.get(entityId).map(softwareModuleToProxyMapper::map);
|
||||
}
|
||||
|
||||
private Long getSelectedEntityIdFromUiState() {
|
||||
return smGridLayoutUiState.getSelectedEntityId();
|
||||
}
|
||||
|
||||
private void setSelectedEntityIdToUiState(final Long entityId) {
|
||||
smGridLayoutUiState.setSelectedEntityId(entityId);
|
||||
}
|
||||
|
||||
private boolean deleteSoftwareModules(final Collection<ProxySoftwareModule> swModulesToBeDeleted) {
|
||||
final Collection<Long> swModuleToBeDeletedIds = swModulesToBeDeleted.stream()
|
||||
.map(ProxyIdentifiableEntity::getId).collect(Collectors.toList());
|
||||
if (isUploadInProgressForSoftwareModule(swModuleToBeDeletedIds)) {
|
||||
notification.displayValidationError(i18n.getMessage("message.error.swModule.notDeleted"));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
softwareModuleManagement.delete(swModuleToBeDeletedIds);
|
||||
|
||||
eventBus.publish(EventTopics.ENTITY_MODIFIED, this, new EntityModifiedEventPayload(
|
||||
EntityModifiedEventType.ENTITY_REMOVED, ProxySoftwareModule.class, swModuleToBeDeletedIds));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isUploadInProgressForSoftwareModule(final Collection<Long> swModuleToBeDeletedIds) {
|
||||
return swModuleToBeDeletedIds.stream().anyMatch(
|
||||
smId -> numberOfArtifactUploadsForSm.containsKey(smId) && numberOfArtifactUploadsForSm.get(smId) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Artifacts upload process
|
||||
*
|
||||
* @param fileUploadProgress
|
||||
* FileUploadProgress
|
||||
*/
|
||||
public void onUploadChanged(final FileUploadProgress fileUploadProgress) {
|
||||
final FileUploadProgress.FileUploadStatus uploadProgressEventType = fileUploadProgress.getFileUploadStatus();
|
||||
final Long fileUploadSmId = fileUploadProgress.getFileUploadId().getSoftwareModuleId();
|
||||
|
||||
if (fileUploadSmId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (FileUploadProgress.FileUploadStatus.UPLOAD_STARTED == uploadProgressEventType) {
|
||||
numberOfArtifactUploadsForSm.merge(fileUploadSmId, 1, Integer::sum);
|
||||
}
|
||||
|
||||
if (FileUploadProgress.FileUploadStatus.UPLOAD_FINISHED == uploadProgressEventType) {
|
||||
numberOfArtifactUploadsForSm.computeIfPresent(fileUploadSmId, (smId, oldCount) -> {
|
||||
final Integer newCount = oldCount - 1;
|
||||
return newCount.equals(0) ? null : newCount;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drag and drop for grid elements
|
||||
*/
|
||||
public void addDragAndDropSupport() {
|
||||
setDragAndDropSupportSupport(
|
||||
new DragAndDropSupport<>(this, i18n, notification, Collections.emptyMap(), eventBus));
|
||||
if (!smGridLayoutUiState.isMaximized()) {
|
||||
getDragAndDropSupportSupport().addDragSource();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add master filter type
|
||||
*/
|
||||
public void addMasterSupport() {
|
||||
getFilterSupport().addMapping(FilterType.MASTER, SwFilterParams::setLastSelectedDistributionId);
|
||||
|
||||
masterEntitySupport = new MasterEntitySupport<>(getFilterSupport());
|
||||
|
||||
initMasterDsStyleGenerator();
|
||||
}
|
||||
|
||||
private void initMasterDsStyleGenerator() {
|
||||
setStyleGenerator(sm -> {
|
||||
if (masterEntitySupport.getMasterId() == null || !sm.isAssigned()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return String.join("-", UIComponentIdProvider.SM_TYPE_COLOR_CLASS,
|
||||
String.valueOf(sm.getTypeInfo().getId()));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return gridId of software module grid
|
||||
*/
|
||||
@Override
|
||||
public String getGridId() {
|
||||
return UIComponentIdProvider.SOFTWARE_MODULE_TABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add columns to Grid
|
||||
*/
|
||||
@Override
|
||||
public void addColumns() {
|
||||
addNameColumn().setExpandRatio(2);
|
||||
addVersionColumn();
|
||||
addDeleteColumn();
|
||||
}
|
||||
|
||||
private Column<ProxySoftwareModule, String> addNameColumn() {
|
||||
return GridComponentBuilder.addNameColumn(this, i18n, SM_NAME_ID);
|
||||
}
|
||||
|
||||
private Column<ProxySoftwareModule, String> addVersionColumn() {
|
||||
return GridComponentBuilder.addVersionColumn(this, i18n, ProxySoftwareModule::getVersion, SM_VERSION_ID);
|
||||
}
|
||||
|
||||
private Column<ProxySoftwareModule, Button> addDeleteColumn() {
|
||||
return GridComponentBuilder.addDeleteColumn(this, i18n, SM_DELETE_BUTTON_ID, swModuleDeleteSupport,
|
||||
UIComponentIdProvider.SM_DELET_ICON, e -> permissionChecker.hasDeleteRepositoryPermission());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addMaxColumns() {
|
||||
addNameColumn().setExpandRatio(7);
|
||||
addVersionColumn();
|
||||
addDescriptionColumn().setExpandRatio(5);
|
||||
addVendorColumn();
|
||||
GridComponentBuilder.addCreatedAndModifiedColumns(this, i18n);
|
||||
addDeleteColumn();
|
||||
|
||||
getColumns().forEach(column -> column.setHidable(true));
|
||||
}
|
||||
|
||||
private Column<ProxySoftwareModule, String> addDescriptionColumn() {
|
||||
return GridComponentBuilder.addDescriptionColumn(this, i18n, SM_DESC_ID);
|
||||
}
|
||||
|
||||
private Column<ProxySoftwareModule, String> addVendorColumn() {
|
||||
return GridComponentBuilder.addColumn(this, ProxySoftwareModule::getVendor).setId(SM_VENDOR_ID)
|
||||
.setCaption(i18n.getMessage("header.vendor"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ProxyDistributionSet of master entity type
|
||||
*/
|
||||
public MasterEntitySupport<ProxyDistributionSet> getMasterEntitySupport() {
|
||||
return masterEntitySupport;
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventLayout;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventView;
|
||||
import org.eclipse.hawkbit.ui.common.grid.header.AbstractEntityGridHeader;
|
||||
import org.eclipse.hawkbit.ui.common.state.GridLayoutUiState;
|
||||
import org.eclipse.hawkbit.ui.common.state.HidableLayoutUiState;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
|
||||
/**
|
||||
* Header of Software module table.
|
||||
*/
|
||||
public class SoftwareModuleGridHeader extends AbstractEntityGridHeader {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String SWM_TABLE_HEADER = "upload.swModuleTable.header";
|
||||
private static final String SWM_CAPTION = "caption.software.module";
|
||||
|
||||
/**
|
||||
* Constructor for SoftwareModuleGridHeader
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param smTypeFilterLayoutUiState
|
||||
* HidableLayoutUiState
|
||||
* @param smGridLayoutUiState
|
||||
* GridLayoutUiState
|
||||
* @param smWindowBuilder
|
||||
* SmWindowBuilder
|
||||
* @param view
|
||||
* EventView
|
||||
*/
|
||||
public SoftwareModuleGridHeader(final CommonUiDependencies uiDependencies,
|
||||
final HidableLayoutUiState smTypeFilterLayoutUiState, final GridLayoutUiState smGridLayoutUiState,
|
||||
final SmWindowBuilder smWindowBuilder, final EventView view) {
|
||||
super(uiDependencies, smTypeFilterLayoutUiState, smGridLayoutUiState, EventLayout.SM_TYPE_FILTER, view);
|
||||
|
||||
addAddHeaderSupport(smWindowBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCaptionMsg() {
|
||||
return SWM_TABLE_HEADER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSearchFieldId() {
|
||||
return UIComponentIdProvider.SW_MODULE_SEARCH_TEXT_FIELD;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSearchResetIconId() {
|
||||
return UIComponentIdProvider.SW_MODULE_SEARCH_RESET_ICON;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends ProxyIdentifiableEntity> getEntityType() {
|
||||
return ProxySoftwareModule.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFilterButtonsIconId() {
|
||||
return UIComponentIdProvider.SHOW_SM_TYPE_ICON;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMaxMinIconId() {
|
||||
return UIComponentIdProvider.SW_MAX_MIN_TABLE_ICON;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EventLayout getLayout() {
|
||||
return EventLayout.SM_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasCreatePermission() {
|
||||
return permChecker.hasCreateRepositoryPermission();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getAddIconId() {
|
||||
return UIComponentIdProvider.SW_MODULE_ADD_BUTTON;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getAddWindowCaptionMsg() {
|
||||
return SWM_CAPTION;
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.detailslayout.SoftwareModuleDetails;
|
||||
import org.eclipse.hawkbit.ui.common.detailslayout.SoftwareModuleDetailsHeader;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventLayout;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventLayoutViewAware;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventTopics;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventView;
|
||||
import org.eclipse.hawkbit.ui.common.layout.MasterEntityAwareComponent;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.EntityModifiedListener;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.EntityModifiedListener.EntityModifiedAwareSupport;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.FilterChangedListener;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.GenericEventListener;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.SelectGridEntityListener;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.SelectionChangedListener;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedGridRefreshAwareSupport;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedSelectionAwareSupport;
|
||||
import org.eclipse.hawkbit.ui.common.softwaremodule.AbstractSoftwareModuleGridLayout;
|
||||
import org.eclipse.hawkbit.ui.common.state.GridLayoutUiState;
|
||||
import org.eclipse.hawkbit.ui.common.state.TypeFilterLayoutUiState;
|
||||
|
||||
/**
|
||||
* Software module table layout. (Upload Management)
|
||||
*/
|
||||
public class SoftwareModuleGridLayout extends AbstractSoftwareModuleGridLayout {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final SoftwareModuleGridHeader softwareModuleGridHeader;
|
||||
private final SoftwareModuleGrid softwareModuleGrid;
|
||||
private final SoftwareModuleDetailsHeader softwareModuleDetailsHeader;
|
||||
private final SoftwareModuleDetails softwareModuleDetails;
|
||||
|
||||
/**
|
||||
* Constructor for SoftwareModuleGridLayout
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param softwareModuleManagement
|
||||
* SoftwareModuleManagement
|
||||
* @param softwareModuleTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
* @param smTypeFilterLayoutUiState
|
||||
* TypeFilterLayoutUiState
|
||||
* @param smGridLayoutUiState
|
||||
* GridLayoutUiState
|
||||
*/
|
||||
public SoftwareModuleGridLayout(final CommonUiDependencies uiDependencies,
|
||||
final SoftwareModuleManagement softwareModuleManagement,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement,
|
||||
final TypeFilterLayoutUiState smTypeFilterLayoutUiState, final GridLayoutUiState smGridLayoutUiState) {
|
||||
super(uiDependencies, softwareModuleManagement, softwareModuleTypeManagement, EventView.UPLOAD);
|
||||
|
||||
this.softwareModuleGridHeader = new SoftwareModuleGridHeader(uiDependencies, smTypeFilterLayoutUiState,
|
||||
smGridLayoutUiState, getSmWindowBuilder(), getEventView());
|
||||
this.softwareModuleGridHeader.buildHeader();
|
||||
this.softwareModuleGrid = new SoftwareModuleGrid(uiDependencies, smTypeFilterLayoutUiState, smGridLayoutUiState,
|
||||
softwareModuleManagement, getEventView());
|
||||
this.softwareModuleGrid.init();
|
||||
|
||||
this.softwareModuleDetailsHeader = new SoftwareModuleDetailsHeader(uiDependencies, getSmWindowBuilder(),
|
||||
getSmMetaDataWindowBuilder());
|
||||
this.softwareModuleDetailsHeader.buildHeader();
|
||||
this.softwareModuleDetails = new SoftwareModuleDetails(uiDependencies, softwareModuleManagement,
|
||||
softwareModuleTypeManagement, getSmMetaDataWindowBuilder());
|
||||
this.softwareModuleDetails.buildDetails();
|
||||
|
||||
final EventLayoutViewAware layoutViewAware = new EventLayoutViewAware(EventLayout.SM_LIST, getEventView());
|
||||
addEventListener(new FilterChangedListener<>(uiDependencies.getEventBus(), ProxySoftwareModule.class,
|
||||
layoutViewAware, softwareModuleGrid.getFilterSupport()));
|
||||
addEventListener(new SelectionChangedListener<>(uiDependencies.getEventBus(), layoutViewAware,
|
||||
getMasterSmAwareComponents()));
|
||||
addEventListener(new SelectGridEntityListener<>(uiDependencies.getEventBus(), layoutViewAware,
|
||||
softwareModuleGrid.getSelectionSupport()));
|
||||
addEventListener(new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(), ProxySoftwareModule.class)
|
||||
.viewAware(layoutViewAware).entityModifiedAwareSupports(getSmModifiedAwareSupports()).build());
|
||||
addEventListener(new GenericEventListener<>(uiDependencies.getEventBus(), EventTopics.FILE_UPLOAD_CHANGED,
|
||||
this::onUploadChanged));
|
||||
|
||||
buildLayout(softwareModuleGridHeader, softwareModuleGrid, softwareModuleDetailsHeader, softwareModuleDetails);
|
||||
}
|
||||
|
||||
private List<MasterEntityAwareComponent<ProxySoftwareModule>> getMasterSmAwareComponents() {
|
||||
return Arrays.asList(softwareModuleDetailsHeader, softwareModuleDetails);
|
||||
}
|
||||
|
||||
private List<EntityModifiedAwareSupport> getSmModifiedAwareSupports() {
|
||||
return Arrays.asList(EntityModifiedGridRefreshAwareSupport.of(softwareModuleGrid::refreshAll),
|
||||
EntityModifiedSelectionAwareSupport.of(softwareModuleGrid.getSelectionSupport(),
|
||||
softwareModuleGrid::mapIdToProxyEntity));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies when file upload is in progress
|
||||
*
|
||||
* @param fileUploadProgress
|
||||
* FileUploadProgress
|
||||
*/
|
||||
public void onUploadChanged(final FileUploadProgress fileUploadProgress) {
|
||||
softwareModuleGrid.onUploadChanged(fileUploadProgress);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SoftwareModuleGridHeader getSoftwareModuleGridHeader() {
|
||||
return softwareModuleGridHeader;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SoftwareModuleGrid getSoftwareModuleGrid() {
|
||||
return softwareModuleGrid;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleUpdate;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractUpdateNamedEntityWindowController;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.EntityWindowLayout;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
|
||||
/**
|
||||
* Controller for update software module window
|
||||
*/
|
||||
public class UpdateSmWindowController
|
||||
extends AbstractUpdateNamedEntityWindowController<ProxySoftwareModule, ProxySoftwareModule, SoftwareModule> {
|
||||
|
||||
private final SoftwareModuleManagement smManagement;
|
||||
private final SmWindowLayout layout;
|
||||
private final ProxySmValidator validator;
|
||||
|
||||
private String nameBeforeEdit;
|
||||
private String versionBeforeEdit;
|
||||
|
||||
/**
|
||||
* Constructor for UpdateSmWindowController
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param smManagement
|
||||
* SoftwareModuleManagement
|
||||
* @param layout
|
||||
* SmWindowLayout
|
||||
*/
|
||||
public UpdateSmWindowController(final CommonUiDependencies uiDependencies,
|
||||
final SoftwareModuleManagement smManagement, final SmWindowLayout layout) {
|
||||
super(uiDependencies);
|
||||
|
||||
this.smManagement = smManagement;
|
||||
this.layout = layout;
|
||||
this.validator = new ProxySmValidator(uiDependencies);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProxySoftwareModule buildEntityFromProxy(final ProxySoftwareModule proxyEntity) {
|
||||
final ProxySoftwareModule sm = new ProxySoftwareModule();
|
||||
|
||||
sm.setId(proxyEntity.getId());
|
||||
sm.setTypeInfo(proxyEntity.getTypeInfo());
|
||||
sm.setName(proxyEntity.getName());
|
||||
sm.setVersion(proxyEntity.getVersion());
|
||||
sm.setVendor(proxyEntity.getVendor());
|
||||
sm.setDescription(proxyEntity.getDescription());
|
||||
sm.setEncrypted(proxyEntity.isEncrypted());
|
||||
|
||||
nameBeforeEdit = proxyEntity.getName();
|
||||
versionBeforeEdit = proxyEntity.getVersion();
|
||||
|
||||
return sm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityWindowLayout<ProxySoftwareModule> getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void adaptLayout(final ProxySoftwareModule proxyEntity) {
|
||||
layout.disableSmTypeSelect();
|
||||
layout.disableNameField();
|
||||
layout.disableVersionField();
|
||||
layout.disableEncryptionField();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SoftwareModule persistEntityInRepository(final ProxySoftwareModule entity) {
|
||||
final SoftwareModuleUpdate smUpdate = getEntityFactory().softwareModule().update(entity.getId())
|
||||
.vendor(entity.getVendor()).description(entity.getDescription());
|
||||
return smManagement.update(smUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDisplayableName(final SoftwareModule entity) {
|
||||
return HawkbitCommonUtil.getFormattedNameVersion(entity.getName(), entity.getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDisplayableNameForFailedMessage(final ProxySoftwareModule entity) {
|
||||
return HawkbitCommonUtil.getFormattedNameVersion(entity.getName(), entity.getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends ProxyIdentifiableEntity> getEntityClass() {
|
||||
return ProxySoftwareModule.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEntityValid(final ProxySoftwareModule entity) {
|
||||
final String name = entity.getName();
|
||||
final String version = entity.getVersion();
|
||||
final Long typeId = entity.getTypeInfo().getId();
|
||||
return validator.isEntityValid(entity, () -> hasNameOrVersionChanged(name, version)
|
||||
&& smManagement.getByNameAndVersionAndType(name, version, typeId).isPresent());
|
||||
}
|
||||
|
||||
private boolean hasNameOrVersionChanged(final String trimmedName, final String trimmedVersion) {
|
||||
return !nameBeforeEdit.equals(trimmedName) || !versionBeforeEdit.equals(trimmedVersion);
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractAddNamedEntityWindowController;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.EntityWindowLayout;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType.SmTypeAssign;
|
||||
import org.eclipse.hawkbit.ui.common.type.ProxyTypeValidator;
|
||||
|
||||
/**
|
||||
* Controller for Add software module type window
|
||||
*/
|
||||
public class AddSmTypeWindowController
|
||||
extends AbstractAddNamedEntityWindowController<ProxyType, ProxyType, SoftwareModuleType> {
|
||||
|
||||
private final SoftwareModuleTypeManagement smTypeManagement;
|
||||
private final SmTypeWindowLayout layout;
|
||||
private final ProxyTypeValidator validator;
|
||||
|
||||
/**
|
||||
* Constructor for AddSmTypeWindowController
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param smTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
* @param layout
|
||||
* SmTypeWindowLayout
|
||||
*/
|
||||
public AddSmTypeWindowController(final CommonUiDependencies uiDependencies,
|
||||
final SoftwareModuleTypeManagement smTypeManagement, final SmTypeWindowLayout layout) {
|
||||
super(uiDependencies);
|
||||
|
||||
this.smTypeManagement = smTypeManagement;
|
||||
this.layout = layout;
|
||||
this.validator = new ProxyTypeValidator(uiDependencies);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityWindowLayout<ProxyType> getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProxyType buildEntityFromProxy(final ProxyType proxyEntity) {
|
||||
// We ignore the method parameter, because we are interested in the
|
||||
// empty object, that we can populate with defaults
|
||||
return new ProxyType();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SoftwareModuleType persistEntityInRepository(final ProxyType entity) {
|
||||
final int assignNumber = entity.getSmTypeAssign() == SmTypeAssign.SINGLE ? 1 : Integer.MAX_VALUE;
|
||||
|
||||
return smTypeManagement
|
||||
.create(getEntityFactory().softwareModuleType().create().key(entity.getKey()).name(entity.getName())
|
||||
.description(entity.getDescription()).colour(entity.getColour()).maxAssignments(assignNumber));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends ProxyIdentifiableEntity> getEntityClass() {
|
||||
return ProxyType.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends ProxyIdentifiableEntity> getParentEntityClass() {
|
||||
return ProxySoftwareModule.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEntityValid(final ProxyType entity) {
|
||||
return validator.isSmTypeValid(entity, () -> smTypeManagement.getByKey(entity.getKey()).isPresent(),
|
||||
() -> smTypeManagement.getByName(entity.getName()).isPresent());
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
|
||||
import com.vaadin.ui.Window;
|
||||
|
||||
/**
|
||||
* Builder for software module type window
|
||||
*/
|
||||
public class SmTypeWindowBuilder extends AbstractEntityWindowBuilder<ProxyType> {
|
||||
|
||||
private final SoftwareModuleTypeManagement smTypeManagement;
|
||||
|
||||
/**
|
||||
* Constructor for SmTypeWindowBuilder
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param smTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
*/
|
||||
public SmTypeWindowBuilder(final CommonUiDependencies uiDependencies, final SoftwareModuleTypeManagement smTypeManagement) {
|
||||
super(uiDependencies);
|
||||
this.smTypeManagement = smTypeManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getWindowId() {
|
||||
return UIComponentIdProvider.TAG_POPUP_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add window for software module type
|
||||
*
|
||||
* @return Window of Software module type
|
||||
*/
|
||||
@Override
|
||||
public Window getWindowForAdd() {
|
||||
return getWindowForNewEntity(
|
||||
new AddSmTypeWindowController(uiDependencies, smTypeManagement, new SmTypeWindowLayout(uiDependencies)));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Update window for software module type
|
||||
*
|
||||
* @param proxyType
|
||||
* ProxyType
|
||||
*
|
||||
* @return Window of Software module type
|
||||
*/
|
||||
@Override
|
||||
public Window getWindowForUpdate(final ProxyType proxyType) {
|
||||
return getWindowForEntity(proxyType,
|
||||
new UpdateSmTypeWindowController(uiDependencies, smTypeManagement, new SmTypeWindowLayout(uiDependencies)));
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.builder.FormComponentBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType.SmTypeAssign;
|
||||
import org.eclipse.hawkbit.ui.management.tag.TagWindowLayout;
|
||||
|
||||
import com.vaadin.ui.FormLayout;
|
||||
import com.vaadin.ui.RadioButtonGroup;
|
||||
import com.vaadin.ui.TextField;
|
||||
|
||||
/**
|
||||
* Software module type Window Layout view
|
||||
*/
|
||||
public class SmTypeWindowLayout extends TagWindowLayout<ProxyType> {
|
||||
private final SmTypeWindowLayoutComponentBuilder smTypeComponentBuilder;
|
||||
|
||||
private final TextField typeKey;
|
||||
private final RadioButtonGroup<SmTypeAssign> smTypeAssignOptionGroup;
|
||||
|
||||
/**
|
||||
* Constructor for SmTypeWindowLayout
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
*/
|
||||
public SmTypeWindowLayout(final CommonUiDependencies uiDependencies) {
|
||||
super(uiDependencies);
|
||||
|
||||
this.smTypeComponentBuilder = new SmTypeWindowLayoutComponentBuilder(i18n);
|
||||
|
||||
this.typeKey = FormComponentBuilder.createTypeKeyField(binder, i18n);
|
||||
this.smTypeAssignOptionGroup = smTypeComponentBuilder.createSmTypeAssignOptionGroup(binder);
|
||||
|
||||
this.colorPickerComponent.getColorPickerBtn().setCaption(i18n.getMessage("label.choose.type.color"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FormLayout buildFormLayout() {
|
||||
final FormLayout formLayout = super.buildFormLayout();
|
||||
|
||||
formLayout.addComponent(typeKey, formLayout.getComponentCount() - 1);
|
||||
formLayout.addComponent(smTypeAssignOptionGroup, formLayout.getComponentCount() - 1);
|
||||
|
||||
return formLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the software module type key text field
|
||||
*/
|
||||
public void disableTypeKey() {
|
||||
typeKey.setEnabled(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the software module type assign option
|
||||
*/
|
||||
public void disableTypeAssignOptionGroup() {
|
||||
smTypeAssignOptionGroup.setEnabled(false);
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType.SmTypeAssign;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
import com.vaadin.data.Binder;
|
||||
import com.vaadin.ui.RadioButtonGroup;
|
||||
|
||||
/**
|
||||
* Builder for software module type window layout component
|
||||
*/
|
||||
public class SmTypeWindowLayoutComponentBuilder {
|
||||
|
||||
public static final String TEXTFIELD_KEY = "textfield.key";
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
|
||||
/**
|
||||
* Constructor for SmTypeWindowLayoutComponentBuilder
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
*/
|
||||
public SmTypeWindowLayoutComponentBuilder(final VaadinMessageSource i18n) {
|
||||
this.i18n = i18n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create software module type assignment group
|
||||
*
|
||||
* @param binder
|
||||
* Vaadin binder of ProxyType
|
||||
*
|
||||
* @return RadioButtonGroup of software module type assignment
|
||||
*/
|
||||
public RadioButtonGroup<SmTypeAssign> createSmTypeAssignOptionGroup(final Binder<ProxyType> binder) {
|
||||
final RadioButtonGroup<SmTypeAssign> smTypeAssignOptionGroup = new RadioButtonGroup<>();
|
||||
smTypeAssignOptionGroup.setId(UIComponentIdProvider.ASSIGN_OPTION_GROUP_SOFTWARE_MODULE_TYPE_ID);
|
||||
|
||||
smTypeAssignOptionGroup.setItemCaptionGenerator(item -> {
|
||||
switch (item) {
|
||||
case SINGLE:
|
||||
return i18n.getMessage("label.singleAssign.type");
|
||||
case MULTI:
|
||||
return i18n.getMessage("label.multiAssign.type");
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
});
|
||||
smTypeAssignOptionGroup.setItemDescriptionGenerator(item -> {
|
||||
switch (item) {
|
||||
case SINGLE:
|
||||
return i18n.getMessage("label.singleAssign.type.desc");
|
||||
case MULTI:
|
||||
return i18n.getMessage("label.multiAssign.type.desc");
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
binder.forField(smTypeAssignOptionGroup).bind(ProxyType::getSmTypeAssign, ProxyType::setSmTypeAssign);
|
||||
smTypeAssignOptionGroup.setItems(SmTypeAssign.values());
|
||||
|
||||
return smTypeAssignOptionGroup;
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractUpdateNamedEntityWindowController;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.EntityWindowLayout;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType.SmTypeAssign;
|
||||
import org.eclipse.hawkbit.ui.common.type.ProxyTypeValidator;
|
||||
|
||||
/**
|
||||
* Controller for update software module type window
|
||||
*/
|
||||
public class UpdateSmTypeWindowController
|
||||
extends AbstractUpdateNamedEntityWindowController<ProxyType, ProxyType, SoftwareModuleType> {
|
||||
|
||||
private final SoftwareModuleTypeManagement smTypeManagement;
|
||||
private final SmTypeWindowLayout layout;
|
||||
private final ProxyTypeValidator validator;
|
||||
|
||||
private String nameBeforeEdit;
|
||||
private String keyBeforeEdit;
|
||||
|
||||
/**
|
||||
* Constructor for UpdateSmTypeWindowController
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param smTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
* @param layout
|
||||
* SmTypeWindowLayout
|
||||
*/
|
||||
public UpdateSmTypeWindowController(final CommonUiDependencies uiDependencies,
|
||||
final SoftwareModuleTypeManagement smTypeManagement, final SmTypeWindowLayout layout) {
|
||||
super(uiDependencies);
|
||||
|
||||
this.smTypeManagement = smTypeManagement;
|
||||
this.layout = layout;
|
||||
this.validator = new ProxyTypeValidator(uiDependencies);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProxyType buildEntityFromProxy(final ProxyType proxyEntity) {
|
||||
final ProxyType smType = new ProxyType();
|
||||
|
||||
smType.setId(proxyEntity.getId());
|
||||
smType.setName(proxyEntity.getName());
|
||||
smType.setDescription(proxyEntity.getDescription());
|
||||
smType.setColour(proxyEntity.getColour());
|
||||
smType.setKey(proxyEntity.getKey());
|
||||
smType.setSmTypeAssign(getSmTypeAssignById(proxyEntity.getId()));
|
||||
|
||||
nameBeforeEdit = proxyEntity.getName();
|
||||
keyBeforeEdit = proxyEntity.getKey();
|
||||
|
||||
return smType;
|
||||
}
|
||||
|
||||
private SmTypeAssign getSmTypeAssignById(final Long id) {
|
||||
return smTypeManagement.get(id)
|
||||
.map(smType -> smType.getMaxAssignments() == 1 ? SmTypeAssign.SINGLE : SmTypeAssign.MULTI)
|
||||
.orElse(SmTypeAssign.SINGLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityWindowLayout<ProxyType> getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void adaptLayout(final ProxyType proxyEntity) {
|
||||
layout.disableTagName();
|
||||
layout.disableTypeKey();
|
||||
layout.disableTypeAssignOptionGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SoftwareModuleType persistEntityInRepository(final ProxyType entity) {
|
||||
final SoftwareModuleTypeUpdate smTypeUpdate = getEntityFactory().softwareModuleType().update(entity.getId())
|
||||
.description(entity.getDescription()).colour(entity.getColour());
|
||||
return smTypeManagement.update(smTypeUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends ProxyIdentifiableEntity> getEntityClass() {
|
||||
return ProxyType.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends ProxyIdentifiableEntity> getParentEntityClass() {
|
||||
return ProxySoftwareModule.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEntityValid(final ProxyType entity) {
|
||||
final String name = entity.getName();
|
||||
final String key = entity.getKey();
|
||||
return validator.isSmTypeValid(entity,
|
||||
() -> hasKeyChanged(key) && smTypeManagement.getByKey(key).isPresent(),
|
||||
() -> hasNameChanged(name) && smTypeManagement.getByName(name).isPresent());
|
||||
}
|
||||
|
||||
private boolean hasNameChanged(final String trimmedName) {
|
||||
return !nameBeforeEdit.equals(trimmedName);
|
||||
}
|
||||
|
||||
private boolean hasKeyChanged(final String trimmedKey) {
|
||||
return !keyBeforeEdit.equals(trimmedKey);
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype.filter;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.ui.artifacts.smtype.SmTypeWindowBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.mappers.TypeToProxyTypeMapper;
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.SoftwareModuleTypeDataProvider;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventView;
|
||||
import org.eclipse.hawkbit.ui.common.filterlayout.AbstractTypeFilterButtons;
|
||||
import org.eclipse.hawkbit.ui.common.state.TypeFilterLayoutUiState;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
|
||||
import com.vaadin.ui.Window;
|
||||
|
||||
/**
|
||||
* Software module type filter buttons.
|
||||
*
|
||||
*/
|
||||
public class SMTypeFilterButtons extends AbstractTypeFilterButtons {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final transient SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
private final transient SmTypeWindowBuilder smTypeWindowBuilder;
|
||||
|
||||
private final EventView view;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param softwareModuleTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
* @param smTypeWindowBuilder
|
||||
* SmTypeWindowBuilder
|
||||
* @param typeFilterLayoutUiState
|
||||
* TypeFilterLayoutUiState
|
||||
* @param view
|
||||
* EventView
|
||||
*/
|
||||
public SMTypeFilterButtons(final CommonUiDependencies uiDependencies,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement,
|
||||
final SmTypeWindowBuilder smTypeWindowBuilder, final TypeFilterLayoutUiState typeFilterLayoutUiState,
|
||||
final EventView view) {
|
||||
super(uiDependencies, typeFilterLayoutUiState);
|
||||
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
this.smTypeWindowBuilder = smTypeWindowBuilder;
|
||||
this.view = view;
|
||||
|
||||
init();
|
||||
setDataProvider(
|
||||
new SoftwareModuleTypeDataProvider<>(softwareModuleTypeManagement, new TypeToProxyTypeMapper<>()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets id of the software module type grid.
|
||||
*
|
||||
* @return id of the grid
|
||||
*/
|
||||
@Override
|
||||
public String getGridId() {
|
||||
return UIComponentIdProvider.SW_MODULE_TYPE_TABLE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMessageKeyEntityTypeSing() {
|
||||
return "caption.entity.software.module.type";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMessageKeyEntityTypePlur() {
|
||||
return "caption.entity.software.module.types";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFilterButtonIdPrefix() {
|
||||
return UIComponentIdProvider.SOFTWARE_MODULE_TYPE_ID_PREFIXS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isDefaultType(final ProxyType type) {
|
||||
// We do not have default type for software module
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends ProxyIdentifiableEntity> getFilterMasterEntityType() {
|
||||
return ProxySoftwareModule.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EventView getView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deleteType(final ProxyType typeToDelete) {
|
||||
softwareModuleTypeManagement.delete(typeToDelete.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Window getUpdateWindow(final ProxyType clickedFilter) {
|
||||
return smTypeWindowBuilder.getWindowForUpdate(clickedFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean typeExists(final Long typeId) {
|
||||
return softwareModuleTypeManagement.exists(typeId);
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype.filter;
|
||||
|
||||
import org.eclipse.hawkbit.ui.artifacts.smtype.SmTypeWindowBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventLayout;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventView;
|
||||
import org.eclipse.hawkbit.ui.common.grid.header.AbstractFilterHeader;
|
||||
import org.eclipse.hawkbit.ui.common.state.TypeFilterLayoutUiState;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
|
||||
|
||||
import com.vaadin.ui.Window;
|
||||
|
||||
/**
|
||||
* Software module type filter buttons header.
|
||||
*/
|
||||
public class SMTypeFilterHeader extends AbstractFilterHeader {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final TypeFilterLayoutUiState smTypeFilterLayoutUiState;
|
||||
|
||||
private final transient SmTypeWindowBuilder smTypeWindowBuilder;
|
||||
|
||||
private final EventView view;
|
||||
|
||||
/**
|
||||
* Constructor for SMTypeFilterHeader
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param smTypeWindowBuilder
|
||||
* SmTypeWindowBuilder
|
||||
* @param smTypeFilterLayoutUiState
|
||||
* TypeFilterLayoutUiState
|
||||
* @param view
|
||||
* EventView
|
||||
*/
|
||||
public SMTypeFilterHeader(final CommonUiDependencies uiDependencies, final SmTypeWindowBuilder smTypeWindowBuilder,
|
||||
final TypeFilterLayoutUiState smTypeFilterLayoutUiState, final EventView view) {
|
||||
super(uiDependencies.getI18n(), uiDependencies.getPermChecker(), uiDependencies.getEventBus());
|
||||
|
||||
this.smTypeFilterLayoutUiState = smTypeFilterLayoutUiState;
|
||||
this.smTypeWindowBuilder = smTypeWindowBuilder;
|
||||
this.view = view;
|
||||
|
||||
buildHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getHeaderCaptionMsgKey() {
|
||||
return UIMessageIdProvider.CAPTION_FILTER_BY_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCrudMenuBarId() {
|
||||
return UIComponentIdProvider.SOFT_MODULE_TYPE_MENU_BAR_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Window getWindowForAdd() {
|
||||
return smTypeWindowBuilder.getWindowForAdd();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getAddEntityWindowCaptionMsgKey() {
|
||||
return "caption.type";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCloseIconId() {
|
||||
return UIComponentIdProvider.HIDE_SM_TYPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateHiddenUiState() {
|
||||
smTypeFilterLayoutUiState.setHidden(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EventLayout getLayout() {
|
||||
return EventLayout.SM_TYPE_FILTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EventView getView() {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype.filter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.ui.artifacts.smtype.SmTypeWindowBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventLayout;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventLayoutViewAware;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventView;
|
||||
import org.eclipse.hawkbit.ui.common.filterlayout.AbstractFilterLayout;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.EntityModifiedListener;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.EntityModifiedListener.EntityModifiedAwareSupport;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.GridActionsVisibilityListener;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedGenericSupport;
|
||||
import org.eclipse.hawkbit.ui.common.layout.listener.support.EntityModifiedGridRefreshAwareSupport;
|
||||
import org.eclipse.hawkbit.ui.common.state.TypeFilterLayoutUiState;
|
||||
|
||||
import com.vaadin.ui.ComponentContainer;
|
||||
|
||||
/**
|
||||
* Software module type filter buttons layout.
|
||||
*/
|
||||
public class SMTypeFilterLayout extends AbstractFilterLayout {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final SMTypeFilterHeader smTypeFilterHeader;
|
||||
private final SMTypeFilterButtons smTypeFilterButtons;
|
||||
|
||||
private final transient GridActionsVisibilityListener gridActionsVisibilityListener;
|
||||
private final transient EntityModifiedListener<ProxyType> entityModifiedListener;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
* @param softwareModuleTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
* @param smTypeFilterLayoutUiState
|
||||
* SMTypeFilterLayoutUiState
|
||||
* @param eventView
|
||||
* {@link EventView}
|
||||
*/
|
||||
public SMTypeFilterLayout(final CommonUiDependencies uiDependencies,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement,
|
||||
final TypeFilterLayoutUiState smTypeFilterLayoutUiState, final EventView eventView) {
|
||||
final SmTypeWindowBuilder smTypeWindowBuilder = new SmTypeWindowBuilder(uiDependencies,
|
||||
softwareModuleTypeManagement);
|
||||
|
||||
this.smTypeFilterHeader = new SMTypeFilterHeader(uiDependencies, smTypeWindowBuilder, smTypeFilterLayoutUiState,
|
||||
eventView);
|
||||
this.smTypeFilterButtons = new SMTypeFilterButtons(uiDependencies, softwareModuleTypeManagement,
|
||||
smTypeWindowBuilder, smTypeFilterLayoutUiState, eventView);
|
||||
|
||||
final EventLayoutViewAware layoutViewAware = new EventLayoutViewAware(EventLayout.SM_TYPE_FILTER, eventView);
|
||||
this.gridActionsVisibilityListener = new GridActionsVisibilityListener(uiDependencies.getEventBus(),
|
||||
layoutViewAware, smTypeFilterButtons::hideActionColumns, smTypeFilterButtons::showEditColumn,
|
||||
smTypeFilterButtons::showDeleteColumn);
|
||||
this.entityModifiedListener = new EntityModifiedListener.Builder<>(uiDependencies.getEventBus(),
|
||||
ProxyType.class).parentEntityType(ProxySoftwareModule.class).viewAware(layoutViewAware)
|
||||
.entityModifiedAwareSupports(getEntityModifiedAwareSupports()).build();
|
||||
|
||||
buildLayout();
|
||||
}
|
||||
|
||||
private List<EntityModifiedAwareSupport> getEntityModifiedAwareSupports() {
|
||||
return Arrays.asList(EntityModifiedGridRefreshAwareSupport.of(this::refreshFilterButtons),
|
||||
EntityModifiedGenericSupport.of(null, null, smTypeFilterButtons::resetFilterOnTypesDeleted));
|
||||
}
|
||||
|
||||
protected void refreshFilterButtons() {
|
||||
smTypeFilterButtons.refreshAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SMTypeFilterHeader getFilterHeader() {
|
||||
return smTypeFilterHeader;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ComponentContainer getFilterContent() {
|
||||
return wrapFilterContent(smTypeFilterButtons);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreState() {
|
||||
smTypeFilterButtons.restoreState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewEnter() {
|
||||
smTypeFilterButtons.reevaluateFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subscribeListeners() {
|
||||
gridActionsVisibilityListener.subscribe();
|
||||
entityModifiedListener.subscribe();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsubscribeListeners() {
|
||||
gridActionsVisibilityListener.unsubscribe();
|
||||
entityModifiedListener.unsubscribe();
|
||||
}
|
||||
}
|
||||
@@ -1,352 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.upload;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.RegexCharacterCollection;
|
||||
import org.eclipse.hawkbit.repository.RegexCharacterCollection.RegexChar;
|
||||
import org.eclipse.hawkbit.repository.exception.ArtifactEncryptionFailedException;
|
||||
import org.eclipse.hawkbit.repository.exception.ArtifactEncryptionUnsupportedException;
|
||||
import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.FileSizeQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException;
|
||||
import org.eclipse.hawkbit.repository.exception.StorageQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.ArtifactUpload;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.artifacts.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress.FileUploadStatus;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
|
||||
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload.EntityModifiedEventType;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventTopics;
|
||||
import org.eclipse.hawkbit.ui.utils.SpringContextHolder;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.vaadin.spring.events.EventBus;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.ui.UI;
|
||||
|
||||
/**
|
||||
* Abstract base class for transferring files from the browser to the
|
||||
* repository.
|
||||
*/
|
||||
public abstract class AbstractFileTransferHandler implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractFileTransferHandler.class);
|
||||
private static final String MESSAGE_UPLOAD_FAILED = "message.upload.failed";
|
||||
|
||||
private volatile boolean uploadInterrupted;
|
||||
|
||||
private volatile String failureReason;
|
||||
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
|
||||
private final transient UIEventBus eventBus;
|
||||
|
||||
private final transient ArtifactManagement artifactManagement;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
|
||||
private final transient Lock uploadLock;
|
||||
|
||||
protected static final RegexCharacterCollection ILLEGAL_FILENAME_CHARACTERS = new RegexCharacterCollection(
|
||||
RegexChar.GREATER_THAN, RegexChar.LESS_THAN, RegexChar.SLASHES);
|
||||
|
||||
AbstractFileTransferHandler(final ArtifactManagement artifactManagement, final VaadinMessageSource i18n,
|
||||
final Lock uploadLock) {
|
||||
this.artifactManagement = artifactManagement;
|
||||
this.i18n = i18n;
|
||||
this.eventBus = SpringContextHolder.getInstance().getBean(EventBus.UIEventBus.class);
|
||||
this.artifactUploadState = SpringContextHolder.getInstance().getBean(ArtifactUploadState.class);
|
||||
this.uploadLock = uploadLock;
|
||||
}
|
||||
|
||||
protected boolean isUploadInterrupted() {
|
||||
return uploadInterrupted;
|
||||
}
|
||||
|
||||
protected void resetState() {
|
||||
uploadInterrupted = false;
|
||||
failureReason = null;
|
||||
}
|
||||
|
||||
protected ArtifactUploadState getUploadState() {
|
||||
return artifactUploadState;
|
||||
}
|
||||
|
||||
protected VaadinMessageSource getI18n() {
|
||||
return i18n;
|
||||
}
|
||||
|
||||
protected void startTransferToRepositoryThread(final InputStream inputStream, final FileUploadId fileUploadId,
|
||||
final String mimeType) {
|
||||
SpringContextHolder.getInstance().getBean("uiExecutor", Executor.class)
|
||||
.execute(new TransferArtifactToRepositoryRunnable(inputStream, fileUploadId, mimeType, UI.getCurrent(),
|
||||
uploadLock));
|
||||
}
|
||||
|
||||
private void interruptUploadAndSetReason(final String failureReason) {
|
||||
uploadInterrupted = true;
|
||||
this.failureReason = failureReason;
|
||||
}
|
||||
|
||||
protected void interruptUploadDueToUploadFailed() {
|
||||
interruptUploadAndSetReason(i18n.getMessage(MESSAGE_UPLOAD_FAILED));
|
||||
}
|
||||
|
||||
protected void interruptUploadDueToAssignmentQuotaExceeded() {
|
||||
interruptUploadAndSetReason(i18n.getMessage("message.upload.assignmentQuota"));
|
||||
}
|
||||
|
||||
protected void interruptUploadDueToFileSizeQuotaExceeded(final String exceededValue) {
|
||||
interruptUploadAndSetReason(i18n.getMessage("message.upload.fileSizeQuota", exceededValue));
|
||||
}
|
||||
|
||||
protected void interruptUploadDueToStorageQuotaExceeded(final String exceededValue) {
|
||||
interruptUploadAndSetReason(i18n.getMessage("message.upload.storageQuota", exceededValue));
|
||||
}
|
||||
|
||||
protected void interruptUploadDueToDuplicateFile() {
|
||||
interruptUploadAndSetReason(i18n.getMessage("message.no.duplicateFiles"));
|
||||
}
|
||||
|
||||
protected void interruptUploadDueToIllegalFilename() {
|
||||
interruptUploadAndSetReason(i18n.getMessage("message.uploadedfile.illegalFilename"));
|
||||
}
|
||||
|
||||
protected void interruptUploadDueToEncryptionError() {
|
||||
interruptUploadAndSetReason(i18n.getMessage("message.encryption.failed"));
|
||||
}
|
||||
|
||||
protected boolean isFileAlreadyContainedInSoftwareModule(final FileUploadId newFileUploadId,
|
||||
final SoftwareModule softwareModule) {
|
||||
for (final Artifact artifact : softwareModule.getArtifacts()) {
|
||||
final FileUploadId existingId = new FileUploadId(artifact.getFilename(), softwareModule);
|
||||
if (existingId.equals(newFileUploadId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void publishUploadStarted(final FileUploadId fileUploadId) {
|
||||
LOG.info("Upload started for file {}", fileUploadId);
|
||||
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
|
||||
FileUploadStatus.UPLOAD_STARTED);
|
||||
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
|
||||
eventBus.publish(EventTopics.FILE_UPLOAD_CHANGED, this, fileUploadProgress);
|
||||
}
|
||||
|
||||
protected void publishUploadProgressEvent(final FileUploadId fileUploadId, final long bytesReceived,
|
||||
final long fileSize) {
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Upload in progress for file {} - {}%", fileUploadId,
|
||||
String.format("%.0f", (double) bytesReceived / (double) fileSize * 100));
|
||||
}
|
||||
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
|
||||
FileUploadStatus.UPLOAD_IN_PROGRESS, bytesReceived, fileSize);
|
||||
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
|
||||
eventBus.publish(EventTopics.FILE_UPLOAD_CHANGED, this, fileUploadProgress);
|
||||
}
|
||||
|
||||
protected void publishUploadFinishedEvent(final FileUploadId fileUploadId) {
|
||||
LOG.debug("Upload finished for file {}", fileUploadId);
|
||||
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
|
||||
FileUploadStatus.UPLOAD_FINISHED);
|
||||
eventBus.publish(EventTopics.FILE_UPLOAD_CHANGED, this, fileUploadProgress);
|
||||
}
|
||||
|
||||
protected void publishUploadSucceeded(final FileUploadId fileUploadId, final long fileSize) {
|
||||
LOG.info("Upload succeeded for file {}", fileUploadId);
|
||||
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
|
||||
FileUploadStatus.UPLOAD_SUCCESSFUL, fileSize, fileSize);
|
||||
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
|
||||
eventBus.publish(EventTopics.FILE_UPLOAD_CHANGED, this, fileUploadProgress);
|
||||
}
|
||||
|
||||
protected void publishUploadFailedEvent(final FileUploadId fileUploadId) {
|
||||
LOG.info("Upload failed for file {} due to reason: {}", fileUploadId, failureReason);
|
||||
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
|
||||
FileUploadStatus.UPLOAD_FAILED,
|
||||
StringUtils.hasText(failureReason) ? failureReason : i18n.getMessage(MESSAGE_UPLOAD_FAILED));
|
||||
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
|
||||
eventBus.publish(EventTopics.FILE_UPLOAD_CHANGED, this, fileUploadProgress);
|
||||
}
|
||||
|
||||
protected void publishArtifactsChanged(final FileUploadId fileUploadId) {
|
||||
eventBus.publish(EventTopics.ENTITY_MODIFIED, this, new EntityModifiedEventPayload(
|
||||
EntityModifiedEventType.ENTITY_UPDATED, ProxySoftwareModule.class, fileUploadId.getSoftwareModuleId()));
|
||||
}
|
||||
|
||||
protected void publishUploadFailedAndFinishedEvent(final FileUploadId fileUploadId) {
|
||||
publishUploadFailedEvent(fileUploadId);
|
||||
publishUploadFinishedEvent(fileUploadId);
|
||||
}
|
||||
|
||||
protected void assertStateConsistency(final FileUploadId fileUploadId, final String filenameExtractedFromEvent) {
|
||||
if (!filenameExtractedFromEvent.equals(fileUploadId.getFilename())) {
|
||||
throw new IllegalStateException("Event filename " + filenameExtractedFromEvent + " but stored filename "
|
||||
+ fileUploadId.getFilename());
|
||||
}
|
||||
}
|
||||
|
||||
protected static void tryToCloseIOStream(final OutputStream outputStream) {
|
||||
if (outputStream != null) {
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (final IOException e1) {
|
||||
LOG.warn("Closing output stream caused by", e1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static void tryToCloseIOStream(final InputStream inputStream) {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (final IOException e1) {
|
||||
LOG.warn("Closing input stream caused by", e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class TransferArtifactToRepositoryRunnable implements Runnable {
|
||||
private final InputStream inputStream;
|
||||
private final FileUploadId fileUploadId;
|
||||
private final String mimeType;
|
||||
private final UI vaadinUi;
|
||||
private final Lock uploadLock;
|
||||
|
||||
/**
|
||||
* Constructor for TransferArtifactToRepositoryRunnable
|
||||
*
|
||||
* @param inputStream
|
||||
* InputStream
|
||||
* @param fileUploadId
|
||||
* FileUploadId
|
||||
* @param mimeType
|
||||
* String
|
||||
* @param vaadinUi
|
||||
* UI
|
||||
* @param uploadLock
|
||||
* Lock
|
||||
*/
|
||||
public TransferArtifactToRepositoryRunnable(final InputStream inputStream, final FileUploadId fileUploadId,
|
||||
final String mimeType, final UI vaadinUi, final Lock uploadLock) {
|
||||
this.inputStream = inputStream;
|
||||
this.fileUploadId = fileUploadId;
|
||||
this.mimeType = mimeType;
|
||||
this.vaadinUi = vaadinUi;
|
||||
this.uploadLock = uploadLock;
|
||||
}
|
||||
|
||||
/**
|
||||
* a lock object is used here that is propagated down from
|
||||
* {@link org.eclipse.hawkbit.ui.artifacts.UploadArtifactView}. It
|
||||
* ensures that from within the same UI instance all uploads are
|
||||
* executed sequentially to avoid issues that occur when multiple files
|
||||
* are processed at the same time (e.g. regarding quota checks)
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
UI.setCurrent(vaadinUi);
|
||||
uploadLock.lock();
|
||||
streamToRepository();
|
||||
} catch (final FileSizeQuotaExceededException e) {
|
||||
interruptUploadDueToFileSizeQuotaExceeded(e.getExceededQuotaValueString());
|
||||
publishUploadFailedAndFinishedEvent(fileUploadId);
|
||||
LOG.debug("Upload failed due to file size quota exceeded:", e);
|
||||
} catch (final StorageQuotaExceededException e) {
|
||||
interruptUploadDueToStorageQuotaExceeded(e.getExceededQuotaValueString());
|
||||
publishUploadFailedAndFinishedEvent(fileUploadId);
|
||||
LOG.debug("Upload failed due to storage quota exceeded:", e);
|
||||
} catch (final AssignmentQuotaExceededException e) {
|
||||
interruptUploadDueToAssignmentQuotaExceeded();
|
||||
publishUploadFailedAndFinishedEvent(fileUploadId);
|
||||
LOG.debug("Upload failed due to assignment quota exceeded:", e);
|
||||
} catch (final ArtifactEncryptionUnsupportedException | ArtifactEncryptionFailedException e) {
|
||||
interruptUploadDueToEncryptionError();
|
||||
publishUploadFailedAndFinishedEvent(fileUploadId);
|
||||
LOG.warn("Upload failed due to encryption error", e);
|
||||
} catch (final RuntimeException e) {
|
||||
interruptUploadDueToUploadFailed();
|
||||
publishUploadFailedAndFinishedEvent(fileUploadId);
|
||||
LOG.warn("Failed to transfer file to repository", e);
|
||||
} finally {
|
||||
tryToCloseIOStream(inputStream);
|
||||
uploadLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void streamToRepository() {
|
||||
if (fileUploadId == null) {
|
||||
throw new ArtifactUploadFailedException();
|
||||
}
|
||||
|
||||
final String filename = fileUploadId.getFilename();
|
||||
final Artifact artifact = uploadArtifact(filename);
|
||||
|
||||
if (isUploadInterrupted()) {
|
||||
LOG.warn("Upload of {} was interrupted", filename);
|
||||
handleUploadFailure(artifact);
|
||||
publishUploadFinishedEvent(fileUploadId);
|
||||
return;
|
||||
}
|
||||
|
||||
publishUploadSucceeded(fileUploadId, artifact.getSize());
|
||||
publishUploadFinishedEvent(fileUploadId);
|
||||
publishArtifactsChanged(fileUploadId);
|
||||
}
|
||||
|
||||
private Artifact uploadArtifact(final String filename) {
|
||||
LOG.debug("Transfering file {} directly to repository", filename);
|
||||
try {
|
||||
return artifactManagement.create(new ArtifactUpload(inputStream, fileUploadId.getSoftwareModuleId(),
|
||||
filename, null, null, null, true, mimeType, -1));
|
||||
} catch (final InvalidSHA1HashException | InvalidMD5HashException e) {
|
||||
throw new ArtifactUploadFailedException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUploadFailure(final Artifact artifact) {
|
||||
Exception exception;
|
||||
int tries = 0;
|
||||
do {
|
||||
try {
|
||||
artifactManagement.delete(artifact.getId());
|
||||
return;
|
||||
} catch (final RuntimeException e) {
|
||||
exception = e;
|
||||
tries++;
|
||||
}
|
||||
} while (tries < 5);
|
||||
LOG.error("Failed to delete artifact from repository after upload was interrupted", exception);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.upload;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.RegexCharacterCollection;
|
||||
import org.eclipse.hawkbit.repository.SizeConversionHelper;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.vaadin.server.StreamVariable;
|
||||
|
||||
/**
|
||||
* {@link StreamVariable} implementation to read and upload a file. One instance
|
||||
* per file stream is used.
|
||||
*
|
||||
* The handler manages the output to the user and at the same time ensures that
|
||||
* the upload does not exceed the configured max file size.
|
||||
*
|
||||
*/
|
||||
public class FileTransferHandlerStreamVariable extends AbstractFileTransferHandler implements StreamVariable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FileTransferHandlerStreamVariable.class);
|
||||
|
||||
private final long maxSize;
|
||||
private final long fileSize;
|
||||
private final String mimeType;
|
||||
private final FileUploadId fileUploadId;
|
||||
|
||||
private final SoftwareModule selectedSoftwareModule;
|
||||
|
||||
FileTransferHandlerStreamVariable(final String fileName, final long fileSize, final long maxSize,
|
||||
final String mimeType, final SoftwareModule selectedSw, final ArtifactManagement artifactManagement,
|
||||
final VaadinMessageSource i18n, final Lock uploadLock) {
|
||||
super(artifactManagement, i18n, uploadLock);
|
||||
this.fileSize = fileSize;
|
||||
this.maxSize = maxSize;
|
||||
this.mimeType = mimeType;
|
||||
this.selectedSoftwareModule = selectedSw;
|
||||
this.fileUploadId = new FileUploadId(fileName, selectedSw);
|
||||
|
||||
publishUploadStarted(fileUploadId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for duplication and invalid file name during file upload process
|
||||
*
|
||||
* @param event
|
||||
* StreamingStartEvent
|
||||
*/
|
||||
@Override
|
||||
public void streamingStarted(final StreamingStartEvent event) {
|
||||
assertStateConsistency(fileUploadId, event.getFileName());
|
||||
|
||||
if (RegexCharacterCollection.stringContainsCharacter(event.getFileName(), ILLEGAL_FILENAME_CHARACTERS)) {
|
||||
LOG.debug("Filename contains illegal characters {} for upload {}", fileUploadId.getFilename(),
|
||||
fileUploadId);
|
||||
interruptUploadDueToIllegalFilename();
|
||||
} else if (isFileAlreadyContainedInSoftwareModule(fileUploadId, selectedSoftwareModule)) {
|
||||
LOG.debug("File {} already contained in Software Module {}", fileUploadId.getFilename(),
|
||||
selectedSoftwareModule);
|
||||
interruptUploadDueToDuplicateFile();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the output stream of uploaded file
|
||||
*
|
||||
* @return OutputStream
|
||||
*/
|
||||
@Override
|
||||
public final OutputStream getOutputStream() {
|
||||
if (isUploadInterrupted()) {
|
||||
return ByteStreams.nullOutputStream();
|
||||
}
|
||||
|
||||
// we return the output stream - we cannot close it here
|
||||
@SuppressWarnings("squid:S2095")
|
||||
final PipedOutputStream outputStream = new PipedOutputStream();
|
||||
final PipedInputStream inputStream;
|
||||
try {
|
||||
inputStream = new PipedInputStream(outputStream);
|
||||
publishUploadProgressEvent(fileUploadId, 0, fileSize);
|
||||
startTransferToRepositoryThread(inputStream, fileUploadId, mimeType);
|
||||
} catch (final IOException e) {
|
||||
LOG.warn("Creating piped Stream failed {}.", e.getMessage());
|
||||
tryToCloseIOStream(outputStream);
|
||||
// input stream is not created in case of and IOException here
|
||||
interruptUploadDueToUploadFailed();
|
||||
publishUploadFailedAndFinishedEvent(fileUploadId);
|
||||
return ByteStreams.nullOutputStream();
|
||||
}
|
||||
return outputStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* listen progress.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
@Override
|
||||
public boolean listenProgress() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports progress in {@link StreamVariable} variant. Interrupts
|
||||
*
|
||||
* @see com.vaadin.server.StreamVariable#onProgress(com.vaadin.server.StreamVariable.StreamingProgressEvent)
|
||||
*/
|
||||
@Override
|
||||
public void onProgress(final StreamingProgressEvent event) {
|
||||
assertStateConsistency(fileUploadId, event.getFileName());
|
||||
|
||||
if (isUploadInterrupted()) {
|
||||
publishUploadFailedAndFinishedEvent(fileUploadId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getBytesReceived() > maxSize || event.getContentLength() > maxSize) {
|
||||
interruptUploadDueToFileSizeQuotaExceeded(SizeConversionHelper.byteValueToReadableString(maxSize));
|
||||
return;
|
||||
}
|
||||
|
||||
publishUploadProgressEvent(fileUploadId, event.getBytesReceived(), event.getContentLength());
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload finished for {@link StreamVariable} variant. Called only in good
|
||||
* case.
|
||||
*
|
||||
* @see com.vaadin.server.StreamVariable#streamingFinished(com.vaadin.server.StreamVariable.StreamingEndEvent)
|
||||
*/
|
||||
@Override
|
||||
public void streamingFinished(final StreamingEndEvent event) {
|
||||
assertStateConsistency(fileUploadId, event.getFileName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload failed for{@link StreamVariable} variant.
|
||||
*
|
||||
* @param event
|
||||
* StreamingEndEvent
|
||||
*/
|
||||
@Override
|
||||
public void streamingFailed(final StreamingErrorEvent event) {
|
||||
assertStateConsistency(fileUploadId, event.getFileName());
|
||||
|
||||
if (!isUploadInterrupted()) {
|
||||
interruptUploadDueToUploadFailed();
|
||||
}
|
||||
LOG.debug("Streaming of file {} failed due to following exception: {}", fileUploadId, event.getException());
|
||||
publishUploadFailedAndFinishedEvent(fileUploadId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if upload process is interrupted
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
@Override
|
||||
public boolean isInterrupted() {
|
||||
return isUploadInterrupted();
|
||||
}
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.upload;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.RegexCharacterCollection;
|
||||
import org.eclipse.hawkbit.repository.SizeConversionHelper;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.vaadin.ui.Upload;
|
||||
import com.vaadin.ui.Upload.FailedEvent;
|
||||
import com.vaadin.ui.Upload.FailedListener;
|
||||
import com.vaadin.ui.Upload.FinishedEvent;
|
||||
import com.vaadin.ui.Upload.FinishedListener;
|
||||
import com.vaadin.ui.Upload.ProgressListener;
|
||||
import com.vaadin.ui.Upload.Receiver;
|
||||
import com.vaadin.ui.Upload.StartedEvent;
|
||||
import com.vaadin.ui.Upload.StartedListener;
|
||||
import com.vaadin.ui.Upload.SucceededEvent;
|
||||
import com.vaadin.ui.Upload.SucceededListener;
|
||||
|
||||
/**
|
||||
* Vaadin Upload implementation to read and upload a file. One instance is used
|
||||
* to handle all the uploads.
|
||||
*
|
||||
* The handler manages the output to the user and at the same time ensures that
|
||||
* the upload does not exceed the configured max file size.
|
||||
*
|
||||
*/
|
||||
public class FileTransferHandlerVaadinUpload extends AbstractFileTransferHandler
|
||||
implements Receiver, SucceededListener, FailedListener, FinishedListener, ProgressListener, StartedListener {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FileTransferHandlerVaadinUpload.class);
|
||||
|
||||
private final transient SoftwareModuleManagement softwareModuleManagement;
|
||||
private final long maxSize;
|
||||
|
||||
private FileUploadId fileUploadId;
|
||||
|
||||
FileTransferHandlerVaadinUpload(final long maxSize, final SoftwareModuleManagement softwareManagement,
|
||||
final ArtifactManagement artifactManagement, final VaadinMessageSource i18n, final Lock uploadLock) {
|
||||
super(artifactManagement, i18n, uploadLock);
|
||||
|
||||
this.maxSize = maxSize;
|
||||
this.softwareModuleManagement = softwareManagement;
|
||||
}
|
||||
|
||||
private synchronized FileUploadId setFileUploadId(final String fileName, final SoftwareModule softwareModule) {
|
||||
this.fileUploadId = new FileUploadId(fileName, softwareModule);
|
||||
return fileUploadId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload started for {@link Upload} variant.
|
||||
*
|
||||
* @see com.vaadin.ui.Upload.StartedListener#uploadStarted(com.vaadin.ui.Upload.StartedEvent)
|
||||
*/
|
||||
@Override
|
||||
public void uploadStarted(final StartedEvent event) {
|
||||
// reset internal state here because instance is reused for next upload!
|
||||
resetState();
|
||||
|
||||
final SoftwareModule softwareModule = getSelectedSoftwareModule();
|
||||
final FileUploadId fupId = setFileUploadId(event.getFilename(), softwareModule);
|
||||
|
||||
if (getUploadState().isFileInUploadState(this.fileUploadId)) {
|
||||
// actual interrupt will happen a bit late so setting the below
|
||||
// flag
|
||||
interruptUploadDueToDuplicateFile();
|
||||
event.getUpload().interruptUpload();
|
||||
} else {
|
||||
publishUploadStarted(fupId);
|
||||
|
||||
if (RegexCharacterCollection.stringContainsCharacter(event.getFilename(), ILLEGAL_FILENAME_CHARACTERS)) {
|
||||
LOG.debug("Filename contains illegal characters {} for upload {}", fupId.getFilename(), fupId);
|
||||
interruptUploadDueToIllegalFilename();
|
||||
event.getUpload().interruptUpload();
|
||||
} else if (isFileAlreadyContainedInSoftwareModule(fupId, softwareModule)) {
|
||||
LOG.debug("File {} already contained in Software Module {}", fupId.getFilename(),
|
||||
softwareModule);
|
||||
interruptUploadDueToDuplicateFile();
|
||||
event.getUpload().interruptUpload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SoftwareModule getSelectedSoftwareModule() {
|
||||
final Long lastSelectedSmId = getUploadState().getSmGridLayoutUiState().getSelectedEntityId();
|
||||
|
||||
return softwareModuleManagement.get(lastSelectedSmId)
|
||||
.orElseThrow(() -> new IllegalStateException("SoftwareModul with unknown ID selected"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create stream for {@link Upload} variant.
|
||||
*
|
||||
* @see com.vaadin.ui.Upload.Receiver#receiveUpload(java.lang.String,
|
||||
* java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public OutputStream receiveUpload(final String fileName, final String mimeType) {
|
||||
if (isUploadInterrupted()) {
|
||||
return ByteStreams.nullOutputStream();
|
||||
}
|
||||
|
||||
// we return the outputstream so we cannot close it here
|
||||
@SuppressWarnings("squid:S2095")
|
||||
final PipedOutputStream outputStream = new PipedOutputStream();
|
||||
try {
|
||||
PipedInputStream inputStream = new PipedInputStream(outputStream);
|
||||
publishUploadProgressEvent(fileUploadId, 0, 0);
|
||||
startTransferToRepositoryThread(inputStream, fileUploadId, mimeType);
|
||||
} catch (final IOException e) {
|
||||
LOG.warn("Creating piped Stream failed!", e);
|
||||
tryToCloseIOStream(outputStream);
|
||||
// input stream is not created in case of an IOException
|
||||
interruptUploadDueToUploadFailed();
|
||||
publishUploadFailedAndFinishedEvent(fileUploadId);
|
||||
return ByteStreams.nullOutputStream();
|
||||
}
|
||||
return outputStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports progress in {@link Upload} variant.
|
||||
*
|
||||
* @see com.vaadin.ui.Upload.ProgressListener#updateProgress(long, long)
|
||||
*/
|
||||
@Override
|
||||
public void updateProgress(final long readBytes, final long contentLength) {
|
||||
if (isUploadInterrupted()) {
|
||||
publishUploadFailedAndFinishedEvent(fileUploadId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (readBytes > maxSize || contentLength > maxSize) {
|
||||
interruptUploadDueToFileSizeQuotaExceeded(SizeConversionHelper.byteValueToReadableString(maxSize));
|
||||
return;
|
||||
}
|
||||
|
||||
publishUploadProgressEvent(fileUploadId, readBytes, contentLength);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Upload sucessfull for {@link Upload} variant.
|
||||
*
|
||||
* @see com.vaadin.ui.Upload.SucceededListener#uploadSucceeded(com.vaadin.ui.Upload.SucceededEvent)
|
||||
*/
|
||||
@Override
|
||||
public void uploadSucceeded(final SucceededEvent event) {
|
||||
if (isUploadInterrupted()) {
|
||||
// Upload interruption is delayed maybe another event is fired
|
||||
// before
|
||||
return;
|
||||
}
|
||||
assertStateConsistency(fileUploadId, event.getFilename());
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload finished for {@link Upload} variant. Both for good and error
|
||||
* variant.
|
||||
*
|
||||
* @see com.vaadin.ui.Upload.FinishedListener#uploadFinished(com.vaadin.ui.Upload.FinishedEvent)
|
||||
*/
|
||||
@Override
|
||||
public void uploadFinished(final FinishedEvent event) {
|
||||
// ignore this event
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload failed for {@link Upload} variant.
|
||||
*
|
||||
* @see com.vaadin.ui.Upload.FailedListener#uploadFailed(com.vaadin.ui.Upload.FailedEvent)
|
||||
*/
|
||||
@Override
|
||||
public void uploadFailed(final FailedEvent event) {
|
||||
assertStateConsistency(fileUploadId, event.getFilename());
|
||||
|
||||
if (!isUploadInterrupted()) {
|
||||
interruptUploadDueToUploadFailed();
|
||||
}
|
||||
LOG.debug("Upload of file {} failed due to following exception: {}", fileUploadId, event.getReason());
|
||||
publishUploadFailedAndFinishedEvent(fileUploadId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetState() {
|
||||
super.resetState();
|
||||
this.fileUploadId = null;
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.upload;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
|
||||
/**
|
||||
* The {@link FileUploadId} identifies a file that is uploaded for a
|
||||
* {@link SoftwareModule}.
|
||||
*
|
||||
*/
|
||||
public class FileUploadId implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String filename;
|
||||
|
||||
private final Long softwareModuleId;
|
||||
private final String softwareModuleName;
|
||||
private final String softwareModuleVersion;
|
||||
|
||||
/**
|
||||
* Creates a new {@link FileUploadId} instance.
|
||||
*
|
||||
* @param filename
|
||||
* the name of the file
|
||||
* @param softwareModule
|
||||
* the {@link SoftwareModule} for which the file is uploaded
|
||||
*/
|
||||
public FileUploadId(final String filename, final SoftwareModule softwareModule) {
|
||||
this.filename = filename;
|
||||
this.softwareModuleId = softwareModule.getId();
|
||||
this.softwareModuleName = softwareModule.getName();
|
||||
this.softwareModuleVersion = softwareModule.getVersion();
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
public Long getSoftwareModuleId() {
|
||||
return softwareModuleId;
|
||||
}
|
||||
|
||||
public String getSoftwareModuleName() {
|
||||
return softwareModuleName;
|
||||
}
|
||||
|
||||
public String getSoftwareModuleVersion() {
|
||||
return softwareModuleVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final FileUploadId other = (FileUploadId) obj;
|
||||
return Objects.equals(this.getFilename(), other.getFilename())
|
||||
&& Objects.equals(this.getSoftwareModuleId(), other.getSoftwareModuleId())
|
||||
&& Objects.equals(this.getSoftwareModuleName(), other.getSoftwareModuleName())
|
||||
&& Objects.equals(this.getSoftwareModuleVersion(), other.getSoftwareModuleVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getFilename(), getSoftwareModuleId(), getSoftwareModuleName(), getSoftwareModuleVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(filename).append(":")
|
||||
.append(HawkbitCommonUtil.getFormattedNameVersion(softwareModuleName, softwareModuleVersion))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.upload;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Holds file and upload progress details.
|
||||
*/
|
||||
public class FileUploadProgress implements Serializable {
|
||||
|
||||
/**
|
||||
* Status of a file upload.
|
||||
*/
|
||||
public enum FileUploadStatus {
|
||||
|
||||
/**
|
||||
* An upload for a file has been started.
|
||||
*/
|
||||
UPLOAD_STARTED,
|
||||
|
||||
/**
|
||||
* Progress changed for one file upload.
|
||||
*/
|
||||
UPLOAD_IN_PROGRESS,
|
||||
|
||||
/**
|
||||
* Upload of one file failed.
|
||||
*/
|
||||
UPLOAD_FAILED,
|
||||
|
||||
/**
|
||||
* One file upload succeeded.
|
||||
*/
|
||||
UPLOAD_SUCCESSFUL,
|
||||
|
||||
/**
|
||||
* One file upload finished ()
|
||||
*/
|
||||
UPLOAD_FINISHED
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final FileUploadId fileUploadId;
|
||||
|
||||
private long contentLength;
|
||||
|
||||
private long bytesRead;
|
||||
|
||||
private String failureReason;
|
||||
|
||||
private String filePath;
|
||||
|
||||
private final FileUploadStatus fileUploadStatus;
|
||||
|
||||
/**
|
||||
* Creates a new {@link FileUploadProgress} instance.
|
||||
*
|
||||
* @param fileUploadId
|
||||
* the {@link FileUploadId} to which this progress information
|
||||
* belongs.
|
||||
* @param fileUploadStatus
|
||||
* the {@link FileUploadStatus} of this progress
|
||||
*/
|
||||
public FileUploadProgress(final FileUploadId fileUploadId, final FileUploadStatus fileUploadStatus) {
|
||||
this.fileUploadId = fileUploadId;
|
||||
this.fileUploadStatus = fileUploadStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link FileUploadProgress} instance.
|
||||
*
|
||||
* @param fileUploadId
|
||||
* the {@link FileUploadId} to which this progress information
|
||||
* belongs.
|
||||
* @param fileUploadStatus
|
||||
* the {@link FileUploadStatus} of this progress
|
||||
* @param bytesRead
|
||||
* number of bytes read
|
||||
* @param contentLength
|
||||
* size of the file in bytes
|
||||
*/
|
||||
FileUploadProgress(final FileUploadId fileUploadId, final FileUploadStatus fileUploadStatus, final long bytesRead,
|
||||
final long contentLength) {
|
||||
this.fileUploadId = fileUploadId;
|
||||
this.fileUploadStatus = fileUploadStatus;
|
||||
this.contentLength = contentLength;
|
||||
this.bytesRead = bytesRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link FileUploadProgress} instance.
|
||||
*
|
||||
* @param fileUploadId
|
||||
* the {@link FileUploadId} to which this progress information
|
||||
* belongs.
|
||||
* @param fileUploadStatus
|
||||
* the {@link FileUploadStatus} of this progress
|
||||
* @param bytesRead
|
||||
* number of bytes read
|
||||
* @param contentLength
|
||||
* size of the file in bytes
|
||||
* @param filePath
|
||||
* the path of the file
|
||||
*/
|
||||
FileUploadProgress(final FileUploadId fileUploadId, final FileUploadStatus fileUploadStatus, final long bytesRead,
|
||||
final long contentLength, final String filePath) {
|
||||
this.fileUploadId = fileUploadId;
|
||||
this.fileUploadStatus = fileUploadStatus;
|
||||
this.contentLength = contentLength;
|
||||
this.bytesRead = bytesRead;
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link FileUploadProgress} instance.
|
||||
*
|
||||
* @param fileUploadId
|
||||
* the {@link FileUploadId} to which this progress information
|
||||
* belongs.
|
||||
* @param fileUploadStatus
|
||||
* the {@link FileUploadStatus} of this progress
|
||||
* @param failureReason
|
||||
* the reason of the failed upload
|
||||
*/
|
||||
FileUploadProgress(final FileUploadId fileUploadId, final FileUploadStatus fileUploadStatus,
|
||||
final String failureReason) {
|
||||
this.fileUploadId = fileUploadId;
|
||||
this.fileUploadStatus = fileUploadStatus;
|
||||
this.failureReason = failureReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for file upload ID
|
||||
*
|
||||
* @return FileUploadId
|
||||
*/
|
||||
public FileUploadId getFileUploadId() {
|
||||
return fileUploadId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for file content length
|
||||
*
|
||||
* @return long
|
||||
*/
|
||||
public long getContentLength() {
|
||||
return contentLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for bytes read of the file
|
||||
*
|
||||
* @return long
|
||||
*/
|
||||
public long getBytesRead() {
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for failed reason for upload
|
||||
* @return String
|
||||
*/
|
||||
public String getFailureReason() {
|
||||
return failureReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for file path
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Status of a file upload
|
||||
*
|
||||
* @return FileUploadStatus
|
||||
*/
|
||||
public FileUploadStatus getFileUploadStatus() {
|
||||
return fileUploadStatus;
|
||||
}
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.upload;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import javax.servlet.MultipartConfigElement;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.artifacts.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.common.CommonUiDependencies;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.layout.MasterEntityAwareComponent;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.shared.ui.ContentMode;
|
||||
import com.vaadin.ui.CustomComponent;
|
||||
import com.vaadin.ui.Html5File;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
import com.vaadin.ui.dnd.FileDropHandler;
|
||||
import com.vaadin.ui.dnd.FileDropTarget;
|
||||
import com.vaadin.ui.dnd.event.FileDropEvent;
|
||||
|
||||
/**
|
||||
* Container for drag and drop area in the upload view.
|
||||
*/
|
||||
public class UploadDropAreaLayout extends CustomComponent implements MasterEntityAwareComponent<ProxySoftwareModule> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
private final UINotification uiNotification;
|
||||
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
|
||||
private final transient ArtifactManagement artifactManagement;
|
||||
private final transient SoftwareModuleManagement softwareManagement;
|
||||
|
||||
private final transient MultipartConfigElement multipartConfigElement;
|
||||
private final transient Lock uploadLock = new ReentrantLock();
|
||||
|
||||
private final UploadProgressButtonLayout uploadButtonLayout;
|
||||
private VerticalLayout dropAreaLayout;
|
||||
|
||||
/**
|
||||
* Creates a new {@link UploadDropAreaLayout} instance.
|
||||
*
|
||||
* @param uiDependencies
|
||||
* the {@link CommonUiDependencies}
|
||||
* @param artifactUploadState
|
||||
* the {@link ArtifactUploadState} for state information
|
||||
* @param multipartConfigElement
|
||||
* the {@link MultipartConfigElement}
|
||||
* @param softwareManagement
|
||||
* the {@link SoftwareModuleManagement} for retrieving the
|
||||
* {@link SoftwareModule}
|
||||
* @param artifactManagement
|
||||
* the {@link ArtifactManagement} for storing the uploaded
|
||||
* artifacts
|
||||
*/
|
||||
public UploadDropAreaLayout(final CommonUiDependencies uiDependencies, final ArtifactUploadState artifactUploadState,
|
||||
final MultipartConfigElement multipartConfigElement, final SoftwareModuleManagement softwareManagement,
|
||||
final ArtifactManagement artifactManagement) {
|
||||
this.i18n = uiDependencies.getI18n();
|
||||
this.uiNotification = uiDependencies.getUiNotification();
|
||||
this.artifactUploadState = artifactUploadState;
|
||||
this.multipartConfigElement = multipartConfigElement;
|
||||
this.softwareManagement = softwareManagement;
|
||||
this.artifactManagement = artifactManagement;
|
||||
|
||||
this.uploadButtonLayout = new UploadProgressButtonLayout(i18n, uiDependencies.getEventBus(), artifactUploadState,
|
||||
multipartConfigElement, artifactManagement, softwareManagement, uploadLock);
|
||||
|
||||
buildLayout();
|
||||
}
|
||||
|
||||
private void buildLayout() {
|
||||
dropAreaLayout = new VerticalLayout();
|
||||
dropAreaLayout.setId(UIComponentIdProvider.UPLOAD_ARTIFACT_FILE_DROP_LAYOUT);
|
||||
dropAreaLayout.setMargin(false);
|
||||
dropAreaLayout.setSpacing(false);
|
||||
dropAreaLayout.addStyleName("upload-drop-area-layout-info");
|
||||
dropAreaLayout.setEnabled(false);
|
||||
dropAreaLayout.setHeightUndefined();
|
||||
|
||||
final Label dropIcon = new Label(VaadinIcons.ARROW_DOWN.getHtml(), ContentMode.HTML);
|
||||
dropIcon.addStyleName("drop-icon");
|
||||
dropIcon.setWidth(null);
|
||||
dropAreaLayout.addComponent(dropIcon);
|
||||
|
||||
final Label dropHereLabel = new Label(i18n.getMessage(UIMessageIdProvider.LABEL_DROP_AREA_UPLOAD));
|
||||
dropHereLabel.setWidth(null);
|
||||
dropAreaLayout.addComponent(dropHereLabel);
|
||||
|
||||
uploadButtonLayout.setWidth(null);
|
||||
uploadButtonLayout.addStyleName("upload-button");
|
||||
dropAreaLayout.addComponent(uploadButtonLayout);
|
||||
|
||||
new FileDropTarget<>(dropAreaLayout, new UploadFileDropHandler());
|
||||
|
||||
setCompositionRoot(dropAreaLayout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the upload view on file drop
|
||||
*
|
||||
* @param masterEntity
|
||||
* ProxySoftwareModule
|
||||
*/
|
||||
@Override
|
||||
public void masterEntityChanged(final ProxySoftwareModule masterEntity) {
|
||||
final Long masterEntityId = masterEntity != null ? masterEntity.getId() : null;
|
||||
|
||||
dropAreaLayout.setEnabled(masterEntityId != null);
|
||||
uploadButtonLayout.updateMasterEntityFilter(masterEntityId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks progress on file upload
|
||||
*
|
||||
* @param fileUploadProgress
|
||||
* FileUploadProgress
|
||||
*/
|
||||
public void onUploadChanged(final FileUploadProgress fileUploadProgress) {
|
||||
uploadButtonLayout.onUploadChanged(fileUploadProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is called when view is shown to the user
|
||||
*/
|
||||
public void restoreState() {
|
||||
uploadButtonLayout.restoreState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file drop area layout
|
||||
*
|
||||
* @return VerticalLayout
|
||||
*/
|
||||
public VerticalLayout getDropAreaLayout() {
|
||||
return dropAreaLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get File upload button layout
|
||||
*
|
||||
* @return UploadProgressButtonLayout
|
||||
*/
|
||||
public UploadProgressButtonLayout getUploadButtonLayout() {
|
||||
return uploadButtonLayout;
|
||||
}
|
||||
|
||||
private class UploadFileDropHandler implements FileDropHandler<VerticalLayout> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Validates the file drop events and triggers the upload
|
||||
*
|
||||
* @param event
|
||||
* FileDropEvent
|
||||
*/
|
||||
@Override
|
||||
public void drop(final FileDropEvent<VerticalLayout> event) {
|
||||
if (validate(event)) {
|
||||
// selected software module at the time of file drop is
|
||||
// considered for upload
|
||||
final Long lastSelectedSmId = artifactUploadState.getSmGridLayoutUiState().getSelectedEntityId();
|
||||
if (lastSelectedSmId != null) {
|
||||
uploadFilesForSoftwareModule(event.getFiles(), lastSelectedSmId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void uploadFilesForSoftwareModule(final Collection<Html5File> files, final Long softwareModuleId) {
|
||||
final SoftwareModule softwareModule = softwareManagement.get(softwareModuleId).orElse(null);
|
||||
|
||||
boolean duplicateFound = false;
|
||||
|
||||
for (final Html5File file : files) {
|
||||
if (artifactUploadState.isFileInUploadState(file.getFileName(), softwareModule)) {
|
||||
duplicateFound = true;
|
||||
} else {
|
||||
file.setStreamVariable(new FileTransferHandlerStreamVariable(file.getFileName(), file.getFileSize(),
|
||||
multipartConfigElement.getMaxFileSize(), file.getType(), softwareModule, artifactManagement,
|
||||
i18n, uploadLock));
|
||||
}
|
||||
}
|
||||
if (duplicateFound) {
|
||||
uiNotification.displayValidationError(i18n.getMessage("message.no.duplicateFiles"));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean validate(final FileDropEvent<VerticalLayout> event) {
|
||||
// check if drop is valid.If valid ,check if software module is
|
||||
// selected.
|
||||
if (!isFilesDropped(event)) {
|
||||
uiNotification.displayValidationError(i18n.getMessage("message.drop.onlyFiles"));
|
||||
return false;
|
||||
}
|
||||
return validateSoftwareModuleSelection();
|
||||
}
|
||||
|
||||
private boolean isFilesDropped(final FileDropEvent<VerticalLayout> event) {
|
||||
return event.getFiles() != null;
|
||||
}
|
||||
|
||||
private boolean validateSoftwareModuleSelection() {
|
||||
final Long lastSelectedSmId = artifactUploadState.getSmGridLayoutUiState().getSelectedEntityId();
|
||||
|
||||
if (lastSelectedSmId == null) {
|
||||
uiNotification.displayValidationError(i18n.getMessage("message.error.noSwModuleSelected"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.upload;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import com.vaadin.server.StreamVariable;
|
||||
import com.vaadin.ui.Upload;
|
||||
|
||||
/**
|
||||
* The {@link Upload} class has a bug.The lifecycle methods of the registered
|
||||
* handler
|
||||
* com.vaadin.ui.Upload.StartedListener#uploadStarted(com.vaadin.ui.Upload.StartedEvent)
|
||||
* etc are called even the upload was interrupted. This bug is fixed in this
|
||||
* class.
|
||||
*
|
||||
*/
|
||||
public class UploadFixed extends Upload {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private boolean uploadInterrupted;
|
||||
|
||||
/**
|
||||
* Stops the file upload
|
||||
*/
|
||||
@Override
|
||||
public void interruptUpload() {
|
||||
super.interruptUpload();
|
||||
uploadInterrupted = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StreamVariable getStreamVariable() {
|
||||
return new StreamVariableFixed(super.getStreamVariable());
|
||||
}
|
||||
|
||||
private class StreamVariableFixed implements StreamVariable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final StreamVariable originalStreamVariable;
|
||||
|
||||
/**
|
||||
* Constructor for StreamVariableFixed
|
||||
*
|
||||
* @param originalStreamVariable
|
||||
* StreamVariable
|
||||
*/
|
||||
public StreamVariableFixed(final StreamVariable originalStreamVariable) {
|
||||
this.originalStreamVariable = originalStreamVariable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean listenProgress() {
|
||||
// this fixes the vaadin bug
|
||||
return originalStreamVariable.listenProgress() && !uploadInterrupted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(final StreamingProgressEvent event) {
|
||||
originalStreamVariable.onProgress(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInterrupted() {
|
||||
return uploadInterrupted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream() {
|
||||
return originalStreamVariable.getOutputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamingStarted(final StreamingStartEvent event) {
|
||||
originalStreamVariable.streamingStarted(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamingFinished(final StreamingEndEvent event) {
|
||||
originalStreamVariable.streamingFinished(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void streamingFailed(final StreamingErrorEvent event) {
|
||||
originalStreamVariable.streamingFailed(event);
|
||||
uploadInterrupted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.upload;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import javax.servlet.MultipartConfigElement;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.artifacts.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorder;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.ui.Button;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.Upload;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
/**
|
||||
* Container for upload and progress button.
|
||||
*/
|
||||
public class UploadProgressButtonLayout extends VerticalLayout {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
|
||||
private final transient ArtifactManagement artifactManagement;
|
||||
private final transient SoftwareModuleManagement softwareModuleManagement;
|
||||
|
||||
private final transient MultipartConfigElement multipartConfigElement;
|
||||
private final Upload upload;
|
||||
private final transient Lock uploadLock;
|
||||
|
||||
private final UploadProgressInfoWindow uploadInfoWindow;
|
||||
|
||||
private Button uploadProgressButton;
|
||||
|
||||
/**
|
||||
* Creates a new {@link UploadProgressButtonLayout} instance.
|
||||
*
|
||||
* @param i18n
|
||||
* the {@link VaadinMessageSource}
|
||||
* @param eventBus
|
||||
* the {@link UIEventBus} for listening to ui events
|
||||
* @param artifactUploadState
|
||||
* the {@link ArtifactUploadState} for state information
|
||||
* @param multipartConfigElement
|
||||
* the {@link MultipartConfigElement}
|
||||
* @param softwareManagement
|
||||
* the {@link SoftwareModuleManagement} for retrieving the
|
||||
* {@link SoftwareModule}
|
||||
* @param artifactManagement
|
||||
* the {@link ArtifactManagement} for storing the uploaded
|
||||
* artifacts
|
||||
* @param uploadLock
|
||||
* A common upload lock that enforced sequential upload within an
|
||||
* UI instance
|
||||
*/
|
||||
public UploadProgressButtonLayout(final VaadinMessageSource i18n, final UIEventBus eventBus,
|
||||
final ArtifactUploadState artifactUploadState, final MultipartConfigElement multipartConfigElement,
|
||||
final ArtifactManagement artifactManagement, final SoftwareModuleManagement softwareManagement,
|
||||
final Lock uploadLock) {
|
||||
this.artifactUploadState = artifactUploadState;
|
||||
this.artifactManagement = artifactManagement;
|
||||
this.uploadInfoWindow = new UploadProgressInfoWindow(i18n, artifactUploadState);
|
||||
this.uploadInfoWindow.addCloseListener(event -> {
|
||||
// ensure that the progress button is hidden when the progress
|
||||
// window is closed and no more uploads running
|
||||
if (artifactUploadState.areAllUploadsFinished()) {
|
||||
hideUploadProgressButton();
|
||||
}
|
||||
});
|
||||
this.i18n = i18n;
|
||||
this.multipartConfigElement = multipartConfigElement;
|
||||
this.softwareModuleManagement = softwareManagement;
|
||||
this.upload = new UploadFixed();
|
||||
this.uploadLock = uploadLock;
|
||||
|
||||
createComponents();
|
||||
buildLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform specific tasks based on the file upload status
|
||||
*
|
||||
* @param fileUploadProgress
|
||||
* FileUploadProgress
|
||||
*/
|
||||
public void onUploadChanged(final FileUploadProgress fileUploadProgress) {
|
||||
final FileUploadProgress.FileUploadStatus uploadProgressEventType = fileUploadProgress.getFileUploadStatus();
|
||||
|
||||
switch (uploadProgressEventType) {
|
||||
case UPLOAD_STARTED:
|
||||
UI.getCurrent().access(() -> {
|
||||
onStartOfUpload();
|
||||
uploadInfoWindow.onUploadStarted(fileUploadProgress);
|
||||
});
|
||||
break;
|
||||
case UPLOAD_FAILED:
|
||||
case UPLOAD_SUCCESSFUL:
|
||||
case UPLOAD_IN_PROGRESS:
|
||||
UI.getCurrent().access(() -> uploadInfoWindow.updateUploadProgressInfoRowObject(fileUploadProgress));
|
||||
break;
|
||||
case UPLOAD_FINISHED:
|
||||
UI.getCurrent().access(() -> {
|
||||
onUploadFinished();
|
||||
uploadInfoWindow.onUploadFinished();
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Enum " + FileUploadProgress.FileUploadStatus.class.getSimpleName()
|
||||
+ " doesn't contain value " + uploadProgressEventType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the upload view after upload is finished
|
||||
*
|
||||
* @param masterEntityId
|
||||
* Long
|
||||
*/
|
||||
public void updateMasterEntityFilter(final Long masterEntityId) {
|
||||
upload.setEnabled(masterEntityId != null && artifactUploadState.areAllUploadsFinished());
|
||||
}
|
||||
|
||||
private void createComponents() {
|
||||
uploadProgressButton = SPUIComponentProvider.getButton(UIComponentIdProvider.UPLOAD_STATUS_BUTTON, "", "", "",
|
||||
false, null, SPUIButtonStyleNoBorder.class);
|
||||
uploadProgressButton.addStyleName(SPUIStyleDefinitions.UPLOAD_PROGRESS_INDICATOR_STYLE);
|
||||
uploadProgressButton.addClickListener(event -> showUploadInfoWindow());
|
||||
}
|
||||
|
||||
private void buildLayout() {
|
||||
final FileTransferHandlerVaadinUpload uploadHandler = new FileTransferHandlerVaadinUpload(
|
||||
multipartConfigElement.getMaxFileSize(), softwareModuleManagement, artifactManagement, i18n,
|
||||
uploadLock);
|
||||
upload.setButtonCaption(i18n.getMessage("upload.file"));
|
||||
upload.setReceiver(uploadHandler);
|
||||
upload.addSucceededListener(uploadHandler);
|
||||
upload.addFailedListener(uploadHandler);
|
||||
upload.addFinishedListener(uploadHandler);
|
||||
upload.addProgressListener(uploadHandler);
|
||||
upload.addStartedListener(uploadHandler);
|
||||
upload.setId(UIComponentIdProvider.UPLOAD_BUTTON);
|
||||
|
||||
addComponent(upload);
|
||||
setSizeFull();
|
||||
setMargin(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is called when view is shown to the user
|
||||
*/
|
||||
public void restoreState() {
|
||||
if (artifactUploadState.areAllUploadsFinished()) {
|
||||
artifactUploadState.clearUploadTempData();
|
||||
hideUploadProgressButton();
|
||||
upload.setEnabled(true);
|
||||
} else if (artifactUploadState.isAtLeastOneUploadInProgress()) {
|
||||
showUploadProgressButton();
|
||||
}
|
||||
}
|
||||
|
||||
private void onStartOfUpload() {
|
||||
showUploadProgressButton();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called for every finished (succeeded or failed) upload.
|
||||
*/
|
||||
private void onUploadFinished() {
|
||||
if (artifactUploadState.areAllUploadsFinished()) {
|
||||
hideUploadProgressButton();
|
||||
upload.setEnabled(true);
|
||||
artifactUploadState.clearUploadTempData();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximize the file upload view
|
||||
*/
|
||||
public void showUploadInfoWindow() {
|
||||
uploadInfoWindow.maximizeWindow();
|
||||
}
|
||||
|
||||
private void showUploadProgressButton() {
|
||||
removeComponent(upload);
|
||||
addComponent(uploadProgressButton);
|
||||
}
|
||||
|
||||
private void hideUploadProgressButton() {
|
||||
removeComponent(uploadProgressButton);
|
||||
addComponent(upload);
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.upload;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.builder.GridComponentBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.builder.StatusIconBuilder.ProgressStatusIconSupplier;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyUploadProgress;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
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.vaadin.ui.Grid;
|
||||
import com.vaadin.ui.renderers.ProgressBarRenderer;
|
||||
|
||||
/**
|
||||
* Grid for Upload Progress pop up info window.
|
||||
*/
|
||||
public class UploadProgressGrid extends Grid<ProxyUploadProgress> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
|
||||
private static final String UPLOAD_PROGRESS_STATUS_ID = "uploadProgressStatus";
|
||||
private static final String UPLOAD_PROGRESS_BAR_ID = "uploadProgressBar";
|
||||
private static final String UPLOAD_PROGRESS_FILENAME_ID = "uploadProgressFileName";
|
||||
private static final String UPLOAD_PROGRESS_SM_ID = "uploadProgressSm";
|
||||
private static final String UPLOAD_PROGRESS_REASON_ID = "uploadProgressReason";
|
||||
|
||||
private final ProgressStatusIconSupplier<ProxyUploadProgress> progressStatusIconSupplier;
|
||||
|
||||
/**
|
||||
* Constructor for UploadProgressGrid
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
*/
|
||||
public UploadProgressGrid(final VaadinMessageSource i18n) {
|
||||
this.i18n = i18n;
|
||||
|
||||
progressStatusIconSupplier = new ProgressStatusIconSupplier<>(i18n, ProxyUploadProgress::getStatus,
|
||||
UIComponentIdProvider.UPLOAD_STATUS_LABEL_ID);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setId(UIComponentIdProvider.UPLOAD_STATUS_POPUP_GRID);
|
||||
addStyleName(SPUIStyleDefinitions.UPLOAD_STATUS_GRID);
|
||||
setSelectionMode(SelectionMode.NONE);
|
||||
setSizeFull();
|
||||
|
||||
addColumns();
|
||||
}
|
||||
|
||||
private void addColumns() {
|
||||
GridComponentBuilder.addIconColumn(this, progressStatusIconSupplier::getLabel, UPLOAD_PROGRESS_STATUS_ID,
|
||||
i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_UPLOAD_STATUS));
|
||||
|
||||
addColumn(ProxyUploadProgress::getProgress, new ProgressBarRenderer()).setId(UPLOAD_PROGRESS_BAR_ID)
|
||||
.setCaption(i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_UPLOAD_PROGRESS)).setExpandRatio(1);
|
||||
|
||||
GridComponentBuilder.addColumn(this, uploadProgress -> uploadProgress.getFileUploadId().getFilename())
|
||||
.setId(UPLOAD_PROGRESS_FILENAME_ID)
|
||||
.setCaption(i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_FILENAME));
|
||||
|
||||
GridComponentBuilder
|
||||
.addColumn(this,
|
||||
uploadProgress -> HawkbitCommonUtil.getFormattedNameVersion(
|
||||
uploadProgress.getFileUploadId().getSoftwareModuleName(),
|
||||
uploadProgress.getFileUploadId().getSoftwareModuleVersion()))
|
||||
.setId(UPLOAD_PROGRESS_SM_ID).setCaption(i18n.getMessage(UIMessageIdProvider.CAPTION_SOFTWARE_MODULE));
|
||||
|
||||
GridComponentBuilder.addColumn(this, ProxyUploadProgress::getReason).setId(UPLOAD_PROGRESS_REASON_ID)
|
||||
.setCaption(i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_UPLOAD_REASON));
|
||||
|
||||
getColumns().forEach(col -> col.setSortable(false));
|
||||
}
|
||||
}
|
||||
@@ -1,251 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.upload;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.ui.artifacts.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress.FileUploadStatus;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyUploadProgress;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyUploadProgress.ProgressSatus;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorder;
|
||||
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 org.springframework.util.StringUtils;
|
||||
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.shared.ui.window.WindowMode;
|
||||
import com.vaadin.ui.Button;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
import com.vaadin.ui.Window;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
/**
|
||||
* Window that shows the progress of all uploads.
|
||||
*/
|
||||
public class UploadProgressInfoWindow extends Window {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
|
||||
private final UploadProgressGrid uploadProgressGrid;
|
||||
private final VerticalLayout mainLayout;
|
||||
|
||||
private Label windowCaption;
|
||||
private Button closeButton;
|
||||
|
||||
private final List<ProxyUploadProgress> uploads;
|
||||
|
||||
UploadProgressInfoWindow(final VaadinMessageSource i18n, final ArtifactUploadState artifactUploadState) {
|
||||
this.i18n = i18n;
|
||||
this.artifactUploadState = artifactUploadState;
|
||||
|
||||
setPopupProperties();
|
||||
createStatusPopupHeaderComponents();
|
||||
|
||||
mainLayout = new VerticalLayout();
|
||||
mainLayout.setSpacing(Boolean.TRUE);
|
||||
mainLayout.setSizeUndefined();
|
||||
setPopupSizeInMinMode();
|
||||
|
||||
uploads = new ArrayList<>();
|
||||
uploadProgressGrid = new UploadProgressGrid(i18n);
|
||||
uploadProgressGrid.setItems(uploads);
|
||||
|
||||
mainLayout.addComponents(getCaptionLayout(), uploadProgressGrid);
|
||||
mainLayout.setExpandRatio(uploadProgressGrid, 1.0F);
|
||||
setContent(mainLayout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the status of each file uploaded in the grid view
|
||||
*
|
||||
* @param fileUploadProgress
|
||||
* FileUploadProgress
|
||||
*/
|
||||
public void updateUploadProgressInfoRowObject(final FileUploadProgress fileUploadProgress) {
|
||||
final FileUploadId fileUploadId = fileUploadProgress.getFileUploadId();
|
||||
final ProxyUploadProgress gridUploadItem = uploads.stream()
|
||||
.filter(upload -> upload.getFileUploadId().equals(fileUploadId)).findAny()
|
||||
.orElse(new ProxyUploadProgress());
|
||||
|
||||
gridUploadItem.setStatus(getStatusRepresentaion(fileUploadProgress.getFileUploadStatus()));
|
||||
gridUploadItem.setReason(getFailureReason(fileUploadId));
|
||||
|
||||
final long bytesRead = fileUploadProgress.getBytesRead();
|
||||
final long fileSize = fileUploadProgress.getContentLength();
|
||||
if (bytesRead > 0 && fileSize > 0) {
|
||||
gridUploadItem.setProgress((double) bytesRead / (double) fileSize);
|
||||
}
|
||||
|
||||
if (gridUploadItem.getFileUploadId() == null) {
|
||||
gridUploadItem.setFileUploadId(fileUploadId);
|
||||
uploads.add(gridUploadItem);
|
||||
}
|
||||
|
||||
uploadProgressGrid.getDataProvider().refreshItem(gridUploadItem);
|
||||
}
|
||||
|
||||
private static ProgressSatus getStatusRepresentaion(final FileUploadStatus uploadStatus) {
|
||||
if (uploadStatus == FileUploadStatus.UPLOAD_FAILED) {
|
||||
return ProgressSatus.FAILED;
|
||||
} else if (uploadStatus == FileUploadStatus.UPLOAD_SUCCESSFUL) {
|
||||
return ProgressSatus.FINISHED;
|
||||
} else {
|
||||
return ProgressSatus.INPROGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the failure reason for the provided fileUploadId or an empty
|
||||
* string but never <code>null</code>.
|
||||
*
|
||||
* @param fileUploadId
|
||||
* @return the failure reason or an empty String.
|
||||
*/
|
||||
private String getFailureReason(final FileUploadId fileUploadId) {
|
||||
String failureReason = "";
|
||||
if (artifactUploadState.getFileUploadProgress(fileUploadId) != null) {
|
||||
failureReason = artifactUploadState.getFileUploadProgress(fileUploadId).getFailureReason();
|
||||
}
|
||||
if (StringUtils.isEmpty(failureReason)) {
|
||||
return "";
|
||||
}
|
||||
return failureReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the file upload process and maximize the upload view
|
||||
*
|
||||
* @param fileUploadProgress
|
||||
* FileUploadProgress
|
||||
*/
|
||||
public void onUploadStarted(final FileUploadProgress fileUploadProgress) {
|
||||
updateUploadProgressInfoRowObject(fileUploadProgress);
|
||||
|
||||
if (isWindowNotAlreadyAttached()) {
|
||||
maximizeWindow();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWindowNotAlreadyAttached() {
|
||||
return !UI.getCurrent().getWindows().contains(this);
|
||||
}
|
||||
|
||||
private void restoreState() {
|
||||
uploads.clear();
|
||||
for (final FileUploadProgress fileUploadProgress : artifactUploadState
|
||||
.getAllFileUploadProgressValuesFromOverallUploadProcessList()) {
|
||||
updateUploadProgressInfoRowObject(fileUploadProgress);
|
||||
}
|
||||
}
|
||||
|
||||
private void setPopupProperties() {
|
||||
setId(UIComponentIdProvider.UPLOAD_STATUS_POPUP_ID);
|
||||
addStyleName(SPUIStyleDefinitions.UPLOAD_INFO);
|
||||
|
||||
setResizable(false);
|
||||
setDraggable(true);
|
||||
setClosable(false);
|
||||
setModal(true);
|
||||
}
|
||||
|
||||
private HorizontalLayout getCaptionLayout() {
|
||||
final HorizontalLayout captionLayout = new HorizontalLayout();
|
||||
captionLayout.setSizeFull();
|
||||
captionLayout.setHeight("36px");
|
||||
captionLayout.addComponents(windowCaption, closeButton);
|
||||
captionLayout.setExpandRatio(windowCaption, 1.0F);
|
||||
captionLayout.addStyleName("v-window-header");
|
||||
return captionLayout;
|
||||
}
|
||||
|
||||
private void createStatusPopupHeaderComponents() {
|
||||
windowCaption = new Label(i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_UPLOAD_POPUP));
|
||||
closeButton = getCloseButton();
|
||||
}
|
||||
|
||||
private void openWindow() {
|
||||
UI.getCurrent().addWindow(this);
|
||||
center();
|
||||
}
|
||||
|
||||
protected void maximizeWindow() {
|
||||
openWindow();
|
||||
restoreState();
|
||||
artifactUploadState.setStatusPopupMinimized(false);
|
||||
}
|
||||
|
||||
private void minimizeWindow() {
|
||||
artifactUploadState.setStatusPopupMinimized(true);
|
||||
closeWindow();
|
||||
|
||||
if (artifactUploadState.areAllUploadsFinished()) {
|
||||
cleanupStates();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called for every finished (succeeded or failed) upload.
|
||||
*/
|
||||
public void onUploadFinished() {
|
||||
if (artifactUploadState.areAllUploadsFinished() && artifactUploadState.isStatusPopupMinimized()) {
|
||||
if (artifactUploadState.getFilesInFailedState().isEmpty()) {
|
||||
cleanupStates();
|
||||
closeWindow();
|
||||
} else {
|
||||
maximizeWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupStates() {
|
||||
uploads.clear();
|
||||
artifactUploadState.clearUploadTempData();
|
||||
}
|
||||
|
||||
private void setPopupSizeInMinMode() {
|
||||
mainLayout.setWidth(900, Unit.PIXELS);
|
||||
mainLayout.setHeight(510, Unit.PIXELS);
|
||||
}
|
||||
|
||||
private Button getCloseButton() {
|
||||
final Button closeBtn = SPUIComponentProvider.getButton(
|
||||
UIComponentIdProvider.UPLOAD_STATUS_POPUP_CLOSE_BUTTON_ID, "", "", "", true, VaadinIcons.CLOSE,
|
||||
SPUIButtonStyleNoBorder.class);
|
||||
closeBtn.addStyleName(ValoTheme.BUTTON_BORDERLESS);
|
||||
closeBtn.addClickListener(event -> onClose());
|
||||
return closeBtn;
|
||||
}
|
||||
|
||||
private void onClose() {
|
||||
if (artifactUploadState.areAllUploadsFinished()) {
|
||||
cleanupStates();
|
||||
closeWindow();
|
||||
} else {
|
||||
minimizeWindow();
|
||||
}
|
||||
}
|
||||
|
||||
private void closeWindow() {
|
||||
setWindowMode(WindowMode.NORMAL);
|
||||
setPopupSizeInMinMode();
|
||||
close();
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.autoconfigure;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.eclipse.hawkbit.DistributedResourceBundleMessageSource;
|
||||
import org.eclipse.hawkbit.ui.MgmtUiConfiguration;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.UiProperties;
|
||||
import org.eclipse.hawkbit.ui.push.DelayedEventBusPushStrategy;
|
||||
import org.eclipse.hawkbit.ui.push.EventPushStrategy;
|
||||
import org.eclipse.hawkbit.ui.push.HawkbitEventPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.push.HawkbitEventProvider;
|
||||
import org.eclipse.hawkbit.ui.push.UIEventPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.push.UIEventProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.SpringContextHolder;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.vaadin.spring.annotation.EnableVaadinExtensions;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
import org.vaadin.spring.events.annotation.EnableEventBus;
|
||||
|
||||
import com.vaadin.spring.annotation.UIScope;
|
||||
|
||||
/**
|
||||
* The Management UI auto configuration.
|
||||
*/
|
||||
@Configuration
|
||||
@EnableVaadinExtensions
|
||||
@EnableEventBus
|
||||
@ConditionalOnClass(MgmtUiConfiguration.class)
|
||||
@Import(MgmtUiConfiguration.class)
|
||||
public class MgmtUiAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
RedirectController uiRedirectController() {
|
||||
return new RedirectController();
|
||||
}
|
||||
|
||||
/**
|
||||
* A message source bean to add distributed message sources.
|
||||
*
|
||||
* @return the message bean.
|
||||
*/
|
||||
@Bean(name = "messageSource")
|
||||
DistributedResourceBundleMessageSource messageSource() {
|
||||
return new DistributedResourceBundleMessageSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* A event provider bean which hold the supported events for the UI.
|
||||
*
|
||||
* @return the provider bean
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
UIEventProvider eventProvider() {
|
||||
return new HawkbitEventProvider();
|
||||
}
|
||||
|
||||
/**
|
||||
* A event permission checker bean which verifies supported events for the
|
||||
* UI.
|
||||
*
|
||||
* @return the permission checker bean
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
UIEventPermissionChecker eventPermissionChecker(final SpPermissionChecker permChecker) {
|
||||
return new HawkbitEventPermissionChecker(permChecker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean for creating a singleton instance of the {@link SpringContextHolder}
|
||||
*
|
||||
* @return the singleton instance of the {@link SpringContextHolder}
|
||||
*/
|
||||
@Bean
|
||||
SpringContextHolder springContextHolder() {
|
||||
return SpringContextHolder.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* The UI scoped event push strategy. Session scope is necessary, that every
|
||||
* UI has an own strategy.
|
||||
*
|
||||
* @param applicationContext
|
||||
* the context to add the listener to
|
||||
* @param executorService
|
||||
* the general scheduler service
|
||||
* @param eventBus
|
||||
* the ui event bus
|
||||
* @param eventProvider
|
||||
* the event provider
|
||||
* @param eventPermissionChecker
|
||||
* the event permission checker
|
||||
* @param uiProperties
|
||||
* the ui properties
|
||||
* @return the push strategy bean
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@UIScope
|
||||
EventPushStrategy eventPushStrategy(final ConfigurableApplicationContext applicationContext,
|
||||
final ScheduledExecutorService executorService, final UIEventBus eventBus,
|
||||
final UIEventProvider eventProvider, final UIEventPermissionChecker eventPermissionChecker,
|
||||
final UiProperties uiProperties) {
|
||||
final DelayedEventBusPushStrategy delayedEventBusPushStrategy = new DelayedEventBusPushStrategy(executorService,
|
||||
eventBus, eventProvider, eventPermissionChecker, uiProperties.getEvent().getPush().getDelay());
|
||||
applicationContext.addApplicationListener(delayedEventBusPushStrategy);
|
||||
|
||||
return delayedEventBusPushStrategy;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.autoconfigure;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* Redirects for convenience. hawkBit's management UI is by default not
|
||||
* listening on / but on /UI.
|
||||
*
|
||||
*/
|
||||
@Controller
|
||||
public class RedirectController {
|
||||
|
||||
/**
|
||||
* @return redirect to the Management UI
|
||||
*/
|
||||
@GetMapping("/")
|
||||
public ModelAndView home() {
|
||||
return new ModelAndView("redirect:/UI/");
|
||||
}
|
||||
}
|
||||
@@ -1,257 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.autoconfigure;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.security.DosFilter;
|
||||
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.ui.MgmtUiConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.access.AccessDecisionManager;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.InsufficientAuthenticationException;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
|
||||
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
|
||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
|
||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||
import org.springframework.security.web.session.HttpSessionEventPublisher;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.vaadin.spring.http.HttpService;
|
||||
import org.vaadin.spring.security.annotation.EnableVaadinSharedSecurity;
|
||||
import org.vaadin.spring.security.config.VaadinSharedSecurityConfiguration;
|
||||
import org.vaadin.spring.security.shared.VaadinAuthenticationSuccessHandler;
|
||||
import org.vaadin.spring.security.shared.VaadinUrlAuthenticationSuccessHandler;
|
||||
import org.vaadin.spring.security.web.VaadinRedirectStrategy;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* {@link WebSecurityConfigurer} for external (management) access.
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableVaadinSharedSecurity
|
||||
@ConditionalOnClass(MgmtUiConfiguration.class)
|
||||
public class UISecurityConfigurationAdapter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(UISecurityConfigurationAdapter.class);
|
||||
|
||||
private static final int DOS_FILTER_ORDER = -200;
|
||||
|
||||
@Autowired
|
||||
private HawkbitSecurityProperties hawkbitSecurityProperties;
|
||||
|
||||
/**
|
||||
* Filter to protect the hawkBit management UI against to many requests.
|
||||
*
|
||||
* @param securityProperties for filter configuration
|
||||
* @return the spring filter registration bean for registering a denial
|
||||
* of service protection filter in the filter chain
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = "hawkbit.server.security.dos.ui-filter", name = "enabled", matchIfMissing = true)
|
||||
public FilterRegistrationBean<DosFilter> dosMgmtUiFilter(final HawkbitSecurityProperties securityProperties) {
|
||||
final HawkbitSecurityProperties.Dos.Filter filterProperties = securityProperties.getDos().getUiFilter();
|
||||
final HawkbitSecurityProperties.Clients clientProperties = securityProperties.getClients();
|
||||
|
||||
final FilterRegistrationBean<DosFilter> filterRegBean = new FilterRegistrationBean<>();
|
||||
|
||||
filterRegBean.setFilter(new DosFilter(null, filterProperties.getMaxRead(),
|
||||
filterProperties.getMaxWrite(), filterProperties.getWhitelist(), clientProperties.getBlacklist(),
|
||||
clientProperties.getRemoteIpHeader()));
|
||||
|
||||
// All URLs that can be called anonymous
|
||||
filterRegBean.setUrlPatterns(Arrays.asList("/UI/login", "/UI/login/*", "/UI/logout", "/UI/logout/*"));
|
||||
filterRegBean.setOrder(DOS_FILTER_ORDER);
|
||||
filterRegBean.setName("dosMgmtUiFilter");
|
||||
|
||||
return filterRegBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(final AuthenticationConfiguration authenticationConfiguration) throws Exception {
|
||||
return authenticationConfiguration.getAuthenticationManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwriting VaadinAuthenticationSuccessHandler of default
|
||||
* VaadinSharedSecurityConfiguration
|
||||
*
|
||||
* @return the vaadin success authentication handler
|
||||
*/
|
||||
@Primary
|
||||
@Bean(name = VaadinSharedSecurityConfiguration.VAADIN_AUTHENTICATION_SUCCESS_HANDLER_BEAN)
|
||||
public VaadinAuthenticationSuccessHandler redirectSaveHandler(final HttpService httpService,
|
||||
final VaadinRedirectStrategy redirectStrategy) {
|
||||
final VaadinUrlAuthenticationSuccessHandler handler = new TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler(
|
||||
httpService, redirectStrategy, "/UI/");
|
||||
handler.setTargetUrlParameter("r");
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener to redirect to login page after session timeout. Close the
|
||||
* vaadin session, because it's is not possible to redirect in
|
||||
* atmosphere.
|
||||
*
|
||||
* @return the servlet listener.
|
||||
*/
|
||||
@Bean
|
||||
public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
|
||||
return new ServletListenerRegistrationBean<>(new HttpSessionEventPublisher());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(400)
|
||||
protected SecurityFilterChain filterChainUI(
|
||||
final HttpSecurity http,
|
||||
@Autowired(required = false)
|
||||
final OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService,
|
||||
@Autowired(required = false)
|
||||
final AuthenticationSuccessHandler authenticationSuccessHandler,
|
||||
final LogoutHandler logoutHandler,
|
||||
final LogoutSuccessHandler logoutSuccessHandler)
|
||||
throws Exception {
|
||||
final boolean enableOidc = oidcUserService != null && authenticationSuccessHandler != null;
|
||||
|
||||
// workaround regex: we need to exclude the URL /UI/HEARTBEAT here
|
||||
// because we bound the vaadin application to /UI and not to root,
|
||||
// described in vaadin-forum:
|
||||
// https://vaadin.com/forum#!/thread/3200565.
|
||||
HttpSecurity httpSec;
|
||||
if (enableOidc) {
|
||||
httpSec = http.requestMatchers().antMatchers("/**/UI/**", "/**/oauth2/**").and();
|
||||
} else {
|
||||
httpSec = http.antMatcher("/**/UI/**");
|
||||
}
|
||||
// disable as CSRF is handled by Vaadin
|
||||
httpSec.csrf(AbstractHttpConfigurer::disable);
|
||||
// allow same origin X-Frame-Options for correct file download under
|
||||
// Safari
|
||||
httpSec.headers().frameOptions().sameOrigin();
|
||||
|
||||
if (hawkbitSecurityProperties.isRequireSsl()) {
|
||||
httpSec = httpSec.requiresChannel(crmRegistry -> crmRegistry.anyRequest().requiresSecure());
|
||||
} else {
|
||||
LOG.info(
|
||||
"""
|
||||
******************
|
||||
** Requires HTTPS Security has been disabled for UI, should only be used for developing purposes **
|
||||
******************""");
|
||||
}
|
||||
|
||||
if (!ObjectUtils.isEmpty(hawkbitSecurityProperties.getContentSecurityPolicy())) {
|
||||
httpSec.headers().contentSecurityPolicy(hawkbitSecurityProperties.getContentSecurityPolicy());
|
||||
}
|
||||
|
||||
// UI
|
||||
httpSec.authorizeRequests().antMatchers("/UI/login/**", "/UI/UIDL/**").permitAll().anyRequest()
|
||||
.authenticated();
|
||||
|
||||
if (enableOidc) {
|
||||
// OIDC
|
||||
httpSec.oauth2Login().userInfoEndpoint().oidcUserService(oidcUserService).and()
|
||||
.successHandler(authenticationSuccessHandler).and().oauth2Client();
|
||||
} else {
|
||||
// UI login / Basic auth
|
||||
httpSec.exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/UI/login"));
|
||||
}
|
||||
|
||||
// UI logout
|
||||
httpSec.logout().logoutUrl("/UI/logout*").addLogoutHandler(logoutHandler)
|
||||
.logoutSuccessHandler(logoutSuccessHandler);
|
||||
|
||||
return httpSec.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebSecurityCustomizer webSecurityCustomizer() {
|
||||
// No security for static content
|
||||
return (web) -> web.ignoring().antMatchers("/documentation/**", "/VAADIN/**", "/*.*", "/docs/**");
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration that defines the {@link AccessDecisionManager} bean for
|
||||
* UI method security used by the Vaadin Servlet. Notice: we can not use
|
||||
* the top-level method security configuration because
|
||||
* AdviceMode.ASPECTJ is not supported.
|
||||
*/
|
||||
@Configuration
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, proxyTargetClass = true)
|
||||
@ConditionalOnClass(MgmtUiConfiguration.class)
|
||||
static class UIMethodSecurity extends GlobalMethodSecurityConfiguration {
|
||||
|
||||
@Bean(name = VaadinSharedSecurityConfiguration.ACCESS_DECISION_MANAGER_BEAN)
|
||||
@Override
|
||||
protected AccessDecisionManager accessDecisionManager() {
|
||||
return super.accessDecisionManager();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* After a successful login on the UI we need to ensure to create the tenant
|
||||
* meta data within SP.
|
||||
*/
|
||||
class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends VaadinUrlAuthenticationSuccessHandler {
|
||||
|
||||
@Autowired
|
||||
private SystemManagement systemManagement;
|
||||
|
||||
@Autowired
|
||||
private SystemSecurityContext systemSecurityContext;
|
||||
|
||||
public TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler(final HttpService http,
|
||||
final VaadinRedirectStrategy redirectStrategy, final String defaultTargetUrl) {
|
||||
super(http, redirectStrategy, defaultTargetUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(final Authentication authentication) throws Exception {
|
||||
systemSecurityContext.runAsSystemAsTenant(systemManagement::getTenantMetadata, getTenantFrom(authentication));
|
||||
|
||||
super.onAuthenticationSuccess(authentication);
|
||||
}
|
||||
|
||||
private static String getTenantFrom(final Authentication authentication) {
|
||||
final Object details = authentication.getDetails();
|
||||
if (details instanceof TenantAwareAuthenticationDetails) {
|
||||
return ((TenantAwareAuthenticationDetails) details).getTenant();
|
||||
}
|
||||
|
||||
throw new InsufficientAuthenticationException("Authentication details/tenant info are not specified!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
|
||||
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload.EntityModifiedEventType;
|
||||
|
||||
/**
|
||||
* Window controller for entity creations.
|
||||
*
|
||||
* @param <T>
|
||||
* Type of proxy entity
|
||||
* @param <E>
|
||||
* Second type of proxy entity
|
||||
* @param <R>
|
||||
* Type of repository entity
|
||||
*/
|
||||
public abstract class AbstractAddEntityWindowController<T, E, R> extends AbstractEntityWindowController<T, E, R> {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
*/
|
||||
protected AbstractAddEntityWindowController(final CommonUiDependencies uiDependencies) {
|
||||
super(uiDependencies);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPersistSuccessMessageKey() {
|
||||
return "message.save.success";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPersistFailureMessageKey() {
|
||||
return "message.save.fail";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityModifiedEventPayload createModifiedEventPayload(final R entity) {
|
||||
return new EntityModifiedEventPayload(EntityModifiedEventType.ENTITY_ADDED, getParentEntityClass(),
|
||||
getEntityClass(), getId(entity));
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyNamedEntity;
|
||||
|
||||
/**
|
||||
* Window controller for named entity creations.
|
||||
*
|
||||
* @param <T>
|
||||
* Type of proxy entity
|
||||
* @param <E>
|
||||
* Second type of proxy entity
|
||||
* @param <R>
|
||||
* Type of repository entity
|
||||
*/
|
||||
public abstract class AbstractAddNamedEntityWindowController<T, E extends ProxyNamedEntity, R extends NamedEntity>
|
||||
extends AbstractAddEntityWindowController<T, E, R> {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
*/
|
||||
protected AbstractAddNamedEntityWindowController(final CommonUiDependencies uiDependencies) {
|
||||
super(uiDependencies);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDisplayableName(final R entity) {
|
||||
return entity.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDisplayableNameForFailedMessage(final E entity) {
|
||||
return entity.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getId(final R entity) {
|
||||
return entity.getId();
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.SaveDialogCloseListener;
|
||||
import org.eclipse.hawkbit.ui.common.builder.WindowBuilder;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
import com.vaadin.ui.Component;
|
||||
import com.vaadin.ui.Window;
|
||||
|
||||
/**
|
||||
* Builder for abstract entity window
|
||||
*
|
||||
* @param <T>
|
||||
* Generic type entity
|
||||
*/
|
||||
public abstract class AbstractEntityWindowBuilder<T> {
|
||||
protected final CommonUiDependencies uiDependencies;
|
||||
|
||||
protected AbstractEntityWindowBuilder(final CommonUiDependencies uiDependencies) {
|
||||
this.uiDependencies = uiDependencies;
|
||||
}
|
||||
|
||||
protected CommonDialogWindow getWindowForNewEntity(final AbstractEntityWindowController<T, ?, ?> controller) {
|
||||
return getWindowForEntity(null, controller);
|
||||
}
|
||||
|
||||
protected CommonDialogWindow getWindowForNewEntity(final AbstractEntityWindowController<T, ?, ?> controller,
|
||||
final Component windowContent) {
|
||||
return getWindowForEntity(null, controller, windowContent);
|
||||
}
|
||||
|
||||
protected CommonDialogWindow getWindowForEntity(final T proxyEntity,
|
||||
final AbstractEntityWindowController<T, ?, ?> controller) {
|
||||
return getWindowForEntity(proxyEntity, controller, controller.getLayout().getRootComponent());
|
||||
}
|
||||
|
||||
protected CommonDialogWindow getWindowForEntity(final T proxyEntity,
|
||||
final AbstractEntityWindowController<T, ?, ?> controller, final Component windowContent) {
|
||||
controller.populateWithData(proxyEntity);
|
||||
|
||||
final CommonDialogWindow window = createWindow(windowContent, controller.getSaveDialogCloseListener());
|
||||
|
||||
controller.getLayout().addValidationListener(window::setSaveButtonEnabled);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
protected CommonDialogWindow createWindow(final Component content,
|
||||
final SaveDialogCloseListener saveDialogCloseListener) {
|
||||
return new WindowBuilder(SPUIDefinitions.CREATE_UPDATE_WINDOW).id(getWindowId()).content(content)
|
||||
.i18n(uiDependencies.getI18n()).helpLink(getHelpLink()).saveDialogCloseListener(saveDialogCloseListener)
|
||||
.buildCommonDialogWindow();
|
||||
}
|
||||
|
||||
protected abstract String getWindowId();
|
||||
|
||||
/**
|
||||
* Gets the add window
|
||||
*
|
||||
* @return window
|
||||
*/
|
||||
public abstract Window getWindowForAdd();
|
||||
|
||||
/**
|
||||
* Gets the update window
|
||||
*
|
||||
* @param entity
|
||||
* Generic type entity
|
||||
*
|
||||
* @return window
|
||||
*/
|
||||
public abstract Window getWindowForUpdate(final T entity);
|
||||
|
||||
protected String getHelpLink() {
|
||||
// can be overriden to provide help link to documentation
|
||||
return null;
|
||||
}
|
||||
|
||||
protected VaadinMessageSource getI18n() {
|
||||
return uiDependencies.getI18n();
|
||||
}
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.SaveDialogCloseListener;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
|
||||
import org.eclipse.hawkbit.ui.common.event.CommandTopics;
|
||||
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventTopics;
|
||||
import org.eclipse.hawkbit.ui.common.event.SelectionChangedEventPayload;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
/**
|
||||
* Controller for abstract entity window
|
||||
*
|
||||
* @param <T>
|
||||
* Type of proxy entity
|
||||
* @param <E>
|
||||
* Second type of proxy entity
|
||||
* @param <R>
|
||||
* Type of repository entity
|
||||
*/
|
||||
public abstract class AbstractEntityWindowController<T, E, R> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractEntityWindowController.class);
|
||||
|
||||
private final CommonUiDependencies uiDependencies;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param uiDependencies
|
||||
* the {@link CommonUiDependencies}
|
||||
*/
|
||||
protected AbstractEntityWindowController(final CommonUiDependencies uiDependencies) {
|
||||
this.uiDependencies = uiDependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate entity with data
|
||||
*
|
||||
* @param proxyEntity
|
||||
* Generic type entity
|
||||
*/
|
||||
public void populateWithData(final T proxyEntity) {
|
||||
getLayout().setEntity(buildEntityFromProxy(proxyEntity));
|
||||
|
||||
adaptLayout(proxyEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return layout
|
||||
*/
|
||||
public abstract EntityWindowLayout<E> getLayout();
|
||||
|
||||
protected abstract E buildEntityFromProxy(final T proxyEntity);
|
||||
|
||||
protected void adaptLayout(final T proxyEntity) {
|
||||
// can be overriden to adapt layout components (e.g. disable/enable
|
||||
// fields, adapt bindings, etc.)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Save dialog close listener
|
||||
*/
|
||||
public SaveDialogCloseListener getSaveDialogCloseListener() {
|
||||
return new SaveDialogCloseListener() {
|
||||
@Override
|
||||
public void saveOrUpdate() {
|
||||
persistEntity(getLayout().getEntity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWindowSaveOrUpdate() {
|
||||
return isEntityValid(getLayout().getEntity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWindowClose() {
|
||||
return closeWindowAfterSave();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected void persistEntity(final E entity) {
|
||||
try {
|
||||
|
||||
final R createdEntity = persistEntityInRepository(entity);
|
||||
|
||||
handleEntityPersistedSuccessfully(createdEntity);
|
||||
|
||||
selectPersistedEntity(createdEntity);
|
||||
|
||||
} catch (final ConstraintViolationException | EntityNotFoundException | EntityReadOnlyException ex) {
|
||||
|
||||
handleEntityPersistFailed(entity, ex);
|
||||
|
||||
} finally {
|
||||
|
||||
postPersist();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract R persistEntityInRepository(E entity);
|
||||
|
||||
protected void handleEntityPersistedSuccessfully(final R persistedEntity) {
|
||||
displaySuccess(getPersistSuccessMessageKey(), getDisplayableName(persistedEntity));
|
||||
publishModifiedEvent(createModifiedEventPayload(persistedEntity));
|
||||
}
|
||||
|
||||
protected void handleEntityPersistFailed(final E entity, final RuntimeException ex) {
|
||||
final String name = getDisplayableNameForFailedMessage(entity);
|
||||
final String id = Objects.toString(entity);
|
||||
final String type = getEntityClass().getSimpleName();
|
||||
LOG.warn("Persist of entity name:{}, id:{}, type:{} failed in UI with reason: {}", name, id, type,
|
||||
ex.getMessage());
|
||||
displayWarning(getPersistFailureMessageKey(), name);
|
||||
}
|
||||
|
||||
protected abstract EntityModifiedEventPayload createModifiedEventPayload(final R entity);
|
||||
|
||||
protected abstract Long getId(R entity);
|
||||
|
||||
protected abstract String getDisplayableNameForFailedMessage(E entity);
|
||||
|
||||
protected abstract String getDisplayableName(R entity);
|
||||
|
||||
protected abstract String getPersistSuccessMessageKey();
|
||||
|
||||
protected abstract String getPersistFailureMessageKey();
|
||||
|
||||
protected abstract Class<? extends ProxyIdentifiableEntity> getEntityClass();
|
||||
|
||||
protected Class<? extends ProxyIdentifiableEntity> getParentEntityClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void selectPersistedEntity(final R entity) {
|
||||
// entity is not selected by default
|
||||
}
|
||||
|
||||
protected void postPersist() {
|
||||
// empty default implementation
|
||||
}
|
||||
|
||||
protected abstract boolean isEntityValid(final E entity);
|
||||
|
||||
protected boolean closeWindowAfterSave() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected VaadinMessageSource getI18n() {
|
||||
return uiDependencies.getI18n();
|
||||
}
|
||||
|
||||
protected EntityFactory getEntityFactory() {
|
||||
return uiDependencies.getEntityFactory();
|
||||
}
|
||||
|
||||
protected UIEventBus getEventBus() {
|
||||
return uiDependencies.getEventBus();
|
||||
}
|
||||
|
||||
protected UINotification getUiNotification() {
|
||||
return uiDependencies.getUiNotification();
|
||||
}
|
||||
|
||||
protected void displaySuccess(final String messageKey, final Object... args) {
|
||||
getUiNotification().displaySuccess(getI18n().getMessage(messageKey, args));
|
||||
}
|
||||
|
||||
protected void displayValidationError(final String messageKey, final Object... args) {
|
||||
getUiNotification().displayValidationError(getI18n().getMessage(messageKey, args));
|
||||
}
|
||||
|
||||
protected void displayWarning(final String messageKey, final Object... args) {
|
||||
getUiNotification().displayWarning(getI18n().getMessage(messageKey, args));
|
||||
}
|
||||
|
||||
protected void publishModifiedEvent(final EntityModifiedEventPayload eventPayload) {
|
||||
getEventBus().publish(EventTopics.ENTITY_MODIFIED, this, eventPayload);
|
||||
}
|
||||
|
||||
protected void publishSelectionEvent(final SelectionChangedEventPayload<E> eventPayload) {
|
||||
getEventBus().publish(CommandTopics.SELECT_GRID_ENTITY, this, eventPayload);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.vaadin.data.Binder;
|
||||
|
||||
/**
|
||||
* Abstract class for entity window layout
|
||||
*
|
||||
* @param <T>
|
||||
* Generic type entity
|
||||
*/
|
||||
public abstract class AbstractEntityWindowLayout<T> implements EntityWindowLayout<T> {
|
||||
|
||||
protected final Binder<T> binder;
|
||||
|
||||
protected Consumer<Boolean> validationCallback;
|
||||
|
||||
protected AbstractEntityWindowLayout() {
|
||||
this.binder = new Binder<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntity(final T proxyEntity) {
|
||||
binder.setBean(proxyEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getEntity() {
|
||||
return binder.getBean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addValidationListener(final Consumer<Boolean> validationCallback) {
|
||||
binder.addStatusChangeListener(event -> validationCallback.accept(event.getBinder().isValid()));
|
||||
this.validationCallback = validationCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Validation callback event
|
||||
*/
|
||||
public Optional<Consumer<Boolean>> getValidationCallback() {
|
||||
return Optional.ofNullable(validationCallback);
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
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;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
/**
|
||||
* Abstract class managing event listeners aware layouts.
|
||||
*
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Adds event aware layout.
|
||||
*
|
||||
* @param eventAwareLayout
|
||||
* event aware layout to add
|
||||
*/
|
||||
protected void addEventAwareLayout(final EventListenersAwareLayout eventAwareLayout) {
|
||||
if (eventAwareLayout != null) {
|
||||
eventAwareLayouts.add(eventAwareLayout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a list of event aware layouts.
|
||||
*
|
||||
* @param eventAwareLayouts
|
||||
* event aware layouts to add
|
||||
*/
|
||||
protected void addEventAwareLayouts(final Collection<EventListenersAwareLayout> eventAwareLayouts) {
|
||||
eventAwareLayouts.forEach(this::addEventAwareLayout);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
protected void init() {
|
||||
buildLayout();
|
||||
initial = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds view layout.
|
||||
*
|
||||
*/
|
||||
protected abstract void buildLayout();
|
||||
|
||||
@Override
|
||||
public void enter(final ViewChangeEvent event) {
|
||||
subscribeListeners();
|
||||
|
||||
if (initial) {
|
||||
restoreState();
|
||||
initial = false;
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes all listeners of added event aware layouts to event bus.
|
||||
*
|
||||
*/
|
||||
protected void subscribeListeners() {
|
||||
eventAwareLayouts.forEach(EventListenersAwareLayout::subscribeListeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores session state of added event aware layouts.
|
||||
*
|
||||
*/
|
||||
protected void restoreState() {
|
||||
eventAwareLayouts.forEach(EventListenersAwareLayout::restoreState);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
eventAwareLayouts.forEach(EventListenersAwareLayout::onViewEnter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeLeave(final ViewBeforeLeaveEvent event) {
|
||||
unsubscribeListeners();
|
||||
event.navigate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribes all listeners of added event aware layouts to event bus.
|
||||
*
|
||||
*/
|
||||
protected void unsubscribeListeners() {
|
||||
eventAwareLayouts.forEach(EventListenersAwareLayout::unsubscribeListeners);
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
unsubscribeListeners();
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload;
|
||||
import org.eclipse.hawkbit.ui.common.event.EntityModifiedEventPayload.EntityModifiedEventType;
|
||||
|
||||
/**
|
||||
* Window controller for entity updates.
|
||||
*
|
||||
* @param <T>
|
||||
* Type of proxy entity
|
||||
* @param <E>
|
||||
* Second type of proxy entity
|
||||
* @param <R>
|
||||
* Type of repository entity
|
||||
*/
|
||||
public abstract class AbstractUpdateEntityWindowController<T, E, R> extends AbstractEntityWindowController<T, E, R> {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
*/
|
||||
protected AbstractUpdateEntityWindowController(final CommonUiDependencies uiDependencies) {
|
||||
super(uiDependencies);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPersistSuccessMessageKey() {
|
||||
return "message.update.success";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPersistFailureMessageKey() {
|
||||
return "message.deleted.or.notAllowed";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityModifiedEventPayload createModifiedEventPayload(final R entity) {
|
||||
return new EntityModifiedEventPayload(EntityModifiedEventType.ENTITY_UPDATED, getParentEntityClass(),
|
||||
getEntityClass(), getId(entity));
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyNamedEntity;
|
||||
|
||||
/**
|
||||
* Window controller for entity updates.
|
||||
*
|
||||
* @param <T>
|
||||
* Type of proxy entity
|
||||
* @param <E>
|
||||
* Second type of proxy entity
|
||||
* @param <R>
|
||||
* Type of repository entity
|
||||
*/
|
||||
public abstract class AbstractUpdateNamedEntityWindowController<T, E extends ProxyNamedEntity, R extends NamedEntity>
|
||||
extends AbstractUpdateEntityWindowController<T, E, R> {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
*/
|
||||
protected AbstractUpdateNamedEntityWindowController(final CommonUiDependencies uiDependencies) {
|
||||
super(uiDependencies);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDisplayableName(final R entity) {
|
||||
return entity.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDisplayableNameForFailedMessage(final E entity) {
|
||||
return entity.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getId(final R entity) {
|
||||
return entity.getId();
|
||||
}
|
||||
}
|
||||
@@ -1,318 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.decorators.SPUIButtonDecorator;
|
||||
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorderWithIcon;
|
||||
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 org.springframework.util.StringUtils;
|
||||
|
||||
import com.vaadin.event.ShortcutAction.KeyCode;
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.ui.AbstractComponent;
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.Button;
|
||||
import com.vaadin.ui.Button.ClickEvent;
|
||||
import com.vaadin.ui.Button.ClickListener;
|
||||
import com.vaadin.ui.Component;
|
||||
import com.vaadin.ui.GridLayout;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.Link;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
import com.vaadin.ui.Window;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
/**
|
||||
*
|
||||
* Table pop-up-windows including a minimize and close icon in the upper right
|
||||
* corner and a save and cancel button at the bottom. Is not intended to reuse.
|
||||
*
|
||||
*/
|
||||
public class CommonDialogWindow extends Window {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
|
||||
private final VerticalLayout mainLayout;
|
||||
private final String caption;
|
||||
private final Component content;
|
||||
private final String helpLink;
|
||||
private final ConfirmStyle confirmStyle;
|
||||
private final Class<? extends SPUIButtonDecorator> buttonDecorator;
|
||||
private Button confirmButton;
|
||||
private Button cancelButton;
|
||||
private HorizontalLayout buttonsLayout;
|
||||
private Label mandatoryLabel;
|
||||
|
||||
private final ClickListener cancelButtonClickListener;
|
||||
private final ClickListener closeClickListener;
|
||||
|
||||
private transient SaveDialogCloseListener closeListener;
|
||||
|
||||
/**
|
||||
* Different kinds of confirm buttons
|
||||
*/
|
||||
public enum ConfirmStyle {
|
||||
SAVE, OK, CONFIRM, NEXT
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param caption
|
||||
* the caption
|
||||
* @param content
|
||||
* the content
|
||||
* @param helpLink
|
||||
* the helpLinks
|
||||
* @param closeListener
|
||||
* the saveDialogCloseListener
|
||||
* @param cancelButtonClickListener
|
||||
* the cancelButtonClickListener
|
||||
* @param confirmStyle
|
||||
* what kind of button is used
|
||||
* @param buttonDecorator
|
||||
* to style the confirm and cancel buttons
|
||||
* @param i18n
|
||||
* internationalization
|
||||
*/
|
||||
public CommonDialogWindow(final String caption, final Component content, final String helpLink,
|
||||
final SaveDialogCloseListener closeListener, final ClickListener cancelButtonClickListener,
|
||||
final ConfirmStyle confirmStyle, final Class<? extends SPUIButtonDecorator> buttonDecorator,
|
||||
final VaadinMessageSource i18n) {
|
||||
this.caption = caption;
|
||||
this.content = content;
|
||||
this.helpLink = helpLink;
|
||||
this.closeListener = closeListener;
|
||||
this.cancelButtonClickListener = cancelButtonClickListener;
|
||||
this.confirmStyle = confirmStyle;
|
||||
this.buttonDecorator = buttonDecorator;
|
||||
this.i18n = i18n;
|
||||
|
||||
this.mainLayout = new VerticalLayout();
|
||||
this.closeClickListener = this::onCloseEvent;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private void onCloseEvent(final ClickEvent clickEvent) {
|
||||
if (!clickEvent.getButton().equals(confirmButton)) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!closeListener.canWindowSaveOrUpdate()) {
|
||||
return;
|
||||
}
|
||||
closeListener.saveOrUpdate();
|
||||
|
||||
if (closeListener.canWindowClose()) {
|
||||
close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
super.close();
|
||||
this.confirmButton.setEnabled(false);
|
||||
}
|
||||
|
||||
private final void init() {
|
||||
mainLayout.setMargin(false);
|
||||
mainLayout.setSpacing(false);
|
||||
|
||||
if (content instanceof GridLayout) {
|
||||
addStyleName("marginTop");
|
||||
}
|
||||
|
||||
if (content != null) {
|
||||
mainLayout.addComponent(content);
|
||||
mainLayout.setExpandRatio(content, 1.0F);
|
||||
}
|
||||
|
||||
createMandatoryLabel();
|
||||
|
||||
final HorizontalLayout buttonLayout = createActionButtonsLayout();
|
||||
mainLayout.addComponent(buttonLayout);
|
||||
mainLayout.setComponentAlignment(buttonLayout, Alignment.TOP_CENTER);
|
||||
|
||||
setCaptionAsHtml(false);
|
||||
setCaption(caption);
|
||||
setContent(mainLayout);
|
||||
setResizable(false);
|
||||
center();
|
||||
setModal(true);
|
||||
addStyleName("fontsize");
|
||||
}
|
||||
|
||||
protected void addCloseListenerForSaveButton() {
|
||||
confirmButton.addClickListener(closeClickListener);
|
||||
}
|
||||
|
||||
protected void addCloseListenerForCancelButton() {
|
||||
cancelButton.addClickListener(closeClickListener);
|
||||
}
|
||||
|
||||
private HorizontalLayout createActionButtonsLayout() {
|
||||
|
||||
buttonsLayout = new HorizontalLayout();
|
||||
buttonsLayout.setSizeFull();
|
||||
buttonsLayout.addStyleName("actionButtonsMargin");
|
||||
|
||||
createSaveButton();
|
||||
createCancelButton();
|
||||
|
||||
addHelpLink();
|
||||
|
||||
return buttonsLayout;
|
||||
}
|
||||
|
||||
private void createMandatoryLabel() {
|
||||
|
||||
mandatoryLabel = new Label(i18n.getMessage("label.mandatory.field"));
|
||||
mandatoryLabel.addStyleName(SPUIStyleDefinitions.SP_TEXTFIELD_ERROR + " " + ValoTheme.LABEL_TINY);
|
||||
|
||||
mainLayout.addComponent(mandatoryLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the line that explains the mandatory decorator
|
||||
*
|
||||
*/
|
||||
public void hideMandatoryExplanation() {
|
||||
if (mandatoryLabel != null) {
|
||||
mainLayout.removeComponent(mandatoryLabel);
|
||||
}
|
||||
}
|
||||
|
||||
private void createCancelButton() {
|
||||
cancelButton = SPUIComponentProvider.getButton(UIComponentIdProvider.CANCEL_BUTTON,
|
||||
i18n.getMessage(UIMessageIdProvider.BUTTON_CANCEL), "", "", true, VaadinIcons.CLOSE,
|
||||
SPUIButtonStyleNoBorderWithIcon.class);
|
||||
cancelButton.setSizeUndefined();
|
||||
cancelButton.addStyleName("default-color");
|
||||
addCloseListenerForCancelButton();
|
||||
if (cancelButtonClickListener != null) {
|
||||
cancelButton.addClickListener(cancelButtonClickListener);
|
||||
}
|
||||
|
||||
buttonsLayout.addComponent(cancelButton);
|
||||
buttonsLayout.setComponentAlignment(cancelButton, Alignment.MIDDLE_LEFT);
|
||||
buttonsLayout.setExpandRatio(cancelButton, 1.0F);
|
||||
}
|
||||
|
||||
private void createSaveButton() {
|
||||
if (confirmStyle == ConfirmStyle.SAVE) {
|
||||
confirmButton = SPUIComponentProvider.getButton(UIComponentIdProvider.SAVE_BUTTON,
|
||||
i18n.getMessage(UIMessageIdProvider.BUTTON_SAVE), "", "", true, VaadinIcons.HARDDRIVE,
|
||||
buttonDecorator);
|
||||
} else if (confirmStyle == ConfirmStyle.NEXT) {
|
||||
confirmButton = SPUIComponentProvider.getButton(UIComponentIdProvider.OK_BUTTON,
|
||||
i18n.getMessage(UIMessageIdProvider.BUTTON_NEXT), "", ValoTheme.BUTTON_PRIMARY, false, null,
|
||||
buttonDecorator);
|
||||
} else if (confirmStyle == ConfirmStyle.CONFIRM) {
|
||||
confirmButton = SPUIComponentProvider.getButton(UIComponentIdProvider.OK_BUTTON,
|
||||
i18n.getMessage(UIMessageIdProvider.BUTTON_CONFIRM), "", ValoTheme.BUTTON_PRIMARY, false, null,
|
||||
buttonDecorator);
|
||||
} else {
|
||||
confirmButton = SPUIComponentProvider.getButton(UIComponentIdProvider.OK_BUTTON,
|
||||
i18n.getMessage(UIMessageIdProvider.BUTTON_OK), "", ValoTheme.BUTTON_PRIMARY, false, null,
|
||||
buttonDecorator);
|
||||
}
|
||||
confirmButton.setSizeUndefined();
|
||||
confirmButton.addStyleName("default-color");
|
||||
addCloseListenerForSaveButton();
|
||||
confirmButton.setEnabled(false);
|
||||
confirmButton.setClickShortcut(KeyCode.ENTER);
|
||||
buttonsLayout.addComponent(confirmButton);
|
||||
buttonsLayout.setComponentAlignment(confirmButton, Alignment.MIDDLE_RIGHT);
|
||||
buttonsLayout.setExpandRatio(confirmButton, 1.0F);
|
||||
}
|
||||
|
||||
private void addHelpLink() {
|
||||
|
||||
if (StringUtils.isEmpty(helpLink)) {
|
||||
return;
|
||||
}
|
||||
final Link helpLinkComponent = SPUIComponentProvider.getHelpLink(i18n, helpLink);
|
||||
buttonsLayout.addComponent(helpLinkComponent);
|
||||
buttonsLayout.setComponentAlignment(helpLinkComponent, Alignment.MIDDLE_RIGHT);
|
||||
}
|
||||
|
||||
public AbstractComponent getButtonsLayout() {
|
||||
return this.buttonsLayout;
|
||||
}
|
||||
|
||||
public VerticalLayout getMainLayout() {
|
||||
return mainLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the save confirmation button
|
||||
*
|
||||
* @param enabled
|
||||
* boolean
|
||||
*
|
||||
*/
|
||||
public void setSaveButtonEnabled(final boolean enabled) {
|
||||
confirmButton.setEnabled(enabled);
|
||||
}
|
||||
|
||||
public void setCancelButtonEnabled(final boolean enabled) {
|
||||
cancelButton.setEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the close listener in save dialog
|
||||
*
|
||||
* @param closeListener
|
||||
* SaveDialogCloseListener
|
||||
*/
|
||||
public void setCloseListener(final SaveDialogCloseListener closeListener) {
|
||||
this.closeListener = closeListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the safe action can executed. After a the save action the
|
||||
* listener checks if the dialog can closed.
|
||||
*
|
||||
*/
|
||||
public interface SaveDialogCloseListener {
|
||||
|
||||
/**
|
||||
* Checks if the safe action can executed.
|
||||
*
|
||||
* @return <true> = save action can executed <false> = cannot execute
|
||||
* safe action .
|
||||
*/
|
||||
boolean canWindowSaveOrUpdate();
|
||||
|
||||
/**
|
||||
* Checks if the window can be closed after the save action is executed
|
||||
*
|
||||
* @return <true> = window will close <false> = will not closed.
|
||||
*/
|
||||
default boolean canWindowClose() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves/Updates action. Is called if canWindowSaveOrUpdate is <true>.
|
||||
*
|
||||
*/
|
||||
void saveOrUpdate();
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
/**
|
||||
* Container for commonly used dependencies in the UI.
|
||||
*/
|
||||
public class CommonUiDependencies {
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
private final EntityFactory entityFactory;
|
||||
private final UIEventBus eventBus;
|
||||
private final UINotification uiNotification;
|
||||
private final SpPermissionChecker permChecker;
|
||||
|
||||
/**
|
||||
* Public constructor.
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param entityFactory
|
||||
* EntityFactory
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param uiNotification
|
||||
* UINotification
|
||||
* @param permChecker
|
||||
* {@link SpPermissionChecker}
|
||||
*/
|
||||
public CommonUiDependencies(final VaadinMessageSource i18n, final EntityFactory entityFactory,
|
||||
final UIEventBus eventBus, final UINotification uiNotification, final SpPermissionChecker permChecker) {
|
||||
super();
|
||||
this.i18n = i18n;
|
||||
this.entityFactory = entityFactory;
|
||||
this.eventBus = eventBus;
|
||||
this.uiNotification = uiNotification;
|
||||
this.permChecker = permChecker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link VaadinMessageSource}
|
||||
*
|
||||
* @return the i18n
|
||||
*/
|
||||
public VaadinMessageSource getI18n() {
|
||||
return i18n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link EntityFactory}
|
||||
*
|
||||
* @return the entityFactory
|
||||
*/
|
||||
public EntityFactory getEntityFactory() {
|
||||
return entityFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link UIEventBus}
|
||||
*
|
||||
* @return the eventBus
|
||||
*/
|
||||
public UIEventBus getEventBus() {
|
||||
return eventBus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link UINotification}
|
||||
*
|
||||
* @return the uiNotification
|
||||
*/
|
||||
public UINotification getUiNotification() {
|
||||
return uiNotification;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link SpPermissionChecker}
|
||||
*
|
||||
* @return the permChecker
|
||||
*/
|
||||
public SpPermissionChecker getPermChecker() {
|
||||
return permChecker;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.ConfirmStyle;
|
||||
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.SaveDialogCloseListener;
|
||||
import org.eclipse.hawkbit.ui.common.builder.WindowBuilder;
|
||||
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleTiny;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.vaadin.server.Resource;
|
||||
import com.vaadin.server.Sizeable.Unit;
|
||||
import com.vaadin.shared.ui.ContentMode;
|
||||
import com.vaadin.ui.Component;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
import com.vaadin.ui.Window;
|
||||
|
||||
/**
|
||||
* Class for the confirmation dialog which pops up when deleting, assigning...
|
||||
* entities.
|
||||
*/
|
||||
public class ConfirmationDialog implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final transient Runnable callback;
|
||||
|
||||
private final CommonDialogWindow window;
|
||||
|
||||
public static Builder newBuilder(final VaadinMessageSource i18n, final String id) {
|
||||
return new Builder(i18n, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for configuring confirmation dialog.
|
||||
*
|
||||
* @param i18n
|
||||
* internationalization
|
||||
* @param caption
|
||||
* the dialog caption.
|
||||
* @param question
|
||||
* the question.
|
||||
* @param hint
|
||||
* added in the dialog
|
||||
* @param onSaveOrUpdate
|
||||
* the callback onSaveOrUpdate.
|
||||
* @param onCancel
|
||||
* the callback on cancel.
|
||||
* @param icon
|
||||
* the icon of the dialog
|
||||
* @param id
|
||||
* the id of the confirmation dialog
|
||||
* @param tab
|
||||
* ConfirmationTab which contains more information about the action
|
||||
* which has to be confirmed, e.g. maintenance window
|
||||
*/
|
||||
private ConfirmationDialog(final VaadinMessageSource i18n, final String caption, final String question,
|
||||
final String hint, final Runnable onSaveOrUpdate, final Runnable onCancel, final Resource icon,
|
||||
final String id, final Component tab) {
|
||||
|
||||
final VerticalLayout content = new VerticalLayout();
|
||||
content.setMargin(false);
|
||||
content.setSpacing(false);
|
||||
|
||||
if (question != null) {
|
||||
content.addComponent(createConfirmationLabel(question));
|
||||
}
|
||||
if (hint != null) {
|
||||
content.addComponent(createConfirmationLabel(hint));
|
||||
}
|
||||
if (tab != null) {
|
||||
content.addComponent(tab);
|
||||
}
|
||||
final WindowBuilder windowBuilder = new WindowBuilder(SPUIDefinitions.CONFIRMATION_WINDOW).caption(caption)
|
||||
.content(content).cancelButtonClickListener(e -> {
|
||||
if (onCancel != null) {
|
||||
onCancel.run();
|
||||
}
|
||||
}).saveDialogCloseListener(getSaveDialogCloseListener()).hideMandatoryExplanation()
|
||||
.buttonDecorator(SPUIButtonStyleTiny.class).confirmStyle(ConfirmStyle.OK).i18n(i18n);
|
||||
|
||||
if (!StringUtils.isEmpty(id)) {
|
||||
windowBuilder.id(id);
|
||||
}
|
||||
this.window = windowBuilder.buildCommonDialogWindow();
|
||||
window.setSaveButtonEnabled(true);
|
||||
this.callback = onSaveOrUpdate;
|
||||
|
||||
if (icon != null) {
|
||||
window.setIcon(icon);
|
||||
}
|
||||
|
||||
window.addStyleName(SPUIStyleDefinitions.CONFIRMBOX_WINDOW_STYLE);
|
||||
}
|
||||
|
||||
private SaveDialogCloseListener getSaveDialogCloseListener() {
|
||||
return new SaveDialogCloseListener() {
|
||||
@Override
|
||||
public void saveOrUpdate() {
|
||||
if (callback != null) {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWindowSaveOrUpdate() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Label createConfirmationLabel(final String text) {
|
||||
// ContentMode.HTML is used instead of ContentMode.PREFORMATTED here due
|
||||
// to no linebreaks if an entity name is very long
|
||||
final String questionHtmlSave = HawkbitCommonUtil.sanitizeHtml(text);
|
||||
final Label questionLbl = new Label(questionHtmlSave, ContentMode.HTML);
|
||||
questionLbl.setWidth(100, Unit.PERCENTAGE);
|
||||
questionLbl.addStyleName(SPUIStyleDefinitions.CONFIRMBOX_QUESTION_LABEL);
|
||||
|
||||
return questionLbl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the ok save button
|
||||
*
|
||||
* @param enabled
|
||||
* boolean
|
||||
*/
|
||||
public void setOkButtonEnabled(final boolean enabled) {
|
||||
window.setSaveButtonEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return confirmation window
|
||||
*/
|
||||
public Window getWindow() {
|
||||
return window;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for a confirmation dialog
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
private final String id;
|
||||
private String caption;
|
||||
private String question;
|
||||
private String hint;
|
||||
private Resource icon;
|
||||
private Component tab;
|
||||
|
||||
private Runnable callbackOnSaveOrUpdate;
|
||||
|
||||
private Runnable callbackOnCancel;
|
||||
|
||||
/**
|
||||
* private constructor
|
||||
*
|
||||
* @param i18n
|
||||
* required field
|
||||
* @param id
|
||||
* required field
|
||||
*/
|
||||
Builder(final VaadinMessageSource i18n, final String id) {
|
||||
this.i18n = i18n;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Builder caption(final String caption) {
|
||||
this.caption = caption;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder question(final String question) {
|
||||
this.question = question;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder hint(final String hint) {
|
||||
this.hint = hint;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder icon(final Resource icon) {
|
||||
this.icon = icon;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder tab(final Component tab) {
|
||||
this.tab = tab;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder onSaveOrUpdate(final Runnable callback) {
|
||||
this.callbackOnSaveOrUpdate = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder onCancel(final Runnable callback) {
|
||||
this.callbackOnCancel = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ConfirmationDialog build() {
|
||||
Assert.isTrue(StringUtils.hasText(caption), "Caption cannot be null.");
|
||||
return new ConfirmationDialog(i18n, caption, question, hint, callbackOnSaveOrUpdate, callbackOnCancel, icon,
|
||||
id, tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
import com.vaadin.shared.ui.colorpicker.Color;
|
||||
import com.vaadin.ui.AbstractColorPicker.Coordinates2Color;
|
||||
|
||||
/**
|
||||
* Converts 2d-coordinates to a Color.
|
||||
*/
|
||||
public class CoordinatesToColor implements Coordinates2Color {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Color calculate(final int x, final int y) {
|
||||
return calculateHSVColor(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] calculate(final Color color) {
|
||||
final float[] hsv = color.getHSV();
|
||||
final int x = (int) Math.round(hsv[0] * 220.0);
|
||||
final int y = calculateYCoordinateOfColor(hsv);
|
||||
return new int[] { x, y };
|
||||
}
|
||||
|
||||
private static Color calculateHSVColor(final int x, final int y) {
|
||||
final float h = (float) (x / 220.0);
|
||||
float s = 1F;
|
||||
float v = 1F;
|
||||
if (y < 110) {
|
||||
s = (float) (y / 110.0);
|
||||
} else if (y > 110) {
|
||||
v = (float) (1.0 - (y - 110.0) / 110.0);
|
||||
}
|
||||
return new Color(Color.HSVtoRGB(h, s, v));
|
||||
}
|
||||
|
||||
private static int calculateYCoordinateOfColor(final float[] hsv) {
|
||||
int y;
|
||||
// lower half
|
||||
/* Assuming hsv[] array value will have in the range of 0 to 1 */
|
||||
if (hsv[1] < 1F) {
|
||||
y = (int) Math.round(hsv[1] * 110.0);
|
||||
} else {
|
||||
y = (int) Math.round(110.0 - ((double) hsv[1] + (double) hsv[2]) * 110.0);
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
/**
|
||||
* Base function for a validator used in window controllers.
|
||||
*/
|
||||
public class EntityValidator {
|
||||
|
||||
private final CommonUiDependencies uiDependencies;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param uiDependencies
|
||||
* {@link CommonUiDependencies}
|
||||
*/
|
||||
protected EntityValidator(final CommonUiDependencies uiDependencies) {
|
||||
this.uiDependencies = uiDependencies;
|
||||
|
||||
}
|
||||
|
||||
protected void displayValidationError(final String messageKey, final Object... args) {
|
||||
uiDependencies.getUiNotification()
|
||||
.displayValidationError(uiDependencies.getI18n().getMessage(messageKey, args));
|
||||
}
|
||||
|
||||
protected VaadinMessageSource getI18n() {
|
||||
return uiDependencies.getI18n();
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.vaadin.ui.ComponentContainer;
|
||||
|
||||
/**
|
||||
* Interface for entity window layout
|
||||
*
|
||||
* @param <T>
|
||||
* Generic type entity
|
||||
*/
|
||||
public interface EntityWindowLayout<T> {
|
||||
|
||||
ComponentContainer getRootComponent();
|
||||
|
||||
void setEntity(final T proxyEntity);
|
||||
|
||||
T getEntity();
|
||||
|
||||
/**
|
||||
* Method to add validation listeners.
|
||||
*
|
||||
* @param validationCallback
|
||||
* Validation callback event
|
||||
*/
|
||||
void addValidationListener(final Consumer<Boolean> validationCallback);
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Interface for event aware event listeners
|
||||
*
|
||||
*/
|
||||
public interface EventListenersAwareLayout {
|
||||
|
||||
/**
|
||||
* Restore components state
|
||||
*/
|
||||
default void restoreState() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Update components on view enter
|
||||
*/
|
||||
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
|
||||
*/
|
||||
default void subscribeListeners() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe event listeners
|
||||
*/
|
||||
default void unsubscribeListeners() {
|
||||
}
|
||||
}
|
||||
@@ -1,219 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
|
||||
import org.eclipse.hawkbit.im.authentication.UserPrincipal;
|
||||
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||
import org.eclipse.hawkbit.ui.utils.SpringContextHolder;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
||||
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
|
||||
import com.vaadin.server.VaadinService;
|
||||
|
||||
/**
|
||||
* A Utility class to user details e.g. username
|
||||
*/
|
||||
public final class UserDetailsFormatter {
|
||||
|
||||
private static final String TRIM_APPENDIX = "...";
|
||||
|
||||
private UserDetailsFormatter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load user details by the user name and format the user name to max 100
|
||||
* characters. See
|
||||
* {@link UserDetailsFormatter#loadAndFormatUsername(String, int)}.
|
||||
*
|
||||
* @param username
|
||||
* the user name
|
||||
* @return the formatted user name (max 100 characters) cannot be <null>
|
||||
*/
|
||||
public static String loadAndFormatUsername(final String username) {
|
||||
return loadAndFormatUsername(username, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load user details by {@link BaseEntity#getCreatedBy()} and format the
|
||||
* user name. Use {@link UserDetailsFormatter#loadAndFormatUsername(String)}
|
||||
*
|
||||
* @param baseEntity
|
||||
* the entity
|
||||
* @return the formatted 'created at user name' (max 100 characters) cannot
|
||||
* be <null>
|
||||
*/
|
||||
public static String loadAndFormatCreatedBy(final BaseEntity baseEntity) {
|
||||
if (baseEntity == null || baseEntity.getCreatedBy() == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return loadAndFormatUsername(baseEntity.getCreatedBy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Load user details by {@link BaseEntity#getLastModifiedBy()} and format
|
||||
* the user name. Use
|
||||
* {@link UserDetailsFormatter#loadAndFormatUsername(String)}
|
||||
*
|
||||
* @param baseEntity
|
||||
* the entity
|
||||
* @return the formatted 'last modified by user name' (max 100 characters)
|
||||
* cannot be <null>
|
||||
*/
|
||||
public static String loadAndFormatLastModifiedBy(final BaseEntity baseEntity) {
|
||||
if (baseEntity == null || baseEntity.getLastModifiedBy() == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return loadAndFormatUsername(baseEntity.getLastModifiedBy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Load user details by the current session information and format the user
|
||||
* name to max 12 characters. @see
|
||||
* {@link UserDetailsFormatter#loadAndFormatUsername(String, int)}
|
||||
*
|
||||
* @return the formatted user name (max 12 characters) cannot be <null>
|
||||
*/
|
||||
public static String formatCurrentUsername() {
|
||||
return loadAndFormatUsername(getCurrentUser().getUsername(), 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load user details by the user name and format the user name. If the
|
||||
* loaded {@link UserDetails} is not an instance of a {@link UserPrincipal},
|
||||
* then just the {@link UserDetails#getUsername()} will return.
|
||||
*
|
||||
* If first and last name available, they will combined. Otherwise the
|
||||
* {@link UserPrincipal#getLoginname()} will formatted. The formatted name
|
||||
* is reduced to 100 characters.
|
||||
*
|
||||
* @param username
|
||||
* the user name
|
||||
* @param expectedNameLength
|
||||
* the name size of each name part
|
||||
* @return the formatted user name (max expectedNameLength characters)
|
||||
* cannot be <null>
|
||||
*/
|
||||
public static String loadAndFormatUsername(final String username, final int expectedNameLength) {
|
||||
final UserDetails userDetails = loadUserByUsername(username);
|
||||
return formatUserName(expectedNameLength, userDetails);
|
||||
}
|
||||
|
||||
private static String formatUserName(final int expectedNameLength, final UserDetails userDetails) {
|
||||
if (!(userDetails instanceof UserPrincipal)) {
|
||||
return userDetails.getUsername();
|
||||
}
|
||||
|
||||
final UserPrincipal userPrincipal = (UserPrincipal) userDetails;
|
||||
return trimAndFormatDetail(userPrincipal.getLoginname(), expectedNameLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the current tenant. The information is loaded by the current
|
||||
* session information.
|
||||
*
|
||||
* @return the formatted user name (max 8 characters) can be <null>
|
||||
*/
|
||||
public static String formatCurrentTenant() {
|
||||
final UserDetails userDetails = getCurrentUser();
|
||||
if (!(userDetails instanceof UserPrincipal)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final UserPrincipal userPrincipal = (UserPrincipal) userDetails;
|
||||
return trimAndFormatDetail(userPrincipal.getTenant(), 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the current tenant. The information is loaded by the current
|
||||
* session information.
|
||||
*
|
||||
* @return the formatted user name (max 8 characters) can be <null>
|
||||
*/
|
||||
public static Optional<String> getCurrentTenant() {
|
||||
final UserDetails userDetails = getCurrentUser();
|
||||
if (!(userDetails instanceof UserPrincipal)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
final UserPrincipal userPrincipal = (UserPrincipal) userDetails;
|
||||
return Optional.of(userPrincipal.getTenant().trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return logged in users Email address
|
||||
*/
|
||||
public static Optional<String> getCurrentUserEmail() {
|
||||
final UserDetails userDetails = getCurrentUser();
|
||||
if (!(userDetails instanceof UserPrincipal)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
final UserPrincipal userPrincipal = (UserPrincipal) userDetails;
|
||||
|
||||
return Optional.ofNullable(userPrincipal.getEmail());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Details of currently logged-in user
|
||||
*/
|
||||
public static UserDetails getCurrentUser() {
|
||||
final SecurityContext context = (SecurityContext) VaadinService.getCurrentRequest().getWrappedSession()
|
||||
.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
|
||||
final Authentication authentication = context.getAuthentication();
|
||||
if (authentication instanceof OAuth2AuthenticationToken) {
|
||||
final OidcUser oidcUser = (OidcUser) authentication.getPrincipal();
|
||||
final Object details = authentication.getDetails();
|
||||
String tenant = "DEFAULT";
|
||||
if (details instanceof TenantAwareAuthenticationDetails) {
|
||||
tenant = ((TenantAwareAuthenticationDetails) details).getTenant();
|
||||
}
|
||||
return new UserPrincipal(oidcUser.getPreferredUsername(), "***", oidcUser.getGivenName(),
|
||||
oidcUser.getFamilyName(), oidcUser.getPreferredUsername(), oidcUser.getEmail(), tenant,
|
||||
oidcUser.getAuthorities());
|
||||
} else {
|
||||
return (UserDetails) authentication.getPrincipal();
|
||||
}
|
||||
}
|
||||
|
||||
private static String trimAndFormatDetail(final String formatString, final int expectedDetailLength) {
|
||||
final String detail = StringUtils.defaultIfEmpty(formatString, "");
|
||||
final String trimmedDetail = StringUtils.substring(detail, 0, expectedDetailLength);
|
||||
if (StringUtils.length(detail) > expectedDetailLength) {
|
||||
return trimmedDetail + TRIM_APPENDIX;
|
||||
}
|
||||
return trimmedDetail;
|
||||
}
|
||||
|
||||
// Exception squid:S1166 - exception has to be hidden
|
||||
@SuppressWarnings({ "squid:S1166" })
|
||||
private static UserDetails loadUserByUsername(final String username) {
|
||||
final UserDetailsService userDetailsService = SpringContextHolder.getInstance()
|
||||
.getBean(UserDetailsService.class);
|
||||
try {
|
||||
return userDetailsService.loadUserByUsername(username);
|
||||
} catch (final UsernameNotFoundException e) {
|
||||
return new User(username, "", Collections.emptyList());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
/**
|
||||
* Interface for getting view name
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ViewNameAware {
|
||||
|
||||
/**
|
||||
* Provides the name of a view
|
||||
*
|
||||
* @return view name
|
||||
*/
|
||||
String getViewName();
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.builder;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.vaadin.ui.AbstractTextField;
|
||||
|
||||
/**
|
||||
* Abstract Text field builder.
|
||||
*
|
||||
* @param <T>
|
||||
* type of the builder
|
||||
* @param <E>
|
||||
* the text component
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractTextFieldBuilder<T, E extends AbstractTextField> {
|
||||
|
||||
private String caption;
|
||||
private String style;
|
||||
private String styleName;
|
||||
private String prompt;
|
||||
private String id;
|
||||
private boolean readOnly;
|
||||
private boolean enabled = true;
|
||||
private final int maxLengthAllowed;
|
||||
|
||||
protected AbstractTextFieldBuilder(final int maxLengthAllowed) {
|
||||
this.maxLengthAllowed = maxLengthAllowed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add caption to text field
|
||||
*
|
||||
* @param caption
|
||||
* the caption to set
|
||||
* @return the builder
|
||||
*/
|
||||
public T caption(final String caption) {
|
||||
this.caption = caption;
|
||||
this.prompt = caption;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add style to text field
|
||||
*
|
||||
* @param style
|
||||
* the style to set * @return the builder
|
||||
* @return the builder
|
||||
*/
|
||||
public T style(final String style) {
|
||||
this.style = style;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add style name to text field
|
||||
*
|
||||
* @param styleName
|
||||
* the styleName to set
|
||||
* @return the builder
|
||||
*/
|
||||
public T styleName(final String styleName) {
|
||||
this.styleName = styleName;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add read only to text field
|
||||
*
|
||||
* @param readOnly
|
||||
* the readOnly to set
|
||||
* @return the builder
|
||||
*/
|
||||
public T readOnly(final boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the text field
|
||||
*
|
||||
* @param enabled
|
||||
* the enabled to set
|
||||
* @return the builder
|
||||
*/
|
||||
public T enabled(final boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add prompt to text field
|
||||
*
|
||||
* @param prompt
|
||||
* the prompt to set
|
||||
* @return the builder
|
||||
*/
|
||||
public T prompt(final String prompt) {
|
||||
this.prompt = prompt;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add id to text field
|
||||
*
|
||||
* @param id
|
||||
* the id to set
|
||||
* @return the builder
|
||||
*/
|
||||
public T id(final String id) {
|
||||
this.id = id;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a textfield
|
||||
*
|
||||
* @return textfield
|
||||
*/
|
||||
public E buildTextComponent() {
|
||||
final E textComponent = createTextComponent();
|
||||
|
||||
textComponent.setReadOnly(readOnly);
|
||||
textComponent.setEnabled(enabled);
|
||||
|
||||
if (!StringUtils.isEmpty(caption)) {
|
||||
textComponent.setCaption(caption);
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(style)) {
|
||||
textComponent.setStyleName(style);
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(styleName)) {
|
||||
textComponent.addStyleName(styleName);
|
||||
}
|
||||
if (!StringUtils.isEmpty(prompt)) {
|
||||
textComponent.setPlaceholder(prompt);
|
||||
}
|
||||
|
||||
if (maxLengthAllowed > 0) {
|
||||
textComponent.setMaxLength(maxLengthAllowed);
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(id)) {
|
||||
textComponent.setId(id);
|
||||
}
|
||||
|
||||
return textComponent;
|
||||
}
|
||||
|
||||
protected abstract E createTextComponent();
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.builder;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.vaadin.data.Binder.Binding;
|
||||
import com.vaadin.ui.Component;
|
||||
|
||||
/**
|
||||
* Holds a {@link Component} and its {@link Binding}
|
||||
*
|
||||
* @param <T>
|
||||
* Component type
|
||||
*/
|
||||
public class BoundComponent<T extends Component> implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final T component;
|
||||
private final Binding<?, ?> binding;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param component
|
||||
* component
|
||||
* @param binding
|
||||
* binding of the component
|
||||
*/
|
||||
public BoundComponent(final T component, final Binding<?, ?> binding) {
|
||||
this.component = component;
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The component
|
||||
*/
|
||||
public T getComponent() {
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the component is required
|
||||
*
|
||||
* @param isRequired
|
||||
* boolean
|
||||
*/
|
||||
public void setRequired(final boolean isRequired) {
|
||||
binding.setAsRequiredEnabled(isRequired);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return !binding.validate(false).isError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate binding
|
||||
*/
|
||||
public void validate() {
|
||||
binding.validate();
|
||||
}
|
||||
|
||||
/**
|
||||
* unbind the component
|
||||
*/
|
||||
public void unbind() {
|
||||
binding.unbind();
|
||||
}
|
||||
}
|
||||
@@ -1,423 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.builder;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
import org.eclipse.hawkbit.repository.model.NamedVersionedEntity;
|
||||
import org.eclipse.hawkbit.repository.model.Type;
|
||||
import org.eclipse.hawkbit.ui.common.data.aware.ActionTypeAware;
|
||||
import org.eclipse.hawkbit.ui.common.data.aware.DescriptionAware;
|
||||
import org.eclipse.hawkbit.ui.common.data.aware.DsIdAware;
|
||||
import org.eclipse.hawkbit.ui.common.data.aware.NameAware;
|
||||
import org.eclipse.hawkbit.ui.common.data.aware.StartOptionAware;
|
||||
import org.eclipse.hawkbit.ui.common.data.aware.TargetFilterQueryAware;
|
||||
import org.eclipse.hawkbit.ui.common.data.aware.TypeInfoAware;
|
||||
import org.eclipse.hawkbit.ui.common.data.aware.VersionAware;
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.AbstractProxyDataProvider;
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.DistributionSetStatelessDataProvider;
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.TargetFilterQueryDataProvider;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSet;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSetInfo;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQueryInfo;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTypeInfo;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.management.miscs.ActionTypeOptionGroupAssignmentLayout;
|
||||
import org.eclipse.hawkbit.ui.rollout.window.components.AutoStartOptionGroupLayout;
|
||||
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.TrimmingStringConverter;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.vaadin.data.Binder;
|
||||
import com.vaadin.data.Binder.Binding;
|
||||
import com.vaadin.data.Binder.BindingBuilder;
|
||||
import com.vaadin.data.Validator;
|
||||
import com.vaadin.data.ValueProvider;
|
||||
import com.vaadin.server.Setter;
|
||||
import com.vaadin.ui.CheckBox;
|
||||
import com.vaadin.ui.ComboBox;
|
||||
import com.vaadin.ui.TextArea;
|
||||
import com.vaadin.ui.TextField;
|
||||
|
||||
/**
|
||||
* Builder class for from components
|
||||
*/
|
||||
public final class FormComponentBuilder {
|
||||
public static final String TEXTFIELD_NAME = "textfield.name";
|
||||
public static final String TEXTFIELD_VERSION = "textfield.version";
|
||||
public static final String TEXTFIELD_DESCRIPTION = "textfield.description";
|
||||
|
||||
public static final String PROMPT_DISTRIBUTION_SET = "prompt.distribution.set";
|
||||
public static final String PROMPT_TARGET_FILTER = "prompt.target.filter";
|
||||
|
||||
public static final String CAPTION_TYPE = "caption.type";
|
||||
|
||||
private FormComponentBuilder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an input field for a name
|
||||
*
|
||||
* @param <T>
|
||||
* type of the binder
|
||||
* @param binder
|
||||
* that is bound to the field
|
||||
* @param i18n
|
||||
* message source
|
||||
* @param fieldId
|
||||
* id of the field
|
||||
* @return the TextField with its Binding
|
||||
*/
|
||||
public static <T extends NameAware> BoundComponent<TextField> createNameInput(final Binder<T> binder,
|
||||
final VaadinMessageSource i18n, final String fieldId) {
|
||||
final TextField nameInput = new TextFieldBuilder(NamedEntity.NAME_MAX_SIZE).id(fieldId)
|
||||
.caption(i18n.getMessage(TEXTFIELD_NAME)).prompt(i18n.getMessage(TEXTFIELD_NAME)).buildTextComponent();
|
||||
nameInput.setSizeUndefined();
|
||||
|
||||
final Binding<T, String> binding = binder.forField(nameInput).withConverter(new TrimmingStringConverter())
|
||||
.asRequired(i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_NAMEREQUIRED))
|
||||
.bind(NameAware::getName, NameAware::setName);
|
||||
|
||||
return new BoundComponent<>(nameInput, binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a required input field for a version
|
||||
*
|
||||
* @param <T>
|
||||
* type of the binder
|
||||
* @param binder
|
||||
* that is bound to the field
|
||||
* @param i18n
|
||||
* message source
|
||||
* @param fieldId
|
||||
* id of the field
|
||||
* @return the TextField
|
||||
*/
|
||||
public static <T extends VersionAware> BoundComponent<TextField> createVersionInput(final Binder<T> binder,
|
||||
final VaadinMessageSource i18n, final String fieldId) {
|
||||
final TextField versionInput = new TextFieldBuilder(NamedVersionedEntity.VERSION_MAX_SIZE).id(fieldId)
|
||||
.caption(i18n.getMessage(TEXTFIELD_VERSION)).prompt(i18n.getMessage(TEXTFIELD_VERSION))
|
||||
.buildTextComponent();
|
||||
versionInput.setSizeUndefined();
|
||||
|
||||
final Binding<T, String> binding = binder.forField(versionInput).withConverter(new TrimmingStringConverter())
|
||||
.asRequired(i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_VERSIONREQUIRED))
|
||||
.bind(VersionAware::getVersion, VersionAware::setVersion);
|
||||
|
||||
return new BoundComponent<>(versionInput, binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an optional input field for a description
|
||||
*
|
||||
* @param <T>
|
||||
* type of the binder
|
||||
* @param binder
|
||||
* that is bound to the field
|
||||
* @param i18n
|
||||
* message source
|
||||
* @param fieldId
|
||||
* id of the field
|
||||
* @return the TextArea
|
||||
*/
|
||||
public static <T extends DescriptionAware> BoundComponent<TextArea> createDescriptionInput(final Binder<T> binder,
|
||||
final VaadinMessageSource i18n, final String fieldId) {
|
||||
return createBigTextInput(binder, i18n, fieldId, TEXTFIELD_DESCRIPTION, TEXTFIELD_DESCRIPTION,
|
||||
DescriptionAware::getDescription, DescriptionAware::setDescription);
|
||||
}
|
||||
|
||||
public static <T> BoundComponent<TextArea> createBigTextInput(final Binder<T> binder,
|
||||
final VaadinMessageSource i18n, final String fieldId, final String caption, final String prompt,
|
||||
final ValueProvider<T, String> getter, final Setter<T, String> setter) {
|
||||
final TextArea descriptionInput = new TextAreaBuilder(NamedEntity.DESCRIPTION_MAX_SIZE).id(fieldId)
|
||||
.caption(i18n.getMessage(caption)).prompt(i18n.getMessage(prompt)).style("text-area-style")
|
||||
.buildTextComponent();
|
||||
descriptionInput.setSizeUndefined();
|
||||
|
||||
final Binding<T, String> binding = binder.forField(descriptionInput).bind(getter, setter);
|
||||
|
||||
return new BoundComponent<>(descriptionInput, binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a bound {@link ActionTypeOptionGroupAssignmentLayout}
|
||||
*
|
||||
* @param <T>
|
||||
* type of the binder
|
||||
* @param binder
|
||||
* that is bound to the layout
|
||||
* @param i18n
|
||||
* message source
|
||||
* @param componentId
|
||||
* id of the input layout
|
||||
* @return a bound layout
|
||||
*/
|
||||
public static <T extends ActionTypeAware> BoundComponent<ActionTypeOptionGroupAssignmentLayout> createActionTypeOptionGroupLayout(
|
||||
final Binder<T> binder, final VaadinMessageSource i18n, final String componentId) {
|
||||
final ActionTypeOptionGroupAssignmentLayout actionTypeOptionGroupLayout = new ActionTypeOptionGroupAssignmentLayout(
|
||||
i18n, componentId);
|
||||
|
||||
binder.forField(actionTypeOptionGroupLayout.getActionTypeOptionGroup()).bind(ActionTypeAware::getActionType,
|
||||
ActionTypeAware::setActionType);
|
||||
|
||||
final Binding<T, Long> binding = binder.forField(actionTypeOptionGroupLayout.getForcedTimeDateField())
|
||||
.asRequired(i18n.getMessage("message.forcedTime.cannotBeEmpty")).withConverter(localDateTime -> {
|
||||
if (localDateTime == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return SPDateTimeUtil.localDateTimeToEpochMilli(localDateTime);
|
||||
}, forcedTime -> {
|
||||
if (forcedTime == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return SPDateTimeUtil.epochMilliToLocalDateTime(forcedTime);
|
||||
}).bind(ActionTypeAware::getForcedTime, ActionTypeAware::setForcedTime);
|
||||
|
||||
return new BoundComponent<>(actionTypeOptionGroupLayout, binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a bound {@link AutoStartOptionGroupLayout}
|
||||
*
|
||||
* @param <T>
|
||||
* type of the binder
|
||||
* @param binder
|
||||
* that is bound to the layout
|
||||
* @param i18n
|
||||
* message source
|
||||
* @param componentId
|
||||
* id of the input layout
|
||||
* @return a bound layout
|
||||
*/
|
||||
public static <T extends StartOptionAware> BoundComponent<AutoStartOptionGroupLayout> createAutoStartOptionGroupLayout(
|
||||
final Binder<T> binder, final VaadinMessageSource i18n, final String componentId) {
|
||||
final AutoStartOptionGroupLayout autoStartOptionGroup = new AutoStartOptionGroupLayout(i18n, componentId);
|
||||
|
||||
binder.forField(autoStartOptionGroup.getAutoStartOptionGroup()).bind(StartOptionAware::getStartOption,
|
||||
StartOptionAware::setStartOption);
|
||||
|
||||
final Binding<T, Long> binding = binder.forField(autoStartOptionGroup.getStartAtDateField())
|
||||
.asRequired(i18n.getMessage("message.scheduledTime.cannotBeEmpty")).withConverter(localDateTime -> {
|
||||
if (localDateTime == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return SPDateTimeUtil.localDateTimeToEpochMilli(localDateTime);
|
||||
}, startAtTime -> {
|
||||
if (startAtTime == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return SPDateTimeUtil.epochMilliToLocalDateTime(startAtTime);
|
||||
}).bind(StartOptionAware::getStartAt, StartOptionAware::setStartAt);
|
||||
|
||||
return new BoundComponent<>(autoStartOptionGroup, binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* create a bound input for distribution sets
|
||||
*
|
||||
* @param <T>
|
||||
* type of the binder
|
||||
* @param binder
|
||||
* that is bound to the input
|
||||
* @param dataProvider
|
||||
* provides distribution sets
|
||||
* @param i18n
|
||||
* i18n
|
||||
* @param componentId
|
||||
* id of the input layout
|
||||
* @return bound ComboBox of distribution sets
|
||||
*/
|
||||
public static <T extends DsIdAware> BoundComponent<ComboBox<ProxyDistributionSet>> createDistributionSetComboBox(
|
||||
final Binder<T> binder, final DistributionSetStatelessDataProvider dataProvider,
|
||||
final VaadinMessageSource i18n, final String componentId) {
|
||||
final ComboBox<ProxyDistributionSet> dsComboBox = SPUIComponentProvider.getComboBox(componentId,
|
||||
i18n.getMessage(UIMessageIdProvider.HEADER_DISTRIBUTION_SET), i18n.getMessage(PROMPT_DISTRIBUTION_SET),
|
||||
i18n.getMessage(PROMPT_DISTRIBUTION_SET), false, ProxyDistributionSet::getNameVersion, dataProvider);
|
||||
|
||||
final Binding<T, ProxyDistributionSetInfo> binding = binder.forField(dsComboBox)
|
||||
.asRequired(i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_DISTRIBUTIONSET_REQUIRED))
|
||||
.withConverter(ds -> {
|
||||
if (ds == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ds.getInfo();
|
||||
}, dsInfo -> {
|
||||
if (dsInfo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ProxyDistributionSet.of(dsInfo);
|
||||
}).bind(DsIdAware::getDistributionSetInfo, DsIdAware::setDistributionSetInfo);
|
||||
|
||||
return new BoundComponent<>(dsComboBox, binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* create a bound input for target filter queries.
|
||||
*
|
||||
* @param <T>
|
||||
* type of the binder
|
||||
* @param binder
|
||||
* that is bound to the input
|
||||
* @param validator
|
||||
* Target filter query validator
|
||||
* @param dataProvider
|
||||
* provides target filter queries
|
||||
* @param i18n
|
||||
* i18n
|
||||
* @param componentId
|
||||
* id of the input layout
|
||||
* @return bound ComboBox of target filter queries
|
||||
*/
|
||||
public static <T extends TargetFilterQueryAware> BoundComponent<ComboBox<ProxyTargetFilterQuery>> createTargetFilterQueryCombo(
|
||||
final Binder<T> binder, final Validator<ProxyTargetFilterQuery> validator,
|
||||
final TargetFilterQueryDataProvider dataProvider, final VaadinMessageSource i18n,
|
||||
final String componentId) {
|
||||
final ComboBox<ProxyTargetFilterQuery> tfqCombo = SPUIComponentProvider.getComboBox(componentId, null,
|
||||
i18n.getMessage(PROMPT_TARGET_FILTER), i18n.getMessage(PROMPT_TARGET_FILTER), true,
|
||||
ProxyTargetFilterQuery::getName, dataProvider);
|
||||
|
||||
final BindingBuilder<T, ProxyTargetFilterQuery> bindingBuilder = binder.forField(tfqCombo)
|
||||
.asRequired(i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_TFQ_REQUIRED));
|
||||
if (validator != null) {
|
||||
bindingBuilder.withValidator(validator);
|
||||
}
|
||||
|
||||
final Binding<T, ProxyTargetFilterQueryInfo> binding = bindingBuilder.withConverter(tfq -> {
|
||||
if (tfq == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return tfq.getInfo();
|
||||
}, tfqInfo -> {
|
||||
if (tfqInfo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ProxyTargetFilterQuery.of(tfqInfo);
|
||||
}).bind(TargetFilterQueryAware::getTargetFilterQueryInfo, TargetFilterQueryAware::setTargetFilterQueryInfo);
|
||||
|
||||
return new BoundComponent<>(tfqCombo, binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* create a bound input for sm/ds types.
|
||||
*
|
||||
* @param <T>
|
||||
* type of the binder
|
||||
* @param binder
|
||||
* that is bound to the input
|
||||
* @param dataProvider
|
||||
* provides types
|
||||
* @param i18n
|
||||
* i18n
|
||||
* @param componentId
|
||||
* id of the input layout
|
||||
* @return bound ComboBox of sm/ds types
|
||||
*/
|
||||
public static <T extends TypeInfoAware> BoundComponent<ComboBox<ProxyTypeInfo>> createTypeCombo(
|
||||
final Binder<T> binder, final AbstractProxyDataProvider<ProxyTypeInfo, ?, String> dataProvider,
|
||||
final VaadinMessageSource i18n, final String componentId, final boolean isRequired) {
|
||||
final ComboBox<ProxyTypeInfo> typeCombo = SPUIComponentProvider.getComboBox(componentId,
|
||||
i18n.getMessage(CAPTION_TYPE), i18n.getMessage(CAPTION_TYPE), i18n.getMessage(CAPTION_TYPE), !isRequired,
|
||||
ProxyTypeInfo::getName, dataProvider.withConvertedFilter(filterString -> filterString.trim() + "%"));
|
||||
|
||||
final BindingBuilder<T, ProxyTypeInfo> bindingBuilder = binder.forField(typeCombo);
|
||||
|
||||
if (isRequired){
|
||||
bindingBuilder.asRequired(i18n.getMessage("message.error.typeRequired"));
|
||||
}
|
||||
|
||||
final Binding<T, ProxyTypeInfo> binding = bindingBuilder.bind(TypeInfoAware::getTypeInfo, TypeInfoAware::setTypeInfo);
|
||||
return new BoundComponent<>(typeCombo, binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create type key text field
|
||||
*
|
||||
* @param binder
|
||||
* that is bound to the input
|
||||
* @param i18n
|
||||
* i18n
|
||||
*
|
||||
* @return text field
|
||||
*/
|
||||
public static TextField createTypeKeyField(final Binder<ProxyType> binder, final VaadinMessageSource i18n) {
|
||||
final TextField typeKey = new TextFieldBuilder(Type.KEY_MAX_SIZE).id(UIComponentIdProvider.TYPE_POPUP_KEY)
|
||||
.caption(i18n.getMessage("textfield.key")).prompt(i18n.getMessage("textfield.key"))
|
||||
.buildTextComponent();
|
||||
typeKey.setSizeUndefined();
|
||||
|
||||
binder.forField(typeKey).withConverter(new TrimmingStringConverter())
|
||||
.asRequired(i18n.getMessage("message.type.key.empty")).bind(ProxyType::getKey, ProxyType::setKey);
|
||||
|
||||
return typeKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a check box
|
||||
*
|
||||
* @param <T>
|
||||
* entity type the check box can be bound to
|
||||
* @param id
|
||||
* id of the check box element
|
||||
* @param binder
|
||||
* the box is bound to
|
||||
* @param getter
|
||||
* getter for the binder
|
||||
* @param setter
|
||||
* setter for the binder
|
||||
* @return the bound box
|
||||
*/
|
||||
public static <T> CheckBox createCheckBox(final String id, final Binder<T> binder,
|
||||
final ValueProvider<T, Boolean> getter, final Setter<T, Boolean> setter) {
|
||||
return createCheckBox(null, id, binder, getter, setter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a check box
|
||||
*
|
||||
* @param <T>
|
||||
* entity type the check box can be bound to
|
||||
* @param caption
|
||||
* check box caption
|
||||
* @param id
|
||||
* id of the check box element
|
||||
* @param binder
|
||||
* the box is bound to
|
||||
* @param getter
|
||||
* getter for the binder
|
||||
* @param setter
|
||||
* setter for the binder
|
||||
* @return the bound box
|
||||
*/
|
||||
public static <T> CheckBox createCheckBox(final String caption, final String id, final Binder<T> binder,
|
||||
final ValueProvider<T, Boolean> getter, final Setter<T, Boolean> setter) {
|
||||
final CheckBox checkBox;
|
||||
if (StringUtils.isEmpty(caption)) {
|
||||
checkBox = new CheckBox();
|
||||
} else {
|
||||
checkBox = new CheckBox(caption);
|
||||
}
|
||||
checkBox.setId(id);
|
||||
binder.forField(checkBox).bind(getter, setter);
|
||||
return checkBox;
|
||||
}
|
||||
}
|
||||
@@ -1,548 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.builder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyNamedEntity;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTarget;
|
||||
import org.eclipse.hawkbit.ui.common.grid.support.DeleteSupport;
|
||||
import org.eclipse.hawkbit.ui.utils.StringHtmlEncoder;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
import com.cronutils.utils.StringUtils;
|
||||
import com.vaadin.data.ValueProvider;
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.server.Resource;
|
||||
import com.vaadin.ui.Button;
|
||||
import com.vaadin.ui.Button.ClickListener;
|
||||
import com.vaadin.ui.Component;
|
||||
import com.vaadin.ui.Grid;
|
||||
import com.vaadin.ui.Grid.Column;
|
||||
import com.vaadin.ui.StyleGenerator;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.components.grid.HeaderRow;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
/**
|
||||
* Builder class for grid components
|
||||
*/
|
||||
public final class GridComponentBuilder {
|
||||
public static final double DEFAULT_MIN_WIDTH = 100D;
|
||||
|
||||
public static final String CREATED_BY_ID = "createdBy";
|
||||
public static final String CREATED_DATE_ID = "createdDate";
|
||||
public static final String MODIFIED_BY_ID = "modifiedBy";
|
||||
public static final String MODIFIED_DATE_ID = "modifiedDate";
|
||||
|
||||
public static final String CREATED_BY_PROPERTY_NAME = "createdBy";
|
||||
public static final String CREATED_AT_PROPERTY_NAME = "createdAt";
|
||||
public static final String LAST_MODIFIED_BY_PROPERTY_NAME = "lastModifiedBy";
|
||||
public static final String LAST_MODIFIED_AT_PROPERTY_NAME = "lastModifiedAt";
|
||||
public static final String VERSION_PROPERTY_NAME = "version";
|
||||
public static final String NAME_PROPERTY_NAME = "name";
|
||||
public static final String CONTROLLER_ID_PROPERTY_NAME = "controllerId";
|
||||
|
||||
private GridComponentBuilder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link Button} with link optic
|
||||
*
|
||||
* @param idSuffix
|
||||
* suffix to build the button ID
|
||||
* @param idPrefix
|
||||
* prefix to build the button ID
|
||||
* @param caption
|
||||
* button caption
|
||||
* @param enabled
|
||||
* is button enabled
|
||||
* @param clickListener
|
||||
* execute on button click (null for none)
|
||||
* @return the button
|
||||
*/
|
||||
public static Button buildLink(final String idSuffix, final String idPrefix, final String caption,
|
||||
final boolean enabled, final ClickListener clickListener) {
|
||||
final Button link = new Button();
|
||||
final String id = new StringBuilder(idPrefix).append('.').append(idSuffix).toString();
|
||||
|
||||
link.setCaption(caption);
|
||||
link.setEnabled(enabled);
|
||||
link.setId(id);
|
||||
link.addStyleName("borderless");
|
||||
link.addStyleName("small");
|
||||
link.addStyleName("on-focus-no-border");
|
||||
link.addStyleName("link");
|
||||
if (clickListener != null) {
|
||||
link.addClickListener(clickListener);
|
||||
}
|
||||
link.setVisible(!StringUtils.isEmpty(caption));
|
||||
return link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link Button} with link optic
|
||||
*
|
||||
* @param entity
|
||||
* to build the button ID
|
||||
* @param idPrefix
|
||||
* prefix to build the button ID
|
||||
* @param caption
|
||||
* button caption
|
||||
* @param enabled
|
||||
* is button enabled
|
||||
* @param clickListener
|
||||
* execute on button click (null for none)
|
||||
* @return the button
|
||||
*/
|
||||
public static <E extends ProxyNamedEntity> Button buildLink(final E entity, final String idPrefix,
|
||||
final String caption, final boolean enabled, final ClickListener clickListener) {
|
||||
final String idSuffix = StringHtmlEncoder.encode(entity.getName());
|
||||
return buildLink(idSuffix, idPrefix, caption, enabled, clickListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add name column to grid. The column is set to sortable which implies a
|
||||
* JPA field "name" that is used for sorting.
|
||||
*
|
||||
* @param <E>
|
||||
* entity type of the grid
|
||||
* @param grid
|
||||
* to add the column to
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param columnId
|
||||
* column ID
|
||||
* @return the created column
|
||||
*/
|
||||
public static <E extends ProxyNamedEntity> Column<E, String> addNameColumn(final Grid<E> grid,
|
||||
final VaadinMessageSource i18n, final String columnId) {
|
||||
final Column<E, String> nameColumn = addColumn(i18n, grid, E::getName, "header.name", columnId,
|
||||
DEFAULT_MIN_WIDTH);
|
||||
setColumnSortable(nameColumn, NAME_PROPERTY_NAME);
|
||||
return nameColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add controllerId column to grid. The column is set to sortable which implies a
|
||||
* JPA field "controllerId" that is used for sorting.
|
||||
*
|
||||
* @param grid
|
||||
* to add the column to
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param columnId
|
||||
* column ID
|
||||
* @return the created column
|
||||
*/
|
||||
public static Column<ProxyTarget, Button> addControllerIdColumn(final Grid<ProxyTarget> grid,
|
||||
final VaadinMessageSource i18n, final String columnId) {
|
||||
final Column<ProxyTarget, Button> column = addComponentColumn(grid,
|
||||
t -> buildControllerIdLink(t, columnId)).setId(columnId)
|
||||
.setCaption(i18n.getMessage("header.controllerId")).setHidable(false)
|
||||
.setMinimumWidth(DEFAULT_MIN_WIDTH);
|
||||
setColumnSortable(column, CONTROLLER_ID_PROPERTY_NAME);
|
||||
return column;
|
||||
}
|
||||
|
||||
private static Button buildControllerIdLink(final ProxyTarget target, final String linkIdPrefix) {
|
||||
final String idSuffix = StringHtmlEncoder.encode(target.getControllerId());
|
||||
return buildLink(idSuffix, linkIdPrefix, target.getControllerId(), true, clickEvent -> UI.getCurrent()
|
||||
.getNavigator().navigateTo("deployment/target=" + target.getControllerId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add description column to grid
|
||||
*
|
||||
* @param <E>
|
||||
* entity type of the grid
|
||||
* @param grid
|
||||
* to add the column to
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param columnId
|
||||
* column ID
|
||||
* @return the created column
|
||||
*/
|
||||
public static <E extends ProxyNamedEntity> Column<E, String> addDescriptionColumn(final Grid<E> grid,
|
||||
final VaadinMessageSource i18n, final String columnId) {
|
||||
return addColumn(i18n, grid, E::getDescription, "header.description", columnId, DEFAULT_MIN_WIDTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "created by", "created at", "modified by" and "modified at" column
|
||||
*
|
||||
* @param <E>
|
||||
* entity type of the grid
|
||||
* @param grid
|
||||
* to add the columns to
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @return the created columns
|
||||
*/
|
||||
public static <E extends ProxyNamedEntity> List<Column<E, String>> addCreatedAndModifiedColumns(final Grid<E> grid,
|
||||
final VaadinMessageSource i18n) {
|
||||
final List<Column<E, String>> columns = new ArrayList<>();
|
||||
|
||||
final Column<E, String> createdByColumn = addColumn(i18n, grid, E::getCreatedBy, "header.createdBy",
|
||||
CREATED_BY_ID, DEFAULT_MIN_WIDTH);
|
||||
setColumnSortable(createdByColumn, CREATED_BY_PROPERTY_NAME);
|
||||
columns.add(createdByColumn);
|
||||
|
||||
final Column<E, String> createdDate = addColumn(i18n, grid, E::getCreatedDate, "header.createdDate", CREATED_DATE_ID, DEFAULT_MIN_WIDTH);
|
||||
setColumnSortable(createdDate, CREATED_AT_PROPERTY_NAME);
|
||||
columns.add(createdDate);
|
||||
|
||||
final Column<E, String> modifiedBy = addColumn(i18n, grid, E::getLastModifiedBy, "header.modifiedBy", MODIFIED_BY_ID, DEFAULT_MIN_WIDTH);
|
||||
setColumnSortable(modifiedBy, LAST_MODIFIED_BY_PROPERTY_NAME);
|
||||
columns.add(modifiedBy);
|
||||
|
||||
final Column<E, String> modifiedDate = addColumn(i18n, grid, E::getModifiedDate, "header.modifiedDate", MODIFIED_DATE_ID, DEFAULT_MIN_WIDTH);
|
||||
setColumnSortable(modifiedDate, LAST_MODIFIED_AT_PROPERTY_NAME);
|
||||
columns.add(modifiedDate);
|
||||
|
||||
return columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add version column to grid
|
||||
*
|
||||
* @param <E>
|
||||
* entity type of the grid
|
||||
* @param grid
|
||||
* to add the column to
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param valueProvider
|
||||
* to get the version of the entity
|
||||
* @param columnId
|
||||
* column ID
|
||||
* @return the created column
|
||||
*/
|
||||
public static <E> Column<E, String> addVersionColumn(final Grid<E> grid, final VaadinMessageSource i18n,
|
||||
final ValueProvider<E, String> valueProvider, final String columnId) {
|
||||
final Column<E, String> column = addColumn(i18n, grid, valueProvider, "header.version", columnId,
|
||||
DEFAULT_MIN_WIDTH);
|
||||
setColumnSortable(column, VERSION_PROPERTY_NAME);
|
||||
return column;
|
||||
}
|
||||
|
||||
private static <E, T> Column<E, T> addColumn(final VaadinMessageSource i18n, final Grid<E> grid,
|
||||
final ValueProvider<E, T> valueProvider, final String caption, final String columnID,
|
||||
final double minWidth) {
|
||||
final Column<E, T> col = addColumn(grid, valueProvider).setCaption(i18n.getMessage(caption))
|
||||
.setMinimumWidth(minWidth);
|
||||
if (columnID != null) {
|
||||
col.setId(columnID);
|
||||
}
|
||||
return col;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add column to grid with the standard settings
|
||||
*
|
||||
* @param <E>
|
||||
* entity type of the grid
|
||||
* @param grid
|
||||
* to add the column to
|
||||
* @param valueProvider
|
||||
* providing the content
|
||||
* @return the created column
|
||||
*/
|
||||
public static <E, T> Column<E, T> addColumn(final Grid<E> grid, final ValueProvider<E, T> valueProvider) {
|
||||
return addColumn(grid, valueProvider, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add column to grid with the standard settings
|
||||
*
|
||||
* @param <E>
|
||||
* entity type of the grid
|
||||
* @param grid
|
||||
* to add the column to
|
||||
* @param valueProvider
|
||||
* providing the content
|
||||
* @param styleGenerator
|
||||
* providing additional styles
|
||||
* @return the created column
|
||||
*/
|
||||
public static <E, T> Column<E, T> addColumn(final Grid<E> grid, final ValueProvider<E, T> valueProvider,
|
||||
final StyleGenerator<E> styleGenerator) {
|
||||
final Column<E, T> column = grid.addColumn(valueProvider);
|
||||
commonColumnConfiguration(column, styleGenerator);
|
||||
return column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove column based on it's id
|
||||
*
|
||||
* @param grid
|
||||
* to add the column to
|
||||
* @param columnId
|
||||
* of the column
|
||||
* @param <E>
|
||||
* entity type of the grid
|
||||
*/
|
||||
public static <E> void removeColumn(final Grid<E> grid, final String columnId) {
|
||||
grid.removeColumn(columnId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a column is present based on it's id
|
||||
*
|
||||
* @param grid
|
||||
* to add the column to
|
||||
* @param columnId
|
||||
* of the column
|
||||
* @param <E>
|
||||
* entity type of the grid
|
||||
* @return if the column is present
|
||||
*/
|
||||
public static <E> boolean isColumnPresent(final Grid<E> grid, final String columnId) {
|
||||
return grid.getColumn(columnId) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add column to grid with the standard settings
|
||||
*
|
||||
* @param <E>
|
||||
* entity type of the grid
|
||||
* @param grid
|
||||
* to add the column to
|
||||
* @param componentProvider
|
||||
* providing the content
|
||||
* @return the created column
|
||||
*/
|
||||
public static <E, T extends Component> Column<E, T> addComponentColumn(final Grid<E> grid,
|
||||
final ValueProvider<E, T> componentProvider) {
|
||||
return addComponentColumn(grid, componentProvider, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add column to grid with the standard settings
|
||||
*
|
||||
* @param <E>
|
||||
* entity type of the grid
|
||||
* @param grid
|
||||
* to add the column to
|
||||
* @param componentProvider
|
||||
* providing the content
|
||||
* @param styleGenerator
|
||||
* providing additional styles
|
||||
* @return the created column
|
||||
*/
|
||||
public static <E, T extends Component> Column<E, T> addComponentColumn(final Grid<E> grid,
|
||||
final ValueProvider<E, T> componentProvider, final StyleGenerator<E> styleGenerator) {
|
||||
final Column<E, T> column = grid.addComponentColumn(componentProvider);
|
||||
commonColumnConfiguration(column, styleGenerator);
|
||||
return column;
|
||||
}
|
||||
|
||||
private static <E, T> Column<E, T> commonColumnConfiguration(final Column<E, T> column,
|
||||
final StyleGenerator<E> styleGenerator) {
|
||||
column.setMinimumWidthFromContent(false);
|
||||
column.setExpandRatio(1);
|
||||
column.setSortable(false);
|
||||
|
||||
if (styleGenerator != null) {
|
||||
column.setStyleGenerator(styleGenerator);
|
||||
}
|
||||
return column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add delete button column to grid
|
||||
*
|
||||
* @param <E>
|
||||
* entity type of the grid
|
||||
* @param grid
|
||||
* to add the column to
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param columnId
|
||||
* column ID
|
||||
* @param deleteSupport
|
||||
* that executes the deletion
|
||||
* @param buttonIdPrefix
|
||||
* prefix to create the button IDs
|
||||
* @param buttonEnabled
|
||||
* is the button enabled
|
||||
* @return the created column
|
||||
*/
|
||||
public static <E extends ProxyIdentifiableEntity> Column<E, Button> addDeleteColumn(final Grid<E> grid,
|
||||
final VaadinMessageSource i18n, final String columnId, final DeleteSupport<E> deleteSupport,
|
||||
final String buttonIdPrefix, final Predicate<E> buttonEnabled) {
|
||||
final ValueProvider<E, Button> getDelButton = entity -> buildActionButton(i18n,
|
||||
clickEvent -> deleteSupport.openConfirmationWindowDeleteAction(entity), VaadinIcons.TRASH,
|
||||
UIMessageIdProvider.TOOLTIP_DELETE, SPUIStyleDefinitions.STATUS_ICON_NEUTRAL,
|
||||
buttonIdPrefix + "." + entity.getId(), buttonEnabled.test(entity));
|
||||
return addIconColumn(grid, getDelButton, columnId, i18n.getMessage("header.action.delete")).setWidth(60D)
|
||||
.setHidingToggleCaption(i18n.getMessage("header.action.delete"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an action button column to a grid
|
||||
*
|
||||
* @param <T>
|
||||
* type of the entity displayed by the grid
|
||||
* @param grid
|
||||
* to add the column to
|
||||
* @param iconProvider
|
||||
* to get the icon from
|
||||
* @param columnId
|
||||
* column ID
|
||||
* @param caption
|
||||
* caption of the column
|
||||
* @return the created column
|
||||
*/
|
||||
public static <T, V extends Component> Column<T, V> addIconColumn(final Grid<T> grid,
|
||||
final ValueProvider<T, V> iconProvider, final String columnId, final String caption) {
|
||||
return addIconColumn(grid, iconProvider, columnId, caption, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an action button column to a grid
|
||||
*
|
||||
* @param <T>
|
||||
* type of the entity displayed by the grid
|
||||
* @param grid
|
||||
* to add the column to
|
||||
* @param iconProvider
|
||||
* to get the icon from
|
||||
* @param columnId
|
||||
* column ID
|
||||
* @param caption
|
||||
* caption of the column
|
||||
* @param styleGenerator
|
||||
* caption of the column
|
||||
* @return the created column
|
||||
*/
|
||||
public static <T, V extends Component> Column<T, V> addIconColumn(final Grid<T> grid,
|
||||
final ValueProvider<T, V> iconProvider, final String columnId, final String caption,
|
||||
final StyleGenerator<T> styleGenerator) {
|
||||
final StyleGenerator<T> additionalStyleGenerator = entity -> SPUIStyleDefinitions.ICON_CELL;
|
||||
|
||||
final StyleGenerator<T> finalStyleGenerator = merge(Arrays.asList(styleGenerator, additionalStyleGenerator));
|
||||
|
||||
final Column<T, V> column = grid.addComponentColumn(iconProvider).setId(columnId)
|
||||
.setStyleGenerator(finalStyleGenerator).setWidth(60D).setResizable(false).setSortable(false);
|
||||
if (!StringUtils.isEmpty(caption)) {
|
||||
column.setCaption(caption);
|
||||
}
|
||||
return column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the column sortable.
|
||||
*
|
||||
* @param <T>
|
||||
* type of the entity displayed by the grid
|
||||
* @param <V>
|
||||
* type of column value
|
||||
* @param column
|
||||
* the column to set sortable
|
||||
* @param sortPropertyName
|
||||
* the jpa property name to sort by
|
||||
* @return the provided column
|
||||
*/
|
||||
public static <T, V> Column<T, V> setColumnSortable(final Column<T, V> column,
|
||||
final String sortPropertyName) {
|
||||
column.setSortable(true).setSortProperty(sortPropertyName);
|
||||
return column;
|
||||
}
|
||||
|
||||
private static <T> StyleGenerator<T> merge(final Collection<StyleGenerator<T>> generators) {
|
||||
return item -> generators.stream().filter(Objects::nonNull).map(gen -> gen.apply(item)).filter(Objects::nonNull)
|
||||
.collect(Collectors.joining(" "));
|
||||
}
|
||||
|
||||
/**
|
||||
* Join columns to form an action column
|
||||
*
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param headerRow
|
||||
* header row
|
||||
* @param columns
|
||||
* columns to join
|
||||
*/
|
||||
public static void joinToActionColumn(final VaadinMessageSource i18n, final HeaderRow headerRow,
|
||||
final List<Column<?, ?>> columns) {
|
||||
joinToIconColumn(headerRow, i18n.getMessage("header.action"), columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Join columns to form an icon column
|
||||
*
|
||||
* @param headerRow
|
||||
* header row
|
||||
* @param headerCaption
|
||||
* header caption
|
||||
* @param columns
|
||||
* columns to join
|
||||
*/
|
||||
public static void joinToIconColumn(final HeaderRow headerRow, final String headerCaption,
|
||||
final List<Column<?, ?>> columns) {
|
||||
columns.forEach(column -> {
|
||||
column.setWidth(30D);
|
||||
column.setResizable(false);
|
||||
});
|
||||
final Column<?, ?>[] columnArray = columns.toArray(new Column<?, ?>[columns.size()]);
|
||||
headerRow.join(columnArray).setText(headerCaption);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an action button (e.g. a delete button)
|
||||
*
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param clickListener
|
||||
* clickListener
|
||||
* @param icon
|
||||
* icon of the button
|
||||
* @param descriptionMsgProperty
|
||||
* displayed as tool tip
|
||||
* @param style
|
||||
* additional style
|
||||
* @param buttonId
|
||||
* ID of the button
|
||||
* @param enabled
|
||||
* is the button enabled
|
||||
* @return the button
|
||||
*/
|
||||
public static Button buildActionButton(final VaadinMessageSource i18n, final ClickListener clickListener,
|
||||
final Resource icon, final String descriptionMsgProperty, final String style, final String buttonId,
|
||||
final boolean enabled) {
|
||||
final Button actionButton = new Button();
|
||||
|
||||
actionButton.addClickListener(clickListener);
|
||||
actionButton.setIcon(icon, i18n.getMessage(descriptionMsgProperty));
|
||||
actionButton.setDescription(i18n.getMessage(descriptionMsgProperty));
|
||||
actionButton.setEnabled(enabled);
|
||||
actionButton.setId(buttonId);
|
||||
actionButton.addStyleName(ValoTheme.BUTTON_BORDERLESS_COLORED);
|
||||
actionButton.addStyleName("button-no-border");
|
||||
actionButton.addStyleName("action-type-padding");
|
||||
actionButton.addStyleName(ValoTheme.BUTTON_ICON_ONLY);
|
||||
actionButton.addStyleName(style);
|
||||
|
||||
return actionButton;
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.builder;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
/**
|
||||
* Label Builder.
|
||||
*
|
||||
*/
|
||||
public class LabelBuilder {
|
||||
|
||||
private String caption;
|
||||
|
||||
private String name;
|
||||
|
||||
private String id;
|
||||
|
||||
private boolean visible = true;
|
||||
|
||||
/**
|
||||
* Add name to label
|
||||
*
|
||||
* @param name
|
||||
* the value to set
|
||||
* @return builder
|
||||
*/
|
||||
public LabelBuilder name(final String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add caption to label
|
||||
*
|
||||
* @param caption
|
||||
* the caption to set
|
||||
* @return builder
|
||||
*/
|
||||
public LabelBuilder caption(final String caption) {
|
||||
this.caption = caption;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add id to label
|
||||
*
|
||||
* @param id
|
||||
* the id to set
|
||||
* @return builder
|
||||
*/
|
||||
public LabelBuilder id(final String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle label visibility
|
||||
*
|
||||
* @param visible
|
||||
* the visible to set
|
||||
* @return builder
|
||||
*/
|
||||
public LabelBuilder visible(final boolean visible) {
|
||||
this.visible = visible;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build caption label.
|
||||
*
|
||||
* @return Label
|
||||
*/
|
||||
public Label buildCaptionLabel() {
|
||||
final Label label = createLabel();
|
||||
label.addStyleName("header-caption");
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build label.
|
||||
*
|
||||
* @return Label
|
||||
*/
|
||||
public Label buildLabel() {
|
||||
final Label label = createLabel();
|
||||
label.setWidth("-1px");
|
||||
label.setHeight("-1px");
|
||||
if (StringUtils.hasText(caption)) {
|
||||
label.setCaption(caption);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
private Label createLabel() {
|
||||
final Label label = new Label(name);
|
||||
label.setVisible(visible);
|
||||
final StringBuilder style = new StringBuilder(ValoTheme.LABEL_SMALL);
|
||||
style.append(' ');
|
||||
style.append(ValoTheme.LABEL_BOLD);
|
||||
label.addStyleName(style.toString());
|
||||
if (id != null) {
|
||||
label.setId(id);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,599 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.builder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyAction;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyAction.IsActiveDecoration;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTarget;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyUploadProgress.ProgressSatus;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.rollout.ProxyFontIcon;
|
||||
import org.eclipse.hawkbit.ui.rollout.RolloutManagementUIState;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.server.FontIcon;
|
||||
import com.vaadin.ui.Label;
|
||||
|
||||
/**
|
||||
*
|
||||
* Generate labels with icons according to entities' states
|
||||
*
|
||||
*/
|
||||
public final class StatusIconBuilder {
|
||||
|
||||
private StatusIconBuilder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate labels with icons according to entities' {@link Status}
|
||||
*
|
||||
* @param <E>
|
||||
* entity type
|
||||
*/
|
||||
public static class ActionStatusIconSupplier<E extends ProxyIdentifiableEntity>
|
||||
extends EntityStatusIconBuilderWithGenetaredTooltip<Status, E> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param getEntityStatus
|
||||
* function to get the entitie's state
|
||||
* @param labelIdPrefix
|
||||
* to generate the label ID
|
||||
*/
|
||||
public ActionStatusIconSupplier(final VaadinMessageSource i18n, final Function<E, Status> getEntityStatus,
|
||||
final String labelIdPrefix) {
|
||||
super(i18n, Status.class, getEntityStatus, labelIdPrefix,
|
||||
status -> UIMessageIdProvider.TOOLTIP_ACTION_STATUS_PREFIX + status.toString().toLowerCase());
|
||||
addMapping(Status.FINISHED, VaadinIcons.CHECK_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_GREEN);
|
||||
addMapping(Status.SCHEDULED, VaadinIcons.HOURGLASS_EMPTY, SPUIStyleDefinitions.STATUS_ICON_PENDING);
|
||||
addMapping(Status.RUNNING, VaadinIcons.ADJUST, SPUIStyleDefinitions.STATUS_ICON_PENDING);
|
||||
addMapping(Status.RETRIEVED, VaadinIcons.CHECK_CIRCLE_O, SPUIStyleDefinitions.STATUS_ICON_PENDING);
|
||||
addMapping(Status.WARNING, VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_ORANGE);
|
||||
addMapping(Status.DOWNLOAD, VaadinIcons.CLOUD_DOWNLOAD, SPUIStyleDefinitions.STATUS_ICON_PENDING);
|
||||
addMapping(Status.DOWNLOADED, VaadinIcons.CLOUD_DOWNLOAD, SPUIStyleDefinitions.STATUS_ICON_GREEN);
|
||||
addMapping(Status.CANCELING, VaadinIcons.CLOSE_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_PENDING);
|
||||
addMapping(Status.CANCEL_REJECTED, VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_ORANGE);
|
||||
addMapping(Status.CANCELED, VaadinIcons.CLOSE_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_GREEN);
|
||||
addMapping(Status.ERROR, VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_RED);
|
||||
addMapping(Status.WAIT_FOR_CONFIRMATION, VaadinIcons.USER_CLOCK, SPUIStyleDefinitions.STATUS_ICON_PENDING);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate labels with icons according to entities' {@link RolloutStatus}
|
||||
*
|
||||
* @param <E>
|
||||
* entity type
|
||||
*/
|
||||
public static class RolloutStatusIconSupplier<E extends ProxyIdentifiableEntity>
|
||||
extends EntityStatusIconBuilderWithGenetaredTooltip<RolloutStatus, E> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param getEntityStatus
|
||||
* function to get the entitie's state
|
||||
* @param labelIdPrefix
|
||||
* to generate the label ID
|
||||
*/
|
||||
public RolloutStatusIconSupplier(final VaadinMessageSource i18n,
|
||||
final Function<E, RolloutStatus> getEntityStatus, final String labelIdPrefix) {
|
||||
super(i18n, RolloutStatus.class, getEntityStatus, labelIdPrefix,
|
||||
status -> UIMessageIdProvider.TOOLTIP_ROLLOUT_STATUS_PREFIX + status.toString().toLowerCase());
|
||||
addMapping(RolloutStatus.FINISHED, VaadinIcons.CHECK_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_GREEN);
|
||||
addMapping(RolloutStatus.PAUSED, VaadinIcons.PAUSE, SPUIStyleDefinitions.STATUS_ICON_BLUE);
|
||||
addMapping(RolloutStatus.RUNNING, null, SPUIStyleDefinitions.STATUS_SPINNER_YELLOW);
|
||||
addMapping(RolloutStatus.WAITING_FOR_APPROVAL, VaadinIcons.HOURGLASS,
|
||||
SPUIStyleDefinitions.STATUS_ICON_ORANGE);
|
||||
addMapping(RolloutStatus.APPROVAL_DENIED, VaadinIcons.CLOSE_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_RED);
|
||||
addMapping(RolloutStatus.READY, VaadinIcons.BULLSEYE, SPUIStyleDefinitions.STATUS_ICON_LIGHT_BLUE);
|
||||
addMapping(RolloutStatus.STOPPED, VaadinIcons.STOP, SPUIStyleDefinitions.STATUS_ICON_RED);
|
||||
addMapping(RolloutStatus.CREATING, null, SPUIStyleDefinitions.STATUS_SPINNER_GREY);
|
||||
addMapping(RolloutStatus.STARTING, null, SPUIStyleDefinitions.STATUS_SPINNER_BLUE);
|
||||
addMapping(RolloutStatus.DELETING, null, SPUIStyleDefinitions.STATUS_SPINNER_RED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate labels with icons according to entities'
|
||||
* {@link RolloutGroupStatus}
|
||||
*
|
||||
* @param <E>
|
||||
* entity type
|
||||
*/
|
||||
public static class RolloutGroupStatusIconSupplier<E extends ProxyIdentifiableEntity>
|
||||
extends EntityStatusIconBuilderWithGenetaredTooltip<RolloutGroupStatus, E> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param getEntityStatus
|
||||
* function to get the entitie's state
|
||||
* @param labelIdPrefix
|
||||
* to generate the label ID
|
||||
*/
|
||||
public RolloutGroupStatusIconSupplier(final VaadinMessageSource i18n,
|
||||
final Function<E, RolloutGroupStatus> getEntityStatus, final String labelIdPrefix) {
|
||||
super(i18n, RolloutGroupStatus.class, getEntityStatus, labelIdPrefix,
|
||||
status -> UIMessageIdProvider.TOOLTIP_ROLLOUT_GROUP_STATUS_PREFIX
|
||||
+ status.toString().toLowerCase());
|
||||
addMapping(RolloutGroupStatus.FINISHED, VaadinIcons.CHECK_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_GREEN);
|
||||
addMapping(RolloutGroupStatus.RUNNING, VaadinIcons.ADJUST, SPUIStyleDefinitions.STATUS_ICON_YELLOW);
|
||||
addMapping(RolloutGroupStatus.READY, VaadinIcons.BULLSEYE, SPUIStyleDefinitions.STATUS_ICON_LIGHT_BLUE);
|
||||
addMapping(RolloutGroupStatus.ERROR, VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_RED);
|
||||
addMapping(RolloutGroupStatus.SCHEDULED, VaadinIcons.HOURGLASS_START,
|
||||
SPUIStyleDefinitions.STATUS_ICON_PENDING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate labels with icons according to entities' {@link Status} and the
|
||||
* current {@link RolloutGroup}
|
||||
*
|
||||
* @param <E>
|
||||
* entity type
|
||||
*/
|
||||
public static class RolloutActionStatusIconSupplier<E extends ProxyIdentifiableEntity>
|
||||
extends ActionStatusIconSupplier<E> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final transient RolloutGroupManagement rolloutGroupManagement;
|
||||
private final RolloutManagementUIState rolloutManagementUIState;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param getEntityStatus
|
||||
* function to get the entitie's state
|
||||
* @param labelIdPrefix
|
||||
* to generate the label ID
|
||||
* @param rolloutGroupManagement
|
||||
* management to get the current {@link RolloutGroup}
|
||||
* @param rolloutManagementUIState
|
||||
* UI state {@link RolloutGroup}
|
||||
*/
|
||||
public RolloutActionStatusIconSupplier(final VaadinMessageSource i18n,
|
||||
final Function<E, Status> getEntityStatus, final String labelIdPrefix,
|
||||
final RolloutGroupManagement rolloutGroupManagement,
|
||||
final RolloutManagementUIState rolloutManagementUIState) {
|
||||
super(i18n, getEntityStatus, labelIdPrefix);
|
||||
this.rolloutGroupManagement = rolloutGroupManagement;
|
||||
this.rolloutManagementUIState = rolloutManagementUIState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Label getLabel(final E entity) {
|
||||
final Optional<RolloutGroup> group = rolloutGroupManagement
|
||||
.get(rolloutManagementUIState.getSelectedRolloutGroupId());
|
||||
final Optional<ProxyFontIcon> optionalIcon = getIcon(entity);
|
||||
|
||||
ProxyFontIcon icon;
|
||||
if (optionalIcon.isPresent()) {
|
||||
icon = getFontIconFromStatusMap(optionalIcon.get(), getEntityStatus.apply(entity), group.orElse(null));
|
||||
} else {
|
||||
icon = buildStatusIcon(group.orElse(null));
|
||||
}
|
||||
|
||||
return getLabel(entity, icon);
|
||||
}
|
||||
|
||||
private ProxyFontIcon getFontIconFromStatusMap(final ProxyFontIcon foundIcon, final Status status,
|
||||
final RolloutGroup group) {
|
||||
if (Status.DOWNLOADED == status && isDownloadOnly(group)) {
|
||||
return getIconMap().get(Status.FINISHED);
|
||||
}
|
||||
|
||||
return foundIcon;
|
||||
}
|
||||
|
||||
private static boolean isDownloadOnly(final RolloutGroup group) {
|
||||
if (group == null) {
|
||||
return false;
|
||||
}
|
||||
return ActionType.DOWNLOAD_ONLY == group.getRollout().getActionType();
|
||||
}
|
||||
|
||||
// Actions are not created for targets when rollout's status is
|
||||
// READY and when duplicate assignment is done. In these cases
|
||||
// display a appropriate status with description
|
||||
private ProxyFontIcon buildStatusIcon(final RolloutGroup rolloutGroup) {
|
||||
if (rolloutGroup != null && rolloutGroup.getStatus() == RolloutGroupStatus.READY) {
|
||||
return new ProxyFontIcon(VaadinIcons.BULLSEYE, SPUIStyleDefinitions.STATUS_ICON_LIGHT_BLUE,
|
||||
i18n.getMessage(UIMessageIdProvider.TOOLTIP_ROLLOUT_GROUP_STATUS_PREFIX
|
||||
+ RolloutGroupStatus.READY.toString().toLowerCase()));
|
||||
} else if (rolloutGroup != null && rolloutGroup.getStatus() == RolloutGroupStatus.FINISHED) {
|
||||
final DistributionSet dist = rolloutGroup.getRollout().getDistributionSet();
|
||||
final String ds = HawkbitCommonUtil.getFormattedNameVersion(dist.getName(), dist.getVersion());
|
||||
if (dist.isValid()) {
|
||||
return new ProxyFontIcon(VaadinIcons.MINUS_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_BLUE,
|
||||
i18n.getMessage(UIMessageIdProvider.MESSAGE_DISTRIBUTION_ASSIGNED, ds));
|
||||
} else {
|
||||
// invalidated ds, finished rollout but ds wasn't assigned
|
||||
// to target
|
||||
return new ProxyFontIcon(VaadinIcons.BAN, SPUIStyleDefinitions.STATUS_ICON_BLUE,
|
||||
i18n.getMessage(UIMessageIdProvider.MESSAGE_DISTRIBUTION_NOT_ASSIGNED, ds));
|
||||
}
|
||||
} else {
|
||||
return generateUnknwonStateIcon();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate labels with icons according to entities'
|
||||
* {@link IsActiveDecoration}
|
||||
*
|
||||
* @param <E>
|
||||
* entity type
|
||||
*/
|
||||
public static class ActiveStatusIconSupplier<E extends ProxyIdentifiableEntity>
|
||||
extends EntityStatusIconBuilderWithGenetaredTooltip<IsActiveDecoration, E> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param getEntityStatus
|
||||
* function to get the entitie's state
|
||||
* @param labelIdPrefix
|
||||
* to generate the label ID
|
||||
*/
|
||||
public ActiveStatusIconSupplier(final VaadinMessageSource i18n,
|
||||
final Function<E, IsActiveDecoration> getEntityStatus, final String labelIdPrefix) {
|
||||
super(i18n, IsActiveDecoration.class, getEntityStatus, labelIdPrefix,
|
||||
status -> UIMessageIdProvider.TOOLTIP_ACTIVE_ACTION_STATUS_PREFIX + status.getMsgName());
|
||||
addMapping(IsActiveDecoration.ACTIVE, null, SPUIStyleDefinitions.STATUS_ICON_ACTIVE);
|
||||
addMapping(IsActiveDecoration.SCHEDULED, VaadinIcons.HOURGLASS_EMPTY,
|
||||
SPUIStyleDefinitions.STATUS_ICON_PENDING);
|
||||
addMapping(IsActiveDecoration.IN_ACTIVE, VaadinIcons.CHECK_CIRCLE,
|
||||
SPUIStyleDefinitions.STATUS_ICON_NEUTRAL);
|
||||
addMapping(IsActiveDecoration.IN_ACTIVE_ERROR, VaadinIcons.CHECK_CIRCLE,
|
||||
SPUIStyleDefinitions.STATUS_ICON_RED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate labels with icons according to entities' {@link ActionType}
|
||||
*
|
||||
* @param <E>
|
||||
* entity type
|
||||
*/
|
||||
public static class ActionTypeIconSupplier<E extends ProxyIdentifiableEntity>
|
||||
extends EntityStatusIconBuilder<ActionType, E> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param getEntityStatus
|
||||
* function to get the entitie's state
|
||||
* @param labelIdPrefix
|
||||
* to generate the label ID
|
||||
*/
|
||||
public ActionTypeIconSupplier(final VaadinMessageSource i18n, final Function<E, ActionType> getEntityStatus,
|
||||
final String labelIdPrefix) {
|
||||
super(i18n, ActionType.class, getEntityStatus, labelIdPrefix);
|
||||
addMapping(ActionType.FORCED, VaadinIcons.BOLT, SPUIStyleDefinitions.STATUS_ICON_FORCED,
|
||||
UIMessageIdProvider.CAPTION_ACTION_FORCED);
|
||||
addMapping(ActionType.TIMEFORCED, VaadinIcons.BOLT, SPUIStyleDefinitions.STATUS_ICON_FORCED,
|
||||
UIMessageIdProvider.CAPTION_ACTION_FORCED);
|
||||
addMapping(ActionType.SOFT, VaadinIcons.STEP_FORWARD, SPUIStyleDefinitions.STATUS_ICON_SOFT,
|
||||
UIMessageIdProvider.CAPTION_ACTION_SOFT);
|
||||
addMapping(ActionType.DOWNLOAD_ONLY, VaadinIcons.DOWNLOAD, SPUIStyleDefinitions.STATUS_ICON_DOWNLOAD_ONLY,
|
||||
UIMessageIdProvider.CAPTION_ACTION_DOWNLOAD_ONLY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate labels with confirmation icons according to entity' {@link ProxyTargetFilterQuery}
|
||||
*/
|
||||
public static class ConfirmationIconSupplier extends AbstractEntityStatusIconBuilder<ProxyTargetFilterQuery> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param labelIdPrefix
|
||||
* to generate the label ID
|
||||
*/
|
||||
public ConfirmationIconSupplier(final VaadinMessageSource i18n, final String labelIdPrefix) {
|
||||
super(i18n, labelIdPrefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Label getLabel(final ProxyTargetFilterQuery entity) {
|
||||
final ProxyFontIcon icon;
|
||||
if (entity.isAutoAssignmentEnabled() && entity.getDistributionSetInfo() != null) {
|
||||
icon = entity.isConfirmationRequired()
|
||||
? new ProxyFontIcon(VaadinIcons.USER_CLOCK, SPUIStyleDefinitions.STATUS_ICON_GREEN,
|
||||
i18n.getMessage(UIMessageIdProvider.TOOLTIP_TARGET_FILTER_CONFIRMATION_REQUIRED))
|
||||
: new ProxyFontIcon(VaadinIcons.USER_CHECK, SPUIStyleDefinitions.STATUS_ICON_RED,
|
||||
i18n.getMessage(UIMessageIdProvider.TOOLTIP_TARGET_FILTER_CONFIRMATION_NOT_REQUIRED));
|
||||
} else {
|
||||
icon = new ProxyFontIcon(VaadinIcons.MINUS_CIRCLE_O, SPUIStyleDefinitions.STATUS_ICON_NEUTRAL,
|
||||
i18n.getMessage(UIMessageIdProvider.TOOLTIP_TARGET_FILTER_CONFIRMATION_NOT_CONFIGURED));
|
||||
}
|
||||
|
||||
return getLabel(entity, icon);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate labels with icons according to entities'
|
||||
* {@link TargetUpdateStatus}
|
||||
*
|
||||
* @param <E>
|
||||
* entity type
|
||||
*/
|
||||
public static class TargetStatusIconSupplier<E extends ProxyIdentifiableEntity>
|
||||
extends EntityStatusIconBuilderWithGenetaredTooltip<TargetUpdateStatus, E> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param getEntityStatus
|
||||
* function to get the entitie's state
|
||||
* @param labelIdPrefix
|
||||
* to generate the label ID
|
||||
*/
|
||||
public TargetStatusIconSupplier(final VaadinMessageSource i18n,
|
||||
final Function<E, TargetUpdateStatus> getEntityStatus, final String labelIdPrefix) {
|
||||
super(i18n, TargetUpdateStatus.class, getEntityStatus, labelIdPrefix,
|
||||
status -> UIMessageIdProvider.TOOLTIP_TARGET_STATUS_PREFIX + status.toString().toLowerCase());
|
||||
addMapping(TargetUpdateStatus.ERROR, VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_RED);
|
||||
addMapping(TargetUpdateStatus.UNKNOWN, VaadinIcons.QUESTION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_BLUE);
|
||||
addMapping(TargetUpdateStatus.IN_SYNC, VaadinIcons.CHECK_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_GREEN);
|
||||
addMapping(TargetUpdateStatus.PENDING, VaadinIcons.ADJUST, SPUIStyleDefinitions.STATUS_ICON_YELLOW);
|
||||
addMapping(TargetUpdateStatus.REGISTERED, VaadinIcons.DOT_CIRCLE,
|
||||
SPUIStyleDefinitions.STATUS_ICON_LIGHT_BLUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate labels with icons according to entities' {@link ProgressSatus}
|
||||
*
|
||||
* @param <E>
|
||||
* entity type
|
||||
*/
|
||||
public static class ProgressStatusIconSupplier<E extends ProxyIdentifiableEntity>
|
||||
extends EntityStatusIconBuilderWithGenetaredTooltip<ProgressSatus, E> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param getEntityStatus
|
||||
* function to get the entitie's state
|
||||
* @param labelIdPrefix
|
||||
* to generate the label ID
|
||||
*/
|
||||
public ProgressStatusIconSupplier(final VaadinMessageSource i18n,
|
||||
final Function<E, ProgressSatus> getEntityStatus, final String labelIdPrefix) {
|
||||
super(i18n, ProgressSatus.class, getEntityStatus, labelIdPrefix,
|
||||
status -> UIMessageIdProvider.TOOLTIP_UPLOAD_STATUS_PREFIX + status.toString().toLowerCase());
|
||||
addMapping(ProgressSatus.INPROGRESS, VaadinIcons.ADJUST, SPUIStyleDefinitions.STATUS_ICON_YELLOW);
|
||||
addMapping(ProgressSatus.FINISHED, VaadinIcons.CHECK_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_GREEN);
|
||||
addMapping(ProgressSatus.FAILED, VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_RED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate labels with icons according to {@link ProxyTarget}s'
|
||||
* PollStatusToolTip
|
||||
*/
|
||||
public static class TargetPollingStatusIconSupplier extends AbstractEntityStatusIconBuilder<ProxyTarget> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param labelIdPrefix
|
||||
* to generate the label ID
|
||||
*/
|
||||
public TargetPollingStatusIconSupplier(final VaadinMessageSource i18n, final String labelIdPrefix) {
|
||||
super(i18n, labelIdPrefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Label getLabel(final ProxyTarget entity) {
|
||||
final String pollStatusToolTip = entity.getPollStatusToolTip();
|
||||
final ProxyFontIcon icon = StringUtils.hasText(pollStatusToolTip)
|
||||
? new ProxyFontIcon(VaadinIcons.EXCLAMATION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_NEUTRAL,
|
||||
pollStatusToolTip)
|
||||
: new ProxyFontIcon(VaadinIcons.CLOCK, SPUIStyleDefinitions.STATUS_ICON_NEUTRAL,
|
||||
i18n.getMessage(UIMessageIdProvider.TOOLTIP_IN_TIME));
|
||||
return getLabel(entity, icon);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate labels with icons according to {@link ProxyAction}s' timeforced
|
||||
* status and current time
|
||||
*/
|
||||
public static class TimeforcedIconSupplier extends AbstractEntityStatusIconBuilder<ProxyAction> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param i18n
|
||||
* message source for internationalization
|
||||
* @param labelIdPrefix
|
||||
* to generate the label ID
|
||||
*/
|
||||
public TimeforcedIconSupplier(final VaadinMessageSource i18n, final String labelIdPrefix) {
|
||||
super(i18n, labelIdPrefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Label getLabel(final ProxyAction action) {
|
||||
if (ActionType.TIMEFORCED != action.getActionType()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final long currentTimeMillis = System.currentTimeMillis();
|
||||
String style;
|
||||
String description;
|
||||
if (action.isHitAutoForceTime(currentTimeMillis)) {
|
||||
style = SPUIStyleDefinitions.STATUS_ICON_GREEN;
|
||||
final String duration = SPDateTimeUtil.getDurationFormattedString(action.getForcedTime(),
|
||||
currentTimeMillis, i18n);
|
||||
description = i18n.getMessage(UIMessageIdProvider.TOOLTIP_TIMEFORCED_FORCED_SINCE, duration);
|
||||
} else {
|
||||
style = SPUIStyleDefinitions.STATUS_ICON_PENDING;
|
||||
final String duration = SPDateTimeUtil.getDurationFormattedString(currentTimeMillis,
|
||||
action.getForcedTime(), i18n);
|
||||
description = i18n.getMessage(UIMessageIdProvider.TOOLTIP_TIMEFORCED_FORCED_IN, duration);
|
||||
}
|
||||
|
||||
final ProxyFontIcon icon = new ProxyFontIcon(VaadinIcons.TIMER, style, description);
|
||||
return getLabel(action, icon);
|
||||
}
|
||||
}
|
||||
|
||||
private static class EntityStatusIconBuilderWithGenetaredTooltip<T extends Enum<T>, E extends ProxyIdentifiableEntity>
|
||||
extends EntityStatusIconBuilder<T, E> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final transient Function<T, String> tooltipGenerator;
|
||||
|
||||
protected EntityStatusIconBuilderWithGenetaredTooltip(final VaadinMessageSource i18n, final Class<T> statusType,
|
||||
final Function<E, T> getEntityStatus, final String labelIdPrefix,
|
||||
final Function<T, String> tooltipGenerator) {
|
||||
super(i18n, statusType, getEntityStatus, labelIdPrefix);
|
||||
this.tooltipGenerator = tooltipGenerator;
|
||||
}
|
||||
|
||||
protected void addMapping(final T status, final FontIcon icon, final String style) {
|
||||
addMapping(status, icon, style, tooltipGenerator.apply(status));
|
||||
}
|
||||
}
|
||||
|
||||
private static class EntityStatusIconBuilder<T extends Enum<T>, E extends ProxyIdentifiableEntity>
|
||||
extends AbstractEntityStatusIconBuilder<E> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Map<T, ProxyFontIcon> iconMap;
|
||||
protected final transient Function<E, T> getEntityStatus;
|
||||
|
||||
protected EntityStatusIconBuilder(final VaadinMessageSource i18n, final Class<T> statusType,
|
||||
final Function<E, T> getEntityStatus, final String labelIdPrefix) {
|
||||
super(i18n, labelIdPrefix);
|
||||
this.iconMap = new EnumMap<>(statusType);
|
||||
this.getEntityStatus = getEntityStatus;
|
||||
}
|
||||
|
||||
protected void addMapping(final T status, final FontIcon icon, final String style, final String tooltip) {
|
||||
iconMap.put(status, new ProxyFontIcon(icon, style, i18n.getMessage(tooltip)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Label getLabel(final E entity) {
|
||||
final ProxyFontIcon icon = getIcon(entity).orElse(generateUnknwonStateIcon());
|
||||
return getLabel(entity, icon);
|
||||
}
|
||||
|
||||
protected Optional<ProxyFontIcon> getIcon(final E entity) {
|
||||
final T status = getEntityStatus.apply(entity);
|
||||
if (status != null) {
|
||||
return Optional.ofNullable(iconMap.getOrDefault(status, null));
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
protected Map<T, ProxyFontIcon> getIconMap() {
|
||||
return iconMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private abstract static class AbstractEntityStatusIconBuilder<E extends ProxyIdentifiableEntity>
|
||||
implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected final VaadinMessageSource i18n;
|
||||
protected final String labelIdPrefix;
|
||||
|
||||
protected AbstractEntityStatusIconBuilder(final VaadinMessageSource i18n, final String labelIdPrefix) {
|
||||
this.i18n = i18n;
|
||||
this.labelIdPrefix = labelIdPrefix;
|
||||
}
|
||||
|
||||
protected Label getLabel(final E entity, final ProxyFontIcon icon) {
|
||||
final String entityStatusId = new StringBuilder(labelIdPrefix).append(".").append(entity.getId())
|
||||
.toString();
|
||||
return SPUIComponentProvider.getLabelIcon(icon, entityStatusId);
|
||||
}
|
||||
|
||||
protected ProxyFontIcon generateUnknwonStateIcon() {
|
||||
return new ProxyFontIcon(VaadinIcons.QUESTION_CIRCLE, SPUIStyleDefinitions.STATUS_ICON_BLUE,
|
||||
i18n.getMessage(UIMessageIdProvider.LABEL_UNKNOWN));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a label from the entity according to its state
|
||||
*
|
||||
* @param entity
|
||||
* to read the state from
|
||||
* @return the label
|
||||
*/
|
||||
public abstract Label getLabel(final E entity);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.builder;
|
||||
|
||||
import com.vaadin.shared.ui.ValueChangeMode;
|
||||
import com.vaadin.ui.TextArea;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
/**
|
||||
* TextArea builder.
|
||||
*
|
||||
*/
|
||||
public class TextAreaBuilder extends AbstractTextFieldBuilder<TextAreaBuilder, TextArea> {
|
||||
private static final int INPUT_DEBOUNCE_TIMEOUT = 500;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param maxLengthAllowed
|
||||
* for the text area
|
||||
*/
|
||||
public TextAreaBuilder(final int maxLengthAllowed) {
|
||||
super(maxLengthAllowed);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TextArea createTextComponent() {
|
||||
final TextArea textArea = new TextArea();
|
||||
textArea.addStyleName(ValoTheme.TEXTAREA_SMALL);
|
||||
textArea.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
textArea.setValueChangeTimeout(INPUT_DEBOUNCE_TIMEOUT);
|
||||
|
||||
return textArea;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.builder;
|
||||
|
||||
import com.vaadin.shared.ui.ValueChangeMode;
|
||||
import com.vaadin.ui.TextField;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
/**
|
||||
* Textfield builder.
|
||||
*
|
||||
*/
|
||||
public class TextFieldBuilder extends AbstractTextFieldBuilder<TextFieldBuilder, TextField> {
|
||||
private static final int INPUT_DEBOUNCE_TIMEOUT = 500;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param maxLengthAllowed
|
||||
* as mandatory field
|
||||
*/
|
||||
public TextFieldBuilder(final int maxLengthAllowed) {
|
||||
super(maxLengthAllowed);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TextField createTextComponent() {
|
||||
final TextField textField = new TextField();
|
||||
textField.addStyleName(ValoTheme.TEXTFIELD_SMALL);
|
||||
textField.setValueChangeMode(ValueChangeMode.LAZY);
|
||||
textField.setValueChangeTimeout(INPUT_DEBOUNCE_TIMEOUT);
|
||||
|
||||
return textField;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.builder;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.CommonDialogWindow;
|
||||
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.ConfirmStyle;
|
||||
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.SaveDialogCloseListener;
|
||||
import org.eclipse.hawkbit.ui.decorators.SPUIButtonDecorator;
|
||||
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorderWithIcon;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
import com.vaadin.ui.Button.ClickListener;
|
||||
import com.vaadin.ui.Component;
|
||||
import com.vaadin.ui.Window;
|
||||
|
||||
/**
|
||||
* Builder for Window.
|
||||
*/
|
||||
public class WindowBuilder {
|
||||
|
||||
private String caption;
|
||||
private Component content;
|
||||
private ClickListener cancelButtonClickListener;
|
||||
private String helpLink;
|
||||
private VaadinMessageSource i18n;
|
||||
private final String type;
|
||||
private String id;
|
||||
private boolean showMandatoryExplanation = true;
|
||||
private ConfirmStyle confirmStyle = ConfirmStyle.SAVE;
|
||||
private Class<? extends SPUIButtonDecorator> buttonDecorator = SPUIButtonStyleNoBorderWithIcon.class;
|
||||
|
||||
private SaveDialogCloseListener saveDialogCloseListener;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param type
|
||||
* window type
|
||||
*/
|
||||
public WindowBuilder(final String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the SaveDialogCloseListener.
|
||||
*
|
||||
* @param saveDialogCloseListener
|
||||
* the saveDialogCloseListener
|
||||
* @return the window builder
|
||||
*/
|
||||
public WindowBuilder saveDialogCloseListener(final SaveDialogCloseListener saveDialogCloseListener) {
|
||||
this.saveDialogCloseListener = saveDialogCloseListener;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the caption.
|
||||
*
|
||||
* @param caption
|
||||
* the caption
|
||||
* @return the window builder
|
||||
*/
|
||||
public WindowBuilder caption(final String caption) {
|
||||
this.caption = caption;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content.
|
||||
*
|
||||
* @param content
|
||||
* the content
|
||||
* @return the window builder
|
||||
*/
|
||||
public WindowBuilder content(final Component content) {
|
||||
this.content = content;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cancelButtonClickListener.
|
||||
*
|
||||
* @param cancelButtonClickListener
|
||||
* the cancelButtonClickListener
|
||||
* @return the window builder
|
||||
*/
|
||||
public WindowBuilder cancelButtonClickListener(final ClickListener cancelButtonClickListener) {
|
||||
this.cancelButtonClickListener = cancelButtonClickListener;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the helpLink.
|
||||
*
|
||||
* @param helpLink
|
||||
* the helpLink
|
||||
* @return the window builder
|
||||
*/
|
||||
public WindowBuilder helpLink(final String helpLink) {
|
||||
this.helpLink = helpLink;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the i18n.
|
||||
*
|
||||
* @param i18n
|
||||
* the i18n
|
||||
* @return the window builder
|
||||
*/
|
||||
public WindowBuilder i18n(final VaadinMessageSource i18n) {
|
||||
this.i18n = i18n;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the id.
|
||||
*
|
||||
* @param id
|
||||
* the id to set * @return the window builder
|
||||
* @return the window builder
|
||||
*/
|
||||
public WindowBuilder id(final String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the line that explains the mandatory decorator
|
||||
*
|
||||
* @return the window builder
|
||||
*/
|
||||
public WindowBuilder hideMandatoryExplanation() {
|
||||
showMandatoryExplanation = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set buttonDecorator.
|
||||
*
|
||||
* @param buttonDecorator
|
||||
* the to style the confirm and cancel buttons
|
||||
* @return the window builder
|
||||
*/
|
||||
public WindowBuilder buttonDecorator(final Class<? extends SPUIButtonDecorator> buttonDecorator) {
|
||||
this.buttonDecorator = buttonDecorator;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set buttonDecorator.
|
||||
*
|
||||
* @param confirmStyle
|
||||
* what kind of button is used
|
||||
* @return the window builder
|
||||
*/
|
||||
public WindowBuilder confirmStyle(final ConfirmStyle confirmStyle) {
|
||||
this.confirmStyle = confirmStyle;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the common dialog window.
|
||||
*
|
||||
* @return the window.
|
||||
*/
|
||||
public CommonDialogWindow buildCommonDialogWindow() {
|
||||
final CommonDialogWindow window = new CommonDialogWindow(caption, content, helpLink, saveDialogCloseListener,
|
||||
cancelButtonClickListener, confirmStyle, buttonDecorator, i18n);
|
||||
if (!showMandatoryExplanation) {
|
||||
window.hideMandatoryExplanation();
|
||||
}
|
||||
decorateWindow(window);
|
||||
return window;
|
||||
|
||||
}
|
||||
|
||||
private void decorateWindow(final Window window) {
|
||||
if (id != null) {
|
||||
window.setId(id);
|
||||
}
|
||||
|
||||
if (SPUIDefinitions.CONFIRMATION_WINDOW.equals(type)) {
|
||||
window.setDraggable(false);
|
||||
window.setClosable(true);
|
||||
window.addStyleName(SPUIStyleDefinitions.CONFIRMATION_WINDOW_CAPTION);
|
||||
|
||||
} else if (SPUIDefinitions.CREATE_UPDATE_WINDOW.equals(type)) {
|
||||
window.setDraggable(true);
|
||||
window.setClosable(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build window based on type.
|
||||
*
|
||||
* @return Window
|
||||
*/
|
||||
public Window buildWindow() {
|
||||
final Window window = new Window(caption);
|
||||
window.setContent(content);
|
||||
window.setSizeUndefined();
|
||||
window.setModal(true);
|
||||
window.setResizable(false);
|
||||
|
||||
decorateWindow(window);
|
||||
|
||||
if (SPUIDefinitions.CREATE_UPDATE_WINDOW.equals(type)) {
|
||||
window.setClosable(false);
|
||||
}
|
||||
|
||||
return window;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.aware;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
|
||||
/**
|
||||
* Element is used for action creation
|
||||
*/
|
||||
public interface ActionTypeAware {
|
||||
void setActionType(ActionType actionType);
|
||||
|
||||
ActionType getActionType();
|
||||
|
||||
void setForcedTime(Long forcedTime);
|
||||
|
||||
Long getForcedTime();
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.aware;
|
||||
|
||||
/**
|
||||
* Element is describable
|
||||
*/
|
||||
public interface DescriptionAware {
|
||||
void setDescription(String name);
|
||||
|
||||
String getDescription();
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.aware;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSetInfo;
|
||||
|
||||
/**
|
||||
* Element provides a distribution set info
|
||||
*/
|
||||
public interface DsIdAware {
|
||||
void setDistributionSetInfo(ProxyDistributionSetInfo dsInfo);
|
||||
|
||||
ProxyDistributionSetInfo getDistributionSetInfo();
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.aware;
|
||||
|
||||
/**
|
||||
* Element is named
|
||||
*/
|
||||
public interface NameAware {
|
||||
void setName(String name);
|
||||
|
||||
String getName();
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.aware;
|
||||
|
||||
import org.eclipse.hawkbit.ui.rollout.window.components.AutoStartOptionGroupLayout.AutoStartOption;
|
||||
|
||||
/**
|
||||
* Element is used for rollout creation
|
||||
*/
|
||||
public interface StartOptionAware {
|
||||
void setStartOption(AutoStartOption startOption);
|
||||
|
||||
AutoStartOption getStartOption();
|
||||
|
||||
void setStartAt(Long forcedTime);
|
||||
|
||||
Long getStartAt();
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.aware;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQueryInfo;
|
||||
|
||||
/**
|
||||
* Element is used for target filter query combobox
|
||||
*/
|
||||
public interface TargetFilterQueryAware {
|
||||
void setTargetFilterQueryInfo(ProxyTargetFilterQueryInfo tfqInfo);
|
||||
|
||||
ProxyTargetFilterQueryInfo getTargetFilterQueryInfo();
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.aware;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTypeInfo;
|
||||
|
||||
/**
|
||||
* Element provides type info.
|
||||
*/
|
||||
public interface TypeInfoAware {
|
||||
void setTypeInfo(ProxyTypeInfo typeInfo);
|
||||
|
||||
ProxyTypeInfo getTypeInfo();
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.aware;
|
||||
|
||||
/**
|
||||
* Element is versioned
|
||||
*/
|
||||
public interface VersionAware {
|
||||
void setVersion(String name);
|
||||
|
||||
String getVersion();
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.filters;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.DistributionSetDistributionsStateDataProvider;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
|
||||
/**
|
||||
* Filter params for {@link DistributionSetDistributionsStateDataProvider}.
|
||||
*/
|
||||
public class DsDistributionsFilterParams extends DsFilterParams {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long dsTypeId;
|
||||
|
||||
/**
|
||||
* Constructor for DsDistributionsFilterParams
|
||||
*/
|
||||
public DsDistributionsFilterParams() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param searchText
|
||||
* String
|
||||
* @param dsTypeId
|
||||
* Long
|
||||
*/
|
||||
public DsDistributionsFilterParams(final String searchText, final Long dsTypeId) {
|
||||
super(searchText);
|
||||
this.dsTypeId = dsTypeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy Constructor.
|
||||
*
|
||||
* @param filter
|
||||
* A filter to be copied
|
||||
*/
|
||||
public DsDistributionsFilterParams(final DsDistributionsFilterParams filter) {
|
||||
super(filter);
|
||||
this.dsTypeId = filter.getDsTypeId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DsTypeId
|
||||
*/
|
||||
public Long getDsTypeId() {
|
||||
return dsTypeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for DsTypeId
|
||||
*
|
||||
* @param dsTypeId
|
||||
* Long
|
||||
*/
|
||||
public void setDsTypeId(final Long dsTypeId) {
|
||||
this.dsTypeId = dsTypeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final DsDistributionsFilterParams other = (DsDistributionsFilterParams) obj;
|
||||
return Objects.equals(this.getSearchText(), other.getSearchText())
|
||||
&& Objects.equals(this.getDsTypeId(), other.getDsTypeId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getSearchText(), getDsTypeId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this).add("searchText", getSearchText()).add("dsTypeId", getDsTypeId())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.filters;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.DistributionSetManagementStateDataProvider;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Filter params for {@link DistributionSetManagementStateDataProvider}.
|
||||
*/
|
||||
public class DsFilterParams implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String searchText;
|
||||
|
||||
/**
|
||||
* Constructor for DsManagementFilterParams
|
||||
*/
|
||||
public DsFilterParams() {
|
||||
this("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param searchText
|
||||
* String as search text
|
||||
*/
|
||||
public DsFilterParams(final String searchText) {
|
||||
this.searchText = !StringUtils.isEmpty(searchText) ? String.format("%%%s%%", searchText) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy Constructor.
|
||||
*
|
||||
* @param filter
|
||||
* A filter to be copied
|
||||
*/
|
||||
public DsFilterParams(final DsFilterParams filter) {
|
||||
this.searchText = filter.getSearchText();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SearchText
|
||||
*/
|
||||
public String getSearchText() {
|
||||
return searchText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for searchText
|
||||
*
|
||||
* @param searchText
|
||||
* String
|
||||
*/
|
||||
public void setSearchText(final String searchText) {
|
||||
this.searchText = !StringUtils.isEmpty(searchText) ? String.format("%%%s%%", searchText) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final DsFilterParams other = (DsFilterParams) obj;
|
||||
return Objects.equals(this.getSearchText(), other.getSearchText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getSearchText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this).add("searchText", getSearchText()).toString();
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.filters;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.DistributionSetManagementStateDataProvider;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
|
||||
/**
|
||||
* Filter params for {@link DistributionSetManagementStateDataProvider}.
|
||||
*/
|
||||
public class DsManagementFilterParams extends DsFilterParams {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private boolean noTagClicked;
|
||||
private Collection<String> distributionSetTags;
|
||||
private String pinnedTargetControllerId;
|
||||
|
||||
/**
|
||||
* Constructor for DsManagementFilterParams
|
||||
*/
|
||||
public DsManagementFilterParams() {
|
||||
this("", false, new ArrayList<>(), "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param searchText
|
||||
* String as search text
|
||||
* @param noTagClicked
|
||||
* boolean
|
||||
* @param distributionSetTags
|
||||
* List of String as distribution tags
|
||||
* @param pinnedTargetControllerId
|
||||
* String as pinned target controller Id
|
||||
*/
|
||||
public DsManagementFilterParams(final String searchText, final boolean noTagClicked,
|
||||
final Collection<String> distributionSetTags, final String pinnedTargetControllerId) {
|
||||
super(searchText);
|
||||
this.noTagClicked = noTagClicked;
|
||||
this.distributionSetTags = distributionSetTags;
|
||||
this.pinnedTargetControllerId = pinnedTargetControllerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy Constructor.
|
||||
*
|
||||
* @param filter
|
||||
* A filter to be copied
|
||||
*/
|
||||
public DsManagementFilterParams(final DsManagementFilterParams filter) {
|
||||
super(filter);
|
||||
this.noTagClicked = filter.isNoTagClicked();
|
||||
this.distributionSetTags = filter.getDistributionSetTags() != null
|
||||
? new ArrayList<>(filter.getDistributionSetTags())
|
||||
: null;
|
||||
this.pinnedTargetControllerId = filter.getPinnedTargetControllerId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DistributionSetTags
|
||||
*/
|
||||
public Collection<String> getDistributionSetTags() {
|
||||
return distributionSetTags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for distributionSetTags
|
||||
*
|
||||
* @param distributionSetTags
|
||||
* collection of String
|
||||
*/
|
||||
public void setDistributionSetTags(final Collection<String> distributionSetTags) {
|
||||
this.distributionSetTags = distributionSetTags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return PinnedTargetControllerId
|
||||
*/
|
||||
public String getPinnedTargetControllerId() {
|
||||
return pinnedTargetControllerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for pinnedTargetControllerId
|
||||
*
|
||||
* @param pinnedTargetControllerId
|
||||
* String
|
||||
*/
|
||||
public void setPinnedTargetControllerId(final String pinnedTargetControllerId) {
|
||||
this.pinnedTargetControllerId = pinnedTargetControllerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return noTagClicked
|
||||
*/
|
||||
public boolean isNoTagClicked() {
|
||||
return noTagClicked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for noTagClicked
|
||||
*
|
||||
* @param noTagClicked
|
||||
* boolean
|
||||
*/
|
||||
public void setNoTagClicked(final boolean noTagClicked) {
|
||||
this.noTagClicked = noTagClicked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final DsManagementFilterParams other = (DsManagementFilterParams) obj;
|
||||
return Objects.equals(this.getSearchText(), other.getSearchText())
|
||||
&& Objects.equals(this.isNoTagClicked(), other.isNoTagClicked())
|
||||
&& Objects.equals(this.getDistributionSetTags(), other.getDistributionSetTags())
|
||||
&& Objects.equals(this.getPinnedTargetControllerId(), other.getPinnedTargetControllerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getSearchText(), isNoTagClicked(), getDistributionSetTags(), getPinnedTargetControllerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this).add("searchText", getSearchText()).add("noTagClicked", isNoTagClicked())
|
||||
.add("distributionSetTags", getDistributionSetTags())
|
||||
.add("pinnedTargetControllerId", getPinnedTargetControllerId()).toString();
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.filters;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.SoftwareModuleDataProvider;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Filter params for {@link SoftwareModuleDataProvider}.
|
||||
*/
|
||||
public class SwFilterParams implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String searchText;
|
||||
private Long softwareModuleTypeId;
|
||||
private Long lastSelectedDistributionId;
|
||||
|
||||
/**
|
||||
* Constructor for SwFilterParams to initialize
|
||||
*/
|
||||
public SwFilterParams() {
|
||||
this(null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param searchText
|
||||
* String as search text
|
||||
* @param softwareModuleTypeId
|
||||
* Long as software module Id
|
||||
* @param lastSelectedDistributionId
|
||||
* Long as Last selected Distribution Id
|
||||
*/
|
||||
public SwFilterParams(final String searchText, final Long softwareModuleTypeId,
|
||||
final Long lastSelectedDistributionId) {
|
||||
this.searchText = !StringUtils.isEmpty(searchText) ? String.format("%%%s%%", searchText) : null;
|
||||
this.softwareModuleTypeId = softwareModuleTypeId;
|
||||
this.lastSelectedDistributionId = lastSelectedDistributionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy Constructor.
|
||||
*
|
||||
* @param filter
|
||||
* A filter to be copied
|
||||
*/
|
||||
public SwFilterParams(final SwFilterParams filter) {
|
||||
this.searchText = filter.getSearchText();
|
||||
this.softwareModuleTypeId = filter.getSoftwareModuleTypeId();
|
||||
this.lastSelectedDistributionId = filter.getLastSelectedDistributionId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SearchText
|
||||
*
|
||||
* @return searchText
|
||||
*/
|
||||
public String getSearchText() {
|
||||
return searchText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for searchText
|
||||
*
|
||||
* @param searchText
|
||||
* String
|
||||
*/
|
||||
public void setSearchText(final String searchText) {
|
||||
this.searchText = !StringUtils.isEmpty(searchText) ? String.format("%%%s%%", searchText) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get softwareModuleTypeId
|
||||
*
|
||||
* @return softwareModuleTypeId
|
||||
*/
|
||||
public Long getSoftwareModuleTypeId() {
|
||||
return softwareModuleTypeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for softwareModuleTypeId
|
||||
*
|
||||
* @param softwareModuleTypeId
|
||||
* Long
|
||||
*/
|
||||
public void setSoftwareModuleTypeId(final Long softwareModuleTypeId) {
|
||||
this.softwareModuleTypeId = softwareModuleTypeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lastSelectedDistributionId
|
||||
*
|
||||
* @return lastSelectedDistributionId
|
||||
*/
|
||||
public Long getLastSelectedDistributionId() {
|
||||
return lastSelectedDistributionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for lastSelectedDistributionId
|
||||
*
|
||||
* @param lastSelectedDistributionId
|
||||
* Long
|
||||
*/
|
||||
public void setLastSelectedDistributionId(final Long lastSelectedDistributionId) {
|
||||
this.lastSelectedDistributionId = lastSelectedDistributionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final SwFilterParams other = (SwFilterParams) obj;
|
||||
return Objects.equals(this.getSearchText(), other.getSearchText())
|
||||
&& Objects.equals(this.getSoftwareModuleTypeId(), other.getSoftwareModuleTypeId())
|
||||
&& Objects.equals(this.getLastSelectedDistributionId(), other.getLastSelectedDistributionId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getSearchText(), getSoftwareModuleTypeId(), getLastSelectedDistributionId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this).add("searchText", getSearchText())
|
||||
.add("softwareModuleTypeId", getSoftwareModuleTypeId())
|
||||
.add("lastSelectedDistributionId", getLastSelectedDistributionId()).toString();
|
||||
}
|
||||
}
|
||||
@@ -1,369 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.filters;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.ui.common.data.providers.TargetManagementStateDataProvider;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Filter params for {@link TargetManagementStateDataProvider}.
|
||||
*/
|
||||
public class TargetManagementFilterParams implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long pinnedDistId;
|
||||
private String searchText;
|
||||
private Collection<TargetUpdateStatus> targetUpdateStatusList;
|
||||
private boolean overdueState;
|
||||
private Long distributionId;
|
||||
private boolean noTagClicked;
|
||||
private Collection<String> targetTags;
|
||||
private Long targetFilterQueryId;
|
||||
private boolean noTargetTypeClicked;
|
||||
private Long targetTypeId;
|
||||
|
||||
/**
|
||||
* Constructor for TargetManagementFilterParams to initialize
|
||||
*/
|
||||
public TargetManagementFilterParams() {
|
||||
this(null, null, Collections.emptyList(), false, null, false, Collections.emptyList(), null, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param pinnedDistId
|
||||
* Id for Pinned distribution
|
||||
* @param searchText
|
||||
* String as search text
|
||||
* @param targetUpdateStatusList
|
||||
* Collection of TargetUpdateStatus
|
||||
* @param overdueState
|
||||
* boolean
|
||||
* @param distributionId
|
||||
* Long
|
||||
* @param noTagClicked
|
||||
* boolean
|
||||
* @param targetTags
|
||||
* Collection of string as target tags
|
||||
* @param targetFilterQueryId
|
||||
* Id for target filter query
|
||||
*/
|
||||
public TargetManagementFilterParams(final Long pinnedDistId, final String searchText,
|
||||
final Collection<TargetUpdateStatus> targetUpdateStatusList, final boolean overdueState,
|
||||
final Long distributionId, final boolean noTagClicked, final Collection<String> targetTags,
|
||||
final Long targetFilterQueryId, final boolean noTargetTypeClicked, final Long targetTypeId) {
|
||||
this.pinnedDistId = pinnedDistId;
|
||||
this.searchText = searchText;
|
||||
this.targetUpdateStatusList = targetUpdateStatusList;
|
||||
this.overdueState = overdueState;
|
||||
this.distributionId = distributionId;
|
||||
this.noTagClicked = noTagClicked;
|
||||
this.targetTags = targetTags;
|
||||
this.targetFilterQueryId = targetFilterQueryId;
|
||||
this.noTargetTypeClicked = noTargetTypeClicked;
|
||||
this.targetTypeId = targetTypeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy Constructor.
|
||||
*
|
||||
* @param filter
|
||||
* A filter to be copied
|
||||
*/
|
||||
public TargetManagementFilterParams(final TargetManagementFilterParams filter) {
|
||||
this.pinnedDistId = filter.getPinnedDistId();
|
||||
this.searchText = filter.getSearchText();
|
||||
this.targetUpdateStatusList = filter.getTargetUpdateStatusList() != null
|
||||
? new ArrayList<>(filter.getTargetUpdateStatusList())
|
||||
: null;
|
||||
this.overdueState = filter.isOverdueState();
|
||||
this.distributionId = filter.getDistributionId();
|
||||
this.noTagClicked = filter.isNoTagClicked();
|
||||
this.targetTags = filter.getTargetTags() != null ? new ArrayList<>(filter.getTargetTags()) : null;
|
||||
this.noTargetTypeClicked = filter.isNoTargetTypeClicked();
|
||||
this.targetTypeId = filter.getTargetTypeId();
|
||||
this.targetFilterQueryId = filter.getTargetFilterQueryId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the flag that indicates if the filter is selected
|
||||
*
|
||||
* @return boolean <code>true</code> if the filter is selected, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean isAnyFilterSelected() {
|
||||
return isAnyTagSelected() || isAnyStatusFilterSelected() || isSearchActive() || isAnyComplexFilterSelected();
|
||||
}
|
||||
|
||||
private boolean isAnyTagSelected() {
|
||||
return !CollectionUtils.isEmpty(targetTags) || noTagClicked;
|
||||
}
|
||||
|
||||
private boolean isAnyStatusFilterSelected() {
|
||||
return !CollectionUtils.isEmpty(targetUpdateStatusList) || overdueState;
|
||||
}
|
||||
|
||||
private boolean isSearchActive() {
|
||||
return !StringUtils.isEmpty(searchText);
|
||||
}
|
||||
|
||||
private boolean isAnyComplexFilterSelected() {
|
||||
return distributionId != null || targetFilterQueryId != null || isAnyTypeSelected();
|
||||
}
|
||||
|
||||
private boolean isAnyTypeSelected(){
|
||||
return targetTypeId != null || isNoTargetTypeClicked();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pinnedDistId
|
||||
*
|
||||
* @return Id for pinned distribution
|
||||
*/
|
||||
public Long getPinnedDistId() {
|
||||
return pinnedDistId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pinnedDistId
|
||||
*
|
||||
* @param pinnedDistId
|
||||
* Id for pinned distribution
|
||||
*/
|
||||
public void setPinnedDistId(final Long pinnedDistId) {
|
||||
this.pinnedDistId = pinnedDistId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the searchText
|
||||
*
|
||||
* @return searchText
|
||||
*/
|
||||
public String getSearchText() {
|
||||
return searchText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the searchText
|
||||
*
|
||||
* @param searchText
|
||||
* Text for search
|
||||
*/
|
||||
public void setSearchText(final String searchText) {
|
||||
this.searchText = !StringUtils.isEmpty(searchText) ? String.format("%%%s%%", searchText) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the targetUpdateStatusList
|
||||
*
|
||||
* @return Collection of targetUpdateStatus
|
||||
*/
|
||||
public Collection<TargetUpdateStatus> getTargetUpdateStatusList() {
|
||||
return targetUpdateStatusList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the targetUpdateStatusList
|
||||
*
|
||||
* @param targetUpdateStatusList
|
||||
* Collection of targetUpdateStatus
|
||||
*/
|
||||
public void setTargetUpdateStatusList(final Collection<TargetUpdateStatus> targetUpdateStatusList) {
|
||||
this.targetUpdateStatusList = targetUpdateStatusList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the distributionId
|
||||
*
|
||||
* @return distributionId
|
||||
*/
|
||||
public Long getDistributionId() {
|
||||
return distributionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the distributionId
|
||||
*
|
||||
* @param distributionId
|
||||
* Distribution Id
|
||||
*/
|
||||
public void setDistributionId(final Long distributionId) {
|
||||
this.distributionId = distributionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the targetTags
|
||||
*
|
||||
* @return targetTags
|
||||
*/
|
||||
public Collection<String> getTargetTags() {
|
||||
return targetTags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the targetTags
|
||||
*
|
||||
* @param targetTags
|
||||
* Collection of targetTags
|
||||
*/
|
||||
public void setTargetTags(final Collection<String> targetTags) {
|
||||
this.targetTags = targetTags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the targetFilterQueryId
|
||||
*
|
||||
* @return targetFilterQueryId Id for target filter query
|
||||
*/
|
||||
public Long getTargetFilterQueryId() {
|
||||
return targetFilterQueryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the targetFilterQueryId
|
||||
*
|
||||
* @param targetFilterQueryId
|
||||
* Id for target filter query
|
||||
*/
|
||||
public void setTargetFilterQueryId(final Long targetFilterQueryId) {
|
||||
this.targetFilterQueryId = targetFilterQueryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the state of overdue
|
||||
*
|
||||
* @return overdueState <code>true</code> if the state is set, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean isOverdueState() {
|
||||
return overdueState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state of overDue
|
||||
*
|
||||
* @param overdueState
|
||||
* <code>true</code> if the state is set, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
public void setOverdueState(final boolean overdueState) {
|
||||
this.overdueState = overdueState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status of tag clicked
|
||||
*
|
||||
* @return noTagClicked <code>true</code> if the tag is clicked, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean isNoTagClicked() {
|
||||
return noTagClicked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state of overDue
|
||||
*
|
||||
* @param noTagClicked
|
||||
* <code>true</code> if the tag is clicked, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
public void setNoTagClicked(final boolean noTagClicked) {
|
||||
this.noTagClicked = noTagClicked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status of no target Type clicked
|
||||
*
|
||||
* @return noTargetTypeClicked <code>true</code> if it is clicked, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean isNoTargetTypeClicked() {
|
||||
return noTargetTypeClicked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state of no target type filter
|
||||
*
|
||||
* @param noTargetTypeClicked
|
||||
* <code>true</code> if the tag is clicked, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
public void setNoTargetTypeClicked(boolean noTargetTypeClicked) {
|
||||
this.noTargetTypeClicked = noTargetTypeClicked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the targetTypeId
|
||||
*
|
||||
* @return targetTypeId for target type filter
|
||||
*/
|
||||
public Long getTargetTypeId() {
|
||||
return targetTypeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the targetType
|
||||
*
|
||||
* @param targetTypeId
|
||||
* Id of targetType
|
||||
*/
|
||||
public void setTargetTypeId(Long targetTypeId) {
|
||||
this.targetTypeId = targetTypeId;
|
||||
}
|
||||
|
||||
// equals requires all fields in condition
|
||||
@SuppressWarnings("squid:S1067")
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final TargetManagementFilterParams other = (TargetManagementFilterParams) obj;
|
||||
return Objects.equals(this.getPinnedDistId(), other.getPinnedDistId())
|
||||
&& Objects.equals(this.getSearchText(), other.getSearchText())
|
||||
&& Objects.equals(this.getTargetUpdateStatusList(), other.getTargetUpdateStatusList())
|
||||
&& Objects.equals(this.isOverdueState(), other.isOverdueState())
|
||||
&& Objects.equals(this.getDistributionId(), other.getDistributionId())
|
||||
&& Objects.equals(this.isNoTagClicked(), other.isNoTagClicked())
|
||||
&& Objects.equals(this.getTargetTags(), other.getTargetTags())
|
||||
&& Objects.equals(this.getTargetFilterQueryId(), other.getTargetFilterQueryId())
|
||||
&& Objects.equals(this.isNoTargetTypeClicked(), other.isNoTargetTypeClicked())
|
||||
&& Objects.equals(this.getTargetTypeId(), other.getTargetTypeId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getPinnedDistId(), getSearchText(), getTargetUpdateStatusList(), isOverdueState(),
|
||||
getDistributionId(), isNoTagClicked(), getTargetTags(), getTargetFilterQueryId(), isNoTargetTypeClicked(), getTargetTypeId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this).add("pinnedDistId", getPinnedDistId())
|
||||
.add("searchText", getSearchText()).add("targetUpdateStatusList", getTargetUpdateStatusList())
|
||||
.add("overdueState", isOverdueState()).add("distributionId", getDistributionId())
|
||||
.add("noTagClicked", isNoTagClicked()).add("targetTags", getTargetTags())
|
||||
.add("targetFilterQueryId", getTargetFilterQueryId())
|
||||
.add("noTargetTypeClicked", isNoTargetTypeClicked()).add("targetTypeId", getTargetTypeId()).toString();
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.mappers;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyNamedEntity;
|
||||
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
|
||||
/**
|
||||
* Maps named entities, fetched from backend, to the proxy named entities.
|
||||
*
|
||||
* @param <T>
|
||||
* Generic type of ProxyNamedEntity
|
||||
* @param <U>
|
||||
* Generic type of NamedEntity
|
||||
*/
|
||||
public abstract class AbstractNamedEntityToProxyNamedEntityMapper<T extends ProxyNamedEntity, U extends NamedEntity>
|
||||
implements NamedEntityToProxyNamedEntityMapper<T, U> {
|
||||
|
||||
protected void mapNamedEntityAttributes(final U namedEntity, final T proxyNamedEntity) {
|
||||
proxyNamedEntity.setId(namedEntity.getId());
|
||||
proxyNamedEntity.setName(namedEntity.getName());
|
||||
proxyNamedEntity.setDescription(namedEntity.getDescription());
|
||||
proxyNamedEntity.setCreatedAt(namedEntity.getCreatedAt());
|
||||
proxyNamedEntity.setCreatedDate(SPDateTimeUtil.getFormattedDate(namedEntity.getCreatedAt()));
|
||||
proxyNamedEntity.setLastModifiedAt(namedEntity.getLastModifiedAt());
|
||||
proxyNamedEntity.setModifiedDate(SPDateTimeUtil.getFormattedDate(namedEntity.getLastModifiedAt()));
|
||||
proxyNamedEntity.setCreatedBy(UserDetailsFormatter.loadAndFormatCreatedBy(namedEntity));
|
||||
proxyNamedEntity.setLastModifiedBy(UserDetailsFormatter.loadAndFormatLastModifiedBy(namedEntity));
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.mappers;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyActionStatus;
|
||||
|
||||
/**
|
||||
* Maps {@link ActionStatus} entities, fetched from backend, to the
|
||||
* {@link ProxyActionStatus} entities.
|
||||
*/
|
||||
public class ActionStatusToProxyActionStatusMapper
|
||||
implements IdentifiableEntityToProxyIdentifiableEntityMapper<ProxyActionStatus, ActionStatus> {
|
||||
|
||||
@Override
|
||||
public ProxyActionStatus map(final ActionStatus actionStatus) {
|
||||
final ProxyActionStatus proxyAS = new ProxyActionStatus();
|
||||
|
||||
proxyAS.setCreatedAt(actionStatus.getCreatedAt());
|
||||
proxyAS.setStatus(actionStatus.getStatus());
|
||||
proxyAS.setId(actionStatus.getId());
|
||||
|
||||
return proxyAS;
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.mappers;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyAction;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyAction.IsActiveDecoration;
|
||||
|
||||
/**
|
||||
* Maps {@link Action} entities, fetched from backend, to the
|
||||
* {@link ProxyAction} entities.
|
||||
*/
|
||||
public class ActionToProxyActionMapper
|
||||
implements IdentifiableEntityToProxyIdentifiableEntityMapper<ProxyAction, Action> {
|
||||
|
||||
@Override
|
||||
public ProxyAction map(final Action action) {
|
||||
final ProxyAction proxyAction = new ProxyAction();
|
||||
|
||||
proxyAction.setId(action.getId());
|
||||
final String dsNameVersion = action.getDistributionSet().getName() + ":"
|
||||
+ action.getDistributionSet().getVersion();
|
||||
proxyAction.setDsNameVersion(dsNameVersion);
|
||||
proxyAction.setActionType(action.getActionType());
|
||||
proxyAction.setActive(action.isActive());
|
||||
proxyAction.setIsActiveDecoration(buildIsActiveDecoration(action));
|
||||
proxyAction.setLastModifiedAt(action.getLastModifiedAt());
|
||||
proxyAction.setRolloutName(action.getRollout() != null ? action.getRollout().getName() : "");
|
||||
proxyAction.setStatus(action.getStatus());
|
||||
proxyAction
|
||||
.setMaintenanceWindow(action.hasMaintenanceSchedule() ? buildMaintenanceWindowDisplayText(action) : "");
|
||||
proxyAction.setMaintenanceWindowStartTime(action.getMaintenanceWindowStartTime().orElse(null));
|
||||
proxyAction.setForcedTime(action.getForcedTime());
|
||||
|
||||
return proxyAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a virtual IsActiveDecoration for the presentation layer that is
|
||||
* calculated from {@link Action#isActive()} and
|
||||
* {@link Action#getActionStatus()}.
|
||||
*
|
||||
* @param action
|
||||
* the action combined IsActiveDecoration is calculated from
|
||||
* @return IsActiveDecoration combined decoration for the presentation
|
||||
* layer.
|
||||
*/
|
||||
private static IsActiveDecoration buildIsActiveDecoration(final Action action) {
|
||||
final Action.Status status = action.getStatus();
|
||||
|
||||
if (status == Action.Status.SCHEDULED) {
|
||||
return IsActiveDecoration.SCHEDULED;
|
||||
} else if (status == Action.Status.ERROR) {
|
||||
return IsActiveDecoration.IN_ACTIVE_ERROR;
|
||||
}
|
||||
|
||||
return action.isActive() ? IsActiveDecoration.ACTIVE : IsActiveDecoration.IN_ACTIVE;
|
||||
}
|
||||
|
||||
private static String buildMaintenanceWindowDisplayText(final Action action) {
|
||||
return action.getMaintenanceWindowSchedule() + "/" + action.getMaintenanceWindowDuration() + "/"
|
||||
+ action.getMaintenanceWindowTimeZone();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.mappers;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorAction;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupErrorCondition;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessAction;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupSuccessCondition;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditionBuilder;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroupConditions;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyAdvancedRolloutGroup;
|
||||
|
||||
/**
|
||||
* Maps {@link ProxyAdvancedRolloutGroup} entities, fetched from advanced group
|
||||
* rows, to the {@link RolloutGroupCreate} entities.
|
||||
*/
|
||||
public class AdvancedRolloutGroupDefinitionToCreateMapper {
|
||||
private final EntityFactory entityFactory;
|
||||
|
||||
/**
|
||||
* Constructor for AdvancedRolloutGroupDefinitionToCreateMapper
|
||||
*
|
||||
* @param entityFactory
|
||||
* the entity factory
|
||||
*/
|
||||
public AdvancedRolloutGroupDefinitionToCreateMapper(final EntityFactory entityFactory) {
|
||||
this.entityFactory = entityFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map rollout group
|
||||
*
|
||||
* @param advancedRolloutGroupDefinition
|
||||
* ProxyAdvancedRolloutGroup
|
||||
*
|
||||
* @return ProxyAdvancedRolloutGroup
|
||||
*/
|
||||
public RolloutGroupCreate map(final ProxyAdvancedRolloutGroup advancedRolloutGroupDefinition) {
|
||||
final RolloutGroupConditions conditions = new RolloutGroupConditionBuilder()
|
||||
.successAction(RolloutGroupSuccessAction.NEXTGROUP, null)
|
||||
.successCondition(RolloutGroupSuccessCondition.THRESHOLD,
|
||||
advancedRolloutGroupDefinition.getTriggerThresholdPercentage())
|
||||
.errorCondition(RolloutGroupErrorCondition.THRESHOLD,
|
||||
advancedRolloutGroupDefinition.getErrorThresholdPercentage())
|
||||
.errorAction(RolloutGroupErrorAction.PAUSE, null).build();
|
||||
|
||||
return entityFactory.rolloutGroup().create().name(advancedRolloutGroupDefinition.getGroupName())
|
||||
.description(advancedRolloutGroupDefinition.getGroupName())
|
||||
.targetFilterQuery(advancedRolloutGroupDefinition.getTargetFilterQuery())
|
||||
.targetPercentage(advancedRolloutGroupDefinition.getTargetPercentage()).conditions(conditions)
|
||||
.confirmationRequired(advancedRolloutGroupDefinition.isConfirmationRequired());
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.mappers;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyArtifact;
|
||||
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
|
||||
|
||||
/**
|
||||
* Maps {@link Artifact} entities, fetched from backend, to the
|
||||
* {@link ProxyArtifact} entities.
|
||||
*/
|
||||
public class ArtifactToProxyArtifactMapper
|
||||
implements IdentifiableEntityToProxyIdentifiableEntityMapper<ProxyArtifact, Artifact> {
|
||||
|
||||
@Override
|
||||
public ProxyArtifact map(final Artifact artifact) {
|
||||
final ProxyArtifact proxyArtifact = new ProxyArtifact();
|
||||
|
||||
proxyArtifact.setId(artifact.getId());
|
||||
proxyArtifact.setFilename(artifact.getFilename());
|
||||
proxyArtifact.setMd5Hash(artifact.getMd5Hash());
|
||||
proxyArtifact.setSha1Hash(artifact.getSha1Hash());
|
||||
proxyArtifact.setSha256Hash(artifact.getSha256Hash());
|
||||
proxyArtifact.setSize(artifact.getSize());
|
||||
proxyArtifact.setModifiedDate(SPDateTimeUtil.getFormattedDate(artifact.getLastModifiedAt()));
|
||||
|
||||
return proxyArtifact;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.mappers;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
|
||||
/**
|
||||
* Maps {@link AssignedSoftwareModule} entities, fetched from backend, to the
|
||||
* {@link ProxySoftwareModule} entities.
|
||||
*/
|
||||
public class AssignedSoftwareModuleToProxyMapper
|
||||
implements IdentifiableEntityToProxyIdentifiableEntityMapper<ProxySoftwareModule, AssignedSoftwareModule> {
|
||||
|
||||
private final SoftwareModuleToProxyMapper softwareModuleToProxyMapper;
|
||||
|
||||
/**
|
||||
* Constructor for SoftwareModuleToProxyMapper
|
||||
*
|
||||
* @param softwareModuleToProxyMapper
|
||||
* SoftwareModuleToProxyMapper
|
||||
*/
|
||||
public AssignedSoftwareModuleToProxyMapper(final SoftwareModuleToProxyMapper softwareModuleToProxyMapper) {
|
||||
this.softwareModuleToProxyMapper = softwareModuleToProxyMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProxySoftwareModule map(final AssignedSoftwareModule assignedSwModule) {
|
||||
final ProxySoftwareModule proxyModule = softwareModuleToProxyMapper.map(assignedSwModule.getSoftwareModule());
|
||||
proxyModule.setAssigned(assignedSwModule.isAssigned());
|
||||
|
||||
return proxyModule;
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.mappers;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSet;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTypeInfo;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
|
||||
/**
|
||||
* Maps {@link DistributionSet} entities, fetched from backend, to the
|
||||
* {@link ProxyDistributionSet} entities.
|
||||
*/
|
||||
public class DistributionSetToProxyDistributionMapper
|
||||
extends AbstractNamedEntityToProxyNamedEntityMapper<ProxyDistributionSet, DistributionSet> {
|
||||
|
||||
@Override
|
||||
public ProxyDistributionSet map(final DistributionSet distributionSet) {
|
||||
final ProxyDistributionSet proxyDistribution = new ProxyDistributionSet();
|
||||
|
||||
mapNamedEntityAttributes(distributionSet, proxyDistribution);
|
||||
|
||||
proxyDistribution.setVersion(distributionSet.getVersion());
|
||||
proxyDistribution.setNameVersion(
|
||||
HawkbitCommonUtil.getFormattedNameVersion(distributionSet.getName(), distributionSet.getVersion()));
|
||||
proxyDistribution.setIsComplete(distributionSet.isComplete());
|
||||
proxyDistribution.setRequiredMigrationStep(distributionSet.isRequiredMigrationStep());
|
||||
proxyDistribution.setIsValid(distributionSet.isValid());
|
||||
|
||||
final DistributionSetType type = distributionSet.getType();
|
||||
final ProxyTypeInfo typeInfo = new ProxyTypeInfo(type.getId(), type.getName(), type.getKey());
|
||||
proxyDistribution.setTypeInfo(typeInfo);
|
||||
|
||||
return proxyDistribution;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.mappers;
|
||||
|
||||
import org.eclipse.hawkbit.repository.Identifiable;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyIdentifiableEntity;
|
||||
|
||||
/**
|
||||
* Interface for mapping identifiable entities, fetched from backend, to the
|
||||
* proxy identifiable entities.
|
||||
*
|
||||
* @param <T>
|
||||
* Generic type of ProxyIdentifiableEntity
|
||||
* @param <U>
|
||||
* Generic type of Identifiable
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface IdentifiableEntityToProxyIdentifiableEntityMapper<T extends ProxyIdentifiableEntity, U extends Identifiable<Long>> {
|
||||
|
||||
/**
|
||||
* Maps the provided {@link Identifiable} loaded from the backend to a new
|
||||
* instance of {@link ProxyIdentifiableEntity}.
|
||||
*
|
||||
* @param identifiableEntity
|
||||
* the {@link Identifiable} to map
|
||||
* @return a new instance of {@link ProxyIdentifiableEntity}
|
||||
*/
|
||||
T map(U identifiableEntity);
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.mappers;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.NamedEntity;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyNamedEntity;
|
||||
|
||||
/**
|
||||
* Interface for mapping named entities, fetched from backend, to the proxy
|
||||
* named entities.
|
||||
*
|
||||
* @param <T>
|
||||
* Generic type of ProxyNamedEntity
|
||||
* @param <U>
|
||||
* Generic type of NamedEntity
|
||||
*/
|
||||
public interface NamedEntityToProxyNamedEntityMapper<T extends ProxyNamedEntity, U extends NamedEntity>
|
||||
extends IdentifiableEntityToProxyIdentifiableEntityMapper<T, U> {
|
||||
|
||||
/**
|
||||
* Maps the provided {@link NamedEntity} loaded from the backend to a new
|
||||
* instance of {@link ProxyNamedEntity}.
|
||||
*
|
||||
* @param namedEntity
|
||||
* the {@link NamedEntity} to map
|
||||
* @return a new instance of {@link ProxyNamedEntity}
|
||||
*/
|
||||
@Override
|
||||
T map(U namedEntity);
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.mappers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyAdvancedRolloutGroup;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQueryInfo;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Maps {@link RolloutGroup} entities, fetched from backend, to the
|
||||
* {@link ProxyAdvancedRolloutGroup} entities.
|
||||
*/
|
||||
public class RolloutGroupToAdvancedDefinitionMapper {
|
||||
|
||||
private final TargetFilterQueryManagement targetFilterQueryManagement;
|
||||
|
||||
/**
|
||||
* Constructor for RolloutGroupToAdvancedDefinitionMapper
|
||||
*
|
||||
* @param targetFilterQueryManagement
|
||||
* TargetFilterQueryManagement
|
||||
*/
|
||||
public RolloutGroupToAdvancedDefinitionMapper(final TargetFilterQueryManagement targetFilterQueryManagement) {
|
||||
this.targetFilterQueryManagement = targetFilterQueryManagement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map advanced Rollout Group
|
||||
*
|
||||
* @param rolloutGroup
|
||||
* RolloutGroup
|
||||
*
|
||||
* @return ProxyAdvancedRolloutGroup
|
||||
*/
|
||||
public ProxyAdvancedRolloutGroup map(final RolloutGroup rolloutGroup) {
|
||||
final ProxyAdvancedRolloutGroup advancedGroupRow = new ProxyAdvancedRolloutGroup();
|
||||
advancedGroupRow.setGroupName(rolloutGroup.getName());
|
||||
advancedGroupRow.setTargetsCount((long) rolloutGroup.getTotalTargets());
|
||||
|
||||
final String groupTargetFilterQuery = rolloutGroup.getTargetFilterQuery();
|
||||
if (!StringUtils.isEmpty(groupTargetFilterQuery)) {
|
||||
advancedGroupRow.setTargetFilterQuery(groupTargetFilterQuery);
|
||||
final Slice<TargetFilterQuery> filterQueries = targetFilterQueryManagement.findByQuery(PageRequest.of(0, 1),
|
||||
groupTargetFilterQuery);
|
||||
if (filterQueries.getNumberOfElements() == 1) {
|
||||
final TargetFilterQuery tfq = filterQueries.getContent().get(0);
|
||||
advancedGroupRow.setTargetFilterQueryInfo(
|
||||
new ProxyTargetFilterQueryInfo(tfq.getId(), tfq.getName(), tfq.getQuery()));
|
||||
}
|
||||
}
|
||||
|
||||
advancedGroupRow.setTargetPercentage(rolloutGroup.getTargetPercentage());
|
||||
advancedGroupRow.setTriggerThresholdPercentage(rolloutGroup.getSuccessConditionExp());
|
||||
advancedGroupRow.setErrorThresholdPercentage(rolloutGroup.getErrorConditionExp());
|
||||
advancedGroupRow.setConfirmationRequired(rolloutGroup.isConfirmationRequired());
|
||||
|
||||
return advancedGroupRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch rollout group data from the backend
|
||||
*
|
||||
* @param rolloutId
|
||||
* Rollout id
|
||||
* @param rolloutGroupManagement
|
||||
* RolloutGroupManagement
|
||||
* @param pageCount
|
||||
* Total page count
|
||||
*
|
||||
* @return List of advance rollout group
|
||||
*/
|
||||
public List<ProxyAdvancedRolloutGroup> loadRolloutGroupsFromBackend(final Long rolloutId,
|
||||
final RolloutGroupManagement rolloutGroupManagement, final int pageCount) {
|
||||
return rolloutGroupManagement.findByRollout(PageRequest.of(0, pageCount), rolloutId).stream().map(this::map)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.mappers;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyRolloutGroup;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
|
||||
/**
|
||||
* Maps {@link RolloutGroup} entities, fetched from backend, to the
|
||||
* {@link ProxyRolloutGroup} entities.
|
||||
*/
|
||||
public class RolloutGroupToProxyRolloutGroupMapper
|
||||
extends AbstractNamedEntityToProxyNamedEntityMapper<ProxyRolloutGroup, RolloutGroup> {
|
||||
|
||||
@Override
|
||||
public ProxyRolloutGroup map(final RolloutGroup rolloutGroup) {
|
||||
final ProxyRolloutGroup proxyRolloutGroup = new ProxyRolloutGroup();
|
||||
|
||||
mapNamedEntityAttributes(rolloutGroup, proxyRolloutGroup);
|
||||
|
||||
proxyRolloutGroup.setStatus(rolloutGroup.getStatus());
|
||||
proxyRolloutGroup.setErrorAction(rolloutGroup.getErrorAction());
|
||||
proxyRolloutGroup.setErrorActionExp(rolloutGroup.getErrorActionExp());
|
||||
proxyRolloutGroup.setErrorCondition(rolloutGroup.getErrorCondition());
|
||||
proxyRolloutGroup.setErrorConditionExp(rolloutGroup.getErrorConditionExp());
|
||||
proxyRolloutGroup.setSuccessCondition(rolloutGroup.getSuccessCondition());
|
||||
proxyRolloutGroup.setSuccessConditionExp(rolloutGroup.getSuccessConditionExp());
|
||||
proxyRolloutGroup.setFinishedPercentage(formatFinishedPercentage(rolloutGroup));
|
||||
proxyRolloutGroup.setTotalTargetsCount(String.valueOf(rolloutGroup.getTotalTargets()));
|
||||
proxyRolloutGroup.setTotalTargetCountStatus(rolloutGroup.getTotalTargetCountStatus());
|
||||
proxyRolloutGroup.setConfirmationRequired(rolloutGroup.isConfirmationRequired());
|
||||
|
||||
return proxyRolloutGroup;
|
||||
}
|
||||
|
||||
private static String formatFinishedPercentage(final RolloutGroup rolloutGroup) {
|
||||
float tmpFinishedPercentage = 0;
|
||||
switch (rolloutGroup.getStatus()) {
|
||||
case READY:
|
||||
case SCHEDULED:
|
||||
case ERROR:
|
||||
tmpFinishedPercentage = 0.0F;
|
||||
break;
|
||||
case FINISHED:
|
||||
tmpFinishedPercentage = 100.0F;
|
||||
break;
|
||||
case RUNNING:
|
||||
tmpFinishedPercentage = rolloutGroup.getTotalTargetCountStatus().getFinishedPercent();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return String.format(HawkbitCommonUtil.getCurrentLocale(), "%.1f", tmpFinishedPercentage);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.mappers;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSetInfo;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyRollout;
|
||||
|
||||
/**
|
||||
* Maps {@link Rollout} entities, fetched from backend, to the
|
||||
* {@link ProxyRollout} entities.
|
||||
*/
|
||||
public class RolloutToProxyRolloutMapper extends AbstractNamedEntityToProxyNamedEntityMapper<ProxyRollout, Rollout> {
|
||||
|
||||
@Override
|
||||
public ProxyRollout map(final Rollout rollout) {
|
||||
final ProxyRollout proxyRollout = new ProxyRollout();
|
||||
|
||||
mapNamedEntityAttributes(rollout, proxyRollout);
|
||||
|
||||
final DistributionSet ds = rollout.getDistributionSet();
|
||||
proxyRollout.setDsInfo(new ProxyDistributionSetInfo(ds.getId(), ds.getName(), ds.getVersion(), ds.isValid()));
|
||||
proxyRollout
|
||||
.setNumberOfGroups(rollout.getRolloutGroupsCreated() > 0 ? rollout.getRolloutGroupsCreated() : null);
|
||||
proxyRollout.setForcedTime(rollout.getForcedTime() > 0 ? rollout.getForcedTime() : null);
|
||||
proxyRollout.setStatus(rollout.getStatus());
|
||||
proxyRollout.setStatusTotalCountMap(rollout.getTotalTargetCountStatus().getStatusTotalCountMap());
|
||||
proxyRollout.setTotalTargets(rollout.getTotalTargets());
|
||||
proxyRollout.setApprovalDecidedBy(rollout.getApprovalDecidedBy());
|
||||
proxyRollout.setApprovalRemark(rollout.getApprovalRemark());
|
||||
proxyRollout.setActionType(rollout.getActionType());
|
||||
proxyRollout.setTargetFilterQuery(rollout.getTargetFilterQuery());
|
||||
proxyRollout.setStartAt(rollout.getStartAt());
|
||||
|
||||
return proxyRollout;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.data.mappers;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTypeInfo;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
|
||||
/**
|
||||
* Maps {@link SoftwareModule} entities, fetched from backend, to the
|
||||
* {@link ProxySoftwareModule} entities.
|
||||
*/
|
||||
public class SoftwareModuleToProxyMapper
|
||||
extends AbstractNamedEntityToProxyNamedEntityMapper<ProxySoftwareModule, SoftwareModule> {
|
||||
|
||||
@Override
|
||||
public ProxySoftwareModule map(final SoftwareModule softwareModule) {
|
||||
final ProxySoftwareModule proxySoftwareModule = new ProxySoftwareModule();
|
||||
|
||||
mapNamedEntityAttributes(softwareModule, proxySoftwareModule);
|
||||
|
||||
proxySoftwareModule.setVersion(softwareModule.getVersion());
|
||||
proxySoftwareModule.setNameAndVersion(
|
||||
HawkbitCommonUtil.concatStrings(":", softwareModule.getName(), softwareModule.getVersion()));
|
||||
proxySoftwareModule.setVendor(softwareModule.getVendor());
|
||||
proxySoftwareModule.setEncrypted(softwareModule.isEncrypted());
|
||||
|
||||
final SoftwareModuleType type = softwareModule.getType();
|
||||
final ProxyTypeInfo typeInfo = new ProxyTypeInfo(type.getId(), type.getName(), type.getKey());
|
||||
proxySoftwareModule.setTypeInfo(typeInfo);
|
||||
|
||||
return proxySoftwareModule;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user