Migrated Hawkbit UI to Vaadin 8 (#980)
* Migrated Hawkbit UI to Vaadin 8
* fixed tag assignment messages
* disable rollout buttons instead of hinding them in Rollout Grid
* fix mssql db error
* small improvements to remove duplications while creating labels and distribution set type combo
* upgraded Vaadin to 8.11.1, upgraded jsoup to 1.11.2 (used by Vaadin 8.11.1), fixed selection in Metadata window, moved Rollout Window components to separate components package
* moved DS/SM type combobox creation to FormComponentBuilder, fixed add to collection error in SoftwareModuleDetails, changed save entity icons to harddrive, common refactoring
* removed duplications between breadcrumb grid headers (RolloutGroupGridHeader, RolloutGroupTargetGridHeader, TargetFilterDetailsGridHeader)
* replace proxy type in proxy objects with simple type info
* made all text fileds lazy (the timeout is 500ms), fixed add rollout window error on getting the bean from layout to controller
* removed duplications between ds to tag and target to tag assignment supports, extracted assignment notification from HawkbitCommonUtils
* fixed search input with caption overlap
* refactored layout visibility and resize listeners
* fixed approval strategy, adapted rollout advanced group ids to always increase
* Combine created and modified column creation
* remove Column<?, ?> variables
* fix confirmation dialog line breaks
* fix grids in details and filters
* fix column creation for upload grids
* add default ExpandRatio, fix rollouts and target filter
* add default addColumn method and fix action grids
* update deployment and rollout grid and grid css
* fix grid column widths
* refactored approval layout
* adapted approval layout
* refactored advanced rollout group layout
* refactored advanced group definitions to use proxy bean
* fixed copy rollout window enable save button
* third draft of Rollout Window validation: added UNKNOWN validation status, validate all layouts after validation listener is added
* second draft of Rollout Window Validation
* first Rollout Window Validation draft for enable/disable save button
* fixed custom target filter de-selection on delete, re-selection on update, reset edit/delete crud menu mode on custom filter tab selection
* added error threshold validation on total target and number of groups change
* added random ids to Proxy identifiable entities without defined ids
* add universal check box generator
* adapted Update and Approve Rollout Window Layout
* adapted setting and getting bean values for Add and Copy Rollout layouts
* fix setting ConfirmationDialog ID
* refactor ConfirmationDialog to use a CommonDialogWindow internally
* fix rollout group definition input width
* remove code duplication in UI grid column creation
* refactored rollout group pie chart and legend by extracing them to their own class VisualGroupDefinitionLayout
* remove code duplication on link creation
* moved creation of AutoStartOptionGroupLayout to FormComponentBuilder
* extracted RolloutFormLayout and SimpleGroupsLayout together with corresponding proxy beans from AddRolloutWindowLayout, adapted code accordingly
* move TimeforcedIcon generation to StatusIconBuilder
* move code to StatusIconBuilder
* use objects to build labels from entity states
* use generic method to generate status icon labels
* moved AdvancedGroupRow from DefineGroupsLayout to separate class
* remove code duplication on icon creation
* removed Optionals from Data Providers
* fixed remaining parts of xss vulnarable components (tags/types)
* added description to key-value details pairs, moved the logic of paginated database access to HawkbitCommonUtils
* further adapted xss atack posibilities
* adapted details header and key-value details
* adapted MetaData header
* adapted Artifact and Action History Grid headers
* adapted artifact download
* adapted already assigned notification and rollout approval permission check
* removed tenant and username cookies from hawkbit login
* adapted attributes sorting by key
* adapted controller attributes details
* removed grid ResizeSupport (can be introduced later if needed)
* refactored grids to not use resizeSupport but rather removing all columns and re-adding them after max/min state transition
* fixed selection of added items
* moved restoreState to AbstractGrid
* unified Ds grids on Distribution and Deployment Views
* moved filter support and drag and drop support to AbstractGrid
* removed stale Sm grid id for Upload view
* removed duplication between SwModuleGrid and SoftwareModuleGrid
* removed unneccessary status icons css properties
* added grid MasterEntitySupport, adapted grids
* fixed tags/types filter deselection after deletion
* fixed deletion success notification, added artifact uploads count check to software module table
* unified target/ds/sm grid headers
* unified DS and SM grid headers and details
* added Delete Support to Rollout, adapted deletion permissions
* introduced EntityResizeSupport, upgraded vaadin version to 8.10.4
* unified ds and sm type filter components
* removed duplications between Target and Ds tag filters
* removed duplication for #buildActionButton
* initial iteration of removing duplications between grids
* added GridActionsVisibilityListener
* added layout visibility listener to filter and rollout views
* unified LayoutResizeListener and LayoutVisibilityListener
* extracted ShowEntityFormLayoutListener
* refactored grid filter listeners
* refactored target filter listeners, introduced filter support
* added GenericEventListener, further unified listeners
* partially unified LayoutViewAware event listeners, added PinningChangedListener, TagFilterListener and TypeFilterListener
* fixed sql exception in case NO_TAG is selected without any additional tags active
* unified entity modified listeners, adapted tag token modified update
* fixed Upload View drop area enable on SM select
* unified selection listeners
* unified search listeners
* added common SearchFilterListener, added temporare EntityModifiedMasterAwareSupport for EntityModifiedListener, fixed Rollout View change after rollout deletion/modification, adapted state restore
* refactored entity modified and selection listeners together with support classes
* added maintenance window and created/modified at tooltips in Action History Window, added id to Bulk Upload popup window and main popup layout, fixed duplicated DS error during DS edit/update
* substituted ShowEntityDetailsEventPayload with SelectionChangedEventPayload in Rollout View for consistency with other Views, unified rollout ui state class
* added builder to EntityModifiedListener, adapted code
* refactored sm type modification of ds type
* fix removing sm type from ds type via ui
* refresh rollout group targets table on group-updated-event
* moved grid label icon creation to SpUiComponent builder
* fixed edit tag/type with invalid colour
* added range validator(0-100) to trigger threshold
* fixed rollout auto start option updates, fixed rollout grid search state restore, extended SPDateTimeUtil
* Rollout Window Form fixes
* small partial fix for error threshold percent/count validation and value change
* fixed time forced empty datetime in Rollouts Update Window
* added workaround for target/ds tags drag and drop due to the missing selection support
* fixed ds unpinning after deletion and completion state change
* added reason to bulk upload failed notification
* fixed target add/update window form name id, introduced separate layout listeners for entity modified events and selection/master changed events, extended grid selection support, refactored corresponding grids, layouts and listeners
* fixed required messages in the from builder, changed asyncExecutor to ui executor for file streaming, fixed auto-assignment for layout
* fixed drag and drop registration for non-selection grid model, small restore state refactoring
* fixed action remote events tests, adapted crudMenu/resize/search header supports to use mode-{mode} classes instead of ids modification
* changed id of metadata popup grid to 'metadata.window.table.id' and details grid to '{typePrefix}.metadata.details.table.id', fixed tag/type cell text wrapping, tooltip shows full tag/type name, removed checkboxes from Distributions Set Type Software module selection grids
* added tooltip to Rollout/RolloutGroup status bar, small bug fixes for Rollout Window target filter and approval
* fixed edit permission validation in DetailsHeader
* unbind distributionsview javascript from vaadin theme
* small refactoring of form component builder, assignment and rollout layout
* remove ds combobox code duplication, fix assig and autoassign popup
* add BoundComponent class, fix assignment popup
* remove duplicates for name, version description and actiontype fields
* removed code duplication, fix assign- and autoassign-popup
* adapted Action history eventing, changed entity modified parent event propagation
* added id to DS details modules grid
* started adapting Action History View
* adapted filter by ds drop area restore
* align drop styling with previous
* fix filter target table by assigned ds
* small refactoring of Deployment View and System config View layouts
* adapted DS tag layout
* fixed incompelete DS deselection and unpinning
* added filter to RemoteEventListener in order to ignore remote events, added select entity on add to grids
* fixed DS modules details, explained why session scope is used for bulk upload
* adapted bulk upload window to be lazy loaded, fixed restore by usinng session scope
* fixed user cell text selection in grid, drop hint highlighting
* fixed undo for iot-update-server config option
* fixed parsing in DurationField and refactored system config view
* removed unused variable from DurationField
* refactored config option view
* fixed polling option value in config option view
* fixed token refresh value in config option view
* added binder auth config option
* added binder to save config option
* added binder for auto cleanup option
* upgraded vaadin to 8.10.0, removed dd package together with CustomAcceptCriteria extension, removed CustomAcceptCriteria tests, removed all vaadin v7 dependencies, removed compatibility server and client
* added selection by pressing key up/down, refactored range selection handler and connector, drag and drop support drop style listener, removed unneccessary styles for selection extension
* show drop hint
* fix h2 cast error
* make unselected row dragable
* add support for selection using Shift and CTRL
* remove grid checkboxes, fix selection and drag and drop
* moved bulk upload classes to own package, started implementing bulk upload window builder
* further adaptations of bulk upload
* started adapting bulk upload
* partially removed stale classes/methods, vaadin v7 imports
* completeted pinning refactoring
* further pinning refactoring, added restore to distributions grid in deployment view
* started adapting pinning of target and distribution set
* further remote eventing refactoring, small styling adaptations
* added 'maximize' and 'minimize' ids to max/min grid icons
* removed event containers, adapting the delayed event bus push strategy, event provider and remote events listener
* small eventing refactoring
* adapted tag filter eventing, removed old event classes
* adapted selection eventing, fixed color styling for grid selection, added countByAssignedId to softwaremodulemanagement
* adapted type filter eventing
* adapted search filter eventing
* adapted actions visibility change eventing in filter layouts
* adapted layout eventing in Deployment View
* adapted layout eventing in Distributions View
* adapted layout eventing in Upload View
* adapted entity modified eventing
* adapted rollout eventing
* fix rollout view and window styling
* handle rollouts view remote events
* adapted eventing in Rollouts View
* fixed Target Filter session state management in Edit Form mode
* adapted target filter query add/update layout to use form layout
* started adapting tags assignment
* removed AbstractNotificationView
* added row border in grids
* fixed restoreState in Target Filters and Target Grid, refatored eventing in Deployment View
* Added event listener for DsSetType
* added confirmation window id for deletion support, added id for action type radio group, reworked restore state, small changes in Deployment view
* started adapting ds grid, ds tags, action history and Deployment View layout
* started adapting target grid
* reworked Target Filter View and event handling
* fixed Target Details error, started adapting Target Grid Layout
* refactored Date time parser
* fixed Date time parser
* fixed formatting
* fixed errors in auto close option
* fixed errors in auto cleanup option
* fixed errors in Polling view option
* adapted filter management view and selection listener behaviour
* cleanup, fix vaadin query to spring pageable convertion
* adapted target tag filter layout
* started adapting Deployment view
* fixed software modules details grid rendering under Distribution Set Details
* adapted artifact details grid popup window for Software Module details
* adapted auto assignment details grid for DS
* added get by ids to target tag management, adapted tag details layout for distribution set tag and target tag
* package structure refactoring
* started adapting software module details tab within distribution set details layout
* excluded javax.validation because of a reference to an old sources file
* fixed system config view misconfiguration
* fixed ids formating, added UI access call for updating entities through listeners
* refactored sm and ds types saving in proxy sm and ds entities
* fixed software module to distribution set assignment and software module dataprovider in Distributions View
* adapted add/update notification for software module and distribution set to show name and version, fixed search text field id
* adapted software module color highlighting in Distributions View
* adapted login ui
* started adapting Distributions View
* unified filter buttons click behaviour, added restore clicked filter to Upload View
* removed duplications in filter headers
* removed duplication in filter type/tag layouts
* added sm and ds type remote events matchers for listener
* adapted metadata details grid, update eventing fo details layout in Upload View
* adapted entity deletion eventing and selection on restore state for Upload View
* adapted file upload events handling, introduced RemoteEventsListener for the complete UI
* adapted Details Header to render two separate labels for caption prefix (entity type) and entity name to prevent xss attack
* upgraded vaadin to version 8.9.3, adapted upload artifact view and corresponding eventing further
* change visibility of components instead of removing them in Upload View
* adapted metadata popup window for target, distribution set and software module
* first iteration of adapting metadata window layout: created meta data dataproviders and window grids for target, ds and sm
* adapted auto assign window layout
* further refactoring of Target filter view and layouts
* adapted software module add/update window layout
* adapted distribution set add/update window layout
* refactored window layouts
* fixed software module add/update layout, adapted target add/update layout
* added validation of empty distribution set type software module types and mandatory property change
* further refactoring of distribution set type add/update window
* adapted distribution set type add/update window
* adapted software module type add/update window layout
* adapted tag layouts and color picker structure
* adapted target and ds tag add/update windows, refactored color picker
* added ds and sm type event containers
* refactored local eventing and remote events handling, mainly only for distributions view
* fixed ui alignment on the right side of the page
* Finalized upload view migration
* Fixed upload layout not enabled problem
* Migrated Upload view. Some small glitches still open.
* moved details headers to layouts
* added callback to update last selected entity in UI state after each grid selection, unified all details layouts
* further refactoring of Target Details
* added selected event publishing to selection support, refactored target details
* started unifying details layouts and adding details support classes
* unified grid layouts
* unified Target Filter Header
* fixed glitches in UI regarding Headers, dapted eventing for crud menu and close header supports
* unified types and tags headers
* unified more headers
* adapted TargetTableHeader to use AbstractGridHeader with Header Support classes, renamed to TargetGridHeader, removed unsused css properties
* added CrudMenuHeaderSupport, refactored AbstractGridHeader
* added AddHeaderSupport, BulkUploadHeaderSupport, CloseHeaderSupport, FilterButtonsHeaderSupport, ResizeHeaderSupport, SearchHeaderSupport, refactored ConfigMenuBar behaviour in MultipleTargetFilter
* started unifying headers
* extracted BulkUpload from AbstractTableHeader to TargetTableHeader
* removed header row for tags and types grids, adapted margin/padding for some layouts, modified css properties for borders, updated vaadin version to 8.8.6, vaadin-spring to 3.2.1
* added javax servlet api maven dependency to hawkbit-autoconfigure, because gwt-user is not used anymore, fixed a couple of runtime errors, hawkbit starts :)
* adapted TargetTableHeader drag and drop in order to filter targets by Distribution Sets, adapted gwt modules to inherit from compatibility Vaadin7WidgetSet, upgraded DistributionBar addon to be compatible with vaadin 8
* added NO TAG button to Target Tag and Distribution Tag layouts
* adapted Distribution Set Types and Software Module Types layouts
* adapted Target Tags layout, Distribution Set Tags Layout, added corresponding drag and drop supports
* migrated from Table to Grid in TargetFilterQueryButtons, adapted click listeners
* adapted twin columns layout for creating/updating Distribution Set Type
* adapted MetaData Details classes
* adapted AbstractMetadataPopupLayout and all children classes, refactored DeleteSupport
* adapted Grid in UploadProgressInfoWindow
* adapted software module details, target filter query details, removed custom combobox for autoassignment, adapted layouts and details
* removed obsolete classes, adapted layouts as needed, removed Custom Renderers because components are used directly within the grids
* added ArtifactDetailsGrid for Upload View, modified Artifact Layout to be consistent with Action History Layout in Deployment View, adapted Views and Layouts
* added SoftwareModuleGrid to Upload View
* migrated SwModuleTable to SwModuleGrid
* migrated Distribution Set Table from Distributions View to Grid, refactored drag and drop
* refactored target grid in Create/Update Filter View
* refactored tag classes to use TagData where possible
* migrated CreateOrupdateFilterTable to grid
* adapted tag token classes
* adapted Layouts, chaned Base Ui Event to except Proxy Entities
* adapted TargetFilterGrid
* Migrated TargetFilterTable to grid
* Removed vaadin Tokenfield dependency
* removed ConfirmationTab, using Component ConfirmationDialog instead; adapted MaintenanceWindowLayout, introduced AssignmentWindowLayout together with corresponding ComponentBuilder and Controller; added Drag and Drop support with differen Assignments support, adapted TargetGrid and DistributionGrid correspondingly; removed TargetAssignmentOperations utility class
* second version of PinSupport
* added DeleteSupport for target and distribution set items deletion
* first draft of PinSupport for pinning targets and distribution setes
* added first draft of Management Distribution Set Grid, adapted the corresponding data provider, adapted AbstractBaseViewFilter (should be checked)
* first draft of Target Grid, refactored Selection support to include multi-selection mode
* extracted single selection support, resize support and master details support from AbstractGrid, added filter type to AbstractGrid so the dataproviders are filterable by default, adapted some data providers to use filters, refactored master-details scenario for action history/status/msg layouts
* Adapted AbstractGrid for resize support, adapted ActionHistoryGrid, ActionStatusGrid, ActionStatusMsgGrid
* added rollout window specific classes (layouts, controllers, component builders)
* changed Rollout/Group/Target List Grids to use vaadin 8 concepts, added temp utility classes
* added ArtifactDataProvider and corresponding ProxyArtifact, SoftwareModuleArtifactsStateDataProvider, SoftwareModuleDistributionsStateDataProvider, TargetFilterStateDataProvider, TargetManagementStateDataProvider, TargetTagDataProvider and corresponding mappers
* added parent Type model class for DistributionSetType and SoftwareModuleType and corresponding ProxyType, added ActionDataProvider, ActionStatusDataProvider, ActionStatusMsgDataProvider, DistributionSetTagDataProvider, DistributionSetTypeDataProvider, SoftwareModuleTypeDataProvider and corresponding mappers
* extended data providers with filter, implemented multiple distribution set data providers for sifferent ui state (views), added target tag data provider, adapted Proxy Tag
* added data providers, mappers and proxy classes for fetching entities from backend and mapping them to ui proxy entities
* removed setImmediate on classes
* fixed usage of option group layouts, removed all setImmediate calls
* removed flexibleoptiongroup dependency and adapted the Option Group Layouts to use the default RadioButtonGroup
* adapted Vaadin Security and fixed Notifications
* Migrated vaadin 7 sources with the Vaadin migration tool to vaadin 8 compatibility mode
* fixed some minor sonar issues
* fixed license headers
* fixed dynamic stylesheet js license header
* adapted java docs parameters description, removed unused event classes
* fixed icon styles, made action icons a little bigger
* fixed download artifact action icon column header, fixed styling for the target filter query add/update layout, made it more responsive instead of hardcoding pixel values
* fixed Notification rendering regarding word wrap
* fixed restore behaviour with the invalid target filter query in Filter View
* replaced List collection with Set for better performance during DS pinning, tag assignment, target status filtering and rollout add/update window validation, ignored irrelevant sonar issues
* disable crud menu button on no CUD permissions, disable Rollout Group Button on missing permissions, removed Target Metadata details tab on missing repository read permissions, removed Autoassignment DS details tab on missing target read permissions, added UIEventPermissionChecker/HawkbitEventPermissionChecker to verify if current user has the required permissions in order to receive push events/notifications
* disable Autoassignment link in case of missing read repository permissions, disable TFQ save button in case of missing update target permissions
* adapted ordering of columns in maximized state
* limited selection in grids to 1000 entities, removed shift+ctrl selection behaviour (due to complex logic for preserving and limiting selection) disable edit/copy rollout on creation, small naming changes and java docs improvements
* added java docs to notification class
* fixed restoration of the default filter value for grids
* added caption to Delete column in grids, made target filter grid columns hidable, stoped propagation of select all event in order to not select the text on the page
* removed com.google.gwt.gwtmockito test dependency
* renamed RemoteEventsListener to HawkbitEntityEventListener to better describe the use-case for the listener
* changed Guava cache to Caffeine cache for EntityModified UI events
* removed obsolete HawkbitErrorNotificationMessage, UINotification is used instead
* added stacked notifications custom extension
* removed unused JUnitParams dependency
* fixed license header for ParallelNotificationConnector
* set ui mode back to production
Signed-off-by: Bogdan Bondar <Bogdan.Bondar@bosch.io>
This commit is contained in:
@@ -91,5 +91,14 @@
|
||||
<artifactId>protostuff-runtime</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.vaadin.spring.extensions</groupId>
|
||||
<artifactId>vaadin-spring-ext-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -12,10 +12,13 @@ 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.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
@@ -26,7 +29,7 @@ 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 org.vaadin.spring.security.annotation.EnableVaadinSecurity;
|
||||
import org.vaadin.spring.security.annotation.EnableVaadinManagedSecurity;
|
||||
|
||||
import com.vaadin.spring.annotation.UIScope;
|
||||
|
||||
@@ -34,7 +37,7 @@ import com.vaadin.spring.annotation.UIScope;
|
||||
* The Management UI auto configuration.
|
||||
*/
|
||||
@Configuration
|
||||
@EnableVaadinSecurity
|
||||
@EnableVaadinManagedSecurity
|
||||
@EnableVaadinExtensions
|
||||
@EnableEventBus
|
||||
@ConditionalOnClass(MgmtUiConfiguration.class)
|
||||
@@ -68,6 +71,18 @@ public class MgmtUiAutoConfiguration {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* The UI scoped event push strategy. Session scope is necessary, that every
|
||||
* UI has an own strategy.
|
||||
@@ -80,6 +95,8 @@ public class MgmtUiAutoConfiguration {
|
||||
* 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
|
||||
@@ -89,10 +106,12 @@ public class MgmtUiAutoConfiguration {
|
||||
@UIScope
|
||||
EventPushStrategy eventPushStrategy(final ConfigurableApplicationContext applicationContext,
|
||||
final ScheduledExecutorService executorService, final UIEventBus eventBus,
|
||||
final UIEventProvider eventProvider, final UiProperties uiProperties) {
|
||||
final UIEventProvider eventProvider, final UIEventPermissionChecker eventPermissionChecker,
|
||||
final UiProperties uiProperties) {
|
||||
final DelayedEventBusPushStrategy delayedEventBusPushStrategy = new DelayedEventBusPushStrategy(executorService,
|
||||
eventBus, eventProvider, uiProperties.getEvent().getPush().getDelay());
|
||||
eventBus, eventProvider, eventPermissionChecker, uiProperties.getEvent().getPush().getDelay());
|
||||
applicationContext.addApplicationListener(delayedEventBusPushStrategy);
|
||||
|
||||
return delayedEventBusPushStrategy;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
package org.eclipse.hawkbit.autoconfigure.mgmt.ui;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
@@ -23,7 +23,7 @@ public class RedirectController {
|
||||
/**
|
||||
* @return redirect to the Management UI
|
||||
*/
|
||||
@RequestMapping("/")
|
||||
@GetMapping("/")
|
||||
public ModelAndView home() {
|
||||
return new ModelAndView("redirect:/UI/");
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.vaadin.spring.security.config.AuthenticationManagerConfigurer;
|
||||
|
||||
/**
|
||||
* Auto-configuration for the in-memory-user-management.
|
||||
@@ -40,7 +41,8 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(UserDetailsService.class)
|
||||
@EnableConfigurationProperties({ MultiUserProperties.class })
|
||||
public class InMemoryUserManagementAutoConfiguration extends GlobalAuthenticationConfigurerAdapter {
|
||||
public class InMemoryUserManagementAutoConfiguration extends GlobalAuthenticationConfigurerAdapter
|
||||
implements AuthenticationManagerConfigurer {
|
||||
|
||||
private static final String DEFAULT_TENANT = "DEFAULT";
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
@@ -26,7 +25,7 @@ import org.eclipse.hawkbit.ddi.rest.api.DdiRestConstants;
|
||||
import org.eclipse.hawkbit.ddi.rest.resource.DdiApiConfiguration;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.im.authentication.TenantUserPasswordAuthenticationToken;
|
||||
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
|
||||
import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter;
|
||||
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
|
||||
import org.eclipse.hawkbit.mgmt.rest.resource.MgmtApiConfiguration;
|
||||
@@ -62,7 +61,7 @@ import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.authentication.InsufficientAuthenticationException;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
@@ -97,11 +96,12 @@ import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.vaadin.spring.security.VaadinSecurityContext;
|
||||
import org.vaadin.spring.security.annotation.EnableVaadinSecurity;
|
||||
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 org.vaadin.spring.security.web.authentication.VaadinAuthenticationSuccessHandler;
|
||||
import org.vaadin.spring.security.web.authentication.VaadinUrlAuthenticationSuccessHandler;
|
||||
|
||||
/**
|
||||
* All configurations related to HawkBit's authentication and authorization
|
||||
@@ -530,11 +530,10 @@ public class SecurityManagedConfiguration {
|
||||
// Only get the first client registration. Testing against every
|
||||
// client could increase the
|
||||
// attack vector
|
||||
ClientRegistration clientRegistration = null;
|
||||
for (final ClientRegistration cr : clientRegistrationRepository) {
|
||||
clientRegistration = cr;
|
||||
break;
|
||||
}
|
||||
final ClientRegistration clientRegistration = clientRegistrationRepository != null
|
||||
&& clientRegistrationRepository.iterator().hasNext()
|
||||
? clientRegistrationRepository.iterator().next()
|
||||
: null;
|
||||
|
||||
Assert.notNull(clientRegistration, "There must be a valid client registration");
|
||||
httpSec.oauth2ResourceServer().jwt().jwkSetUri(clientRegistration.getProviderDetails().getJwkSetUri());
|
||||
@@ -596,18 +595,13 @@ public class SecurityManagedConfiguration {
|
||||
*/
|
||||
@Configuration
|
||||
@Order(400)
|
||||
@EnableVaadinSecurity
|
||||
@EnableVaadinSharedSecurity
|
||||
@ConditionalOnClass(MgmtUiConfiguration.class)
|
||||
public static class UISecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
private VaadinSecurityContext vaadinSecurityContext;
|
||||
|
||||
@Autowired
|
||||
private HawkbitSecurityProperties hawkbitSecurityProperties;
|
||||
|
||||
private final VaadinUrlAuthenticationSuccessHandler handler;
|
||||
|
||||
@Autowired(required = false)
|
||||
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService;
|
||||
|
||||
@@ -620,14 +614,6 @@ public class SecurityManagedConfiguration {
|
||||
@Autowired
|
||||
private LogoutSuccessHandler logoutSuccessHandler;
|
||||
|
||||
|
||||
public UISecurityConfigurationAdapter(final VaadinRedirectStrategy redirectStrategy) {
|
||||
handler = new TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler();
|
||||
handler.setRedirectStrategy(redirectStrategy);
|
||||
handler.setDefaultTargetUrl("/UI/");
|
||||
handler.setTargetUrlParameter("r");
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter to protect the hawkBit management UI against to many requests.
|
||||
*
|
||||
@@ -651,17 +637,8 @@ public class SecurityManagedConfiguration {
|
||||
return filterRegBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* post construct for setting the authentication success handler for the
|
||||
* vaadin security context.
|
||||
*/
|
||||
@PostConstruct
|
||||
public void afterPropertiesSet() {
|
||||
this.vaadinSecurityContext.addAuthenticationSuccessHandler(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean(name = "authenticationManager")
|
||||
@Bean(name = VaadinSharedSecurityConfiguration.AUTHENTICATION_MANAGER_BEAN)
|
||||
public AuthenticationManager authenticationManagerBean() throws Exception {
|
||||
return super.authenticationManagerBean();
|
||||
}
|
||||
@@ -669,8 +646,13 @@ public class SecurityManagedConfiguration {
|
||||
/**
|
||||
* @return the vaadin success authentication handler
|
||||
*/
|
||||
@Bean
|
||||
public VaadinAuthenticationSuccessHandler redirectSaveHandler() {
|
||||
@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;
|
||||
}
|
||||
|
||||
@@ -717,8 +699,8 @@ public class SecurityManagedConfiguration {
|
||||
}
|
||||
|
||||
// UI
|
||||
httpSec.authorizeRequests().antMatchers("/UI/login/**", "/UI/UIDL/**").permitAll()
|
||||
.anyRequest().authenticated();
|
||||
httpSec.authorizeRequests().antMatchers("/UI/login/**", "/UI/UIDL/**").permitAll().anyRequest()
|
||||
.authenticated();
|
||||
|
||||
if (enableOidc) {
|
||||
// OIDC
|
||||
@@ -737,7 +719,7 @@ public class SecurityManagedConfiguration {
|
||||
|
||||
@Override
|
||||
public void configure(final WebSecurity webSecurity) throws Exception {
|
||||
// Not security for static content
|
||||
// No security for static content
|
||||
webSecurity.ignoring().antMatchers("/documentation/**", "/VAADIN/**", "/*.*", "/docs/**");
|
||||
}
|
||||
}
|
||||
@@ -756,30 +738,31 @@ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends
|
||||
@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 {
|
||||
|
||||
if (authentication.getClass().equals(TenantUserPasswordAuthenticationToken.class)) {
|
||||
systemSecurityContext.runAsSystemAsTenant(systemManagement::getTenantMetadata,
|
||||
((TenantUserPasswordAuthenticationToken) authentication).getTenant().toString());
|
||||
} else if (authentication.getClass().equals(UsernamePasswordAuthenticationToken.class)) {
|
||||
// TODO: vaadin4spring-ext-security does not give us the
|
||||
// fullyAuthenticatedToken
|
||||
// in the GenericVaadinSecurity class. Only the token which has been
|
||||
// created in the
|
||||
// LoginView. This needs to be changed with the update of
|
||||
// vaadin4spring 0.0.7 because it
|
||||
// has been fixed.
|
||||
final String defaultTenant = "DEFAULT";
|
||||
systemSecurityContext.runAsSystemAsTenant(systemManagement::getTenantMetadata, defaultTenant);
|
||||
}
|
||||
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!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Servletfilter to create metadata after successful authentication over RESTful.
|
||||
* Servletfilter to create metadata after successful authentication over
|
||||
* RESTful.
|
||||
*/
|
||||
class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ import org.eclipse.hawkbit.repository.builder.SoftwareModuleCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||
import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule;
|
||||
@@ -135,6 +135,21 @@ public interface SoftwareModuleManagement
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
Page<SoftwareModule> findByAssignedTo(@NotNull Pageable pageable, long setId);
|
||||
|
||||
/**
|
||||
* Returns count of all modules assigned to given {@link DistributionSet}.
|
||||
*
|
||||
* @param setId
|
||||
* to search for
|
||||
*
|
||||
* @return count of {@link SoftwareModule}s that are assigned to given
|
||||
* {@link DistributionSet}.
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
long countByAssignedTo(long setId);
|
||||
|
||||
/**
|
||||
* Filter {@link SoftwareModule}s with given
|
||||
* {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()}
|
||||
|
||||
@@ -155,6 +155,16 @@ public interface TargetTagManagement {
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
Optional<TargetTag> get(long id);
|
||||
|
||||
/**
|
||||
* Finds {@link TargetTag} by given ids.
|
||||
*
|
||||
* @param ids
|
||||
* the ids to for
|
||||
* @return the found {@link TargetTag}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
List<TargetTag> get(@NotEmpty Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* updates the {@link TargetTag}.
|
||||
*
|
||||
|
||||
@@ -16,6 +16,7 @@ import org.eclipse.hawkbit.repository.model.Action;
|
||||
public abstract class AbstractActionEvent extends RemoteEntityEvent<Action> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long targetId;
|
||||
private Long rolloutId;
|
||||
private Long rolloutGroupId;
|
||||
|
||||
@@ -31,6 +32,8 @@ public abstract class AbstractActionEvent extends RemoteEntityEvent<Action> {
|
||||
*
|
||||
* @param action
|
||||
* the created action
|
||||
* @param targetId
|
||||
* targetId identifier (optional)
|
||||
* @param rolloutId
|
||||
* rollout identifier (optional)
|
||||
* @param rolloutGroupId
|
||||
@@ -38,13 +41,18 @@ public abstract class AbstractActionEvent extends RemoteEntityEvent<Action> {
|
||||
* @param applicationId
|
||||
* the origin application id
|
||||
*/
|
||||
public AbstractActionEvent(final Action action, final Long rolloutId, final Long rolloutGroupId,
|
||||
final String applicationId) {
|
||||
public AbstractActionEvent(final Action action, final Long targetId, final Long rolloutId,
|
||||
final Long rolloutGroupId, final String applicationId) {
|
||||
super(action, applicationId);
|
||||
this.targetId = targetId;
|
||||
this.rolloutId = rolloutId;
|
||||
this.rolloutGroupId = rolloutGroupId;
|
||||
}
|
||||
|
||||
public Long getTargetId() {
|
||||
return targetId;
|
||||
}
|
||||
|
||||
public Long getRolloutId() {
|
||||
return rolloutId;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ public class ActionCreatedEvent extends AbstractActionEvent implements EntityCre
|
||||
*
|
||||
* @param action
|
||||
* the created action
|
||||
* @param targetId
|
||||
* targetId identifier (optional)
|
||||
* @param rolloutId
|
||||
* rollout identifier (optional)
|
||||
* @param rolloutGroupId
|
||||
@@ -36,9 +38,9 @@ public class ActionCreatedEvent extends AbstractActionEvent implements EntityCre
|
||||
* @param applicationId
|
||||
* the origin application id
|
||||
*/
|
||||
public ActionCreatedEvent(final Action action, final Long rolloutId, final Long rolloutGroupId,
|
||||
public ActionCreatedEvent(final Action action, final Long targetId, final Long rolloutId, final Long rolloutGroupId,
|
||||
final String applicationId) {
|
||||
super(action, rolloutId, rolloutGroupId, applicationId);
|
||||
super(action, targetId, rolloutId, rolloutGroupId, applicationId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ public class ActionUpdatedEvent extends AbstractActionEvent implements EntityUpd
|
||||
*
|
||||
* @param action
|
||||
* the updated action
|
||||
* @param targetId
|
||||
* targetId identifier (optional)
|
||||
* @param rolloutId
|
||||
* rollout identifier (optional)
|
||||
* @param rolloutGroupId
|
||||
@@ -36,9 +38,9 @@ public class ActionUpdatedEvent extends AbstractActionEvent implements EntityUpd
|
||||
* @param applicationId
|
||||
* the origin application id
|
||||
*/
|
||||
public ActionUpdatedEvent(final Action action, final Long rolloutId, final Long rolloutGroupId,
|
||||
public ActionUpdatedEvent(final Action action, final Long targetId, final Long rolloutId, final Long rolloutGroupId,
|
||||
final String applicationId) {
|
||||
super(action, rolloutId, rolloutGroupId, applicationId);
|
||||
super(action, targetId, rolloutId, rolloutGroupId, applicationId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,13 +8,15 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.event.remote.entity;
|
||||
|
||||
import org.eclipse.hawkbit.repository.event.entity.EntityUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
|
||||
/**
|
||||
* Defines the remote event for updating a {@link SoftwareModuleType}.
|
||||
*
|
||||
*/
|
||||
public class SoftwareModuleTypeUpdatedEvent extends RemoteEntityEvent<SoftwareModuleType> {
|
||||
public class SoftwareModuleTypeUpdatedEvent extends RemoteEntityEvent<SoftwareModuleType>
|
||||
implements EntityUpdatedEvent {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
@@ -10,13 +10,15 @@ package org.eclipse.hawkbit.repository.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.hateoas.Identifiable;
|
||||
|
||||
/**
|
||||
* Use to display software modules for the selected distribution.
|
||||
*
|
||||
*/
|
||||
public class AssignedSoftwareModule implements Serializable {
|
||||
public class AssignedSoftwareModule implements Serializable, Identifiable<Long> {
|
||||
|
||||
private static final long serialVersionUID = 6144585781451168439L;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final SoftwareModule softwareModule;
|
||||
|
||||
@@ -89,4 +91,9 @@ public class AssignedSoftwareModule implements Serializable {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return softwareModule.getId();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,22 +18,7 @@ import java.util.Set;
|
||||
* assigned to a {@link Target}.
|
||||
*
|
||||
*/
|
||||
public interface DistributionSetType extends NamedEntity {
|
||||
/**
|
||||
* Maximum length of key.
|
||||
*/
|
||||
int KEY_MAX_SIZE = 64;
|
||||
|
||||
/**
|
||||
* Maximum length of colour in Management UI.
|
||||
*/
|
||||
int COLOUR_MAX_SIZE = 16;
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the type is deleted and only kept for
|
||||
* history purposes.
|
||||
*/
|
||||
boolean isDeleted();
|
||||
public interface DistributionSetType extends Type {
|
||||
|
||||
/**
|
||||
* @return immutable set of {@link SoftwareModuleType}s that need to be in a
|
||||
@@ -60,6 +45,18 @@ public interface DistributionSetType extends NamedEntity {
|
||||
return containsMandatoryModuleType(softwareModuleType) || containsOptionalModuleType(softwareModuleType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given {@link SoftwareModuleType} is in this
|
||||
* {@link DistributionSetType}.
|
||||
*
|
||||
* @param softwareModuleTypeId
|
||||
* search for by {@link SoftwareModuleType#getId()}
|
||||
* @return <code>true</code> if found
|
||||
*/
|
||||
default boolean containsModuleType(final Long softwareModuleTypeId) {
|
||||
return containsMandatoryModuleType(softwareModuleTypeId) || containsOptionalModuleType(softwareModuleTypeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given {@link SoftwareModuleType} is in
|
||||
* {@link #getMandatoryModuleTypes()}.
|
||||
@@ -118,11 +115,6 @@ public interface DistributionSetType extends NamedEntity {
|
||||
*/
|
||||
boolean areModuleEntriesIdentical(DistributionSetType dsType);
|
||||
|
||||
/**
|
||||
* @return business key of this {@link DistributionSetType}.
|
||||
*/
|
||||
String getKey();
|
||||
|
||||
/**
|
||||
* @param distributionSet
|
||||
* to check for completeness
|
||||
@@ -130,10 +122,4 @@ public interface DistributionSetType extends NamedEntity {
|
||||
* in the system.
|
||||
*/
|
||||
boolean checkComplete(DistributionSet distributionSet);
|
||||
|
||||
/**
|
||||
* @return get color code to by used in management UI views.
|
||||
*/
|
||||
String getColour();
|
||||
|
||||
}
|
||||
|
||||
@@ -14,37 +14,11 @@ package org.eclipse.hawkbit.repository.model;
|
||||
* specific information.
|
||||
*
|
||||
*/
|
||||
public interface SoftwareModuleType extends NamedEntity {
|
||||
/**
|
||||
* Maximum length of key.
|
||||
*/
|
||||
int KEY_MAX_SIZE = 64;
|
||||
|
||||
/**
|
||||
* Maximum length of colour in Management UI.
|
||||
*/
|
||||
int COLOUR_MAX_SIZE = 16;
|
||||
|
||||
/**
|
||||
* @return business key of this {@link SoftwareModuleType}.
|
||||
*/
|
||||
String getKey();
|
||||
public interface SoftwareModuleType extends Type {
|
||||
|
||||
/**
|
||||
* @return maximum assignments of an {@link SoftwareModule} of this type to
|
||||
* a {@link DistributionSet}.
|
||||
*/
|
||||
int getMaxAssignments();
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the type is deleted and only kept for
|
||||
* history purposes.
|
||||
*/
|
||||
boolean isDeleted();
|
||||
|
||||
/**
|
||||
* @return get color code to by used in management UI views.
|
||||
*/
|
||||
String getColour();
|
||||
|
||||
}
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
package org.eclipse.hawkbit.repository.model;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.springframework.hateoas.Identifiable;
|
||||
|
||||
/**
|
||||
*
|
||||
* Target with action status.
|
||||
*
|
||||
*/
|
||||
public class TargetWithActionStatus {
|
||||
public class TargetWithActionStatus implements Identifiable<Long> {
|
||||
|
||||
private Target target;
|
||||
|
||||
@@ -46,4 +47,9 @@ public class TargetWithActionStatus {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return target.getId();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.model;
|
||||
|
||||
/**
|
||||
* {@link Type} is an abstract definition for {@link DistributionSetType}s and
|
||||
* {@link SoftwareModuleType}s
|
||||
*/
|
||||
public interface Type extends NamedEntity {
|
||||
/**
|
||||
* Maximum length of key.
|
||||
*/
|
||||
int KEY_MAX_SIZE = 64;
|
||||
|
||||
/**
|
||||
* Maximum length of color in Management UI.
|
||||
*/
|
||||
int COLOUR_MAX_SIZE = 16;
|
||||
|
||||
/**
|
||||
* @return business key.
|
||||
*/
|
||||
String getKey();
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the type is deleted and only kept for
|
||||
* history purposes.
|
||||
*/
|
||||
boolean isDeleted();
|
||||
|
||||
/**
|
||||
* @return get color code to be used in management UI views.
|
||||
*/
|
||||
String getColour();
|
||||
|
||||
}
|
||||
@@ -41,18 +41,10 @@ public abstract class AbstractDistributionSetTypeUpdateCreate<T> extends Abstrac
|
||||
}
|
||||
|
||||
public Optional<Collection<Long>> getMandatory() {
|
||||
if (CollectionUtils.isEmpty(mandatory)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.ofNullable(mandatory);
|
||||
}
|
||||
|
||||
public Optional<Collection<Long>> getOptional() {
|
||||
if (CollectionUtils.isEmpty(optional)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.ofNullable(optional);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,16 +8,22 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.im.authentication.UserPrincipal;
|
||||
import org.eclipse.hawkbit.repository.RolloutApprovalStrategy;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link RolloutApprovalStrategy}. Decides whether
|
||||
@@ -33,38 +39,50 @@ public class DefaultRolloutApprovalStrategy implements RolloutApprovalStrategy {
|
||||
|
||||
private final SystemSecurityContext systemSecurityContext;
|
||||
|
||||
DefaultRolloutApprovalStrategy(UserDetailsService userDetailsService,
|
||||
TenantConfigurationManagement tenantConfigurationManagement,
|
||||
SystemSecurityContext systemSecurityContext) {
|
||||
DefaultRolloutApprovalStrategy(final UserDetailsService userDetailsService,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
this.tenantConfigurationManagement = tenantConfigurationManagement;
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true, if rollout approval is enabled and rollout creator doesn't have
|
||||
* approval role.
|
||||
* Returns true, if rollout approval is enabled and rollout creator doesn't
|
||||
* have approval role.
|
||||
*/
|
||||
@Override
|
||||
public boolean isApprovalNeeded(final Rollout rollout) {
|
||||
final UserDetails userDetails = this.getActor(rollout);
|
||||
final boolean approvalEnabled = this.tenantConfigurationManagement
|
||||
.getConfigurationValue(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class).getValue();
|
||||
return approvalEnabled && userDetails.getAuthorities().stream()
|
||||
.noneMatch(authority -> SpPermission.APPROVE_ROLLOUT.equals(authority.getAuthority()));
|
||||
return isApprovalEnabled() && hasNoApproveRolloutPermission(getActor(rollout).getAuthorities());
|
||||
}
|
||||
|
||||
private boolean isApprovalEnabled() {
|
||||
return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement
|
||||
.getConfigurationValue(TenantConfigurationKey.ROLLOUT_APPROVAL_ENABLED, Boolean.class).getValue());
|
||||
}
|
||||
|
||||
private UserDetails getActor(Rollout rollout) {
|
||||
final String actor = rollout.getLastModifiedBy() != null ? rollout.getLastModifiedBy() : rollout.getCreatedBy();
|
||||
return systemSecurityContext.runAsSystem(() -> {
|
||||
UserPrincipal userPrincipal = (UserPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
if(userPrincipal.getUsername().equals(actor)) {
|
||||
return userPrincipal;
|
||||
} else {
|
||||
return this.userDetailsService.loadUserByUsername(actor);
|
||||
private UserDetails getActor(final Rollout rollout) {
|
||||
// rollout state transition from CREATING to CREATED is managed by
|
||||
// scheduler under SYSTEM user context, thus we get the
|
||||
// user based on the properties of initially created rollout entity
|
||||
if (RolloutStatus.CREATING == rollout.getStatus()) {
|
||||
final String actor = rollout.getLastModifiedBy() != null ? rollout.getLastModifiedBy()
|
||||
: rollout.getCreatedBy();
|
||||
if (!StringUtils.isEmpty(actor)) {
|
||||
return systemSecurityContext.runAsSystem(() -> userDetailsService.loadUserByUsername(actor));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return (UserPrincipal) getCurrentAuthentication().getPrincipal();
|
||||
}
|
||||
|
||||
private static Authentication getCurrentAuthentication() {
|
||||
return SecurityContextHolder.getContext().getAuthentication();
|
||||
}
|
||||
|
||||
private static boolean hasNoApproveRolloutPermission(final Collection<? extends GrantedAuthority> authorities) {
|
||||
return authorities.stream()
|
||||
.noneMatch(authority -> SpPermission.APPROVE_ROLLOUT.equals(authority.getAuthority()));
|
||||
}
|
||||
|
||||
/***
|
||||
@@ -74,12 +92,12 @@ public class DefaultRolloutApprovalStrategy implements RolloutApprovalStrategy {
|
||||
* rollout to create approval task for.
|
||||
*/
|
||||
@Override
|
||||
public void onApprovalRequired(Rollout rollout) {
|
||||
public void onApprovalRequired(final Rollout rollout) {
|
||||
// do nothing per default, can be extended by further implementations.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApprovalUser(Rollout rollout) {
|
||||
return SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
public String getApprovalUser(final Rollout rollout) {
|
||||
return getCurrentAuthentication().getName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -630,7 +630,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
specList.add(spec);
|
||||
}
|
||||
|
||||
if (isDSWithNoTagSelected(distributionSetFilter) || isTagsSelected(distributionSetFilter)) {
|
||||
if (hasTagsFilterActive(distributionSetFilter)) {
|
||||
spec = DistributionSetSpecification.hasTags(distributionSetFilter.getTagNames(),
|
||||
distributionSetFilter.getSelectDSWithNoTag());
|
||||
specList.add(spec);
|
||||
@@ -666,12 +666,11 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
}
|
||||
}
|
||||
|
||||
private static Boolean isDSWithNoTagSelected(final DistributionSetFilter distributionSetFilter) {
|
||||
return distributionSetFilter.getSelectDSWithNoTag() != null && distributionSetFilter.getSelectDSWithNoTag();
|
||||
}
|
||||
private static boolean hasTagsFilterActive(final DistributionSetFilter distributionSetFilter) {
|
||||
final boolean isNoTagActive = Boolean.TRUE.equals(distributionSetFilter.getSelectDSWithNoTag());
|
||||
final boolean isAtLeastOneTagActive = !CollectionUtils.isEmpty(distributionSetFilter.getTagNames());
|
||||
|
||||
private static Boolean isTagsSelected(final DistributionSetFilter distributionSetFilter) {
|
||||
return !CollectionUtils.isEmpty(distributionSetFilter.getTagNames());
|
||||
return isNoTagActive || isAtLeastOneTagActive;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,11 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.LongFunction;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeFields;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTypeManagement;
|
||||
@@ -21,9 +25,9 @@ import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.DistributionSetTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericDistributionSetTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaDistributionSetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
@@ -95,18 +99,51 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
update.getDescription().ifPresent(type::setDescription);
|
||||
update.getColour().ifPresent(type::setColour);
|
||||
|
||||
if (hasModules(update)) {
|
||||
if (hasModuleChanges(update)) {
|
||||
checkDistributionSetTypeSoftwareModuleTypesIsAllowedToModify(update.getId());
|
||||
|
||||
update.getMandatory().ifPresent(
|
||||
mand -> softwareModuleTypeRepository.findAllById(mand).forEach(type::addMandatoryModuleType));
|
||||
update.getOptional().ifPresent(
|
||||
opt -> softwareModuleTypeRepository.findAllById(opt).forEach(type::addOptionalModuleType));
|
||||
final Collection<Long> currentMandatorySmTypeIds = type.getMandatoryModuleTypes().stream()
|
||||
.map(SoftwareModuleType::getId).collect(Collectors.toSet());
|
||||
final Collection<Long> currentOptionalSmTypeIds = type.getOptionalModuleTypes().stream()
|
||||
.map(SoftwareModuleType::getId).collect(Collectors.toSet());
|
||||
final Collection<Long> currentSmTypeIds = Stream
|
||||
.concat(currentMandatorySmTypeIds.stream(), currentOptionalSmTypeIds.stream())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final Collection<Long> updatedMandatorySmTypeIds = update.getMandatory().orElse(currentMandatorySmTypeIds);
|
||||
final Collection<Long> updatedOptionalSmTypeIds = update.getOptional().orElse(currentOptionalSmTypeIds);
|
||||
final Collection<Long> updatedSmTypeIds = Stream
|
||||
.concat(updatedMandatorySmTypeIds.stream(), updatedOptionalSmTypeIds.stream())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
addModuleTypes(currentMandatorySmTypeIds, updatedMandatorySmTypeIds, type::addMandatoryModuleType);
|
||||
addModuleTypes(currentOptionalSmTypeIds, updatedOptionalSmTypeIds, type::addOptionalModuleType);
|
||||
|
||||
removeModuleTypes(currentSmTypeIds, updatedSmTypeIds, type::removeModuleType);
|
||||
}
|
||||
|
||||
return distributionSetTypeRepository.save(type);
|
||||
}
|
||||
|
||||
private void addModuleTypes(final Collection<Long> currentSmTypeIds, final Collection<Long> updatedSmTypeIds,
|
||||
final Function<SoftwareModuleType, JpaDistributionSetType> addModuleTypeCallback) {
|
||||
final Set<Long> smTypeIdsToAdd = updatedSmTypeIds.stream().filter(id -> !currentSmTypeIds.contains(id))
|
||||
.collect(Collectors.toSet());
|
||||
if (!CollectionUtils.isEmpty(smTypeIdsToAdd)) {
|
||||
softwareModuleTypeRepository.findAllById(smTypeIdsToAdd).forEach(addModuleTypeCallback::apply);
|
||||
}
|
||||
}
|
||||
|
||||
private static void removeModuleTypes(final Collection<Long> currentSmTypeIds,
|
||||
final Collection<Long> updatedSmTypeIds,
|
||||
final LongFunction<JpaDistributionSetType> removeModuleTypeCallback) {
|
||||
final Set<Long> smTypeIdsToRemove = currentSmTypeIds.stream().filter(id -> !updatedSmTypeIds.contains(id))
|
||||
.collect(Collectors.toSet());
|
||||
if (!CollectionUtils.isEmpty(smTypeIdsToRemove)) {
|
||||
smTypeIdsToRemove.forEach(removeModuleTypeCallback::apply);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
@@ -258,7 +295,7 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, setId));
|
||||
}
|
||||
|
||||
private static boolean hasModules(final GenericDistributionSetTypeUpdate update) {
|
||||
private static boolean hasModuleChanges(final GenericDistributionSetTypeUpdate update) {
|
||||
return update.getOptional().isPresent() || update.getMandatory().isPresent();
|
||||
}
|
||||
|
||||
|
||||
@@ -44,8 +44,6 @@ import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupCreatedEve
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.RolloutUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
||||
import org.eclipse.hawkbit.repository.exception.NoWeightProvidedInMultiAssignmentModeException;
|
||||
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
@@ -61,7 +59,6 @@ import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.WeightValidationHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.TenantConfigHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
@@ -1019,7 +1016,9 @@ public class JpaRolloutManagement extends AbstractRolloutManagement {
|
||||
update.getActionType().ifPresent(rollout::setActionType);
|
||||
update.getForcedTime().ifPresent(rollout::setForcedTime);
|
||||
update.getWeight().ifPresent(rollout::setWeight);
|
||||
update.getStartAt().ifPresent(rollout::setStartAt);
|
||||
// reseting back to manual start is done by setting start at time to
|
||||
// null
|
||||
rollout.setStartAt(update.getStartAt().orElse(null));
|
||||
update.getSet().ifPresent(setId -> {
|
||||
final DistributionSet set = distributionSetManagement.get(setId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, setId));
|
||||
|
||||
@@ -21,8 +21,11 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Tuple;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.ListJoin;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
@@ -344,70 +347,43 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
|
||||
@Override
|
||||
public Slice<AssignedSoftwareModule> findAllOrderBySetAssignmentAndModuleNameAscModuleVersionAsc(
|
||||
final Pageable pageable, final long orderByDistributionId, final String searchText, final Long typeId) {
|
||||
final Pageable pageable, final long dsId, final String searchText, final Long smTypeId) {
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<Tuple> query = cb.createTupleQuery();
|
||||
final Root<JpaSoftwareModule> smRoot = query.from(JpaSoftwareModule.class);
|
||||
|
||||
final ListJoin<JpaSoftwareModule, JpaDistributionSet> assignedDsList = smRoot
|
||||
.join(JpaSoftwareModule_.assignedTo, JoinType.LEFT);
|
||||
|
||||
final Expression<Integer> assignedCaseMax = cb.max(
|
||||
cb.<Long, Integer> selectCase(assignedDsList.get(JpaDistributionSet_.id)).when(dsId, 1).otherwise(0));
|
||||
|
||||
query.multiselect(smRoot.alias("sm"), assignedCaseMax.alias("assigned"));
|
||||
|
||||
final Predicate[] specPredicate = specificationsToPredicate(buildSpecificationList(searchText, smTypeId),
|
||||
smRoot, query, cb);
|
||||
|
||||
if (specPredicate.length > 0) {
|
||||
query.where(specPredicate);
|
||||
}
|
||||
|
||||
query.groupBy(smRoot);
|
||||
|
||||
query.orderBy(cb.desc(assignedCaseMax), cb.asc(smRoot.get(JpaSoftwareModule_.name)),
|
||||
cb.asc(smRoot.get(JpaSoftwareModule_.version)));
|
||||
|
||||
final int pageSize = pageable.getPageSize();
|
||||
final List<Tuple> smWithAssignedFlagList = entityManager.createQuery(query)
|
||||
.setFirstResult((int) pageable.getOffset()).setMaxResults(pageSize).getResultList();
|
||||
final boolean hasNext = smWithAssignedFlagList.size() > pageSize;
|
||||
|
||||
final List<AssignedSoftwareModule> resultList = new ArrayList<>();
|
||||
final int pageSize = pageable.getPageSize();
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
|
||||
// get the assigned software modules
|
||||
final CriteriaQuery<JpaSoftwareModule> assignedQuery = cb.createQuery(JpaSoftwareModule.class);
|
||||
final Root<JpaSoftwareModule> assignedRoot = assignedQuery.from(JpaSoftwareModule.class);
|
||||
assignedQuery.distinct(true);
|
||||
final ListJoin<JpaSoftwareModule, JpaDistributionSet> assignedDsJoin = assignedRoot
|
||||
.join(JpaSoftwareModule_.assignedTo);
|
||||
// build the specifications and then to predicates necessary by the
|
||||
// given filters
|
||||
final Predicate[] specPredicate = specificationsToPredicate(buildSpecificationList(searchText, typeId),
|
||||
assignedRoot, assignedQuery, cb,
|
||||
cb.equal(assignedDsJoin.get(JpaDistributionSet_.id), orderByDistributionId));
|
||||
// if we have some predicates then add it to the where clause of the
|
||||
// multi select
|
||||
assignedQuery.where(specPredicate);
|
||||
assignedQuery.orderBy(cb.asc(assignedRoot.get(JpaSoftwareModule_.name)),
|
||||
cb.asc(assignedRoot.get(JpaSoftwareModule_.version)));
|
||||
// don't page the assigned query on database, we need all assigned
|
||||
// software modules to filter
|
||||
// them out in the unassigned query
|
||||
final List<JpaSoftwareModule> assignedSoftwareModules = entityManager.createQuery(assignedQuery)
|
||||
.getResultList();
|
||||
// map result
|
||||
if (pageable.getOffset() < assignedSoftwareModules.size()) {
|
||||
assignedSoftwareModules
|
||||
.subList((int) pageable.getOffset(),
|
||||
Math.min(assignedSoftwareModules.size(), pageable.getPageSize()))
|
||||
.forEach(sw -> resultList.add(new AssignedSoftwareModule(sw, true)));
|
||||
}
|
||||
smWithAssignedFlagList.forEach(smWithAssignedFlag -> resultList
|
||||
.add(new AssignedSoftwareModule(smWithAssignedFlag.get("sm", JpaSoftwareModule.class),
|
||||
smWithAssignedFlag.get("assigned", Number.class).longValue() == 1)));
|
||||
|
||||
if (assignedSoftwareModules.size() >= pageSize) {
|
||||
return new SliceImpl<>(resultList);
|
||||
}
|
||||
|
||||
// get the unassigned software modules
|
||||
final CriteriaQuery<JpaSoftwareModule> unassignedQuery = cb.createQuery(JpaSoftwareModule.class);
|
||||
unassignedQuery.distinct(true);
|
||||
final Root<JpaSoftwareModule> unassignedRoot = unassignedQuery.from(JpaSoftwareModule.class);
|
||||
|
||||
Predicate[] unassignedSpec;
|
||||
if (!assignedSoftwareModules.isEmpty()) {
|
||||
unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, typeId), unassignedRoot,
|
||||
unassignedQuery, cb, cb.not(unassignedRoot.get(JpaSoftwareModule_.id).in(
|
||||
assignedSoftwareModules.stream().map(SoftwareModule::getId).collect(Collectors.toList()))));
|
||||
} else {
|
||||
unassignedSpec = specificationsToPredicate(buildSpecificationList(searchText, typeId), unassignedRoot,
|
||||
unassignedQuery, cb);
|
||||
}
|
||||
|
||||
unassignedQuery.where(unassignedSpec);
|
||||
unassignedQuery.orderBy(cb.asc(unassignedRoot.get(JpaSoftwareModule_.name)),
|
||||
cb.asc(unassignedRoot.get(JpaSoftwareModule_.version)));
|
||||
final List<JpaSoftwareModule> unassignedSoftwareModules = entityManager.createQuery(unassignedQuery)
|
||||
.setFirstResult((int) Math.max(0, pageable.getOffset() - assignedSoftwareModules.size()))
|
||||
.setMaxResults(pageSize).getResultList();
|
||||
// map result
|
||||
unassignedSoftwareModules.forEach(sw -> resultList.add(new AssignedSoftwareModule(sw, false)));
|
||||
|
||||
return new SliceImpl<>(resultList);
|
||||
return new SliceImpl<>(Collections.unmodifiableList(resultList), pageable, hasNext);
|
||||
}
|
||||
|
||||
private List<Specification<JpaSoftwareModule>> buildSpecificationList(final String searchText, final Long typeId) {
|
||||
@@ -464,6 +440,15 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
return softwareModuleRepository.findByAssignedToId(pageable, setId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByAssignedTo(final long setId) {
|
||||
if (!distributionSetRepository.existsById(setId)) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, setId);
|
||||
}
|
||||
|
||||
return softwareModuleRepository.countByAssignedToId(setId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -22,6 +23,7 @@ import javax.persistence.EntityManager;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.MapJoin;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
@@ -293,8 +295,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
public Optional<TargetMetadata> getMetaDataByControllerId(final String controllerId, final String key) {
|
||||
final Long targetId = getByControllerIdAndThrowIfNotFound(controllerId).getId();
|
||||
|
||||
return targetMetadataRepository.findById(new TargetMetadataCompositeKey(targetId, key))
|
||||
.map(t -> t);
|
||||
return targetMetadataRepository.findById(new TargetMetadataCompositeKey(targetId, key)).map(t -> t);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -457,7 +458,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
if ((filterParams.getFilterByStatus() != null) && !filterParams.getFilterByStatus().isEmpty()) {
|
||||
specList.add(TargetSpecifications.hasTargetUpdateStatus(filterParams.getFilterByStatus()));
|
||||
}
|
||||
if (filterParams.getOverdueState() != null) {
|
||||
if (filterParams.getOverdueState() != null && filterParams.getOverdueState()) {
|
||||
specList.add(TargetSpecifications.isOverdue(TimestampCalculator.calculateOverdueTimestamp()));
|
||||
}
|
||||
if (filterParams.getFilterByDistributionId() != null) {
|
||||
@@ -478,8 +479,11 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
}
|
||||
|
||||
private static boolean hasTagsFilterActive(final FilterParams filterParams) {
|
||||
return ((filterParams.getSelectTargetWithNoTag() != null) && filterParams.getSelectTargetWithNoTag())
|
||||
|| ((filterParams.getFilterByTagNames() != null) && (filterParams.getFilterByTagNames().length > 0));
|
||||
final boolean isNoTagActive = Boolean.TRUE.equals(filterParams.getSelectTargetWithNoTag());
|
||||
final boolean isAtLeastOneTagActive = filterParams.getFilterByTagNames() != null
|
||||
&& filterParams.getFilterByTagNames().length > 0;
|
||||
|
||||
return isNoTagActive || isAtLeastOneTagActive;
|
||||
}
|
||||
|
||||
private Slice<Target> findByCriteriaAPI(final Pageable pageable, final List<Specification<JpaTarget>> specList) {
|
||||
@@ -611,16 +615,10 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
}
|
||||
// add the order to the multi select first based on the selectCase
|
||||
query.orderBy(cb.asc(selectCase), cb.desc(targetRoot.get(JpaTarget_.id)));
|
||||
// the result is a Object[] due the fact that the selectCase is an extra
|
||||
// column, so it cannot
|
||||
// be mapped directly to a Target entity because the selectCase is not a
|
||||
// attribute of the
|
||||
// Target entity, the the Object array contains the Target on the first
|
||||
// index of the array and
|
||||
// the 2nd contains the selectCase int value.
|
||||
|
||||
final int pageSize = pageable.getPageSize();
|
||||
final List<JpaTarget> resultList = entityManager.createQuery(query).setFirstResult((int) pageable.getOffset())
|
||||
.setMaxResults(pageSize + 1).getResultList();
|
||||
.setMaxResults(pageSize).getResultList();
|
||||
final boolean hasNext = resultList.size() > pageSize;
|
||||
return new SliceImpl<>(Collections.unmodifiableList(resultList), pageable, hasNext);
|
||||
}
|
||||
@@ -785,9 +783,20 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public Map<String, String> getControllerAttributes(final String controllerId) {
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId);
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<Object[]> query = cb.createQuery(Object[].class);
|
||||
|
||||
return target.getControllerAttributes();
|
||||
final Root<JpaTarget> targetRoot = query.from(JpaTarget.class);
|
||||
query.where(cb.equal(targetRoot.get(JpaTarget_.controllerId), controllerId));
|
||||
|
||||
final MapJoin<JpaTarget, String, String> attributes = targetRoot.join(JpaTarget_.controllerAttributes);
|
||||
query.multiselect(attributes.key(), attributes.value());
|
||||
query.orderBy(cb.asc(attributes.key()));
|
||||
|
||||
final List<Object[]> attr = entityManager.createQuery(query).getResultList();
|
||||
|
||||
return attr.stream().collect(Collectors.toMap(entry -> (String) entry[0], entry -> (String) entry[1],
|
||||
(v1, v2) -> v1, LinkedHashMap::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -142,6 +142,11 @@ public class JpaTargetTagManagement implements TargetTagManagement {
|
||||
return targetTagRepository.findById(id).map(tt -> (TargetTag) tt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TargetTag> get(final Collection<Long> ids) {
|
||||
return Collections.unmodifiableList(targetTagRepository.findAllById(ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<TargetTag> findAll(final Pageable pageable) {
|
||||
return convertTPage(targetTagRepository.findAll(pageable), pageable);
|
||||
|
||||
@@ -81,4 +81,9 @@ public interface TargetTagRepository
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaTargetTag t WHERE t.tenant = :tenant")
|
||||
void deleteByTenant(@Param("tenant") String tenant);
|
||||
|
||||
@Override
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("SELECT t FROM JpaTargetTag t WHERE t.id IN ?1")
|
||||
List<JpaTargetTag> findAllById(Iterable<Long> ids);
|
||||
}
|
||||
|
||||
@@ -236,15 +236,17 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
|
||||
@Override
|
||||
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
|
||||
EventPublisherHolder.getInstance().getEventPublisher()
|
||||
.publishEvent(new ActionCreatedEvent(this, BaseEntity.getIdOrNull(rollout),
|
||||
BaseEntity.getIdOrNull(rolloutGroup), EventPublisherHolder.getInstance().getApplicationId()));
|
||||
.publishEvent(new ActionCreatedEvent(this, BaseEntity.getIdOrNull(target),
|
||||
BaseEntity.getIdOrNull(rollout), BaseEntity.getIdOrNull(rolloutGroup),
|
||||
EventPublisherHolder.getInstance().getApplicationId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireUpdateEvent(final DescriptorEvent descriptorEvent) {
|
||||
EventPublisherHolder.getInstance().getEventPublisher()
|
||||
.publishEvent(new ActionUpdatedEvent(this, BaseEntity.getIdOrNull(rollout),
|
||||
BaseEntity.getIdOrNull(rolloutGroup), EventPublisherHolder.getInstance().getApplicationId()));
|
||||
.publishEvent(new ActionUpdatedEvent(this, BaseEntity.getIdOrNull(target),
|
||||
BaseEntity.getIdOrNull(rollout), BaseEntity.getIdOrNull(rolloutGroup),
|
||||
EventPublisherHolder.getInstance().getApplicationId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,13 +8,16 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.ListJoin;
|
||||
import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.criteria.SetJoin;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
@@ -149,27 +152,36 @@ public final class DistributionSetSpecification {
|
||||
public static Specification<JpaDistributionSet> hasTags(final Collection<String> tagNames,
|
||||
final Boolean selectDSWithNoTag) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final SetJoin<JpaDistributionSet, JpaDistributionSetTag> tags = targetRoot.join(JpaDistributionSet_.tags,
|
||||
JoinType.LEFT);
|
||||
final Predicate predicate = getPredicate(tags, tagNames, selectDSWithNoTag, cb);
|
||||
final Predicate predicate = getHasTagsPredicate(targetRoot, cb, selectDSWithNoTag, tagNames);
|
||||
query.distinct(true);
|
||||
return predicate;
|
||||
};
|
||||
}
|
||||
|
||||
private static Predicate getPredicate(final SetJoin<JpaDistributionSet, JpaDistributionSetTag> tags,
|
||||
final Collection<String> tagNames, final Boolean selectDSWithNoTag, final CriteriaBuilder cb) {
|
||||
tags.get(JpaDistributionSetTag_.name);
|
||||
private static Predicate getHasTagsPredicate(final Root<JpaDistributionSet> targetRoot, final CriteriaBuilder cb,
|
||||
final Boolean selectDSWithNoTag, final Collection<String> tagNames) {
|
||||
final SetJoin<JpaDistributionSet, JpaDistributionSetTag> tags = targetRoot.join(JpaDistributionSet_.tags,
|
||||
JoinType.LEFT);
|
||||
final Path<String> exp = tags.get(JpaDistributionSetTag_.name);
|
||||
if (selectDSWithNoTag != null && selectDSWithNoTag) {
|
||||
if (!CollectionUtils.isEmpty(tagNames)) {
|
||||
return cb.or(exp.isNull(), exp.in(tagNames));
|
||||
} else {
|
||||
return exp.isNull();
|
||||
}
|
||||
} else {
|
||||
return exp.in(tagNames);
|
||||
|
||||
final List<Predicate> hasTagsPredicates = new ArrayList<>();
|
||||
if (isNoTagActive(selectDSWithNoTag)) {
|
||||
hasTagsPredicates.add(exp.isNull());
|
||||
}
|
||||
if (isAtLeastOneTagActive(tagNames)) {
|
||||
hasTagsPredicates.add(exp.in(tagNames));
|
||||
}
|
||||
|
||||
return hasTagsPredicates.stream().reduce(cb::or).orElseThrow(
|
||||
() -> new RuntimeException("Neither NO_TAG, nor TAG distribution set tag filter was provided!"));
|
||||
}
|
||||
|
||||
private static boolean isNoTagActive(final Boolean selectDSWithNoTag) {
|
||||
return Boolean.TRUE.equals(selectDSWithNoTag);
|
||||
}
|
||||
|
||||
private static boolean isAtLeastOneTagActive(final Collection<String> tagNames) {
|
||||
return !CollectionUtils.isEmpty(tagNames);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,17 +8,18 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.ListJoin;
|
||||
import javax.persistence.criteria.MapJoin;
|
||||
import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.criteria.SetJoin;
|
||||
import javax.persistence.criteria.MapJoin;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
@@ -226,25 +227,35 @@ public final class TargetSpecifications {
|
||||
*/
|
||||
public static Specification<JpaTarget> hasTags(final String[] tagNames, final Boolean selectTargetWithNoTag) {
|
||||
return (targetRoot, query, cb) -> {
|
||||
final Predicate predicate = getPredicate(targetRoot, cb, selectTargetWithNoTag, tagNames);
|
||||
final Predicate predicate = getHasTagsPredicate(targetRoot, cb, selectTargetWithNoTag, tagNames);
|
||||
query.distinct(true);
|
||||
return predicate;
|
||||
};
|
||||
}
|
||||
|
||||
private static Predicate getPredicate(final Root<JpaTarget> targetRoot, final CriteriaBuilder cb,
|
||||
private static Predicate getHasTagsPredicate(final Root<JpaTarget> targetRoot, final CriteriaBuilder cb,
|
||||
final Boolean selectTargetWithNoTag, final String[] tagNames) {
|
||||
final SetJoin<JpaTarget, JpaTargetTag> tags = targetRoot.join(JpaTarget_.tags, JoinType.LEFT);
|
||||
final Path<String> exp = tags.get(JpaTargetTag_.name);
|
||||
if (selectTargetWithNoTag) {
|
||||
if (tagNames != null) {
|
||||
return cb.or(exp.isNull(), exp.in(tagNames));
|
||||
} else {
|
||||
return exp.isNull();
|
||||
}
|
||||
} else {
|
||||
return exp.in(tagNames);
|
||||
|
||||
final List<Predicate> hasTagsPredicates = new ArrayList<>();
|
||||
if (isNoTagActive(selectTargetWithNoTag)) {
|
||||
hasTagsPredicates.add(exp.isNull());
|
||||
}
|
||||
if (isAtLeastOneTagActive(tagNames)) {
|
||||
hasTagsPredicates.add(exp.in(tagNames));
|
||||
}
|
||||
|
||||
return hasTagsPredicates.stream().reduce(cb::or)
|
||||
.orElseThrow(() -> new RuntimeException("Neither NO_TAG, nor TAG target tag filter was provided!"));
|
||||
}
|
||||
|
||||
private static boolean isNoTagActive(final Boolean selectTargetWithNoTag) {
|
||||
return Boolean.TRUE.equals(selectTargetWithNoTag);
|
||||
}
|
||||
|
||||
private static boolean isAtLeastOneTagActive(final String[] tagNames) {
|
||||
return tagNames != null && tagNames.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,6 +12,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEventTest;
|
||||
|
||||
@@ -35,25 +36,32 @@ public abstract class AbstractRemoteEntityEventTest<E> extends AbstractRemoteEve
|
||||
protected RemoteEntityEvent<?> createRemoteEvent(final E baseEntity,
|
||||
final Class<? extends RemoteEntityEvent<?>> eventType) {
|
||||
|
||||
Constructor<?> constructor = null;
|
||||
for (final Constructor<?> constructors : eventType.getDeclaredConstructors()) {
|
||||
if (constructors.getParameterCount() == 2) {
|
||||
constructor = constructors;
|
||||
}
|
||||
}
|
||||
|
||||
if (constructor == null) {
|
||||
throw new IllegalArgumentException("No suitable constructor foundes");
|
||||
}
|
||||
|
||||
final int constructorParamCount = getConstructorParamCount();
|
||||
final Constructor<?> eventConstructor = findEventConstructorByParamCount(eventType, constructorParamCount);
|
||||
final Object[] eventConstructorParams = getConstructorParams(baseEntity);
|
||||
try {
|
||||
return (RemoteEntityEvent<?>) constructor.newInstance(baseEntity, "Node");
|
||||
return (RemoteEntityEvent<?>) eventConstructor.newInstance(eventConstructorParams);
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
fail("Exception should not happen " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected int getConstructorParamCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
protected Constructor<?> findEventConstructorByParamCount(final Class<? extends RemoteEntityEvent<?>> eventType,
|
||||
final int paramCount) {
|
||||
return Arrays.stream(eventType.getDeclaredConstructors())
|
||||
.filter(constructor -> constructor.getParameterCount() == paramCount).findAny()
|
||||
.orElseThrow(() -> new IllegalArgumentException("No suitable constructor founded"));
|
||||
}
|
||||
|
||||
protected Object[] getConstructorParams(final E baseEntity) {
|
||||
return new Object[] { baseEntity, "Node" };
|
||||
}
|
||||
|
||||
protected RemoteEntityEvent<?> assertEntity(final E baseEntity, final RemoteEntityEvent<?> event) {
|
||||
assertThat(event.getEntity()).isSameAs(baseEntity);
|
||||
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
package org.eclipse.hawkbit.repository.event.remote.entity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
@@ -45,26 +42,13 @@ public class ActionEventTest extends AbstractRemoteEntityEventTest<Action> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RemoteEntityEvent<?> createRemoteEvent(final Action baseEntity,
|
||||
final Class<? extends RemoteEntityEvent<?>> eventType) {
|
||||
protected int getConstructorParamCount() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
Constructor<?> constructor = null;
|
||||
for (final Constructor<?> constructors : eventType.getDeclaredConstructors()) {
|
||||
if (constructors.getParameterCount() == 4) {
|
||||
constructor = constructors;
|
||||
}
|
||||
}
|
||||
|
||||
if (constructor == null) {
|
||||
throw new IllegalArgumentException("No suitable constructor foundes");
|
||||
}
|
||||
|
||||
try {
|
||||
return (RemoteEntityEvent<?>) constructor.newInstance(baseEntity, 1L, 2L, "Node");
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
fail("Exception should not happen " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
@Override
|
||||
protected Object[] getConstructorParams(final Action baseEntity) {
|
||||
return new Object[] { baseEntity, 1L, 1L, 2L, "Node" };
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,15 +56,19 @@ public class ActionEventTest extends AbstractRemoteEntityEventTest<Action> {
|
||||
final AbstractActionEvent event = (AbstractActionEvent) e;
|
||||
|
||||
assertThat(event.getEntity()).isSameAs(baseEntity);
|
||||
assertThat(event.getTargetId()).isEqualTo(1L);
|
||||
assertThat(event.getRolloutId()).isEqualTo(1L);
|
||||
assertThat(event.getRolloutGroupId()).isEqualTo(2L);
|
||||
|
||||
AbstractActionEvent underTestCreatedEvent = createProtoStuffEvent(event);
|
||||
assertThat(underTestCreatedEvent.getEntity()).isEqualTo(baseEntity);
|
||||
assertThat(underTestCreatedEvent.getTargetId()).isEqualTo(1L);
|
||||
assertThat(underTestCreatedEvent.getRolloutId()).isEqualTo(1L);
|
||||
assertThat(underTestCreatedEvent.getRolloutGroupId()).isEqualTo(2L);
|
||||
|
||||
underTestCreatedEvent = createJacksonEvent(event);
|
||||
assertThat(underTestCreatedEvent.getEntity()).isEqualTo(baseEntity);
|
||||
assertThat(underTestCreatedEvent.getTargetId()).isEqualTo(1L);
|
||||
assertThat(underTestCreatedEvent.getRolloutId()).isEqualTo(1L);
|
||||
assertThat(underTestCreatedEvent.getRolloutGroupId()).isEqualTo(2L);
|
||||
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
package org.eclipse.hawkbit.repository.event.remote.entity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -47,26 +45,13 @@ public class RolloutGroupEventTest extends AbstractRemoteEntityEventTest<Rollout
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RemoteEntityEvent<?> createRemoteEvent(final RolloutGroup baseEntity,
|
||||
final Class<? extends RemoteEntityEvent<?>> eventType) {
|
||||
protected int getConstructorParamCount() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
Constructor<?> constructor = null;
|
||||
for (final Constructor<?> constructors : eventType.getDeclaredConstructors()) {
|
||||
if (constructors.getParameterCount() == 3) {
|
||||
constructor = constructors;
|
||||
}
|
||||
}
|
||||
|
||||
if (constructor == null) {
|
||||
throw new IllegalArgumentException("No suitable constructor foundes");
|
||||
}
|
||||
|
||||
try {
|
||||
return (RemoteEntityEvent<?>) constructor.newInstance(baseEntity, 1L, "Node");
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
fail("Exception should not happen " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
@Override
|
||||
protected Object[] getConstructorParams(final RolloutGroup baseEntity) {
|
||||
return new Object[] { baseEntity, 1L, "Node" };
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -91,8 +76,8 @@ public class RolloutGroupEventTest extends AbstractRemoteEntityEventTest<Rollout
|
||||
protected RolloutGroup createEntity() {
|
||||
testdataFactory.createTarget(UUID.randomUUID().toString());
|
||||
|
||||
final DistributionSet ds = distributionSetManagement.create(entityFactory.distributionSet()
|
||||
.create().name("incomplete").version("2").description("incomplete").type("os"));
|
||||
final DistributionSet ds = distributionSetManagement.create(entityFactory.distributionSet().create()
|
||||
.name("incomplete").version("2").description("incomplete").type("os"));
|
||||
|
||||
final Rollout entity = rolloutManagement.create(
|
||||
entityFactory.rollout().create().name("exampleRollout").targetFilterQuery("controllerId==*").set(ds),
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.eclipse.hawkbit.ui.UiProperties;
|
||||
import org.eclipse.hawkbit.ui.components.NotificationUnreadButton;
|
||||
import org.eclipse.hawkbit.ui.menu.DashboardMenu;
|
||||
import org.eclipse.hawkbit.ui.push.EventPushStrategy;
|
||||
import org.eclipse.hawkbit.ui.push.UIEventProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -43,12 +44,12 @@ public class MyUI extends AbstractHawkbitUI {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Autowired
|
||||
MyUI(final EventPushStrategy pushStrategy, final UIEventBus eventBus, final SpringViewProvider viewProvider,
|
||||
final ApplicationContext context, final DashboardMenu dashboardMenu, final ErrorView errorview,
|
||||
final NotificationUnreadButton notificationUnreadButton, final UiProperties uiProperties,
|
||||
final VaadinMessageSource i18n) {
|
||||
super(pushStrategy, eventBus, viewProvider, context, dashboardMenu, errorview, notificationUnreadButton,
|
||||
uiProperties, i18n);
|
||||
MyUI(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) {
|
||||
super(pushStrategy, eventBus, eventProvider, viewProvider, context, dashboardMenu, errorview,
|
||||
notificationUnreadButton, uiProperties, i18n);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -68,18 +68,6 @@
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- hawkBit - END -->
|
||||
|
||||
<!-- exclude gwt-elemental as there are class conflicts -->
|
||||
<dependency>
|
||||
<groupId>com.vaadin</groupId>
|
||||
<artifactId>vaadin-client</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.vaadin.external.gwt</groupId>
|
||||
<artifactId>gwt-elemental</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -25,7 +25,7 @@
|
||||
<artifactId>vaadin-maven-plugin</artifactId>
|
||||
<version>${vaadin.plugin.version}</version>
|
||||
<configuration>
|
||||
<extraJvmArgs>-Xmx1g -Xss1024k</extraJvmArgs>
|
||||
<extraJvmArgs>-Xmx2g -Xss1024k</extraJvmArgs>
|
||||
<!-- We are doing "inplace" gwt compilation but into subdir VAADIN/widgetsets -->
|
||||
<webappDirectory>src/main/resources/VAADIN/widgetsets</webappDirectory>
|
||||
<hostedWebapp>src/main/resources/VAADIN/widgetsets</hostedWebapp>
|
||||
@@ -78,24 +78,6 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<index>true</index>
|
||||
<manifest>
|
||||
<addClasspath>true</addClasspath>
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
</manifest>
|
||||
<manifestEntries>
|
||||
<Implementation-Title>CustomRenderers</Implementation-Title>
|
||||
<Vaadin-Package-Version>1</Vaadin-Package-Version>
|
||||
<Vaadin-Widgetsets>org.eclipse.hawkbit.ui.customrenderers.CustomRendererWidgetSet</Vaadin-Widgetsets>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
@@ -205,14 +187,6 @@
|
||||
<groupId>com.vaadin</groupId>
|
||||
<artifactId>vaadin-themes</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.vaadin.addons.lazyquerycontainer</groupId>
|
||||
<artifactId>vaadin-lazyquerycontainer</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.vaadin.addons</groupId>
|
||||
<artifactId>flexibleoptiongroup</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.vaadin.alump.distributionbar</groupId>
|
||||
<artifactId>dbar-addon</artifactId>
|
||||
@@ -233,6 +207,10 @@
|
||||
<groupId>com.cronutils</groupId>
|
||||
<artifactId>cron-utils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
@@ -246,11 +224,6 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.gwt.gwtmockito</groupId>
|
||||
<artifactId>gwtmockito</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.qameta.allure</groupId>
|
||||
<artifactId>allure-junit4</artifactId>
|
||||
|
||||
@@ -14,6 +14,7 @@ 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;
|
||||
@@ -22,7 +23,6 @@ import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.vaadin.spring.events.EventBus;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.annotations.Theme;
|
||||
@@ -35,7 +35,6 @@ import com.vaadin.navigator.ViewProvider;
|
||||
import com.vaadin.server.ClientConnector.DetachListener;
|
||||
import com.vaadin.server.Responsive;
|
||||
import com.vaadin.server.VaadinRequest;
|
||||
import com.vaadin.spring.navigator.SpringNavigator;
|
||||
import com.vaadin.spring.navigator.SpringViewProvider;
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.Component;
|
||||
@@ -61,32 +60,27 @@ public abstract class AbstractHawkbitUI extends UI implements DetachListener {
|
||||
|
||||
private static final String EMPTY_VIEW = "";
|
||||
|
||||
private transient EventPushStrategy pushStrategy;
|
||||
|
||||
protected final transient EventBus.UIEventBus eventBus;
|
||||
|
||||
private final SpringViewProvider viewProvider;
|
||||
|
||||
private final transient ApplicationContext context;
|
||||
|
||||
private final DashboardMenu dashboardMenu;
|
||||
|
||||
private final ErrorView errorview;
|
||||
|
||||
private final NotificationUnreadButton notificationUnreadButton;
|
||||
private final VaadinMessageSource i18n;
|
||||
private final UiProperties uiProperties;
|
||||
|
||||
private Label viewTitle;
|
||||
|
||||
private final UiProperties uiProperties;
|
||||
private final DashboardMenu dashboardMenu;
|
||||
private final ErrorView errorview;
|
||||
private final NotificationUnreadButton notificationUnreadButton;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
private final SpringViewProvider viewProvider;
|
||||
private final transient ApplicationContext context;
|
||||
private final transient EventPushStrategy pushStrategy;
|
||||
|
||||
private final transient HawkbitEntityEventListener entityEventsListener;
|
||||
|
||||
protected AbstractHawkbitUI(final EventPushStrategy pushStrategy, final UIEventBus eventBus,
|
||||
final SpringViewProvider viewProvider, final ApplicationContext context, final DashboardMenu dashboardMenu,
|
||||
final ErrorView errorview, final NotificationUnreadButton notificationUnreadButton,
|
||||
final UiProperties uiProperties, final VaadinMessageSource i18n) {
|
||||
final UIEventProvider eventProvider, final SpringViewProvider viewProvider,
|
||||
final ApplicationContext context, final DashboardMenu dashboardMenu, final ErrorView errorview,
|
||||
final NotificationUnreadButton notificationUnreadButton, final UiProperties uiProperties,
|
||||
final VaadinMessageSource i18n) {
|
||||
this.pushStrategy = pushStrategy;
|
||||
this.eventBus = eventBus;
|
||||
this.viewProvider = viewProvider;
|
||||
this.context = context;
|
||||
this.dashboardMenu = dashboardMenu;
|
||||
@@ -94,12 +88,16 @@ public abstract class AbstractHawkbitUI extends UI implements DetachListener {
|
||||
this.notificationUnreadButton = notificationUnreadButton;
|
||||
this.uiProperties = uiProperties;
|
||||
this.i18n = i18n;
|
||||
|
||||
this.entityEventsListener = new HawkbitEntityEventListener(eventBus, eventProvider, notificationUnreadButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach(final DetachEvent event) {
|
||||
LOG.info("ManagementUI is detached uiid - {}", getUIId());
|
||||
eventBus.unsubscribe(this);
|
||||
LOG.debug("ManagementUI is detached uiid - {}", getUIId());
|
||||
|
||||
entityEventsListener.unsubscribeListeners();
|
||||
|
||||
if (pushStrategy != null) {
|
||||
pushStrategy.clean();
|
||||
}
|
||||
@@ -107,7 +105,7 @@ public abstract class AbstractHawkbitUI extends UI implements DetachListener {
|
||||
|
||||
@Override
|
||||
protected void init(final VaadinRequest vaadinRequest) {
|
||||
LOG.info("ManagementUI init starts uiid - {}", getUI().getUIId());
|
||||
LOG.debug("ManagementUI init starts uiid - {}", getUI().getUIId());
|
||||
if (pushStrategy != null) {
|
||||
pushStrategy.init(getUI());
|
||||
}
|
||||
@@ -119,6 +117,8 @@ public abstract class AbstractHawkbitUI extends UI implements DetachListener {
|
||||
setResponsive(Boolean.TRUE);
|
||||
|
||||
final HorizontalLayout rootLayout = new HorizontalLayout();
|
||||
rootLayout.setMargin(false);
|
||||
rootLayout.setSpacing(false);
|
||||
rootLayout.setSizeFull();
|
||||
|
||||
HawkbitCommonUtil.initLocalization(this, uiProperties.getLocalization(), i18n);
|
||||
@@ -128,6 +128,8 @@ public abstract class AbstractHawkbitUI extends UI implements DetachListener {
|
||||
dashboardMenu.setResponsive(true);
|
||||
|
||||
final VerticalLayout contentVerticalLayout = new VerticalLayout();
|
||||
contentVerticalLayout.setMargin(false);
|
||||
contentVerticalLayout.setSpacing(false);
|
||||
contentVerticalLayout.setSizeFull();
|
||||
contentVerticalLayout.setStyleName("main-content");
|
||||
contentVerticalLayout.addComponent(buildHeader());
|
||||
@@ -135,11 +137,11 @@ public abstract class AbstractHawkbitUI extends UI implements DetachListener {
|
||||
|
||||
final Panel content = buildContent();
|
||||
contentVerticalLayout.addComponent(content);
|
||||
contentVerticalLayout.setExpandRatio(content, 1);
|
||||
contentVerticalLayout.setExpandRatio(content, 1.0F);
|
||||
|
||||
rootLayout.addComponent(dashboardMenu);
|
||||
rootLayout.addComponent(contentVerticalLayout);
|
||||
rootLayout.setExpandRatio(contentVerticalLayout, 1);
|
||||
rootLayout.setExpandRatio(contentVerticalLayout, 1.0F);
|
||||
setContent(rootLayout);
|
||||
|
||||
final Navigator navigator = new Navigator(this, content);
|
||||
@@ -160,23 +162,22 @@ public abstract class AbstractHawkbitUI extends UI implements DetachListener {
|
||||
return;
|
||||
}
|
||||
viewTitle.setCaption(view.getDashboardCaptionLong());
|
||||
notificationUnreadButton.setCurrentView(event.getNewView());
|
||||
}
|
||||
});
|
||||
|
||||
navigator.setErrorView(errorview);
|
||||
navigator.addView(EMPTY_VIEW, new Navigator.EmptyView());
|
||||
navigator.addProvider(new ManagementViewProvider());
|
||||
setNavigator(navigator);
|
||||
navigator.addView(EMPTY_VIEW, new Navigator.EmptyView());
|
||||
|
||||
if (UI.getCurrent().getErrorHandler() == null) {
|
||||
UI.getCurrent().setErrorHandler(new HawkbitUIErrorHandler());
|
||||
}
|
||||
|
||||
LOG.info("Current locale of the application is : {}", getLocale());
|
||||
LOG.debug("Current locale of the application is : {}", getLocale());
|
||||
}
|
||||
|
||||
private Panel buildContent() {
|
||||
private static Panel buildContent() {
|
||||
final Panel content = new Panel();
|
||||
content.setSizeFull();
|
||||
content.setStyleName("view-content");
|
||||
@@ -185,6 +186,8 @@ public abstract class AbstractHawkbitUI extends UI implements DetachListener {
|
||||
|
||||
private HorizontalLayout buildViewTitle() {
|
||||
final HorizontalLayout viewHeadercontent = new HorizontalLayout();
|
||||
viewHeadercontent.setMargin(false);
|
||||
viewHeadercontent.setSpacing(false);
|
||||
viewHeadercontent.setWidth("100%");
|
||||
viewHeadercontent.addStyleName("view-header-layout");
|
||||
|
||||
@@ -198,14 +201,13 @@ public abstract class AbstractHawkbitUI extends UI implements DetachListener {
|
||||
return viewHeadercontent;
|
||||
}
|
||||
|
||||
private Component buildHeader() {
|
||||
private static Component buildHeader() {
|
||||
final CssLayout cssLayout = new CssLayout();
|
||||
cssLayout.setStyleName("view-header");
|
||||
return cssLayout;
|
||||
}
|
||||
|
||||
private class ManagementViewProvider extends SpringNavigator implements ViewProvider {
|
||||
|
||||
private class ManagementViewProvider implements ViewProvider {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,17 +13,12 @@
|
||||
<module>
|
||||
<!-- This file is automatically updated based on new dependencies by the goal "vaadin:update-widgetset". -->
|
||||
|
||||
<!-- Inherit DefaultWidgetSet -->
|
||||
<inherits name="com.vaadin.DefaultWidgetSet" />
|
||||
|
||||
<inherits name="org.vaadin.hene.flexibleoptiongroup.widgetset.FlexibleOptionGroupWidgetset" />
|
||||
|
||||
|
||||
|
||||
<inherits name="org.vaadin.alump.distributionbar.gwt.DistributionBarWidgetset" />
|
||||
|
||||
<inherits name="org.eclipse.hawkbit.ui.customrenderers.CustomRendererWidgetSet" />
|
||||
<inherits name="org.eclipse.hawkbit.ui.filtermanagement.TextFieldSuggestionBox" />
|
||||
<inherits name="org.eclipse.hawkbit.ui.rollout.groupschart.GroupsPieChart" />
|
||||
<inherits name="org.eclipse.hawkbit.ui.dd.CustomAcceptCriteria" />
|
||||
<inherits
|
||||
name="org.eclipse.hawkbit.ui.common.grid.selection.RangeSelectionWidgetset" />
|
||||
<inherits
|
||||
name="org.eclipse.hawkbit.ui.common.notification.ParallelNotificationWidgetset" />
|
||||
</module>
|
||||
|
||||
@@ -34,12 +34,30 @@ import com.vaadin.spring.server.SpringVaadinServlet;
|
||||
@Import(VaadinServletConfiguration.class)
|
||||
public class AsyncVaadinServletConfiguration extends VaadinServletConfiguration {
|
||||
|
||||
/**
|
||||
* Localized system message provider bean.
|
||||
*
|
||||
* @param uiProperties
|
||||
* UiProperties
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
*
|
||||
* @return Localized system message provider
|
||||
*/
|
||||
@Bean
|
||||
public LocalizedSystemMessagesProvider localizedSystemMessagesProvider(final UiProperties uiProperties,
|
||||
final VaadinMessageSource i18n) {
|
||||
return new LocalizedSystemMessagesProvider(uiProperties, i18n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vaadin servlet bean.
|
||||
*
|
||||
* @param localizedSystemMessagesProvider
|
||||
* LocalizedSystemMessagesProvider
|
||||
*
|
||||
* @return Vaadin servlet service
|
||||
*/
|
||||
@Bean
|
||||
public VaadinServlet vaadinServlet(final LocalizedSystemMessagesProvider localizedSystemMessagesProvider) {
|
||||
return new SpringVaadinServlet() {
|
||||
|
||||
@@ -11,19 +11,16 @@ package org.eclipse.hawkbit.ui;
|
||||
import org.eclipse.hawkbit.ui.menu.DashboardMenu;
|
||||
import org.eclipse.hawkbit.ui.menu.DashboardMenuItem;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.vaadin.navigator.Navigator;
|
||||
import com.vaadin.navigator.View;
|
||||
import com.vaadin.navigator.ViewChangeListener;
|
||||
import com.vaadin.shared.Position;
|
||||
import com.vaadin.spring.annotation.SpringComponent;
|
||||
import com.vaadin.spring.annotation.UIScope;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.Notification;
|
||||
import com.vaadin.ui.Notification.Type;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
/**
|
||||
@@ -49,6 +46,8 @@ public class ErrorView extends VerticalLayout implements View {
|
||||
this.i18n = i18n;
|
||||
this.dashboardMenu = dashboardMenu;
|
||||
setMargin(true);
|
||||
setSpacing(false);
|
||||
|
||||
message = new Label();
|
||||
addComponent(message);
|
||||
}
|
||||
@@ -61,11 +60,9 @@ public class ErrorView extends VerticalLayout implements View {
|
||||
return;
|
||||
}
|
||||
if (dashboardMenu.isAccessDenied(event.getViewName())) {
|
||||
final Notification nt = new Notification("Access denied",
|
||||
i18n.getMessage("message.accessdenied.view", event.getViewName()), Type.ERROR_MESSAGE, false);
|
||||
nt.setStyleName(SPUIStyleDefinitions.SP_NOTIFICATION_ERROR_MESSAGE_STYLE);
|
||||
nt.setPosition(Position.BOTTOM_RIGHT);
|
||||
nt.show(UI.getCurrent().getPage());
|
||||
UINotification.showNotification(SPUIStyleDefinitions.SP_NOTIFICATION_ERROR_MESSAGE_STYLE,
|
||||
i18n.getMessage("message.accessdenied"),
|
||||
i18n.getMessage("message.accessdenied.view", event.getViewName()), null, true);
|
||||
message.setValue(i18n.getMessage("message.accessdenied.view", event.getViewName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui;
|
||||
|
||||
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.getEventTypeMessageKey(), 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,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Bosch Software Innovations GmbH and others.
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
@@ -30,6 +30,8 @@ public class LocalizedSystemMessagesProvider implements SystemMessagesProvider {
|
||||
private final UiProperties uiProperties;
|
||||
|
||||
/**
|
||||
* Constructor for LocalizedSystemMessagesProvider
|
||||
*
|
||||
* @param uiProperties
|
||||
* Properties to determine the available Locales
|
||||
* @param i18n
|
||||
|
||||
@@ -80,6 +80,15 @@ public class SpPermissionChecker implements Serializable {
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -32,24 +32,40 @@ public class UiProperties implements Serializable {
|
||||
|
||||
private final Links links = new Links();
|
||||
|
||||
private final Login login = new Login();
|
||||
|
||||
private final Demo demo = new Demo();
|
||||
|
||||
private final Event event = new Event();
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
@@ -70,18 +86,36 @@ public class UiProperties implements Serializable {
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@@ -112,34 +146,70 @@ public class UiProperties implements Serializable {
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -211,6 +281,9 @@ public class UiProperties implements Serializable {
|
||||
|
||||
private String provisioningStateMachine = "";
|
||||
|
||||
/**
|
||||
* @return Link to documentation of deployment view
|
||||
*/
|
||||
public String getDeploymentView() {
|
||||
return deploymentView;
|
||||
}
|
||||
@@ -219,26 +292,44 @@ public class UiProperties implements Serializable {
|
||||
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;
|
||||
}
|
||||
@@ -247,10 +338,16 @@ public class UiProperties implements Serializable {
|
||||
return uploadView;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to documentation of maintenance window
|
||||
*/
|
||||
public String getMaintenanceWindowView() {
|
||||
return maintenanceWindowView;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Link to documentation of provisioning state machine
|
||||
*/
|
||||
public String getProvisioningStateMachine() {
|
||||
return provisioningStateMachine;
|
||||
}
|
||||
@@ -267,14 +364,32 @@ public class UiProperties implements Serializable {
|
||||
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;
|
||||
}
|
||||
@@ -318,70 +433,66 @@ public class UiProperties implements Serializable {
|
||||
*/
|
||||
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 login view.
|
||||
*
|
||||
*/
|
||||
public static class Login implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Cookie configuration for login credential cookie.
|
||||
*
|
||||
*/
|
||||
public static class Cookie implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* Secure cookie enabled.
|
||||
*/
|
||||
private boolean secure = true;
|
||||
|
||||
public boolean isSecure() {
|
||||
return secure;
|
||||
}
|
||||
|
||||
public void setSecure(final boolean secure) {
|
||||
this.secure = secure;
|
||||
}
|
||||
}
|
||||
|
||||
private final Cookie cookie = new Cookie();
|
||||
|
||||
public Cookie getCookie() {
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration of the UI event bus.
|
||||
*/
|
||||
@@ -417,22 +528,30 @@ public class UiProperties implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Demo account details
|
||||
*/
|
||||
public Demo getDemo() {
|
||||
return demo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Document links
|
||||
*/
|
||||
public Links getLinks() {
|
||||
return links;
|
||||
}
|
||||
|
||||
public Login getLogin() {
|
||||
return login;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Events
|
||||
*/
|
||||
public Event getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Localization
|
||||
*/
|
||||
public Localization getLocalization() {
|
||||
return localization;
|
||||
}
|
||||
|
||||
@@ -6,28 +6,26 @@
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.state;
|
||||
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.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
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.ManagementEntityState;
|
||||
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.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
@@ -39,29 +37,14 @@ import com.vaadin.spring.annotation.VaadinSessionScope;
|
||||
*/
|
||||
@VaadinSessionScope
|
||||
@SpringComponent
|
||||
public class ArtifactUploadState implements ManagementEntityState, Serializable {
|
||||
|
||||
public class ArtifactUploadState implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ArtifactUploadState.class);
|
||||
|
||||
private final SoftwareModuleFilters softwareModuleFilters;
|
||||
|
||||
private final Map<Long, String> deleteSofwareModules = new HashMap<>();
|
||||
|
||||
private transient Optional<Long> selectedBaseSwModuleId = Optional.empty();
|
||||
|
||||
private Set<Long> selectedSoftwareModules = Collections.emptySet();
|
||||
|
||||
private boolean swTypeFilterClosed;
|
||||
|
||||
private boolean swModuleTableMaximized;
|
||||
|
||||
private boolean artifactDetailsMaximized;
|
||||
|
||||
private final Set<String> selectedDeleteSWModuleTypes = new HashSet<>();
|
||||
|
||||
private boolean noDataAvilableSoftwareModule;
|
||||
private final TypeFilterLayoutUiState smTypeFilterLayoutUiState;
|
||||
private final GridLayoutUiState smGridLayoutUiState;
|
||||
private final ArtifactDetailsGridLayoutUiState artifactDetailsGridLayoutUiState;
|
||||
|
||||
private boolean statusPopupMinimized;
|
||||
|
||||
@@ -71,125 +54,163 @@ public class ArtifactUploadState implements ManagementEntityState, Serializable
|
||||
*/
|
||||
private Map<FileUploadId, FileUploadProgress> overallFilesInUploadProcess;
|
||||
|
||||
@Autowired
|
||||
ArtifactUploadState(final SoftwareModuleFilters softwareModuleFilters) {
|
||||
this.softwareModuleFilters = softwareModuleFilters;
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
public SoftwareModuleFilters getSoftwareModuleFilters() {
|
||||
return softwareModuleFilters;
|
||||
/**
|
||||
* Get the Software module type filter UI state
|
||||
*
|
||||
* @return TypeFilterLayoutUiState
|
||||
*/
|
||||
public TypeFilterLayoutUiState getSmTypeFilterLayoutUiState() {
|
||||
return smTypeFilterLayoutUiState;
|
||||
}
|
||||
|
||||
public Map<Long, String> getDeleteSoftwareModules() {
|
||||
return deleteSofwareModules;
|
||||
/**
|
||||
* Get the Software module grid UI state
|
||||
*
|
||||
* @return GridLayoutUiState
|
||||
*/
|
||||
public GridLayoutUiState getSmGridLayoutUiState() {
|
||||
return smGridLayoutUiState;
|
||||
}
|
||||
|
||||
public Optional<Long> getSelectedBaseSwModuleId() {
|
||||
return selectedBaseSwModuleId;
|
||||
}
|
||||
|
||||
public Set<Long> getSelectedSoftwareModules() {
|
||||
return selectedSoftwareModules;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastSelectedEntityId(final Long value) {
|
||||
this.selectedBaseSwModuleId = Optional.ofNullable(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedEnitities(final Set<Long> values) {
|
||||
this.selectedSoftwareModules = values;
|
||||
}
|
||||
|
||||
public boolean isSwTypeFilterClosed() {
|
||||
return swTypeFilterClosed;
|
||||
}
|
||||
|
||||
public void setSwTypeFilterClosed(final boolean swTypeFilterClosed) {
|
||||
this.swTypeFilterClosed = swTypeFilterClosed;
|
||||
}
|
||||
|
||||
public boolean isSwModuleTableMaximized() {
|
||||
return swModuleTableMaximized;
|
||||
}
|
||||
|
||||
public void setSwModuleTableMaximized(final boolean swModuleTableMaximized) {
|
||||
this.swModuleTableMaximized = swModuleTableMaximized;
|
||||
}
|
||||
|
||||
public Set<String> getSelectedDeleteSWModuleTypes() {
|
||||
return selectedDeleteSWModuleTypes;
|
||||
}
|
||||
|
||||
public boolean isArtifactDetailsMaximized() {
|
||||
return artifactDetailsMaximized;
|
||||
}
|
||||
|
||||
public void setArtifactDetailsMaximized(final boolean artifactDetailsMaximized) {
|
||||
this.artifactDetailsMaximized = artifactDetailsMaximized;
|
||||
}
|
||||
|
||||
public boolean isNoDataAvilableSoftwareModule() {
|
||||
return noDataAvilableSoftwareModule;
|
||||
}
|
||||
|
||||
public void setNoDataAvilableSoftwareModule(final boolean noDataAvilableSoftwareModule) {
|
||||
this.noDataAvilableSoftwareModule = noDataAvilableSoftwareModule;
|
||||
}
|
||||
|
||||
public boolean isMoreThanOneSoftwareModulesSelected() {
|
||||
return getSelectedSoftwareModules().size() > 1;
|
||||
}
|
||||
|
||||
public boolean isNoSoftwareModuleSelected() {
|
||||
return !getSelectedBaseSwModuleId().isPresent();
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
@@ -223,7 +244,10 @@ public class ArtifactUploadState implements ManagementEntityState, Serializable
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
void clearFileStates() {
|
||||
/**
|
||||
* Removes all of the data from this Upload process collection
|
||||
*/
|
||||
public void clearFileStates() {
|
||||
getOverallFilesInUploadProcessMap().clear();
|
||||
}
|
||||
|
||||
@@ -234,7 +258,7 @@ public class ArtifactUploadState implements ManagementEntityState, Serializable
|
||||
LOG.debug("Cleaning up temp data...");
|
||||
// delete file system zombies
|
||||
for (final FileUploadProgress fileUploadProgress : getAllFileUploadProgressValuesFromOverallUploadProcessList()) {
|
||||
if (!StringUtils.isBlank(fileUploadProgress.getFilePath())) {
|
||||
if (StringUtils.hasText(fileUploadProgress.getFilePath())) {
|
||||
final boolean deleted = FileUtils.deleteQuietly(new File(fileUploadProgress.getFilePath()));
|
||||
if (!deleted) {
|
||||
LOG.warn("TempFile was not deleted: {}", fileUploadProgress.getFilePath());
|
||||
@@ -249,6 +273,7 @@ public class ArtifactUploadState implements ManagementEntityState, Serializable
|
||||
*
|
||||
* @param softwareModuleId
|
||||
* id of the software module
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isUploadInProgressForSelectedSoftwareModule(final Long softwareModuleId) {
|
||||
@@ -290,5 +315,4 @@ public class ArtifactUploadState implements ManagementEntityState, Serializable
|
||||
}
|
||||
return succeededFileUploads;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.servlet.MultipartConfigElement;
|
||||
@@ -18,34 +21,29 @@ 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.ArtifactDetailsLayout;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.ArtifactDetailsEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.smtable.SoftwareModuleTableLayout;
|
||||
import org.eclipse.hawkbit.ui.artifacts.smtype.filter.SMTypeFilterButtons;
|
||||
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.state.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.artifacts.upload.UploadDropAreaLayout;
|
||||
import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType;
|
||||
import org.eclipse.hawkbit.ui.dd.criteria.UploadViewClientCriterion;
|
||||
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.utils.SPUIDefinitions;
|
||||
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;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
import org.vaadin.spring.events.EventScope;
|
||||
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
|
||||
|
||||
import com.vaadin.navigator.View;
|
||||
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
|
||||
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.Alignment;
|
||||
import com.vaadin.ui.GridLayout;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
/**
|
||||
@@ -54,202 +52,208 @@ import com.vaadin.ui.VerticalLayout;
|
||||
@UIScope
|
||||
@SpringView(name = UploadArtifactView.VIEW_NAME, ui = AbstractHawkbitUI.class)
|
||||
public class UploadArtifactView extends VerticalLayout implements View, BrowserWindowResizeListener {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String VIEW_NAME = "spUpload";
|
||||
|
||||
private final transient EventBus.UIEventBus eventBus;
|
||||
|
||||
private final SpPermissionChecker permChecker;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
|
||||
private final UINotification uiNotification;
|
||||
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
|
||||
private final SMTypeFilterLayout filterByTypeLayout;
|
||||
private final SMTypeFilterLayout smTypeFilterLayout;
|
||||
private final SoftwareModuleGridLayout smGridLayout;
|
||||
private final ArtifactDetailsGridLayout artifactDetailsGridLayout;
|
||||
|
||||
private final SoftwareModuleTableLayout smTableLayout;
|
||||
private HorizontalLayout mainLayout;
|
||||
|
||||
private final ArtifactDetailsLayout artifactDetailsLayout;
|
||||
|
||||
private final UploadDropAreaLayout dropAreaLayout;
|
||||
|
||||
private VerticalLayout detailAndUploadLayout;
|
||||
|
||||
private GridLayout 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 UploadViewClientCriterion uploadViewClientCriterion,
|
||||
final MultipartConfigElement multipartConfigElement, final ArtifactManagement artifactManagement) {
|
||||
this.eventBus = eventBus;
|
||||
this.permChecker = permChecker;
|
||||
this.i18n = i18n;
|
||||
this.uiNotification = uiNotification;
|
||||
this.artifactUploadState = artifactUploadState;
|
||||
this.smTableLayout = new SoftwareModuleTableLayout(i18n, permChecker, artifactUploadState, uiNotification,
|
||||
eventBus, softwareModuleManagement, softwareModuleTypeManagement, entityFactory,
|
||||
uploadViewClientCriterion);
|
||||
this.artifactDetailsLayout = new ArtifactDetailsLayout(i18n, eventBus, artifactUploadState, uiNotification,
|
||||
artifactManagement, softwareModuleManagement);
|
||||
final SMTypeFilterButtons smTypeFilterButtons = new SMTypeFilterButtons(eventBus, artifactUploadState,
|
||||
uploadViewClientCriterion, softwareModuleTypeManagement, i18n, entityFactory, permChecker,
|
||||
uiNotification);
|
||||
this.filterByTypeLayout = new SMTypeFilterLayout(artifactUploadState, i18n, permChecker, eventBus,
|
||||
entityFactory, uiNotification, softwareModuleTypeManagement, smTypeFilterButtons);
|
||||
this.dropAreaLayout = new UploadDropAreaLayout(i18n, eventBus, uiNotification, artifactUploadState,
|
||||
multipartConfigElement, softwareModuleManagement, artifactManagement);
|
||||
|
||||
if (permChecker.hasReadRepositoryPermission()) {
|
||||
this.smTypeFilterLayout = new SMTypeFilterLayout(i18n, permChecker, eventBus, entityFactory, uiNotification,
|
||||
softwareModuleTypeManagement, artifactUploadState.getSmTypeFilterLayoutUiState());
|
||||
this.smGridLayout = new SoftwareModuleGridLayout(i18n, permChecker, uiNotification, eventBus,
|
||||
softwareModuleManagement, softwareModuleTypeManagement, entityFactory,
|
||||
artifactUploadState.getSmTypeFilterLayoutUiState(), artifactUploadState.getSmGridLayoutUiState());
|
||||
this.artifactDetailsGridLayout = new ArtifactDetailsGridLayout(i18n, eventBus, permChecker, uiNotification,
|
||||
artifactUploadState, artifactUploadState.getArtifactDetailsGridLayoutUiState(), artifactManagement,
|
||||
softwareModuleManagement, multipartConfigElement);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
void init() {
|
||||
buildLayout();
|
||||
restoreState();
|
||||
checkNoDataAvaialble();
|
||||
eventBus.subscribe(this);
|
||||
Page.getCurrent().addBrowserWindowResizeListener(this);
|
||||
showOrHideFilterButtons(Page.getCurrent().getBrowserWindowWidth());
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
void destroy() {
|
||||
eventBus.unsubscribe(this);
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final SoftwareModuleEvent event) {
|
||||
if (BaseEntityEventType.MINIMIZED == event.getEventType()) {
|
||||
minimizeSwTable();
|
||||
} else if (BaseEntityEventType.MAXIMIZED == event.getEventType()) {
|
||||
maximizeSwTable();
|
||||
}
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final ArtifactDetailsEvent event) {
|
||||
if (event == ArtifactDetailsEvent.MINIMIZED) {
|
||||
minimizeArtifactoryDetails();
|
||||
} else if (event == ArtifactDetailsEvent.MAXIMIZED) {
|
||||
maximizeArtifactoryDetails();
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreState() {
|
||||
if (artifactUploadState.isSwModuleTableMaximized()) {
|
||||
maximizeSwTable();
|
||||
}
|
||||
if (artifactUploadState.isArtifactDetailsMaximized()) {
|
||||
maximizeArtifactoryDetails();
|
||||
if (permChecker.hasReadRepositoryPermission()) {
|
||||
buildLayout();
|
||||
restoreState();
|
||||
Page.getCurrent().addBrowserWindowResizeListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildLayout() {
|
||||
if (permChecker.hasReadRepositoryPermission() || permChecker.hasCreateRepositoryPermission()) {
|
||||
setSizeFull();
|
||||
createMainLayout();
|
||||
addComponents(mainLayout);
|
||||
setExpandRatio(mainLayout, 1);
|
||||
}
|
||||
setMargin(false);
|
||||
setSpacing(false);
|
||||
setSizeFull();
|
||||
|
||||
createMainLayout();
|
||||
|
||||
addComponent(mainLayout);
|
||||
setExpandRatio(mainLayout, 1.0F);
|
||||
}
|
||||
|
||||
private VerticalLayout createDetailsAndUploadLayout() {
|
||||
detailAndUploadLayout = new VerticalLayout();
|
||||
detailAndUploadLayout.addComponent(artifactDetailsLayout);
|
||||
detailAndUploadLayout.setComponentAlignment(artifactDetailsLayout, Alignment.TOP_CENTER);
|
||||
detailAndUploadLayout.setExpandRatio(artifactDetailsLayout, 1.0F);
|
||||
|
||||
if (permChecker.hasCreateRepositoryPermission()) {
|
||||
detailAndUploadLayout.addComponent(dropAreaLayout.getDropAreaWrapper());
|
||||
}
|
||||
|
||||
detailAndUploadLayout.setSizeFull();
|
||||
detailAndUploadLayout.addStyleName("group");
|
||||
detailAndUploadLayout.setSpacing(true);
|
||||
return detailAndUploadLayout;
|
||||
}
|
||||
|
||||
private GridLayout createMainLayout() {
|
||||
createDetailsAndUploadLayout();
|
||||
mainLayout = new GridLayout(3, 1);
|
||||
private void createMainLayout() {
|
||||
mainLayout = new HorizontalLayout();
|
||||
mainLayout.setSizeFull();
|
||||
mainLayout.setMargin(false);
|
||||
mainLayout.setSpacing(true);
|
||||
mainLayout.setStyleName("fullSize");
|
||||
mainLayout.addComponent(filterByTypeLayout, 0, 0);
|
||||
mainLayout.addComponent(smTableLayout, 1, 0);
|
||||
mainLayout.addComponent(detailAndUploadLayout, 2, 0);
|
||||
|
||||
mainLayout.setRowExpandRatio(0, 1.0F);
|
||||
mainLayout.setColumnExpandRatio(1, 0.5F);
|
||||
mainLayout.setColumnExpandRatio(2, 0.5F);
|
||||
mainLayout.addComponent(smTypeFilterLayout);
|
||||
mainLayout.addComponent(smGridLayout);
|
||||
mainLayout.addComponent(artifactDetailsGridLayout);
|
||||
|
||||
return mainLayout;
|
||||
mainLayout.setExpandRatio(smTypeFilterLayout, 0F);
|
||||
mainLayout.setExpandRatio(smGridLayout, 0.5F);
|
||||
mainLayout.setExpandRatio(artifactDetailsGridLayout, 0.5F);
|
||||
}
|
||||
|
||||
private void minimizeSwTable() {
|
||||
mainLayout.addComponent(detailAndUploadLayout, 2, 0);
|
||||
addOtherComponents();
|
||||
}
|
||||
|
||||
private void maximizeSwTable() {
|
||||
mainLayout.removeComponent(detailAndUploadLayout);
|
||||
mainLayout.setColumnExpandRatio(1, 1F);
|
||||
mainLayout.setColumnExpandRatio(2, 0F);
|
||||
}
|
||||
|
||||
private void minimizeArtifactoryDetails() {
|
||||
mainLayout.setSpacing(true);
|
||||
detailAndUploadLayout.addComponent(dropAreaLayout.getDropAreaWrapper());
|
||||
mainLayout.addComponent(filterByTypeLayout, 0, 0);
|
||||
mainLayout.addComponent(smTableLayout, 1, 0);
|
||||
addOtherComponents();
|
||||
}
|
||||
|
||||
private void maximizeArtifactoryDetails() {
|
||||
mainLayout.setSpacing(false);
|
||||
mainLayout.removeComponent(filterByTypeLayout);
|
||||
mainLayout.removeComponent(smTableLayout);
|
||||
detailAndUploadLayout.removeComponent(dropAreaLayout.getDropAreaWrapper());
|
||||
mainLayout.setColumnExpandRatio(1, 0F);
|
||||
mainLayout.setColumnExpandRatio(2, 1F);
|
||||
}
|
||||
|
||||
private void addOtherComponents() {
|
||||
mainLayout.setColumnExpandRatio(1, 0.5F);
|
||||
mainLayout.setColumnExpandRatio(2, 0.5F);
|
||||
}
|
||||
|
||||
private void checkNoDataAvaialble() {
|
||||
if (artifactUploadState.isNoDataAvilableSoftwareModule()) {
|
||||
uiNotification.displayValidationError(i18n.getMessage("message.no.data"));
|
||||
private void restoreState() {
|
||||
if (artifactUploadState.getSmTypeFilterLayoutUiState().isHidden()
|
||||
|| artifactUploadState.getArtifactDetailsGridLayoutUiState().isMaximized()) {
|
||||
hideSmTypeLayout();
|
||||
} else {
|
||||
showSmTypeLayout();
|
||||
}
|
||||
smTypeFilterLayout.restoreState();
|
||||
|
||||
if (artifactUploadState.getSmGridLayoutUiState().isMaximized()) {
|
||||
maximizeSmGridLayout();
|
||||
}
|
||||
smGridLayout.restoreState();
|
||||
|
||||
if (artifactUploadState.getArtifactDetailsGridLayoutUiState().isMaximized()) {
|
||||
maximizeArtifactGridLayout();
|
||||
}
|
||||
artifactDetailsGridLayout.restoreState();
|
||||
}
|
||||
|
||||
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) {
|
||||
filterByTypeLayout.setVisible(false);
|
||||
smTableLayout.setShowFilterButtonVisible(true);
|
||||
} else if (!artifactUploadState.isSwTypeFilterClosed()) {
|
||||
filterByTypeLayout.setVisible(true);
|
||||
smTableLayout.setShowFilterButtonVisible(false);
|
||||
if (!artifactUploadState.getSmTypeFilterLayoutUiState().isHidden()) {
|
||||
hideSmTypeLayout();
|
||||
}
|
||||
} else {
|
||||
if (artifactUploadState.getSmTypeFilterLayoutUiState().isHidden()) {
|
||||
showSmTypeLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enter(final ViewChangeEvent event) {
|
||||
smTableLayout.getSoftwareModuleTable()
|
||||
.selectEntity(artifactUploadState.getSelectedBaseSwModuleId().orElse(null));
|
||||
dropAreaLayout.getUploadButtonLayout().restoreState();
|
||||
}
|
||||
@PreDestroy
|
||||
void destroy() {
|
||||
if (permChecker.hasReadRepositoryPermission()) {
|
||||
layoutVisibilityListener.unsubscribe();
|
||||
layoutResizeListener.unsubscribe();
|
||||
|
||||
smTypeFilterLayout.unsubscribeListener();
|
||||
smGridLayout.unsubscribeListener();
|
||||
artifactDetailsGridLayout.unsubscribeListener();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,12 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.ui.management.AbstractDashboardMenuItemNotification;
|
||||
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.server.FontAwesome;
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.server.Resource;
|
||||
import com.vaadin.spring.annotation.SpringComponent;
|
||||
import com.vaadin.spring.annotation.UIScope;
|
||||
@@ -31,7 +31,6 @@ import com.vaadin.spring.annotation.UIScope;
|
||||
@UIScope
|
||||
@Order(500)
|
||||
public class UploadArtifactViewMenuItem extends AbstractDashboardMenuItemNotification {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Autowired
|
||||
@@ -46,17 +45,17 @@ public class UploadArtifactViewMenuItem extends AbstractDashboardMenuItemNotific
|
||||
|
||||
@Override
|
||||
public Resource getDashboardIcon() {
|
||||
return FontAwesome.UPLOAD;
|
||||
return VaadinIcons.UPLOAD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDashboardCaption() {
|
||||
return getI18n().getMessage("dashboard.upload.caption");
|
||||
return i18n.getMessage("dashboard.upload.caption");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDashboardCaptionLong() {
|
||||
return getI18n().getMessage("dashboard.upload.caption-long");
|
||||
return i18n.getMessage("dashboard.upload.caption-long");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.details;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.SpringContextHelper;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.vaadin.addons.lazyquerycontainer.AbstractBeanQuery;
|
||||
import org.vaadin.addons.lazyquerycontainer.QueryDefinition;
|
||||
|
||||
/**
|
||||
* Simple implementation of generics bean query which dynamically loads artifact
|
||||
* beans.
|
||||
*/
|
||||
public class ArtifactBeanQuery extends AbstractBeanQuery<Artifact> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private Sort sort = new Sort(Direction.DESC, "filename");
|
||||
private transient ArtifactManagement artifactManagement;
|
||||
private transient Page<Artifact> firstPagetArtifacts;
|
||||
private Long baseSwModuleId;
|
||||
|
||||
/**
|
||||
* Parametric Constructor.
|
||||
*
|
||||
* @param definition
|
||||
* as Def
|
||||
* @param queryConfig
|
||||
* as Config
|
||||
* @param sortIds
|
||||
* as sort
|
||||
* @param sortStates
|
||||
* as Sort status
|
||||
*/
|
||||
public ArtifactBeanQuery(final QueryDefinition definition, final Map<String, Object> queryConfig,
|
||||
final Object[] sortIds, final boolean[] sortStates) {
|
||||
|
||||
super(definition, queryConfig, sortIds, sortStates);
|
||||
|
||||
if (HawkbitCommonUtil.isNotNullOrEmpty(queryConfig)) {
|
||||
baseSwModuleId = (Long) queryConfig.get(SPUIDefinitions.BY_BASE_SOFTWARE_MODULE);
|
||||
}
|
||||
|
||||
if (!ArrayUtils.isEmpty(sortStates)) {
|
||||
sort = new Sort(sortStates[0] ? Direction.ASC : Direction.DESC, (String) sortIds[0]);
|
||||
|
||||
for (int targetId = 1; targetId < sortIds.length; targetId++) {
|
||||
sort.and(new Sort(sortStates[targetId] ? Direction.ASC : Direction.DESC, (String) sortIds[targetId]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Artifact constructBean() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Artifact> loadBeans(final int startIndex, final int count) {
|
||||
Page<Artifact> artifactBeans;
|
||||
if (startIndex == 0 && firstPagetArtifacts != null) {
|
||||
artifactBeans = firstPagetArtifacts;
|
||||
} else {
|
||||
artifactBeans = getArtifactManagement()
|
||||
.findBySoftwareModule(new OffsetBasedPageRequest(startIndex, count, sort), baseSwModuleId);
|
||||
}
|
||||
|
||||
return artifactBeans.getContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveBeans(final List<Artifact> addedTargets, final List<Artifact> modifiedTargets,
|
||||
final List<Artifact> removedTargets) {
|
||||
// CRUD operations on Target will be done through repository methods
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
long size = 0;
|
||||
if (baseSwModuleId != null) {
|
||||
firstPagetArtifacts = getArtifactManagement().findBySoftwareModule(
|
||||
new OffsetBasedPageRequest(0, SPUIDefinitions.PAGE_SIZE, sort), baseSwModuleId);
|
||||
size = firstPagetArtifacts.getTotalElements();
|
||||
}
|
||||
if (size > Integer.MAX_VALUE) {
|
||||
size = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
private ArtifactManagement getArtifactManagement() {
|
||||
if (artifactManagement == null) {
|
||||
artifactManagement = SpringContextHelper.getBean(ArtifactManagement.class);
|
||||
}
|
||||
return artifactManagement;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.details;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.artifact.repository.model.AbstractDbArtifact;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
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.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.server.FileDownloader;
|
||||
import com.vaadin.server.StreamResource;
|
||||
import com.vaadin.ui.Button;
|
||||
|
||||
/**
|
||||
* 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 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;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param permissionChecker
|
||||
* SpPermissionChecker
|
||||
* @param notification
|
||||
* UINotification
|
||||
* @param artifactManagement
|
||||
* ArtifactManagement
|
||||
*/
|
||||
public ArtifactDetailsGrid(final UIEventBus eventBus, final VaadinMessageSource i18n,
|
||||
final SpPermissionChecker permissionChecker, final UINotification notification,
|
||||
final ArtifactManagement artifactManagement) {
|
||||
super(i18n, eventBus, permissionChecker);
|
||||
|
||||
this.notification = notification;
|
||||
this.artifactManagement = artifactManagement;
|
||||
|
||||
this.artifactDeleteSupport = new DeleteSupport<>(this, i18n, notification,
|
||||
i18n.getMessage("artifact.details.header"), ProxyArtifact::getFilename, this::artifactsDeletionCallback,
|
||||
UIComponentIdProvider.ARTIFACT_DELETE_CONFIRMATION_DIALOG);
|
||||
|
||||
setFilterSupport(
|
||||
new FilterSupport<>(new ArtifactDataProvider(artifactManagement, new ArtifactToProxyArtifactMapper())));
|
||||
initFilterMappings();
|
||||
|
||||
this.masterEntitySupport = new MasterEntitySupport<>(getFilterSupport());
|
||||
|
||||
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,
|
||||
getMasterEntitySupport().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()).map(AbstractDbArtifact::getFileInputStream).orElse(null),
|
||||
artifact.getFilename());
|
||||
|
||||
final FileDownloader fileDownloader = new FileDownloader(artifactStreamResource);
|
||||
fileDownloader.setErrorHandler(event -> notification
|
||||
.displayValidationError(i18n.getMessage(UIMessageIdProvider.ARTIFACT_DOWNLOAD_FAILURE_MSG)));
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.details;
|
||||
|
||||
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;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
/**
|
||||
* 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 i18n
|
||||
* VaadinMessageSource
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param artifactDetailsGridLayoutUiState
|
||||
* ArtifactDetailsGridLayoutUiState
|
||||
*/
|
||||
public ArtifactDetailsGridHeader(final VaadinMessageSource i18n, final UIEventBus eventBus,
|
||||
final ArtifactDetailsGridLayoutUiState artifactDetailsGridLayoutUiState) {
|
||||
super(i18n, null, eventBus);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.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.SpPermissionChecker;
|
||||
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.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;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
/**
|
||||
* 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 i18n
|
||||
* VaadinMessageSource
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param permChecker
|
||||
* SpPermissionChecker
|
||||
* @param notification
|
||||
* UINotification
|
||||
* @param artifactUploadState
|
||||
* ArtifactUploadState
|
||||
* @param artifactDetailsGridLayoutUiState
|
||||
* ArtifactDetailsGridLayoutUiState
|
||||
* @param artifactManagement
|
||||
* ArtifactManagement
|
||||
* @param softwareManagement
|
||||
* SoftwareModuleManagement
|
||||
* @param multipartConfigElement
|
||||
* MultipartConfigElement
|
||||
*/
|
||||
public ArtifactDetailsGridLayout(final VaadinMessageSource i18n, final UIEventBus eventBus,
|
||||
final SpPermissionChecker permChecker, final UINotification notification,
|
||||
final ArtifactUploadState artifactUploadState,
|
||||
final ArtifactDetailsGridLayoutUiState artifactDetailsGridLayoutUiState,
|
||||
final ArtifactManagement artifactManagement, final SoftwareModuleManagement softwareManagement,
|
||||
final MultipartConfigElement multipartConfigElement) {
|
||||
this.artifactDetailsHeader = new ArtifactDetailsGridHeader(i18n, eventBus, artifactDetailsGridLayoutUiState);
|
||||
this.artifactDetailsGrid = new ArtifactDetailsGrid(eventBus, i18n, permChecker, notification,
|
||||
artifactManagement);
|
||||
|
||||
if (permChecker.hasCreateRepositoryPermission()) {
|
||||
this.uploadDropAreaLayout = new UploadDropAreaLayout(i18n, eventBus, notification, 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<>(eventBus, masterLayoutView,
|
||||
getMasterEntityAwareComponents());
|
||||
this.fileUploadChangedListener = new GenericEventListener<>(eventBus, 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is called when view is shown to the user
|
||||
*/
|
||||
public void restoreState() {
|
||||
artifactDetailsHeader.restoreState();
|
||||
|
||||
if (uploadDropAreaLayout != null) {
|
||||
uploadDropAreaLayout.restoreState();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe the even listeners for selection change and fileupload
|
||||
*/
|
||||
public void unsubscribeListener() {
|
||||
selectionChangedListener.unsubscribe();
|
||||
fileUploadChangedListener.unsubscribe();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.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,606 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.details;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.artifact.repository.model.AbstractDbArtifact;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.ArtifactDetailsEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent.SoftwareModuleEventType;
|
||||
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.common.ConfirmationDialog;
|
||||
import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIButton;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorder;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
|
||||
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.util.StringUtils;
|
||||
import org.vaadin.addons.lazyquerycontainer.BeanQueryFactory;
|
||||
import org.vaadin.addons.lazyquerycontainer.LazyQueryContainer;
|
||||
import org.vaadin.addons.lazyquerycontainer.LazyQueryDefinition;
|
||||
import org.vaadin.spring.events.EventBus;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
import org.vaadin.spring.events.EventScope;
|
||||
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.vaadin.data.Container;
|
||||
import com.vaadin.server.ErrorHandler;
|
||||
import com.vaadin.server.FileDownloader;
|
||||
import com.vaadin.server.FontAwesome;
|
||||
import com.vaadin.server.StreamResource;
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.Button;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.Table;
|
||||
import com.vaadin.ui.Table.ColumnGenerator;
|
||||
import com.vaadin.ui.Table.TableDragMode;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
/**
|
||||
* Display the details of the artifacts for a selected software module.
|
||||
*/
|
||||
public class ArtifactDetailsLayout extends VerticalLayout {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String PROVIDED_FILE_NAME = "filename";
|
||||
|
||||
private static final String LAST_MODIFIED_DATE = "lastModifiedAt";
|
||||
|
||||
private static final String CREATE_MODIFIED_DATE_UPLOAD = "Created/Modified Date";
|
||||
|
||||
private static final String ACTION = "action";
|
||||
|
||||
private static final String CREATED_DATE = "createdAt";
|
||||
|
||||
private static final String SIZE = "size";
|
||||
|
||||
private static final String SHA1HASH = "sha1Hash";
|
||||
|
||||
private static final String MD5HASH = "md5Hash";
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
|
||||
private final transient EventBus.UIEventBus eventBus;
|
||||
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
|
||||
private final UINotification uINotification;
|
||||
|
||||
private Label prefixTitleOfArtifactDetails;
|
||||
|
||||
private Label titleOfArtifactDetails;
|
||||
|
||||
private HorizontalLayout headerCaptionLayout;
|
||||
|
||||
private SPUIButton maxMinButton;
|
||||
|
||||
private Table artifactDetailsTable;
|
||||
|
||||
private Table maxArtifactDetailsTable;
|
||||
|
||||
private boolean fullWindowMode;
|
||||
|
||||
private boolean readOnly;
|
||||
|
||||
private final transient ArtifactManagement artifactManagement;
|
||||
|
||||
private final transient SoftwareModuleManagement softwareModuleManagement;
|
||||
|
||||
/**
|
||||
* Constructor for ArtifactDetailsLayout
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param artifactUploadState
|
||||
* ArtifactUploadState
|
||||
* @param uINotification
|
||||
* UINotification
|
||||
* @param artifactManagement
|
||||
* ArtifactManagement
|
||||
* @param softwareManagement
|
||||
* SoftwareManagement
|
||||
*/
|
||||
public ArtifactDetailsLayout(final VaadinMessageSource i18n, final UIEventBus eventBus,
|
||||
final ArtifactUploadState artifactUploadState, final UINotification uINotification,
|
||||
final ArtifactManagement artifactManagement, final SoftwareModuleManagement softwareManagement) {
|
||||
this.i18n = i18n;
|
||||
this.eventBus = eventBus;
|
||||
this.artifactUploadState = artifactUploadState;
|
||||
this.uINotification = uINotification;
|
||||
this.artifactManagement = artifactManagement;
|
||||
this.softwareModuleManagement = softwareManagement;
|
||||
|
||||
final Optional<SoftwareModule> selectedSoftwareModule = findSelectedSoftwareModule();
|
||||
|
||||
String labelSoftwareModule = "";
|
||||
if (selectedSoftwareModule.isPresent()) {
|
||||
labelSoftwareModule = HawkbitCommonUtil.getFormattedNameVersion(selectedSoftwareModule.get().getName(),
|
||||
selectedSoftwareModule.get().getVersion());
|
||||
}
|
||||
createComponents();
|
||||
buildLayout();
|
||||
eventBus.subscribe(this);
|
||||
|
||||
if (selectedSoftwareModule.isPresent()) {
|
||||
populateArtifactDetails(selectedSoftwareModule.get().getId(), labelSoftwareModule);
|
||||
}
|
||||
|
||||
if (isMaximized()) {
|
||||
maximizedArtifactDetailsView();
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<SoftwareModule> findSelectedSoftwareModule() {
|
||||
final Optional<Long> selectedBaseSwModuleId = artifactUploadState.getSelectedBaseSwModuleId();
|
||||
|
||||
if (selectedBaseSwModuleId.isPresent()) {
|
||||
return softwareModuleManagement.get(selectedBaseSwModuleId.get());
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private void createComponents() {
|
||||
prefixTitleOfArtifactDetails = new Label();
|
||||
prefixTitleOfArtifactDetails.addStyleName(ValoTheme.LABEL_SMALL);
|
||||
prefixTitleOfArtifactDetails.addStyleName(ValoTheme.LABEL_BOLD);
|
||||
prefixTitleOfArtifactDetails.setSizeUndefined();
|
||||
|
||||
titleOfArtifactDetails = new Label();
|
||||
titleOfArtifactDetails.setId(UIComponentIdProvider.ARTIFACT_DETAILS_HEADER_LABEL_ID);
|
||||
titleOfArtifactDetails.setSizeFull();
|
||||
titleOfArtifactDetails.setImmediate(true);
|
||||
titleOfArtifactDetails.setWidth("100%");
|
||||
titleOfArtifactDetails.addStyleName(ValoTheme.LABEL_SMALL);
|
||||
titleOfArtifactDetails.addStyleName("text-bold");
|
||||
titleOfArtifactDetails.addStyleName("text-cut");
|
||||
titleOfArtifactDetails.addStyleName("header-caption-right");
|
||||
|
||||
headerCaptionLayout = new HorizontalLayout();
|
||||
headerCaptionLayout.setMargin(false);
|
||||
headerCaptionLayout.setSpacing(true);
|
||||
headerCaptionLayout.setSizeFull();
|
||||
headerCaptionLayout.addStyleName("header-caption");
|
||||
|
||||
headerCaptionLayout.addComponent(prefixTitleOfArtifactDetails);
|
||||
headerCaptionLayout.setComponentAlignment(prefixTitleOfArtifactDetails, Alignment.TOP_LEFT);
|
||||
headerCaptionLayout.setExpandRatio(prefixTitleOfArtifactDetails, 0.0F);
|
||||
|
||||
headerCaptionLayout.addComponent(titleOfArtifactDetails);
|
||||
headerCaptionLayout.setComponentAlignment(titleOfArtifactDetails, Alignment.TOP_LEFT);
|
||||
headerCaptionLayout.setExpandRatio(titleOfArtifactDetails, 1.0F);
|
||||
|
||||
maxMinButton = createMaxMinButton();
|
||||
|
||||
artifactDetailsTable = createArtifactDetailsTable();
|
||||
|
||||
artifactDetailsTable.setContainerDataSource(createArtifactLazyQueryContainer());
|
||||
addGeneratedColumn(artifactDetailsTable);
|
||||
if (!readOnly) {
|
||||
addGeneratedColumnButton(artifactDetailsTable);
|
||||
}
|
||||
setTableColumnDetails(artifactDetailsTable);
|
||||
}
|
||||
|
||||
private SPUIButton createMaxMinButton() {
|
||||
final SPUIButton button = (SPUIButton) SPUIComponentProvider.getButton(SPUIDefinitions.EXPAND_ACTION_HISTORY,
|
||||
"", i18n.getMessage(UIMessageIdProvider.TOOLTIP_MAXIMIZE), null, true, FontAwesome.EXPAND,
|
||||
SPUIButtonStyleNoBorder.class);
|
||||
button.addClickListener(event -> maxArtifactDetails());
|
||||
return button;
|
||||
|
||||
}
|
||||
|
||||
private void buildLayout() {
|
||||
final HorizontalLayout header = new HorizontalLayout();
|
||||
header.addStyleName("artifact-details-header");
|
||||
header.addStyleName("bordered-layout");
|
||||
header.addStyleName("no-border-bottom");
|
||||
header.setSpacing(false);
|
||||
header.setMargin(false);
|
||||
header.setSizeFull();
|
||||
header.setHeightUndefined();
|
||||
header.setImmediate(true);
|
||||
header.addComponents(headerCaptionLayout, maxMinButton);
|
||||
header.setComponentAlignment(headerCaptionLayout, Alignment.TOP_LEFT);
|
||||
header.setComponentAlignment(maxMinButton, Alignment.TOP_RIGHT);
|
||||
header.setExpandRatio(headerCaptionLayout, 1.0F);
|
||||
|
||||
setSizeFull();
|
||||
setImmediate(true);
|
||||
addStyleName("artifact-table");
|
||||
addStyleName("table-layout");
|
||||
addComponent(header);
|
||||
setComponentAlignment(header, Alignment.MIDDLE_CENTER);
|
||||
addComponent(artifactDetailsTable);
|
||||
setComponentAlignment(artifactDetailsTable, Alignment.MIDDLE_CENTER);
|
||||
setExpandRatio(artifactDetailsTable, 1.0F);
|
||||
}
|
||||
|
||||
private Container createArtifactLazyQueryContainer() {
|
||||
return getArtifactLazyQueryContainer(Collections.emptyMap());
|
||||
}
|
||||
|
||||
private LazyQueryContainer getArtifactLazyQueryContainer(final Map<String, Object> queryConfig) {
|
||||
|
||||
final BeanQueryFactory<ArtifactBeanQuery> artifactQF = new BeanQueryFactory<>(ArtifactBeanQuery.class);
|
||||
artifactQF.setQueryConfiguration(queryConfig);
|
||||
final LazyQueryContainer artifactCont = new LazyQueryContainer(new LazyQueryDefinition(true, 10, "id"),
|
||||
artifactQF);
|
||||
addArtifactTableProperties(artifactCont);
|
||||
return artifactCont;
|
||||
}
|
||||
|
||||
private void addArtifactTableProperties(final LazyQueryContainer artifactCont) {
|
||||
artifactCont.addContainerProperty(PROVIDED_FILE_NAME, Label.class, "", false, false);
|
||||
artifactCont.addContainerProperty(SIZE, Long.class, null, false, false);
|
||||
artifactCont.addContainerProperty(SHA1HASH, String.class, null, false, false);
|
||||
artifactCont.addContainerProperty(MD5HASH, String.class, null, false, false);
|
||||
artifactCont.addContainerProperty(CREATED_DATE, Date.class, null, false, false);
|
||||
artifactCont.addContainerProperty(LAST_MODIFIED_DATE, Date.class, null, false, false);
|
||||
if (!readOnly) {
|
||||
artifactCont.addContainerProperty(ACTION, Label.class, null, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addGeneratedColumn(final Table table) {
|
||||
table.addGeneratedColumn(CREATE_MODIFIED_DATE_UPLOAD, new ColumnGenerator() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public String generateCell(final Table source, final Object itemId, final Object columnId) {
|
||||
final Long createdDate = (Long) table.getContainerDataSource().getItem(itemId)
|
||||
.getItemProperty(CREATED_DATE).getValue();
|
||||
final Long modifiedDATE = (Long) table.getContainerDataSource().getItem(itemId)
|
||||
.getItemProperty(LAST_MODIFIED_DATE).getValue();
|
||||
if (modifiedDATE != null) {
|
||||
return SPDateTimeUtil.getFormattedDate(modifiedDATE);
|
||||
}
|
||||
return SPDateTimeUtil.getFormattedDate(createdDate);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addGeneratedColumnButton(final Table table) {
|
||||
table.addGeneratedColumn(ACTION, new ColumnGenerator() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public HorizontalLayout generateCell(final Table source, final Object itemId, final Object columnId) {
|
||||
HorizontalLayout actioncellLayout = new HorizontalLayout();
|
||||
actioncellLayout.addComponent(getArtifactDeleteButton(table, itemId));
|
||||
actioncellLayout.addComponent(getArtifactDownloadButton(table, itemId));
|
||||
actioncellLayout.setImmediate(true);
|
||||
return actioncellLayout;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Button getArtifactDeleteButton(final Table table, final Object itemId) {
|
||||
final String fileName = (String) table.getContainerDataSource().getItem(itemId)
|
||||
.getItemProperty(PROVIDED_FILE_NAME).getValue();
|
||||
final Button deleteIcon = SPUIComponentProvider.getButton(
|
||||
fileName + "-" + UIComponentIdProvider.UPLOAD_FILE_DELETE_ICON, "",
|
||||
i18n.getMessage(UIMessageIdProvider.CAPTION_DISCARD), ValoTheme.BUTTON_TINY + " " + "blueicon",
|
||||
true, FontAwesome.TRASH_O, SPUIButtonStyleNoBorder.class);
|
||||
deleteIcon.setData(itemId);
|
||||
deleteIcon.addClickListener(event -> confirmAndDeleteArtifact((Long) itemId, fileName));
|
||||
return deleteIcon;
|
||||
}
|
||||
|
||||
private Button getArtifactDownloadButton(final Table table, final Object itemId) {
|
||||
final String fileName = (String) table.getContainerDataSource().getItem(itemId)
|
||||
.getItemProperty(PROVIDED_FILE_NAME).getValue();
|
||||
final Button downloadIcon = SPUIComponentProvider.getButton(
|
||||
fileName + "-" + UIComponentIdProvider.ARTIFACT_FILE_DOWNLOAD_ICON, "",
|
||||
i18n.getMessage(UIMessageIdProvider.TOOLTIP_ARTIFACT_DOWNLOAD), ValoTheme.BUTTON_TINY + " " + "blueicon",
|
||||
true, FontAwesome.DOWNLOAD, SPUIButtonStyleNoBorder.class);
|
||||
downloadIcon.setData(itemId);
|
||||
FileDownloader fileDownloader = new FileDownloader(createStreamResource((Long) itemId));
|
||||
fileDownloader.extend(downloadIcon);
|
||||
fileDownloader.setErrorHandler(new ErrorHandler() {
|
||||
|
||||
/**
|
||||
* Error handler for file downloader
|
||||
*/
|
||||
private static final long serialVersionUID = 4030230501114422570L;
|
||||
|
||||
@Override
|
||||
public void error(com.vaadin.server.ErrorEvent event) {
|
||||
uINotification.displayValidationError(i18n.getMessage(UIMessageIdProvider.ARTIFACT_DOWNLOAD_FAILURE_MSG));
|
||||
}
|
||||
});
|
||||
return downloadIcon;
|
||||
}
|
||||
|
||||
private StreamResource createStreamResource(final Long id) {
|
||||
|
||||
Optional<Artifact> artifact = this.artifactManagement.get(id);
|
||||
if (artifact.isPresent()) {
|
||||
Optional<AbstractDbArtifact> file = artifactManagement.loadArtifactBinary(artifact.get().getSha1Hash());
|
||||
return new StreamResource(new StreamResource.StreamSource() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public InputStream getStream() {
|
||||
if (file.isPresent()) {
|
||||
return file.get().getFileInputStream();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, artifact.get().getFilename());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void confirmAndDeleteArtifact(final Long id, final String fileName) {
|
||||
final ConfirmationDialog confirmDialog = new ConfirmationDialog(
|
||||
i18n.getMessage("caption.delete.artifact.confirmbox"),
|
||||
i18n.getMessage("message.delete.artifact", fileName), i18n.getMessage(UIMessageIdProvider.BUTTON_OK),
|
||||
i18n.getMessage(UIMessageIdProvider.BUTTON_CANCEL), ok -> {
|
||||
if (ok) {
|
||||
artifactManagement.delete(id);
|
||||
uINotification.displaySuccess(i18n.getMessage("message.artifact.deleted", fileName));
|
||||
final Optional<SoftwareModule> softwareModule = findSelectedSoftwareModule();
|
||||
populateArtifactDetails(softwareModule.orElse(null));
|
||||
}
|
||||
});
|
||||
UI.getCurrent().addWindow(confirmDialog.getWindow());
|
||||
confirmDialog.getWindow().bringToFront();
|
||||
}
|
||||
|
||||
private void setTableColumnDetails(final Table table) {
|
||||
|
||||
table.setColumnHeader(PROVIDED_FILE_NAME, i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_FILENAME));
|
||||
table.setColumnHeader(SIZE, i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_FILESIZE_BYTES));
|
||||
if (fullWindowMode) {
|
||||
table.setColumnHeader(SHA1HASH, i18n.getMessage("upload.sha1"));
|
||||
table.setColumnHeader(MD5HASH, i18n.getMessage("upload.md5"));
|
||||
}
|
||||
table.setColumnHeader(CREATE_MODIFIED_DATE_UPLOAD, i18n.getMessage("upload.last.modified.date"));
|
||||
if (!readOnly) {
|
||||
table.setColumnHeader(ACTION, i18n.getMessage(UIMessageIdProvider.MESSAGE_UPLOAD_ACTION));
|
||||
}
|
||||
|
||||
table.setColumnExpandRatio(PROVIDED_FILE_NAME, 3.5F);
|
||||
table.setColumnExpandRatio(SIZE, 2F);
|
||||
if (fullWindowMode) {
|
||||
table.setColumnExpandRatio(SHA1HASH, 2.8F);
|
||||
table.setColumnExpandRatio(MD5HASH, 2.4F);
|
||||
}
|
||||
table.setColumnExpandRatio(CREATE_MODIFIED_DATE_UPLOAD, 3F);
|
||||
if (!readOnly) {
|
||||
table.setColumnExpandRatio(ACTION, 2.5F);
|
||||
}
|
||||
|
||||
table.setVisibleColumns(getVisbleColumns().toArray());
|
||||
}
|
||||
|
||||
private List<Object> getVisbleColumns() {
|
||||
final List<Object> visibileColumn = new ArrayList<>();
|
||||
visibileColumn.add(PROVIDED_FILE_NAME);
|
||||
visibileColumn.add(SIZE);
|
||||
if (fullWindowMode) {
|
||||
visibileColumn.add(SHA1HASH);
|
||||
visibileColumn.add(MD5HASH);
|
||||
}
|
||||
visibileColumn.add(CREATE_MODIFIED_DATE_UPLOAD);
|
||||
if (!readOnly) {
|
||||
visibileColumn.add(ACTION);
|
||||
}
|
||||
return visibileColumn;
|
||||
}
|
||||
|
||||
private static Table createArtifactDetailsTable() {
|
||||
final Table detailsTable = new Table();
|
||||
detailsTable.addStyleName("sp-table");
|
||||
|
||||
detailsTable.setImmediate(true);
|
||||
detailsTable.setSizeFull();
|
||||
|
||||
detailsTable.setId(UIComponentIdProvider.UPLOAD_ARTIFACT_DETAILS_TABLE);
|
||||
detailsTable.addStyleName(ValoTheme.TABLE_NO_VERTICAL_LINES);
|
||||
detailsTable.addStyleName(ValoTheme.TABLE_SMALL);
|
||||
return detailsTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* will be used by button click listener of action history expand icon.
|
||||
*/
|
||||
private void maxArtifactDetails() {
|
||||
final Boolean flag = (Boolean) maxMinButton.getData();
|
||||
if (flag == null || Boolean.FALSE.equals(flag)) {
|
||||
// Clicked on max Button
|
||||
maximizedArtifactDetailsView();
|
||||
} else {
|
||||
minimizedArtifactDetailsView();
|
||||
}
|
||||
}
|
||||
|
||||
private void minimizedArtifactDetailsView() {
|
||||
fullWindowMode = Boolean.FALSE;
|
||||
showMaxIcon();
|
||||
setTableColumnDetails(artifactDetailsTable);
|
||||
createArtifactDetailsMinView();
|
||||
|
||||
}
|
||||
|
||||
private void maximizedArtifactDetailsView() {
|
||||
fullWindowMode = Boolean.TRUE;
|
||||
showMinIcon();
|
||||
setTableColumnDetails(artifactDetailsTable);
|
||||
createArtifactDetailsMaxView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Max artifact details Table.
|
||||
*/
|
||||
public void createMaxArtifactDetailsTable() {
|
||||
maxArtifactDetailsTable = createArtifactDetailsTable();
|
||||
maxArtifactDetailsTable.setId(UIComponentIdProvider.UPLOAD_ARTIFACT_DETAILS_TABLE_MAX);
|
||||
maxArtifactDetailsTable.setContainerDataSource(artifactDetailsTable.getContainerDataSource());
|
||||
addGeneratedColumn(maxArtifactDetailsTable);
|
||||
if (!readOnly) {
|
||||
addGeneratedColumnButton(maxArtifactDetailsTable);
|
||||
}
|
||||
setTableColumnDetails(maxArtifactDetailsTable);
|
||||
}
|
||||
|
||||
private void createArtifactDetailsMaxView() {
|
||||
|
||||
artifactDetailsTable.setValue(null);
|
||||
artifactDetailsTable.setSelectable(false);
|
||||
artifactDetailsTable.setMultiSelect(false);
|
||||
artifactDetailsTable.setDragMode(TableDragMode.NONE);
|
||||
artifactDetailsTable.setColumnCollapsingAllowed(true);
|
||||
artifactUploadState.setArtifactDetailsMaximized(Boolean.TRUE);
|
||||
eventBus.publish(this, ArtifactDetailsEvent.MAXIMIZED);
|
||||
}
|
||||
|
||||
private void createArtifactDetailsMinView() {
|
||||
artifactUploadState.setArtifactDetailsMaximized(Boolean.FALSE);
|
||||
artifactDetailsTable.setColumnCollapsingAllowed(false);
|
||||
eventBus.publish(this, ArtifactDetailsEvent.MINIMIZED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate artifact details.
|
||||
*
|
||||
* @param softwareModule
|
||||
* software module
|
||||
*/
|
||||
public void populateArtifactDetails(final SoftwareModule softwareModule) {
|
||||
if (softwareModule == null) {
|
||||
populateArtifactDetails(null, null);
|
||||
} else {
|
||||
populateArtifactDetails(softwareModule.getId(),
|
||||
HawkbitCommonUtil.getFormattedNameVersion(softwareModule.getName(), softwareModule.getVersion()));
|
||||
}
|
||||
}
|
||||
|
||||
private void populateArtifactDetails(final Long baseSwModuleId, final String swModuleName) {
|
||||
if (!readOnly) {
|
||||
|
||||
if (StringUtils.hasText(swModuleName)) {
|
||||
prefixTitleOfArtifactDetails.setValue(i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_DETAILS_OF));
|
||||
titleOfArtifactDetails.setValue(swModuleName);
|
||||
} else {
|
||||
setTitleOfLayoutHeader();
|
||||
}
|
||||
|
||||
}
|
||||
final Map<String, Object> queryConfiguration;
|
||||
if (baseSwModuleId != null) {
|
||||
queryConfiguration = Maps.newHashMapWithExpectedSize(1);
|
||||
queryConfiguration.put(SPUIDefinitions.BY_BASE_SOFTWARE_MODULE, baseSwModuleId);
|
||||
} else {
|
||||
queryConfiguration = Collections.emptyMap();
|
||||
}
|
||||
final LazyQueryContainer artifactContainer = getArtifactLazyQueryContainer(queryConfiguration);
|
||||
artifactDetailsTable.setContainerDataSource(artifactContainer);
|
||||
if (fullWindowMode && maxArtifactDetailsTable != null) {
|
||||
maxArtifactDetailsTable.setContainerDataSource(artifactContainer);
|
||||
}
|
||||
setTableColumnDetails(artifactDetailsTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set title of artifact details header layout.
|
||||
*/
|
||||
private void setTitleOfLayoutHeader() {
|
||||
prefixTitleOfArtifactDetails.setValue(i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_DETAILS));
|
||||
titleOfArtifactDetails.setValue("");
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final SoftwareModuleEvent softwareModuleEvent) {
|
||||
if (softwareModuleEvent.getEventType() == BaseEntityEventType.SELECTED_ENTITY) {
|
||||
UI.getCurrent().access(() -> {
|
||||
if (softwareModuleEvent.getEntity() != null) {
|
||||
populateArtifactDetails(softwareModuleEvent.getEntity());
|
||||
} else {
|
||||
populateArtifactDetails(null, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (isArtifactChangedEvent(softwareModuleEvent) && areEntityIdsNotEmpty(softwareModuleEvent)) {
|
||||
UI.getCurrent().access(() -> findSelectedSoftwareModule().ifPresent(selectedSoftwareModule -> {
|
||||
if (hasSelectedSoftwareModuleChanged(softwareModuleEvent.getEntityIds(), selectedSoftwareModule)) {
|
||||
populateArtifactDetails(selectedSoftwareModule);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean areEntityIdsNotEmpty(final SoftwareModuleEvent softwareModuleEvent) {
|
||||
return softwareModuleEvent.getEntityIds() != null && !softwareModuleEvent.getEntityIds().isEmpty();
|
||||
}
|
||||
|
||||
private static boolean isArtifactChangedEvent(final SoftwareModuleEvent softwareModuleEvent) {
|
||||
return softwareModuleEvent.getSoftwareModuleEventType() == SoftwareModuleEventType.ARTIFACTS_CHANGED;
|
||||
}
|
||||
|
||||
private static boolean hasSelectedSoftwareModuleChanged(final Collection<Long> changedSoftwareModuleIds,
|
||||
final SoftwareModule selectedSoftwareModule) {
|
||||
return changedSoftwareModuleIds.stream().anyMatch(smId -> selectedSoftwareModule.getId().equals(smId));
|
||||
}
|
||||
|
||||
public Table getArtifactDetailsTable() {
|
||||
return artifactDetailsTable;
|
||||
}
|
||||
|
||||
public Table getMaxArtifactDetailsTable() {
|
||||
return maxArtifactDetailsTable;
|
||||
}
|
||||
|
||||
public void setFullWindowMode(final boolean fullWindowMode) {
|
||||
this.fullWindowMode = fullWindowMode;
|
||||
}
|
||||
|
||||
private void showMinIcon() {
|
||||
maxMinButton.toggleIcon(FontAwesome.COMPRESS);
|
||||
maxMinButton.setData(Boolean.TRUE);
|
||||
maxMinButton.setDescription(i18n.getMessage(UIMessageIdProvider.TOOLTIP_MINIMIZE));
|
||||
}
|
||||
|
||||
private void showMaxIcon() {
|
||||
maxMinButton.toggleIcon(FontAwesome.EXPAND);
|
||||
maxMinButton.setData(Boolean.FALSE);
|
||||
maxMinButton.setDescription(i18n.getMessage(UIMessageIdProvider.TOOLTIP_MAXIMIZE));
|
||||
}
|
||||
|
||||
private boolean isMaximized() {
|
||||
return artifactUploadState.isArtifactDetailsMaximized();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.event;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.table.BaseUIEvent;
|
||||
|
||||
/**
|
||||
* Software module filter event. Is thrown when there is a filter action on a
|
||||
* software module table on the Distribution or Upload View. It is possible to
|
||||
* filter by text or type.
|
||||
*/
|
||||
public class RefreshSoftwareModuleByFilterEvent extends BaseUIEvent {
|
||||
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.event;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType;
|
||||
import org.eclipse.hawkbit.ui.common.table.BaseUIEntityEvent;
|
||||
|
||||
/**
|
||||
* TenantAwareEvent to represent software add, update or delete.
|
||||
*
|
||||
*/
|
||||
public class SoftwareModuleEvent extends BaseUIEntityEvent<SoftwareModule> {
|
||||
|
||||
/**
|
||||
* Software module events in the Upload UI.
|
||||
*
|
||||
*/
|
||||
public enum SoftwareModuleEventType {
|
||||
ARTIFACTS_CHANGED, ASSIGN_SOFTWARE_MODULE
|
||||
}
|
||||
|
||||
private SoftwareModuleEventType softwareModuleEventType;
|
||||
|
||||
/**
|
||||
* Creates software module event.
|
||||
*
|
||||
* @param entityEventType
|
||||
* the event type
|
||||
*/
|
||||
public SoftwareModuleEvent(final BaseEntityEventType entityEventType) {
|
||||
super(entityEventType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates software module event.
|
||||
*
|
||||
* @param entityEventType
|
||||
* the event type
|
||||
* @param softwareModule
|
||||
* the module
|
||||
*/
|
||||
public SoftwareModuleEvent(final BaseEntityEventType entityEventType, final SoftwareModule softwareModule) {
|
||||
super(entityEventType, softwareModule);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param eventType
|
||||
* the event type
|
||||
* @param entityIds
|
||||
* the entity ids
|
||||
*/
|
||||
public SoftwareModuleEvent(final BaseEntityEventType eventType, final Collection<Long> entityIds) {
|
||||
super(eventType, entityIds, SoftwareModule.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates software module event.
|
||||
*
|
||||
* @param softwareModuleEventType
|
||||
* the event type
|
||||
* @param softwareModule
|
||||
* the module
|
||||
*/
|
||||
public SoftwareModuleEvent(final SoftwareModuleEventType softwareModuleEventType,
|
||||
final SoftwareModule softwareModule) {
|
||||
super(null, softwareModule);
|
||||
this.softwareModuleEventType = softwareModuleEventType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates software module event.
|
||||
*
|
||||
* @param softwareModuleEventType
|
||||
* the event type
|
||||
* @param softwareModuleId
|
||||
* the id of the {@link SoftwareModule}
|
||||
*/
|
||||
public SoftwareModuleEvent(final SoftwareModuleEventType softwareModuleEventType, final long softwareModuleId) {
|
||||
super(null, Arrays.asList(softwareModuleId), SoftwareModule.class);
|
||||
this.softwareModuleEventType = softwareModuleEventType;
|
||||
}
|
||||
|
||||
public SoftwareModuleEventType getSoftwareModuleEventType() {
|
||||
return softwareModuleEventType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.event;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
|
||||
/**
|
||||
* TenantAwareEvent to represent software module type add, update or delete.
|
||||
*/
|
||||
public class SoftwareModuleTypeEvent {
|
||||
|
||||
/**
|
||||
* Software module type events in the Upload UI.
|
||||
*/
|
||||
public enum SoftwareModuleTypeEnum {
|
||||
ADD_SOFTWARE_MODULE_TYPE, UPDATE_SOFTWARE_MODULE_TYPE
|
||||
}
|
||||
|
||||
private SoftwareModuleType softwareModuleType;
|
||||
|
||||
private final SoftwareModuleTypeEnum softwareModuleTypeEnum;
|
||||
|
||||
/**
|
||||
* @param softwareModuleTypeEnum
|
||||
* @param softwareModuleType
|
||||
*/
|
||||
public SoftwareModuleTypeEvent(final SoftwareModuleTypeEnum softwareModuleTypeEnum,
|
||||
final SoftwareModuleType softwareModuleType) {
|
||||
this.softwareModuleTypeEnum = softwareModuleTypeEnum;
|
||||
this.softwareModuleType = softwareModuleType;
|
||||
}
|
||||
|
||||
public SoftwareModuleTypeEnum getSoftwareModuleTypeEnum() {
|
||||
return softwareModuleTypeEnum;
|
||||
}
|
||||
|
||||
public SoftwareModuleType getSoftwareModuleType() {
|
||||
return softwareModuleType;
|
||||
}
|
||||
|
||||
public void setSoftwareModuleType(final SoftwareModuleType softwareModuleType) {
|
||||
this.softwareModuleType = softwareModuleType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.event;
|
||||
|
||||
/**
|
||||
* TenantAwareEvent generated in Upload artifact UI.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public enum UploadArtifactUIEvent {
|
||||
HIDE_DROP_HINTS, HIDE_FILTER_BY_TYPE, SHOW_FILTER_BY_TYPE, DISCARD_DELETE_SOFTWARE, DISCARD_ALL_DELETE_SOFTWARE, DELETED_ALL_SOFTWARE, DISCARD_DELETE_SOFTWARE_TYPE, DISCARD_ALL_DELETE_SOFTWARE_TYPE, DELETED_ALL_SOFTWARE_TYPE
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
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.AbstractEntityWindowController;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowLayout;
|
||||
import org.eclipse.hawkbit.ui.common.data.mappers.SoftwareModuleToProxyMapper;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.event.CommandTopics;
|
||||
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.SelectionChangedEventPayload;
|
||||
import org.eclipse.hawkbit.ui.common.event.SelectionChangedEventPayload.SelectionChangedEventType;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
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.UIEventBus;
|
||||
|
||||
/**
|
||||
* Controller for populating and saving data in Add Software Module Window.
|
||||
*/
|
||||
public class AddSmWindowController extends AbstractEntityWindowController<ProxySoftwareModule, ProxySoftwareModule> {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AddSmWindowController.class);
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
private final EntityFactory entityFactory;
|
||||
private final UIEventBus eventBus;
|
||||
private final UINotification uiNotification;
|
||||
|
||||
private final SoftwareModuleManagement smManagement;
|
||||
|
||||
private final SmWindowLayout layout;
|
||||
|
||||
private final EventView view;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param entityFactory
|
||||
* EntityFactory
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param uiNotification
|
||||
* UINotification
|
||||
* @param smManagement
|
||||
* SoftwareModuleManagement
|
||||
* @param layout
|
||||
* SoftwareModuleWindowLayout
|
||||
* @param view
|
||||
* EventView
|
||||
*/
|
||||
public AddSmWindowController(final VaadinMessageSource i18n, final EntityFactory entityFactory,
|
||||
final UIEventBus eventBus, final UINotification uiNotification, final SoftwareModuleManagement smManagement,
|
||||
final SmWindowLayout layout, final EventView view) {
|
||||
this.i18n = i18n;
|
||||
this.entityFactory = entityFactory;
|
||||
this.eventBus = eventBus;
|
||||
this.uiNotification = uiNotification;
|
||||
|
||||
this.smManagement = smManagement;
|
||||
|
||||
this.layout = layout;
|
||||
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return software module layout
|
||||
*/
|
||||
@Override
|
||||
public AbstractEntityWindowLayout<ProxySoftwareModule> getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@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 void persistEntity(final ProxySoftwareModule entity) {
|
||||
final SoftwareModuleCreate smCreate = entityFactory.softwareModule().create()
|
||||
.type(entity.getTypeInfo().getKey()).name(entity.getName()).version(entity.getVersion())
|
||||
.vendor(entity.getVendor()).description(entity.getDescription());
|
||||
|
||||
final SoftwareModule newSoftwareModule;
|
||||
try {
|
||||
newSoftwareModule = smManagement.create(smCreate);
|
||||
} catch (final ConstraintViolationException ex) {
|
||||
LOG.trace("Create of software module failed in UI: {}", ex.getMessage());
|
||||
uiNotification.displayValidationError(
|
||||
i18n.getMessage("message.save.fail", entity.getName() + ":" + entity.getVersion()));
|
||||
return;
|
||||
}
|
||||
|
||||
uiNotification.displaySuccess(i18n.getMessage("message.save.success",
|
||||
newSoftwareModule.getName() + ":" + newSoftwareModule.getVersion()));
|
||||
eventBus.publish(EventTopics.ENTITY_MODIFIED, this, new EntityModifiedEventPayload(
|
||||
EntityModifiedEventType.ENTITY_ADDED, ProxySoftwareModule.class, newSoftwareModule.getId()));
|
||||
|
||||
final ProxySoftwareModule addedItem = new SoftwareModuleToProxyMapper().map(newSoftwareModule);
|
||||
eventBus.publish(CommandTopics.SELECT_GRID_ENTITY, this, new SelectionChangedEventPayload<>(
|
||||
SelectionChangedEventType.ENTITY_SELECTED, addedItem, EventLayout.SM_LIST, view));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEntityValid(final ProxySoftwareModule entity) {
|
||||
if (!StringUtils.hasText(entity.getName()) || !StringUtils.hasText(entity.getVersion())
|
||||
|| entity.getTypeInfo() == null) {
|
||||
uiNotification.displayValidationError(i18n.getMessage("message.error.missing.nameorversionortype"));
|
||||
return false;
|
||||
}
|
||||
|
||||
final String trimmedName = StringUtils.trimWhitespace(entity.getName());
|
||||
final String trimmedVersion = StringUtils.trimWhitespace(entity.getVersion());
|
||||
final Long typeId = entity.getTypeInfo().getId();
|
||||
if (smManagement.getByNameAndVersionAndType(trimmedName, trimmedVersion, typeId).isPresent()) {
|
||||
uiNotification.displayValidationError(
|
||||
i18n.getMessage("message.duplicate.softwaremodule", trimmedName, trimmedVersion));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.OffsetBasedPageRequest;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.SpringContextHelper;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.vaadin.addons.lazyquerycontainer.AbstractBeanQuery;
|
||||
import org.vaadin.addons.lazyquerycontainer.QueryDefinition;
|
||||
|
||||
/**
|
||||
* Simple implementation of generics bean query which dynamically loads a batch
|
||||
* of beans.
|
||||
*
|
||||
*/
|
||||
public class BaseSwModuleBeanQuery extends AbstractBeanQuery<ProxyBaseSoftwareModuleItem> {
|
||||
private static final long serialVersionUID = 4362142538539335466L;
|
||||
private transient SoftwareModuleManagement softwareManagementService;
|
||||
private Long type;
|
||||
private String searchText;
|
||||
private final Sort sort = new Sort(Direction.ASC, "name", "version");
|
||||
|
||||
/**
|
||||
* Parametric Constructor.
|
||||
*
|
||||
* @param definition
|
||||
* as Def
|
||||
* @param queryConfig
|
||||
* as Config
|
||||
* @param sortIds
|
||||
* as sort
|
||||
* @param sortStates
|
||||
* as Sort status
|
||||
*/
|
||||
public BaseSwModuleBeanQuery(final QueryDefinition definition, final Map<String, Object> queryConfig,
|
||||
final Object[] sortIds, final boolean[] sortStates) {
|
||||
super(definition, queryConfig, sortIds, sortStates);
|
||||
if (HawkbitCommonUtil.isNotNullOrEmpty(queryConfig)) {
|
||||
type = Optional.ofNullable((SoftwareModuleType) queryConfig.get(SPUIDefinitions.BY_SOFTWARE_MODULE_TYPE))
|
||||
.map(SoftwareModuleType::getId).orElse(null);
|
||||
searchText = (String) queryConfig.get(SPUIDefinitions.FILTER_BY_TEXT);
|
||||
if (!StringUtils.isEmpty(searchText)) {
|
||||
searchText = String.format("%%%s%%", searchText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProxyBaseSoftwareModuleItem constructBean() {
|
||||
return new ProxyBaseSoftwareModuleItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ProxyBaseSoftwareModuleItem> loadBeans(final int startIndex, final int count) {
|
||||
final Slice<SoftwareModule> swModuleBeans;
|
||||
|
||||
if (type == null && StringUtils.isEmpty(searchText)) {
|
||||
swModuleBeans = getSoftwareManagementService().findAll(new OffsetBasedPageRequest(startIndex, count, sort));
|
||||
} else {
|
||||
swModuleBeans = getSoftwareManagementService()
|
||||
.findByTextAndType(new OffsetBasedPageRequest(startIndex, count, sort), searchText, type);
|
||||
}
|
||||
|
||||
return swModuleBeans.getContent().stream().map(this::getProxyBean).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private ProxyBaseSoftwareModuleItem getProxyBean(final SoftwareModule bean) {
|
||||
final ProxyBaseSoftwareModuleItem proxy = new ProxyBaseSoftwareModuleItem();
|
||||
proxy.setSwId(bean.getId());
|
||||
final String swNameVersion = HawkbitCommonUtil.concatStrings(":", bean.getName(), bean.getVersion());
|
||||
proxy.setNameAndVersion(swNameVersion);
|
||||
proxy.setCreatedDate(SPDateTimeUtil.getFormattedDate(bean.getCreatedAt()));
|
||||
proxy.setLastModifiedDate(SPDateTimeUtil.getFormattedDate(bean.getLastModifiedAt()));
|
||||
proxy.setName(bean.getName());
|
||||
proxy.setVersion(bean.getVersion());
|
||||
proxy.setVendor(bean.getVendor());
|
||||
proxy.setDescription(bean.getDescription());
|
||||
proxy.setCreatedByUser(UserDetailsFormatter.loadAndFormatCreatedBy(bean));
|
||||
proxy.setModifiedByUser(UserDetailsFormatter.loadAndFormatLastModifiedBy(bean));
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
long size;
|
||||
if (type == null && StringUtils.isEmpty(searchText)) {
|
||||
size = getSoftwareManagementService().count();
|
||||
} else {
|
||||
size = getSoftwareManagementService().countByTextAndType(searchText, type);
|
||||
}
|
||||
|
||||
if (size > Integer.MAX_VALUE) {
|
||||
size = Integer.MAX_VALUE;
|
||||
}
|
||||
return (int) size;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveBeans(final List<ProxyBaseSoftwareModuleItem> addedBeans,
|
||||
final List<ProxyBaseSoftwareModuleItem> modifiedBeans,
|
||||
final List<ProxyBaseSoftwareModuleItem> removedBeans) {
|
||||
// save of the entity not required from this method
|
||||
}
|
||||
|
||||
private SoftwareModuleManagement getSoftwareManagementService() {
|
||||
if (softwareManagementService == null) {
|
||||
softwareManagementService = SpringContextHelper.getBean(SoftwareModuleManagement.class);
|
||||
}
|
||||
return softwareManagementService;
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
*
|
||||
* Proxy for software module to display details in Software modules table.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class ProxyBaseSoftwareModuleItem {
|
||||
|
||||
private static final long serialVersionUID = -1555306616599140635L;
|
||||
|
||||
private static final SecureRandom RANDOM_OBJ = new SecureRandom();
|
||||
|
||||
private String nameAndVersion;
|
||||
|
||||
private Long swId;
|
||||
|
||||
private boolean assigned;
|
||||
|
||||
private String createdDate;
|
||||
|
||||
private String lastModifiedDate;
|
||||
|
||||
private String createdByUser;
|
||||
|
||||
private String modifiedByUser;
|
||||
|
||||
private String name;
|
||||
private String version;
|
||||
private String vendor;
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public ProxyBaseSoftwareModuleItem() {
|
||||
swId = RANDOM_OBJ.nextLong();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(final String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getVendor() {
|
||||
return vendor;
|
||||
}
|
||||
|
||||
public void setVendor(final String vendor) {
|
||||
this.vendor = vendor;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(final String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getCreatedByUser() {
|
||||
return createdByUser;
|
||||
}
|
||||
|
||||
public Long getSwId() {
|
||||
return swId;
|
||||
}
|
||||
|
||||
public void setCreatedByUser(final String createdByUser) {
|
||||
this.createdByUser = createdByUser;
|
||||
}
|
||||
|
||||
public void setSwId(final Long swId) {
|
||||
this.swId = swId;
|
||||
}
|
||||
|
||||
public String getModifiedByUser() {
|
||||
return modifiedByUser;
|
||||
}
|
||||
|
||||
public void setModifiedByUser(final String modifiedByUser) {
|
||||
this.modifiedByUser = modifiedByUser;
|
||||
}
|
||||
|
||||
public String getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
|
||||
public void setCreatedDate(final String createdDate) {
|
||||
this.createdDate = createdDate;
|
||||
}
|
||||
|
||||
public String getLastModifiedDate() {
|
||||
return lastModifiedDate;
|
||||
}
|
||||
|
||||
public void setLastModifiedDate(final String lastModifiedDate) {
|
||||
this.lastModifiedDate = lastModifiedDate;
|
||||
}
|
||||
|
||||
public String getNameAndVersion() {
|
||||
return nameAndVersion;
|
||||
}
|
||||
|
||||
public void setNameAndVersion(final String nameAndVersion) {
|
||||
this.nameAndVersion = nameAndVersion;
|
||||
}
|
||||
|
||||
public boolean isAssigned() {
|
||||
return assigned;
|
||||
}
|
||||
|
||||
public void setAssigned(final boolean assigned) {
|
||||
this.assigned = assigned;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.detailslayout.MetaDataAddUpdateWindowLayout;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
import com.vaadin.ui.CheckBox;
|
||||
import com.vaadin.ui.ComponentContainer;
|
||||
|
||||
/**
|
||||
* Class for sm metadata add/update window layout.
|
||||
*/
|
||||
public class SmMetaDataAddUpdateWindowLayout extends MetaDataAddUpdateWindowLayout {
|
||||
protected final CheckBox isVisibleForTarget;
|
||||
|
||||
/**
|
||||
* Constructor for AbstractTagWindowLayout
|
||||
*
|
||||
* @param i18n
|
||||
* I18N
|
||||
*/
|
||||
public SmMetaDataAddUpdateWindowLayout(final VaadinMessageSource i18n) {
|
||||
super(i18n);
|
||||
|
||||
this.isVisibleForTarget = metaDataComponentBuilder.createVisibleForTargetsField(binder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return form layout checkbox container for software module
|
||||
*/
|
||||
@Override
|
||||
public ComponentContainer getRootComponent() {
|
||||
final ComponentContainer formLayout = super.getRootComponent();
|
||||
|
||||
formLayout.addComponent(isVisibleForTarget);
|
||||
|
||||
return formLayout;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyMetaData;
|
||||
import org.eclipse.hawkbit.ui.common.detailslayout.AbstractMetaDataWindowBuilder;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.ui.Window;
|
||||
|
||||
/**
|
||||
* Builder for Software module meta data windows
|
||||
*/
|
||||
public class SmMetaDataWindowBuilder extends AbstractMetaDataWindowBuilder<Long> {
|
||||
private final EntityFactory entityFactory;
|
||||
private final UIEventBus eventBus;
|
||||
private final UINotification uiNotification;
|
||||
private final SpPermissionChecker permChecker;
|
||||
|
||||
private final SoftwareModuleManagement smManagement;
|
||||
|
||||
/**
|
||||
* Constructor for SmMetaDataWindowBuilder
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param entityFactory
|
||||
* EntityFactory
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param uiNotification
|
||||
* UINotification
|
||||
* @param permChecker
|
||||
* SpPermissionChecker
|
||||
* @param smManagement
|
||||
* SoftwareModuleManagement
|
||||
*/
|
||||
public SmMetaDataWindowBuilder(final VaadinMessageSource i18n, final EntityFactory entityFactory,
|
||||
final UIEventBus eventBus, final UINotification uiNotification, final SpPermissionChecker permChecker,
|
||||
final SoftwareModuleManagement smManagement) {
|
||||
super(i18n);
|
||||
|
||||
this.entityFactory = entityFactory;
|
||||
this.eventBus = eventBus;
|
||||
this.uiNotification = uiNotification;
|
||||
this.permChecker = permChecker;
|
||||
|
||||
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(i18n, eventBus, permChecker, uiNotification, entityFactory, smManagement),
|
||||
smId, name, proxyMetaData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.model.MetaData;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
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;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
/**
|
||||
* 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 transient EntityFactory entityFactory;
|
||||
|
||||
private final MetaDataWindowGrid<Long> smMetaDataWindowGrid;
|
||||
|
||||
private final transient SmMetaDataAddUpdateWindowLayout smMetaDataAddUpdateWindowLayout;
|
||||
private final transient AddMetaDataWindowController addSmMetaDataWindowController;
|
||||
private final transient UpdateMetaDataWindowController updateSmMetaDataWindowController;
|
||||
|
||||
/**
|
||||
* Constructor for AbstractTagWindowLayout
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param permChecker
|
||||
* SpPermissionChecker
|
||||
* @param uiNotification
|
||||
* UINotification
|
||||
* @param entityFactory
|
||||
* EntityFactory
|
||||
* @param smManagement
|
||||
* SoftwareModuleManagement
|
||||
*/
|
||||
public SmMetaDataWindowLayout(final VaadinMessageSource i18n, final UIEventBus eventBus,
|
||||
final SpPermissionChecker permChecker, final UINotification uiNotification,
|
||||
final EntityFactory entityFactory, final SoftwareModuleManagement smManagement) {
|
||||
super(i18n, eventBus, uiNotification, permChecker);
|
||||
|
||||
this.smManagement = smManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
|
||||
this.smMetaDataWindowGrid = new MetaDataWindowGrid<>(i18n, eventBus, permChecker, uiNotification,
|
||||
new SmMetaDataDataProvider(smManagement), this::deleteMetaData);
|
||||
|
||||
this.smMetaDataAddUpdateWindowLayout = new SmMetaDataAddUpdateWindowLayout(i18n);
|
||||
this.addSmMetaDataWindowController = new AddMetaDataWindowController(i18n, uiNotification,
|
||||
smMetaDataAddUpdateWindowLayout, this::createMetaData, this::isDuplicate);
|
||||
this.updateSmMetaDataWindowController = new UpdateMetaDataWindowController(i18n, uiNotification,
|
||||
smMetaDataAddUpdateWindowLayout, this::updateMetaData);
|
||||
|
||||
buildLayout();
|
||||
addGridSelectionListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getEntityType() {
|
||||
return i18n.getMessage("caption.software.module");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MetaData doCreateMetaData(final ProxyMetaData entity) {
|
||||
return smManagement.createMetaData(entityFactory.softwareModuleMetadata().create(masterEntityFilter)
|
||||
.key(entity.getKey()).value(entity.getValue()).targetVisible(entity.isVisibleForTargets()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MetaData doUpdateMetaData(final ProxyMetaData entity) {
|
||||
return smManagement
|
||||
.updateMetaData(entityFactory.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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
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.data.proxies.ProxySoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.event.EventView;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.ui.Window;
|
||||
|
||||
/**
|
||||
* Builder for Software module windows
|
||||
*/
|
||||
public class SmWindowBuilder extends AbstractEntityWindowBuilder<ProxySoftwareModule> {
|
||||
private final EntityFactory entityFactory;
|
||||
private final UIEventBus eventBus;
|
||||
private final UINotification uiNotification;
|
||||
|
||||
private final SoftwareModuleManagement smManagement;
|
||||
private final SoftwareModuleTypeManagement smTypeManagement;
|
||||
|
||||
private final EventView view;
|
||||
|
||||
/**
|
||||
* Constructor for SmWindowBuilder
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param entityFactory
|
||||
* EntityFactory
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param uiNotification
|
||||
* UINotification
|
||||
* @param smManagement
|
||||
* SoftwareModuleManagement
|
||||
* @param smTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
* @param view
|
||||
* EventView
|
||||
*/
|
||||
public SmWindowBuilder(final VaadinMessageSource i18n, final EntityFactory entityFactory, final UIEventBus eventBus,
|
||||
final UINotification uiNotification, final SoftwareModuleManagement smManagement,
|
||||
final SoftwareModuleTypeManagement smTypeManagement, final EventView view) {
|
||||
super(i18n);
|
||||
|
||||
this.entityFactory = entityFactory;
|
||||
this.eventBus = eventBus;
|
||||
this.uiNotification = uiNotification;
|
||||
|
||||
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(i18n, entityFactory, eventBus, uiNotification,
|
||||
smManagement, new SmWindowLayout(i18n, smTypeManagement), view));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param proxySm
|
||||
* ProxySoftwareModule
|
||||
*
|
||||
* @return update window for software module
|
||||
*/
|
||||
@Override
|
||||
public Window getWindowForUpdate(final ProxySoftwareModule proxySm) {
|
||||
return getWindowForEntity(proxySm, new UpdateSmWindowController(i18n, entityFactory, eventBus, uiNotification,
|
||||
smManagement, new SmWindowLayout(i18n, smTypeManagement)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
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.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;
|
||||
|
||||
/**
|
||||
* 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<SoftwareModuleType>());
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.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.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
import com.vaadin.data.Binder;
|
||||
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";
|
||||
|
||||
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).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).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();
|
||||
}
|
||||
}
|
||||
@@ -1,317 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleCreate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent;
|
||||
import org.eclipse.hawkbit.ui.common.CommonDialogWindow;
|
||||
import org.eclipse.hawkbit.ui.common.CommonDialogWindow.SaveDialogCloseListener;
|
||||
import org.eclipse.hawkbit.ui.common.SoftwareModuleTypeBeanQuery;
|
||||
import org.eclipse.hawkbit.ui.common.builder.LabelBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.builder.TextAreaBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.builder.TextFieldBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.builder.WindowBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.table.AbstractTable;
|
||||
import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions;
|
||||
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.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.vaadin.addons.lazyquerycontainer.BeanQueryFactory;
|
||||
import org.vaadin.spring.events.EventBus;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.vaadin.ui.ComboBox;
|
||||
import com.vaadin.ui.CustomComponent;
|
||||
import com.vaadin.ui.FormLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.TextArea;
|
||||
import com.vaadin.ui.TextField;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
/**
|
||||
* Generates window for Software module add or update.
|
||||
*/
|
||||
public class SoftwareModuleAddUpdateWindow extends CustomComponent {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SoftwareModuleAddUpdateWindow.class.getName());
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final VaadinMessageSource i18n;
|
||||
private final UINotification uiNotifcation;
|
||||
private final transient EventBus.UIEventBus eventBus;
|
||||
private final transient SoftwareModuleManagement softwareModuleManagement;
|
||||
private final transient SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
private final transient EntityFactory entityFactory;
|
||||
private final AbstractTable<SoftwareModule> softwareModuleTable;
|
||||
private TextField nameTextField;
|
||||
private TextField versionTextField;
|
||||
private TextField vendorTextField;
|
||||
private ComboBox typeComboBox;
|
||||
private TextArea descTextArea;
|
||||
private Boolean editSwModule = Boolean.FALSE;
|
||||
private Long baseSwModuleId;
|
||||
private FormLayout formLayout;
|
||||
private Label softwareModuleType;
|
||||
|
||||
/**
|
||||
* Constructor for SoftwareModuleAddUpdateWindow
|
||||
*
|
||||
* @param i18n
|
||||
* I18N
|
||||
* @param uiNotifcation
|
||||
* UINotification
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param softwareModuleManagement
|
||||
* management for {@link SoftwareModule}s
|
||||
* @param softwareModuleTypeManagement
|
||||
* management for {@link SoftwareModuleType}s
|
||||
* @param entityFactory
|
||||
* EntityFactory
|
||||
*/
|
||||
public SoftwareModuleAddUpdateWindow(final VaadinMessageSource i18n, final UINotification uiNotifcation,
|
||||
final UIEventBus eventBus, final SoftwareModuleManagement softwareModuleManagement,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement, final EntityFactory entityFactory,
|
||||
final AbstractTable<SoftwareModule> softwareModuleTable) {
|
||||
this.i18n = i18n;
|
||||
this.uiNotifcation = uiNotifcation;
|
||||
this.eventBus = eventBus;
|
||||
this.softwareModuleManagement = softwareModuleManagement;
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
this.softwareModuleTable = softwareModuleTable;
|
||||
|
||||
createRequiredComponents();
|
||||
}
|
||||
|
||||
private void createRequiredComponents() {
|
||||
|
||||
nameTextField = createTextField("textfield.name", UIComponentIdProvider.SOFT_MODULE_NAME,
|
||||
SoftwareModule.NAME_MAX_SIZE);
|
||||
|
||||
versionTextField = createTextField("textfield.version", UIComponentIdProvider.SOFT_MODULE_VERSION,
|
||||
SoftwareModule.VERSION_MAX_SIZE);
|
||||
|
||||
vendorTextField = new TextFieldBuilder(SoftwareModule.VENDOR_MAX_SIZE)
|
||||
.caption(i18n.getMessage("textfield.vendor")).id(UIComponentIdProvider.SOFT_MODULE_VENDOR)
|
||||
.buildTextComponent();
|
||||
|
||||
descTextArea = new TextAreaBuilder(SoftwareModule.DESCRIPTION_MAX_SIZE)
|
||||
.caption(i18n.getMessage("textfield.description")).style("text-area-style")
|
||||
.id(UIComponentIdProvider.ADD_SW_MODULE_DESCRIPTION).buildTextComponent();
|
||||
|
||||
typeComboBox = SPUIComponentProvider.getComboBox(
|
||||
i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_SOFTWARE_MODULE_TYPE), "", null, null, true, null,
|
||||
i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_SOFTWARE_MODULE_TYPE));
|
||||
typeComboBox.setId(UIComponentIdProvider.SW_MODULE_TYPE);
|
||||
typeComboBox.setStyleName(SPUIDefinitions.COMBO_BOX_SPECIFIC_STYLE + " " + ValoTheme.COMBOBOX_TINY);
|
||||
typeComboBox.setNewItemsAllowed(Boolean.FALSE);
|
||||
typeComboBox.setImmediate(Boolean.TRUE);
|
||||
}
|
||||
|
||||
private TextField createTextField(final String in18Key, final String id, final int maxLength) {
|
||||
return new TextFieldBuilder(maxLength).caption(i18n.getMessage(in18Key)).required(true, i18n).id(id)
|
||||
.buildTextComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates window for new software module.
|
||||
*
|
||||
* @return reference of {@link com.vaadin.ui.Window} to add new software
|
||||
* module.
|
||||
*/
|
||||
public CommonDialogWindow createAddSoftwareModuleWindow() {
|
||||
return createUpdateSoftwareModuleWindow(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates window for update software module.
|
||||
*
|
||||
* @param baseSwModuleId
|
||||
* id of the software module to edit.
|
||||
* @return reference of {@link com.vaadin.ui.Window} to update software
|
||||
* module.
|
||||
*/
|
||||
public CommonDialogWindow createUpdateSoftwareModuleWindow(final Long baseSwModuleId) {
|
||||
this.baseSwModuleId = baseSwModuleId;
|
||||
resetComponents();
|
||||
populateTypeNameCombo();
|
||||
populateValuesOfSwModule();
|
||||
return createWindow();
|
||||
}
|
||||
|
||||
private void resetComponents() {
|
||||
vendorTextField.clear();
|
||||
nameTextField.clear();
|
||||
versionTextField.clear();
|
||||
descTextArea.clear();
|
||||
if (!editSwModule) {
|
||||
typeComboBox.clear();
|
||||
}
|
||||
editSwModule = Boolean.FALSE;
|
||||
}
|
||||
|
||||
private void populateTypeNameCombo() {
|
||||
typeComboBox.setContainerDataSource(
|
||||
HawkbitCommonUtil.createLazyQueryContainer(new BeanQueryFactory<>(SoftwareModuleTypeBeanQuery.class)));
|
||||
typeComboBox.setItemCaptionPropertyId(SPUILabelDefinitions.VAR_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* fill the data of a softwareModule in the content of the window
|
||||
*/
|
||||
private void populateValuesOfSwModule() {
|
||||
if (baseSwModuleId == null) {
|
||||
return;
|
||||
}
|
||||
editSwModule = Boolean.TRUE;
|
||||
softwareModuleManagement.get(baseSwModuleId).ifPresent(swModule -> {
|
||||
nameTextField.setValue(swModule.getName());
|
||||
versionTextField.setValue(swModule.getVersion());
|
||||
vendorTextField.setValue(swModule.getVendor());
|
||||
descTextArea.setValue(swModule.getDescription());
|
||||
softwareModuleType = new LabelBuilder().name(swModule.getType().getName())
|
||||
.caption(i18n.getMessage(UIMessageIdProvider.CAPTION_ARTIFACT_SOFTWARE_MODULE_TYPE)).buildLabel();
|
||||
});
|
||||
}
|
||||
|
||||
private CommonDialogWindow createWindow() {
|
||||
final Label madatoryStarLabel = new Label("*");
|
||||
madatoryStarLabel.setStyleName("v-caption v-required-field-indicator");
|
||||
madatoryStarLabel.setWidth(null);
|
||||
addStyleName("lay-color");
|
||||
setSizeUndefined();
|
||||
|
||||
formLayout = new FormLayout();
|
||||
formLayout.setCaption(null);
|
||||
if (editSwModule) {
|
||||
formLayout.addComponent(softwareModuleType);
|
||||
} else {
|
||||
formLayout.addComponent(typeComboBox);
|
||||
typeComboBox.focus();
|
||||
}
|
||||
|
||||
formLayout.addComponent(nameTextField);
|
||||
formLayout.addComponent(versionTextField);
|
||||
formLayout.addComponent(vendorTextField);
|
||||
formLayout.addComponent(descTextArea);
|
||||
|
||||
setCompositionRoot(formLayout);
|
||||
|
||||
final CommonDialogWindow window = new WindowBuilder(SPUIDefinitions.CREATE_UPDATE_WINDOW)
|
||||
.caption(i18n.getMessage("caption.create.new", i18n.getMessage("caption.software.module")))
|
||||
.id(UIComponentIdProvider.SW_MODULE_CREATE_DIALOG).content(this).layout(formLayout).i18n(i18n)
|
||||
.saveDialogCloseListener(new SaveOnDialogCloseListener()).buildCommonDialogWindow();
|
||||
nameTextField.setEnabled(!editSwModule);
|
||||
versionTextField.setEnabled(!editSwModule);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
public FormLayout getFormLayout() {
|
||||
return formLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save or update the sw module.
|
||||
*/
|
||||
private final class SaveOnDialogCloseListener implements SaveDialogCloseListener {
|
||||
@Override
|
||||
public boolean canWindowSaveOrUpdate() {
|
||||
return editSwModule || !isDuplicate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveOrUpdate() {
|
||||
if (editSwModule) {
|
||||
updateSwModule();
|
||||
return;
|
||||
}
|
||||
addNewBaseSoftware();
|
||||
}
|
||||
|
||||
/**
|
||||
* updates a softwareModule
|
||||
*/
|
||||
private void updateSwModule() {
|
||||
final SoftwareModule newSWModule = softwareModuleManagement.update(entityFactory.softwareModule()
|
||||
.update(baseSwModuleId).description(descTextArea.getValue()).vendor(vendorTextField.getValue()));
|
||||
if (newSWModule != null) {
|
||||
uiNotifcation.displaySuccess(i18n.getMessage("message.save.success",
|
||||
newSWModule.getName() + ":" + newSWModule.getVersion()));
|
||||
|
||||
eventBus.publish(this, new SoftwareModuleEvent(BaseEntityEventType.UPDATED_ENTITY, newSWModule));
|
||||
}
|
||||
}
|
||||
|
||||
private void addNewBaseSoftware() {
|
||||
final String name = nameTextField.getValue();
|
||||
final String version = versionTextField.getValue();
|
||||
final String vendor = vendorTextField.getValue();
|
||||
final String description = descTextArea.getValue();
|
||||
final String type = typeComboBox.getValue() != null ? typeComboBox.getValue().toString() : null;
|
||||
|
||||
final SoftwareModuleType softwareModuleTypeByName = softwareModuleTypeManagement.getByName(type)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModuleType.class, type));
|
||||
final SoftwareModuleCreate softwareModule = entityFactory.softwareModule().create()
|
||||
.type(softwareModuleTypeByName).name(name).version(version).description(description).vendor(vendor);
|
||||
final SoftwareModule newSoftwareModule;
|
||||
try {
|
||||
newSoftwareModule = softwareModuleManagement.create(softwareModule);
|
||||
} catch (ConstraintViolationException ex) {
|
||||
String message = "This SoftwareModuleName is not valid! "
|
||||
+ "Please choose a SoftwareModuleName without the characters /, ?, #, blank, and quota chars"
|
||||
+ ex.getMessage();
|
||||
LOGGER.warn(message, ex);
|
||||
uiNotifcation.displayValidationError(i18n.getMessage("message.save.fail", name + ":" + version));
|
||||
return;
|
||||
}
|
||||
eventBus.publish(this, new SoftwareModuleEvent(BaseEntityEventType.ADD_ENTITY, newSoftwareModule));
|
||||
uiNotifcation.displaySuccess(i18n.getMessage("message.save.success",
|
||||
newSoftwareModule.getName() + ":" + newSoftwareModule.getVersion()));
|
||||
softwareModuleTable.setValue(Sets.newHashSet(newSoftwareModule.getId()));
|
||||
}
|
||||
|
||||
private boolean isDuplicate() {
|
||||
final String name = nameTextField.getValue();
|
||||
final String version = versionTextField.getValue();
|
||||
final String type = typeComboBox.getValue() != null ? typeComboBox.getValue().toString() : null;
|
||||
|
||||
final Optional<Long> moduleType = softwareModuleTypeManagement.getByName(type)
|
||||
.map(SoftwareModuleType::getId);
|
||||
if (moduleType.isPresent() && softwareModuleManagement
|
||||
.getByNameAndVersionAndType(name, version, moduleType.get()).isPresent()) {
|
||||
uiNotifcation
|
||||
.displayValidationError(i18n.getMessage("message.duplicate.softwaremodule", name, version));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.common.detailslayout.AbstractSoftwareModuleDetails;
|
||||
import org.eclipse.hawkbit.ui.distributions.smtable.SwMetadataPopupLayout;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
/**
|
||||
* Software module details.
|
||||
*/
|
||||
public class SoftwareModuleDetails extends AbstractSoftwareModuleDetails {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
|
||||
SoftwareModuleDetails(final VaadinMessageSource i18n, final UIEventBus eventBus,
|
||||
final SpPermissionChecker permissionChecker,
|
||||
final SoftwareModuleAddUpdateWindow softwareModuleAddUpdateWindow,
|
||||
final ArtifactUploadState artifactUploadState, final SoftwareModuleManagement softwareManagement,
|
||||
final SwMetadataPopupLayout swMetadataPopupLayout) {
|
||||
super(i18n, eventBus, permissionChecker, null, softwareManagement, swMetadataPopupLayout,
|
||||
softwareModuleAddUpdateWindow);
|
||||
this.artifactUploadState = artifactUploadState;
|
||||
restoreState();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onLoadIsTableMaximized() {
|
||||
return artifactUploadState.isSwModuleTableMaximized();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTabSheetId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSoftwareModuleSelected(final SoftwareModule softwareModule) {
|
||||
return compareSoftwareModulesById(softwareModule, artifactUploadState.getSelectedBaseSwModuleId().orElse(null));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress;
|
||||
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 org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
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 eventBus
|
||||
* UIEventBus
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param permissionChecker
|
||||
* SpPermissionChecker
|
||||
* @param notification
|
||||
* UINotification
|
||||
* @param smTypeFilterLayoutUiState
|
||||
* TypeFilterLayoutUiState
|
||||
* @param smGridLayoutUiState
|
||||
* GridLayoutUiState
|
||||
* @param softwareModuleManagement
|
||||
* SoftwareModuleManagement
|
||||
* @param view
|
||||
* EventView
|
||||
*/
|
||||
public SoftwareModuleGrid(final UIEventBus eventBus, final VaadinMessageSource i18n,
|
||||
final SpPermissionChecker permissionChecker, final UINotification notification,
|
||||
final TypeFilterLayoutUiState smTypeFilterLayoutUiState, final GridLayoutUiState smGridLayoutUiState,
|
||||
final SoftwareModuleManagement softwareModuleManagement, final EventView view) {
|
||||
super(i18n, eventBus, permissionChecker);
|
||||
|
||||
this.smTypeFilterLayoutUiState = smTypeFilterLayoutUiState;
|
||||
this.smGridLayoutUiState = smGridLayoutUiState;
|
||||
this.notification = notification;
|
||||
this.softwareModuleManagement = softwareModuleManagement;
|
||||
this.softwareModuleToProxyMapper = new SoftwareModuleToProxyMapper();
|
||||
|
||||
setSelectionSupport(new SelectionSupport<ProxySoftwareModule>(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,
|
||||
i18n.getMessage("caption.software.module"), ProxySoftwareModule::getNameAndVersion,
|
||||
this::deleteSoftwareModules, UIComponentIdProvider.SM_DELETE_CONFIRMATION_DIALOG);
|
||||
|
||||
setFilterSupport(new FilterSupport<>(
|
||||
new SoftwareModuleDataProvider(softwareModuleManagement,
|
||||
new AssignedSoftwareModuleToProxyMapper(softwareModuleToProxyMapper)),
|
||||
getSelectionSupport()::deselectAll));
|
||||
initFilterMappings();
|
||||
getFilterSupport().setFilter(new SwFilterParams());
|
||||
|
||||
this.numberOfArtifactUploadsForSm = new HashMap<>();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
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;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
/**
|
||||
* 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 i18n
|
||||
* VaadinMessageSource
|
||||
* @param permChecker
|
||||
* SpPermissionChecker
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param smTypeFilterLayoutUiState
|
||||
* HidableLayoutUiState
|
||||
* @param smGridLayoutUiState
|
||||
* GridLayoutUiState
|
||||
* @param smWindowBuilder
|
||||
* SmWindowBuilder
|
||||
* @param view
|
||||
* EventView
|
||||
*/
|
||||
public SoftwareModuleGridHeader(final VaadinMessageSource i18n, final SpPermissionChecker permChecker,
|
||||
final UIEventBus eventBus, final HidableLayoutUiState smTypeFilterLayoutUiState,
|
||||
final GridLayoutUiState smGridLayoutUiState, final SmWindowBuilder smWindowBuilder, final EventView view) {
|
||||
super(i18n, permChecker, eventBus, 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.artifacts.upload.FileUploadProgress;
|
||||
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.event.EventViewAware;
|
||||
import org.eclipse.hawkbit.ui.common.layout.AbstractGridComponentLayout;
|
||||
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.state.GridLayoutUiState;
|
||||
import org.eclipse.hawkbit.ui.common.state.TypeFilterLayoutUiState;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
/**
|
||||
* Software module table layout. (Upload Management)
|
||||
*/
|
||||
public class SoftwareModuleGridLayout extends AbstractGridComponentLayout {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final SoftwareModuleGridHeader softwareModuleGridHeader;
|
||||
private final SoftwareModuleGrid softwareModuleGrid;
|
||||
private final SoftwareModuleDetailsHeader softwareModuleDetailsHeader;
|
||||
private final SoftwareModuleDetails softwareModuleDetails;
|
||||
|
||||
private final transient FilterChangedListener<ProxySoftwareModule> smFilterListener;
|
||||
private final transient SelectionChangedListener<ProxySoftwareModule> masterSmChangedListener;
|
||||
private final transient SelectGridEntityListener<ProxySoftwareModule> selectSmListener;
|
||||
private final transient EntityModifiedListener<ProxySoftwareModule> smModifiedListener;
|
||||
private final transient GenericEventListener<FileUploadProgress> fileUploadChangedListener;
|
||||
|
||||
/**
|
||||
* Constructor for SoftwareModuleGridLayout
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param permChecker
|
||||
* SpPermissionChecker
|
||||
* @param uiNotification
|
||||
* UINotification
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param softwareModuleManagement
|
||||
* SoftwareModuleManagement
|
||||
* @param softwareModuleTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
* @param entityFactory
|
||||
* EntityFactory
|
||||
* @param smTypeFilterLayoutUiState
|
||||
* TypeFilterLayoutUiState
|
||||
* @param smGridLayoutUiState
|
||||
* GridLayoutUiState
|
||||
*/
|
||||
public SoftwareModuleGridLayout(final VaadinMessageSource i18n, final SpPermissionChecker permChecker,
|
||||
final UINotification uiNotification, final UIEventBus eventBus,
|
||||
final SoftwareModuleManagement softwareModuleManagement,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement, final EntityFactory entityFactory,
|
||||
final TypeFilterLayoutUiState smTypeFilterLayoutUiState, final GridLayoutUiState smGridLayoutUiState) {
|
||||
super();
|
||||
|
||||
final SmWindowBuilder smWindowBuilder = new SmWindowBuilder(i18n, entityFactory, eventBus, uiNotification,
|
||||
softwareModuleManagement, softwareModuleTypeManagement, EventView.UPLOAD);
|
||||
final SmMetaDataWindowBuilder smMetaDataWindowBuilder = new SmMetaDataWindowBuilder(i18n, entityFactory,
|
||||
eventBus, uiNotification, permChecker, softwareModuleManagement);
|
||||
|
||||
this.softwareModuleGridHeader = new SoftwareModuleGridHeader(i18n, permChecker, eventBus,
|
||||
smTypeFilterLayoutUiState, smGridLayoutUiState, smWindowBuilder, EventView.UPLOAD);
|
||||
this.softwareModuleGridHeader.buildHeader();
|
||||
this.softwareModuleGrid = new SoftwareModuleGrid(eventBus, i18n, permChecker, uiNotification,
|
||||
smTypeFilterLayoutUiState, smGridLayoutUiState, softwareModuleManagement, EventView.UPLOAD);
|
||||
this.softwareModuleGrid.init();
|
||||
|
||||
this.softwareModuleDetailsHeader = new SoftwareModuleDetailsHeader(i18n, permChecker, eventBus, uiNotification,
|
||||
smWindowBuilder, smMetaDataWindowBuilder);
|
||||
this.softwareModuleDetailsHeader.buildHeader();
|
||||
this.softwareModuleDetails = new SoftwareModuleDetails(i18n, eventBus, softwareModuleManagement,
|
||||
softwareModuleTypeManagement, smMetaDataWindowBuilder);
|
||||
this.softwareModuleDetails.buildDetails();
|
||||
|
||||
this.smFilterListener = new FilterChangedListener<>(eventBus, ProxySoftwareModule.class,
|
||||
new EventViewAware(EventView.UPLOAD), softwareModuleGrid.getFilterSupport());
|
||||
this.masterSmChangedListener = new SelectionChangedListener<>(eventBus,
|
||||
new EventLayoutViewAware(EventLayout.SM_LIST, EventView.UPLOAD), getMasterSmAwareComponents());
|
||||
this.selectSmListener = new SelectGridEntityListener<>(eventBus,
|
||||
new EventLayoutViewAware(EventLayout.SM_LIST, EventView.UPLOAD),
|
||||
softwareModuleGrid.getSelectionSupport());
|
||||
this.smModifiedListener = new EntityModifiedListener.Builder<>(eventBus, ProxySoftwareModule.class)
|
||||
.entityModifiedAwareSupports(getSmModifiedAwareSupports()).build();
|
||||
this.fileUploadChangedListener = new GenericEventListener<>(eventBus, 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show software module grid header
|
||||
*/
|
||||
public void showSmTypeHeaderIcon() {
|
||||
softwareModuleGridHeader.showFilterIcon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide software module grid header
|
||||
*/
|
||||
public void hideSmTypeHeaderIcon() {
|
||||
softwareModuleGridHeader.hideFilterIcon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximize the software module grid
|
||||
*/
|
||||
public void maximize() {
|
||||
softwareModuleGrid.createMaximizedContent();
|
||||
hideDetailsLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimize the software module grid
|
||||
*/
|
||||
public void minimize() {
|
||||
softwareModuleGrid.createMinimizedContent();
|
||||
showDetailsLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is called when view is shown to the user
|
||||
*/
|
||||
public void restoreState() {
|
||||
softwareModuleGridHeader.restoreState();
|
||||
softwareModuleGrid.restoreState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe all the events listeners
|
||||
*/
|
||||
public void unsubscribeListener() {
|
||||
smFilterListener.unsubscribe();
|
||||
masterSmChangedListener.unsubscribe();
|
||||
selectSmListener.unsubscribe();
|
||||
smModifiedListener.unsubscribe();
|
||||
fileUploadChangedListener.unsubscribe();
|
||||
}
|
||||
}
|
||||
@@ -1,255 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.RefreshSoftwareModuleByFilterEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.common.table.AbstractNamedVersionTable;
|
||||
import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType;
|
||||
import org.eclipse.hawkbit.ui.dd.criteria.UploadViewClientCriterion;
|
||||
import org.eclipse.hawkbit.ui.push.SoftwareModuleUpdatedEventContainer;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.TableColumn;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.eclipse.hawkbit.ui.view.filter.OnlyEventsFromUploadArtifactViewFilter;
|
||||
import org.vaadin.addons.lazyquerycontainer.BeanQueryFactory;
|
||||
import org.vaadin.addons.lazyquerycontainer.LazyQueryContainer;
|
||||
import org.vaadin.addons.lazyquerycontainer.LazyQueryDefinition;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
import org.vaadin.spring.events.EventScope;
|
||||
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.vaadin.data.Container;
|
||||
import com.vaadin.data.Item;
|
||||
import com.vaadin.event.dd.DragAndDropEvent;
|
||||
import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
|
||||
import com.vaadin.ui.UI;
|
||||
|
||||
/**
|
||||
* The Software module table.
|
||||
*/
|
||||
public class SoftwareModuleTable extends AbstractNamedVersionTable<SoftwareModule> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
|
||||
private final transient SoftwareModuleManagement softwareModuleManagement;
|
||||
|
||||
private final UploadViewClientCriterion uploadViewClientCriterion;
|
||||
|
||||
SoftwareModuleTable(final UIEventBus eventBus, final VaadinMessageSource i18n, final UINotification uiNotification,
|
||||
final ArtifactUploadState artifactUploadState, final SoftwareModuleManagement softwareManagement,
|
||||
final UploadViewClientCriterion uploadViewClientCriterion, final SpPermissionChecker permChecker) {
|
||||
super(eventBus, i18n, uiNotification, permChecker);
|
||||
this.artifactUploadState = artifactUploadState;
|
||||
this.softwareModuleManagement = softwareManagement;
|
||||
this.uploadViewClientCriterion = uploadViewClientCriterion;
|
||||
|
||||
addNewContainerDS();
|
||||
setColumnProperties();
|
||||
setDataAvailable(getContainerDataSource().size() != 0);
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI, filter = OnlyEventsFromUploadArtifactViewFilter.class)
|
||||
void onEvent(final RefreshSoftwareModuleByFilterEvent filterEvent) {
|
||||
UI.getCurrent().access(this::refreshFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTableId() {
|
||||
return UIComponentIdProvider.UPLOAD_SOFTWARE_MODULE_TABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Container createContainer() {
|
||||
final Map<String, Object> queryConfiguration = prepareQueryConfigFilters();
|
||||
|
||||
final BeanQueryFactory<BaseSwModuleBeanQuery> swQF = new BeanQueryFactory<>(BaseSwModuleBeanQuery.class);
|
||||
swQF.setQueryConfiguration(queryConfiguration);
|
||||
|
||||
return new LazyQueryContainer(
|
||||
new LazyQueryDefinition(true, SPUIDefinitions.PAGE_SIZE, SPUILabelDefinitions.VAR_SWM_ID), swQF);
|
||||
}
|
||||
|
||||
private Map<String, Object> prepareQueryConfigFilters() {
|
||||
final Map<String, Object> queryConfig = Maps.newHashMapWithExpectedSize(2);
|
||||
artifactUploadState.getSoftwareModuleFilters().getSearchText()
|
||||
.ifPresent(value -> queryConfig.put(SPUIDefinitions.FILTER_BY_TEXT, value));
|
||||
artifactUploadState.getSoftwareModuleFilters().getSoftwareModuleType()
|
||||
.ifPresent(type -> queryConfig.put(SPUIDefinitions.BY_SOFTWARE_MODULE_TYPE, type));
|
||||
return queryConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addContainerProperties(final Container container) {
|
||||
final LazyQueryContainer lqc = (LazyQueryContainer) container;
|
||||
lqc.addContainerProperty("nameAndVersion", String.class, null, false, false);
|
||||
lqc.addContainerProperty(SPUILabelDefinitions.VAR_ID, Long.class, null, false, false);
|
||||
lqc.addContainerProperty(SPUILabelDefinitions.VAR_DESC, String.class, "", false, true);
|
||||
lqc.addContainerProperty(SPUILabelDefinitions.VAR_VERSION, String.class, null, false, false);
|
||||
lqc.addContainerProperty(SPUILabelDefinitions.VAR_NAME, String.class, null, false, true);
|
||||
lqc.addContainerProperty(SPUILabelDefinitions.VAR_VENDOR, String.class, null, false, true);
|
||||
lqc.addContainerProperty(SPUILabelDefinitions.VAR_CREATED_BY, String.class, null, false, true);
|
||||
lqc.addContainerProperty(SPUILabelDefinitions.VAR_LAST_MODIFIED_BY, String.class, null, false, true);
|
||||
lqc.addContainerProperty(SPUILabelDefinitions.VAR_CREATED_DATE, String.class, null, false, true);
|
||||
lqc.addContainerProperty(SPUILabelDefinitions.VAR_LAST_MODIFIED_DATE, String.class, null, false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object getItemIdToSelect() {
|
||||
return artifactUploadState.getSelectedSoftwareModules().isEmpty() ? null
|
||||
: artifactUploadState.getSelectedSoftwareModules();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isMaximized() {
|
||||
return artifactUploadState.isSwModuleTableMaximized();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<SoftwareModule> findEntityByTableValue(final Long entityTableId) {
|
||||
return softwareModuleManagement.get(entityTableId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ArtifactUploadState getManagementEntityState() {
|
||||
return artifactUploadState;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void publishSelectedEntityEvent(final SoftwareModule lastSoftwareModule) {
|
||||
getEventBus().publish(this, new SoftwareModuleEvent(BaseEntityEventType.SELECTED_ENTITY, lastSoftwareModule));
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final SoftwareModuleEvent event) {
|
||||
onBaseEntityEvent(event);
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final UploadArtifactUIEvent event) {
|
||||
if (event == UploadArtifactUIEvent.DELETED_ALL_SOFTWARE) {
|
||||
UI.getCurrent().access(this::refreshFilter);
|
||||
}
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onSoftwareModuleUpdateEvents(final SoftwareModuleUpdatedEventContainer eventContainer) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final List<Long> visibleItemIds = (List<Long>) getVisibleItemIds();
|
||||
eventContainer.getEvents().stream().filter(event -> visibleItemIds.contains(event.getEntityId()))
|
||||
.filter(Objects::nonNull).forEach(event -> updateSoftwareModuleInTable(event.getEntity()));
|
||||
}
|
||||
|
||||
private void updateSoftwareModuleInTable(final SoftwareModule editedSm) {
|
||||
final Item item = getContainerDataSource().getItem(editedSm.getId());
|
||||
updateEntity(editedSm, item);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void updateEntity(final SoftwareModule baseEntity, final Item item) {
|
||||
final String swNameVersion = HawkbitCommonUtil.concatStrings(":", baseEntity.getName(),
|
||||
baseEntity.getVersion());
|
||||
item.getItemProperty(SPUILabelDefinitions.NAME_VERSION).setValue(swNameVersion);
|
||||
item.getItemProperty("swId").setValue(baseEntity.getId());
|
||||
item.getItemProperty(SPUILabelDefinitions.VAR_VENDOR).setValue(baseEntity.getVendor());
|
||||
super.updateEntity(baseEntity, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<TableColumn> getTableVisibleColumns() {
|
||||
final List<TableColumn> columnList = super.getTableVisibleColumns();
|
||||
if (isMaximized()) {
|
||||
columnList
|
||||
.add(new TableColumn(SPUILabelDefinitions.VAR_VENDOR, getI18n().getMessage("header.vendor"), 0.1F));
|
||||
}
|
||||
return columnList;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AcceptCriterion getDropAcceptCriterion() {
|
||||
return uploadViewClientCriterion;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isDropValid(final DragAndDropEvent dragEvent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setDataAvailable(final boolean available) {
|
||||
artifactUploadState.setNoDataAvilableSoftwareModule(!available);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleOkDelete(final List<Long> entitiesToDelete) {
|
||||
if (isUploadInProgressForSoftwareModule(entitiesToDelete)) {
|
||||
getNotification().displayValidationError(getI18n().getMessage("message.error.swModule.notDeleted"));
|
||||
return;
|
||||
}
|
||||
softwareModuleManagement.delete(entitiesToDelete);
|
||||
getEventBus().publish(this, new SoftwareModuleEvent(BaseEntityEventType.REMOVE_ENTITY, entitiesToDelete));
|
||||
getNotification().displaySuccess(getI18n().getMessage("message.delete.success",
|
||||
entitiesToDelete.size() + " " + getI18n().getMessage("caption.software.module") + "(s)"));
|
||||
|
||||
artifactUploadState.getSelectedSoftwareModules().clear();
|
||||
getEventBus().publish(this, UploadArtifactUIEvent.DELETED_ALL_SOFTWARE);
|
||||
}
|
||||
|
||||
private boolean isUploadInProgressForSoftwareModule(final List<Long> entitiesToDelete) {
|
||||
for (final Long id : entitiesToDelete) {
|
||||
if (artifactUploadState.isUploadInProgressForSelectedSoftwareModule(id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getEntityType() {
|
||||
return getI18n().getMessage("upload.swModuleTable.header");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<Long> getSelectedEntities() {
|
||||
return artifactUploadState.getSelectedSoftwareModules();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getEntityId(final Object itemId) {
|
||||
final String entityId = String.valueOf(
|
||||
getContainerDataSource().getItem(itemId).getItemProperty(SPUILabelDefinitions.VAR_SWM_ID).getValue());
|
||||
return "softwareModule." + entityId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDeletedEntityName(final Long entityId) {
|
||||
final Optional<SoftwareModule> softwareModule = softwareModuleManagement.get(entityId);
|
||||
return softwareModule.map(module -> module.getName() + ":" + module.getVersion()).orElse("");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.RefreshSoftwareModuleByFilterEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.common.table.AbstractSoftwareModuleTableHeader;
|
||||
import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
import org.vaadin.spring.events.EventScope;
|
||||
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
|
||||
|
||||
/**
|
||||
* Header of Software module table.
|
||||
*/
|
||||
public class SoftwareModuleTableHeader extends AbstractSoftwareModuleTableHeader {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
SoftwareModuleTableHeader(final VaadinMessageSource i18n, final SpPermissionChecker permChecker,
|
||||
final UIEventBus eventbus, final ArtifactUploadState artifactUploadState,
|
||||
final SoftwareModuleAddUpdateWindow softwareModuleAddUpdateWindow) {
|
||||
super(i18n, permChecker, eventbus, null, null, artifactUploadState, softwareModuleAddUpdateWindow);
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final UploadArtifactUIEvent event) {
|
||||
if (event == UploadArtifactUIEvent.HIDE_FILTER_BY_TYPE) {
|
||||
setFilterButtonsIconVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String onLoadSearchBoxValue() {
|
||||
return getArtifactUploadState().getSoftwareModuleFilters().getSearchText().orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void showFilterButtonsLayout() {
|
||||
getArtifactUploadState().setSwTypeFilterClosed(false);
|
||||
eventBus.publish(this, UploadArtifactUIEvent.SHOW_FILTER_BY_TYPE);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetSearchText() {
|
||||
if (getArtifactUploadState().getSoftwareModuleFilters().getSearchText().isPresent()) {
|
||||
getArtifactUploadState().getSoftwareModuleFilters().setSearchText(null);
|
||||
eventBus.publish(this, new RefreshSoftwareModuleByFilterEvent());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maximizeTable() {
|
||||
getArtifactUploadState().setSwModuleTableMaximized(Boolean.TRUE);
|
||||
eventBus.publish(this, new SoftwareModuleEvent(BaseEntityEventType.MAXIMIZED));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void minimizeTable() {
|
||||
getArtifactUploadState().setSwModuleTableMaximized(Boolean.FALSE);
|
||||
eventBus.publish(this, new SoftwareModuleEvent(BaseEntityEventType.MINIMIZED));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean onLoadIsTableMaximized() {
|
||||
return getArtifactUploadState().isSwModuleTableMaximized();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean onLoadIsShowFilterButtonDisplayed() {
|
||||
return getArtifactUploadState().isSwTypeFilterClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void searchBy(final String newSearchText) {
|
||||
getArtifactUploadState().getSoftwareModuleFilters().setSearchText(newSearchText);
|
||||
eventBus.publish(this, new RefreshSoftwareModuleByFilterEvent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isDropHintRequired() {
|
||||
/* No dropping on software module table header in Upload View */
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.common.table.AbstractTableLayout;
|
||||
import org.eclipse.hawkbit.ui.dd.criteria.UploadViewClientCriterion;
|
||||
import org.eclipse.hawkbit.ui.distributions.smtable.SwMetadataPopupLayout;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
/**
|
||||
* Software module table layout. (Upload Management)
|
||||
*/
|
||||
public class SoftwareModuleTableLayout extends AbstractTableLayout<SoftwareModuleTable> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final SoftwareModuleTable softwareModuleTable;
|
||||
|
||||
public SoftwareModuleTableLayout(final VaadinMessageSource i18n, final SpPermissionChecker permChecker,
|
||||
final ArtifactUploadState artifactUploadState, final UINotification uiNotification,
|
||||
final UIEventBus eventBus, final SoftwareModuleManagement softwareModuleManagement,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement, final EntityFactory entityFactory,
|
||||
final UploadViewClientCriterion uploadViewClientCriterion) {
|
||||
|
||||
final SwMetadataPopupLayout swMetadataPopupLayout = new SwMetadataPopupLayout(i18n, uiNotification, eventBus,
|
||||
softwareModuleManagement, entityFactory, permChecker);
|
||||
this.softwareModuleTable = new SoftwareModuleTable(eventBus, i18n, uiNotification, artifactUploadState,
|
||||
softwareModuleManagement, uploadViewClientCriterion, permChecker);
|
||||
|
||||
final SoftwareModuleAddUpdateWindow softwareModuleAddUpdateWindow = new SoftwareModuleAddUpdateWindow(i18n,
|
||||
uiNotification, eventBus, softwareModuleManagement, softwareModuleTypeManagement, entityFactory,
|
||||
softwareModuleTable);
|
||||
|
||||
super.init(i18n,
|
||||
new SoftwareModuleTableHeader(i18n, permChecker, eventBus, artifactUploadState,
|
||||
softwareModuleAddUpdateWindow),
|
||||
softwareModuleTable,
|
||||
new SoftwareModuleDetails(i18n, eventBus, permChecker, softwareModuleAddUpdateWindow,
|
||||
artifactUploadState, softwareModuleManagement, swMetadataPopupLayout));
|
||||
}
|
||||
|
||||
public SoftwareModuleTable getSoftwareModuleTable() {
|
||||
return softwareModuleTable;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowController;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowLayout;
|
||||
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.UINotification;
|
||||
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.UIEventBus;
|
||||
|
||||
/**
|
||||
* Controller for update software module window
|
||||
*/
|
||||
public class UpdateSmWindowController extends AbstractEntityWindowController<ProxySoftwareModule, ProxySoftwareModule> {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(UpdateSmWindowController.class);
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
private final EntityFactory entityFactory;
|
||||
private final UIEventBus eventBus;
|
||||
private final UINotification uiNotification;
|
||||
|
||||
private final SoftwareModuleManagement smManagement;
|
||||
|
||||
private final SmWindowLayout layout;
|
||||
|
||||
/**
|
||||
* Constructor for UpdateSmWindowController
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param entityFactory
|
||||
* EntityFactory
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param uiNotification
|
||||
* UINotification
|
||||
* @param smManagement
|
||||
* SoftwareModuleManagement
|
||||
* @param layout
|
||||
* SmWindowLayout
|
||||
*/
|
||||
public UpdateSmWindowController(final VaadinMessageSource i18n, final EntityFactory entityFactory,
|
||||
final UIEventBus eventBus, final UINotification uiNotification, final SoftwareModuleManagement smManagement,
|
||||
final SmWindowLayout layout) {
|
||||
this.i18n = i18n;
|
||||
this.entityFactory = entityFactory;
|
||||
this.eventBus = eventBus;
|
||||
this.uiNotification = uiNotification;
|
||||
|
||||
this.smManagement = smManagement;
|
||||
|
||||
this.layout = layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Software module layout
|
||||
*/
|
||||
@Override
|
||||
public AbstractEntityWindowLayout<ProxySoftwareModule> getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@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());
|
||||
|
||||
return sm;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void adaptLayout(final ProxySoftwareModule proxyEntity) {
|
||||
layout.disableSmTypeSelect();
|
||||
layout.disableNameField();
|
||||
layout.disableVersionField();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void persistEntity(final ProxySoftwareModule entity) {
|
||||
final SoftwareModuleUpdate smUpdate = entityFactory.softwareModule().update(entity.getId())
|
||||
.vendor(entity.getVendor()).description(entity.getDescription());
|
||||
|
||||
try {
|
||||
final SoftwareModule updatedSm = smManagement.update(smUpdate);
|
||||
|
||||
uiNotification.displaySuccess(
|
||||
i18n.getMessage("message.update.success", updatedSm.getName() + ":" + updatedSm.getVersion()));
|
||||
eventBus.publish(EventTopics.ENTITY_MODIFIED, this, new EntityModifiedEventPayload(
|
||||
EntityModifiedEventType.ENTITY_UPDATED, ProxySoftwareModule.class, updatedSm.getId()));
|
||||
} catch (final EntityNotFoundException | EntityReadOnlyException e) {
|
||||
LOG.trace("Update of software module failed in UI: {}", e.getMessage());
|
||||
final String entityType = i18n.getMessage("caption.software.module");
|
||||
uiNotification
|
||||
.displayWarning(i18n.getMessage("message.deleted.or.notAllowed", entityType, entity.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEntityValid(final ProxySoftwareModule entity) {
|
||||
if (!StringUtils.hasText(entity.getName()) || !StringUtils.hasText(entity.getVersion())
|
||||
|| entity.getTypeInfo() == null) {
|
||||
uiNotification.displayValidationError(i18n.getMessage("message.error.missing.nameorversionortype"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.common.builder.LabelBuilder;
|
||||
import org.eclipse.hawkbit.ui.layouts.AbstractTypeLayout;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.OptionGroup;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
/**
|
||||
* General Layout for the software module types pop-up window which is provided
|
||||
* on the Distribution and Upload view when creating, updating or deleting a
|
||||
* software module type
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractSoftwareModuleTypeLayout extends AbstractTypeLayout<SoftwareModuleType> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final transient SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
|
||||
private String singleAssignStr;
|
||||
|
||||
private String multiAssignStr;
|
||||
|
||||
private Label singleAssign;
|
||||
|
||||
private Label multiAssign;
|
||||
|
||||
private OptionGroup assignOptiongroup;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param entityFactory
|
||||
* EntityFactory
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param permChecker
|
||||
* SpPermissionChecker
|
||||
* @param uiNotification
|
||||
* UINotification
|
||||
* @param softwareModuleTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
*/
|
||||
public AbstractSoftwareModuleTypeLayout(final VaadinMessageSource i18n, final EntityFactory entityFactory,
|
||||
final UIEventBus eventBus, final SpPermissionChecker permChecker, final UINotification uiNotification,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement) {
|
||||
super(i18n, entityFactory, eventBus, permChecker, uiNotification);
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getTagNameSize() {
|
||||
return SoftwareModuleType.NAME_MAX_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getTagDescSize() {
|
||||
return SoftwareModuleType.DESCRIPTION_MAX_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getTypeKeySize() {
|
||||
return SoftwareModuleType.KEY_MAX_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTagNameId() {
|
||||
return UIComponentIdProvider.NEW_SOFTWARE_TYPE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTagDescId() {
|
||||
return UIComponentIdProvider.NEW_SOFTWARE_TYPE_DESC;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTypeKeyId() {
|
||||
return UIComponentIdProvider.NEW_SOFTWARE_TYPE_KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createRequiredComponents() {
|
||||
super.createRequiredComponents();
|
||||
singleAssignStr = getI18n().getMessage("label.singleAssign.type");
|
||||
multiAssignStr = getI18n().getMessage("label.multiAssign.type");
|
||||
singleAssign = new LabelBuilder().name(singleAssignStr).buildLabel();
|
||||
multiAssign = new LabelBuilder().name(multiAssignStr).buildLabel();
|
||||
singleMultiOptionGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildLayout() {
|
||||
super.buildLayout();
|
||||
getFormLayout().addComponent(assignOptiongroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<SoftwareModuleType> findEntityByKey() {
|
||||
return softwareModuleTypeManagement.getByKey(getTypeKey().getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<SoftwareModuleType> findEntityByName() {
|
||||
return softwareModuleTypeManagement.getByName(getTagName().getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDuplicateKeyErrorMessage(final SoftwareModuleType existingType) {
|
||||
return getI18n().getMessage("message.type.key.swmodule.duplicate.check", existingType.getKey());
|
||||
}
|
||||
|
||||
public SoftwareModuleTypeManagement getSoftwareModuleTypeManagement() {
|
||||
return softwareModuleTypeManagement;
|
||||
}
|
||||
|
||||
public String getSingleAssignStr() {
|
||||
return singleAssignStr;
|
||||
}
|
||||
|
||||
public void setSingleAssignStr(final String singleAssignStr) {
|
||||
this.singleAssignStr = singleAssignStr;
|
||||
}
|
||||
|
||||
public String getMultiAssignStr() {
|
||||
return multiAssignStr;
|
||||
}
|
||||
|
||||
public void setMultiAssignStr(final String multiAssignStr) {
|
||||
this.multiAssignStr = multiAssignStr;
|
||||
}
|
||||
|
||||
public Label getSingleAssign() {
|
||||
return singleAssign;
|
||||
}
|
||||
|
||||
public void setSingleAssign(final Label singleAssign) {
|
||||
this.singleAssign = singleAssign;
|
||||
}
|
||||
|
||||
public Label getMultiAssign() {
|
||||
return multiAssign;
|
||||
}
|
||||
|
||||
public void setMultiAssign(final Label multiAssign) {
|
||||
this.multiAssign = multiAssign;
|
||||
}
|
||||
|
||||
public OptionGroup getAssignOptiongroup() {
|
||||
return assignOptiongroup;
|
||||
}
|
||||
|
||||
public void setAssignOptiongroup(final OptionGroup assignOptiongroup) {
|
||||
this.assignOptiongroup = assignOptiongroup;
|
||||
}
|
||||
|
||||
private void singleMultiOptionGroup() {
|
||||
final List<String> optionValues = new ArrayList<>();
|
||||
optionValues.add(singleAssign.getValue());
|
||||
optionValues.add(multiAssign.getValue());
|
||||
assignOptionGroupByValues(optionValues);
|
||||
}
|
||||
|
||||
private void assignOptionGroupByValues(final List<String> tagOptions) {
|
||||
assignOptiongroup = new OptionGroup("", tagOptions);
|
||||
assignOptiongroup.setStyleName(ValoTheme.OPTIONGROUP_SMALL);
|
||||
assignOptiongroup.addStyleName("custom-option-group");
|
||||
assignOptiongroup.setNullSelectionAllowed(false);
|
||||
assignOptiongroup.setId(UIComponentIdProvider.ASSIGN_OPTION_GROUP_SOFTWARE_MODULE_TYPE_ID);
|
||||
assignOptiongroup.select(tagOptions.get(0));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowController;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowLayout;
|
||||
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.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.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
/**
|
||||
* Controller for Add software module type window
|
||||
*/
|
||||
public class AddSmTypeWindowController extends AbstractEntityWindowController<ProxyType, ProxyType> {
|
||||
private final VaadinMessageSource i18n;
|
||||
private final EntityFactory entityFactory;
|
||||
private final UIEventBus eventBus;
|
||||
private final UINotification uiNotification;
|
||||
|
||||
private final SoftwareModuleTypeManagement smTypeManagement;
|
||||
|
||||
private final SmTypeWindowLayout layout;
|
||||
|
||||
/**
|
||||
* Constructor for AddSmTypeWindowController
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param entityFactory
|
||||
* EntityFactory
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param uiNotification
|
||||
* UINotification
|
||||
* @param smTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
* @param layout
|
||||
* SmTypeWindowLayout
|
||||
*/
|
||||
public AddSmTypeWindowController(final VaadinMessageSource i18n, final EntityFactory entityFactory,
|
||||
final UIEventBus eventBus, final UINotification uiNotification,
|
||||
final SoftwareModuleTypeManagement smTypeManagement, final SmTypeWindowLayout layout) {
|
||||
this.i18n = i18n;
|
||||
this.entityFactory = entityFactory;
|
||||
this.eventBus = eventBus;
|
||||
this.uiNotification = uiNotification;
|
||||
|
||||
this.smTypeManagement = smTypeManagement;
|
||||
|
||||
this.layout = layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for Software module type Window Layout
|
||||
*
|
||||
* @return AbstractEntityWindowLayout
|
||||
*/
|
||||
@Override
|
||||
public AbstractEntityWindowLayout<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 void persistEntity(final ProxyType entity) {
|
||||
final int assignNumber = entity.getSmTypeAssign() == SmTypeAssign.SINGLE ? 1 : Integer.MAX_VALUE;
|
||||
|
||||
final SoftwareModuleType newSmType = smTypeManagement
|
||||
.create(entityFactory.softwareModuleType().create().key(entity.getKey()).name(entity.getName())
|
||||
.description(entity.getDescription()).colour(entity.getColour()).maxAssignments(assignNumber));
|
||||
|
||||
uiNotification.displaySuccess(i18n.getMessage("message.save.success", newSmType.getName()));
|
||||
eventBus.publish(EventTopics.ENTITY_MODIFIED, this, new EntityModifiedEventPayload(
|
||||
EntityModifiedEventType.ENTITY_ADDED, ProxySoftwareModule.class, ProxyType.class, newSmType.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEntityValid(final ProxyType entity) {
|
||||
if (!StringUtils.hasText(entity.getName()) || !StringUtils.hasText(entity.getKey())
|
||||
|| entity.getSmTypeAssign() == null) {
|
||||
uiNotification.displayValidationError(i18n.getMessage("message.error.missing.typenameorkeyorsmtype"));
|
||||
return false;
|
||||
}
|
||||
|
||||
final String trimmedName = StringUtils.trimWhitespace(entity.getName());
|
||||
final String trimmedKey = StringUtils.trimWhitespace(entity.getKey());
|
||||
if (smTypeManagement.getByName(trimmedName).isPresent()) {
|
||||
uiNotification.displayValidationError(i18n.getMessage("message.type.duplicate.check", trimmedName));
|
||||
return false;
|
||||
}
|
||||
if (smTypeManagement.getByKey(trimmedKey).isPresent()) {
|
||||
uiNotification
|
||||
.displayValidationError(i18n.getMessage("message.type.key.swmodule.duplicate.check", trimmedKey));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleTypeEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleTypeEvent.SoftwareModuleTypeEnum;
|
||||
import org.eclipse.hawkbit.ui.colorpicker.ColorPickerHelper;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
/**
|
||||
* Layout for the pop-up window which is created when creating a software module
|
||||
* type on the Upload or Distribution View.
|
||||
*/
|
||||
public class CreateSoftwareModuleTypeLayout extends AbstractSoftwareModuleTypeLayout {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructor for CreateUpdateSoftwareTypeLayout
|
||||
*
|
||||
* @param i18n
|
||||
* I18N
|
||||
* @param entityFactory
|
||||
* EntityFactory
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param permChecker
|
||||
* SpPermissionChecker
|
||||
* @param uiNotification
|
||||
* UINotification
|
||||
* @param softwareModuleTypeManagement
|
||||
* management for {@link SoftwareModuleType}s
|
||||
*/
|
||||
public CreateSoftwareModuleTypeLayout(final VaadinMessageSource i18n, final EntityFactory entityFactory,
|
||||
final UIEventBus eventBus, final SpPermissionChecker permChecker, final UINotification uiNotification,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement) {
|
||||
super(i18n, entityFactory, eventBus, permChecker, uiNotification, softwareModuleTypeManagement);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getWindowCaption() {
|
||||
return getI18n().getMessage("caption.create.new", getI18n().getMessage("caption.type"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveEntity() {
|
||||
createNewSWModuleType();
|
||||
}
|
||||
|
||||
private void createNewSWModuleType() {
|
||||
int assignNumber = 0;
|
||||
final String colorPicked = ColorPickerHelper.getColorPickedString(getColorPickerLayout().getSelPreview());
|
||||
final String typeNameValue = getTagName().getValue();
|
||||
final String typeKeyValue = getTypeKey().getValue();
|
||||
final String typeDescValue = getTagDesc().getValue();
|
||||
final String assignValue = (String) getAssignOptiongroup().getValue();
|
||||
if (assignValue != null && assignValue.equalsIgnoreCase(getSingleAssignStr())) {
|
||||
assignNumber = 1;
|
||||
} else if (assignValue != null && assignValue.equalsIgnoreCase(getMultiAssignStr())) {
|
||||
assignNumber = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
if (typeNameValue != null && typeKeyValue != null) {
|
||||
final SoftwareModuleType newSWType = getSoftwareModuleTypeManagement()
|
||||
.create(getEntityFactory().softwareModuleType().create().key(typeKeyValue).name(typeNameValue)
|
||||
.description(typeDescValue).colour(colorPicked).maxAssignments(assignNumber));
|
||||
getUiNotification().displaySuccess(getI18n().getMessage("message.save.success", newSWType.getName()));
|
||||
getEventBus().publish(this,
|
||||
new SoftwareModuleTypeEvent(SoftwareModuleTypeEnum.ADD_SOFTWARE_MODULE_TYPE, newSWType));
|
||||
} else {
|
||||
getUiNotification().displayValidationError(getI18n().getMessage("message.error.missing.typenameorkey"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isUpdateAction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.ui.Window;
|
||||
|
||||
/**
|
||||
* Builder for software module type window
|
||||
*/
|
||||
public class SmTypeWindowBuilder extends AbstractEntityWindowBuilder<ProxyType> {
|
||||
private final EntityFactory entityFactory;
|
||||
private final UIEventBus eventBus;
|
||||
private final UINotification uiNotification;
|
||||
|
||||
private final SoftwareModuleTypeManagement smTypeManagement;
|
||||
|
||||
/**
|
||||
* Constructor for SmTypeWindowBuilder
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param entityFactory
|
||||
* EntityFactory
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param uiNotification
|
||||
* UINotification
|
||||
* @param smTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
*/
|
||||
public SmTypeWindowBuilder(final VaadinMessageSource i18n, final EntityFactory entityFactory,
|
||||
final UIEventBus eventBus, final UINotification uiNotification,
|
||||
final SoftwareModuleTypeManagement smTypeManagement) {
|
||||
super(i18n);
|
||||
|
||||
this.entityFactory = entityFactory;
|
||||
this.eventBus = eventBus;
|
||||
this.uiNotification = uiNotification;
|
||||
|
||||
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(i18n, entityFactory, eventBus, uiNotification,
|
||||
smTypeManagement, new SmTypeWindowLayout(i18n, uiNotification)));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(i18n, entityFactory, eventBus,
|
||||
uiNotification, smTypeManagement, new SmTypeWindowLayout(i18n, uiNotification)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype;
|
||||
|
||||
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 org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
|
||||
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 i18n
|
||||
* VaadinMessageSource
|
||||
* @param uiNotification
|
||||
* UINotification
|
||||
*/
|
||||
public SmTypeWindowLayout(final VaadinMessageSource i18n, final UINotification uiNotification) {
|
||||
super(i18n, uiNotification);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowController;
|
||||
import org.eclipse.hawkbit.ui.common.AbstractEntityWindowLayout;
|
||||
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.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.UINotification;
|
||||
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.UIEventBus;
|
||||
|
||||
/**
|
||||
* Controller for update software module type window
|
||||
*/
|
||||
public class UpdateSmTypeWindowController extends AbstractEntityWindowController<ProxyType, ProxyType> {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(UpdateSmTypeWindowController.class);
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
private final EntityFactory entityFactory;
|
||||
private final UIEventBus eventBus;
|
||||
private final UINotification uiNotification;
|
||||
|
||||
private final SoftwareModuleTypeManagement smTypeManagement;
|
||||
|
||||
private final SmTypeWindowLayout layout;
|
||||
|
||||
private String nameBeforeEdit;
|
||||
private String keyBeforeEdit;
|
||||
|
||||
/**
|
||||
* Constructor for UpdateSmTypeWindowController
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param entityFactory
|
||||
* EntityFactory
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param uiNotification
|
||||
* UINotification
|
||||
* @param smTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
* @param layout
|
||||
* SmTypeWindowLayout
|
||||
*/
|
||||
public UpdateSmTypeWindowController(final VaadinMessageSource i18n, final EntityFactory entityFactory,
|
||||
final UIEventBus eventBus, final UINotification uiNotification,
|
||||
final SoftwareModuleTypeManagement smTypeManagement, final SmTypeWindowLayout layout) {
|
||||
this.i18n = i18n;
|
||||
this.entityFactory = entityFactory;
|
||||
this.eventBus = eventBus;
|
||||
this.uiNotification = uiNotification;
|
||||
|
||||
this.smTypeManagement = smTypeManagement;
|
||||
|
||||
this.layout = layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for Software module type Window Layout
|
||||
*
|
||||
* @return AbstractEntityWindowLayout
|
||||
*/
|
||||
@Override
|
||||
public AbstractEntityWindowLayout<ProxyType> getLayout() {
|
||||
return layout;
|
||||
}
|
||||
|
||||
@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
|
||||
protected void adaptLayout(final ProxyType proxyEntity) {
|
||||
layout.disableTagName();
|
||||
layout.disableTypeKey();
|
||||
layout.disableTypeAssignOptionGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void persistEntity(final ProxyType entity) {
|
||||
final SoftwareModuleTypeUpdate smTypeUpdate = entityFactory.softwareModuleType().update(entity.getId())
|
||||
.description(entity.getDescription()).colour(entity.getColour());
|
||||
|
||||
try {
|
||||
final SoftwareModuleType updatedSmType = smTypeManagement.update(smTypeUpdate);
|
||||
|
||||
uiNotification.displaySuccess(i18n.getMessage("message.update.success", updatedSmType.getName()));
|
||||
eventBus.publish(EventTopics.ENTITY_MODIFIED, this,
|
||||
new EntityModifiedEventPayload(EntityModifiedEventType.ENTITY_UPDATED, ProxySoftwareModule.class,
|
||||
ProxyType.class, updatedSmType.getId()));
|
||||
} catch (final EntityNotFoundException | EntityReadOnlyException e) {
|
||||
LOG.trace("Update of software module type failed in UI: {}", e.getMessage());
|
||||
|
||||
final String entityType = i18n.getMessage("caption.entity.software.module.type");
|
||||
uiNotification
|
||||
.displayWarning(i18n.getMessage("message.deleted.or.notAllowed", entityType, entity.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEntityValid(final ProxyType entity) {
|
||||
if (!StringUtils.hasText(entity.getName()) || !StringUtils.hasText(entity.getKey())
|
||||
|| entity.getSmTypeAssign() == null) {
|
||||
uiNotification.displayValidationError(i18n.getMessage("message.error.missing.typenameorkeyorsmtype"));
|
||||
return false;
|
||||
}
|
||||
|
||||
final String trimmedName = StringUtils.trimWhitespace(entity.getName());
|
||||
final String trimmedKey = StringUtils.trimWhitespace(entity.getKey());
|
||||
if (!nameBeforeEdit.equals(trimmedName) && smTypeManagement.getByName(trimmedName).isPresent()) {
|
||||
uiNotification.displayValidationError(i18n.getMessage("message.type.duplicate.check", trimmedName));
|
||||
return false;
|
||||
}
|
||||
if (!keyBeforeEdit.equals(trimmedKey) && smTypeManagement.getByKey(trimmedKey).isPresent()) {
|
||||
uiNotification
|
||||
.displayValidationError(i18n.getMessage("message.type.key.swmodule.duplicate.check", trimmedKey));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleTypeEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleTypeEvent.SoftwareModuleTypeEnum;
|
||||
import org.eclipse.hawkbit.ui.colorpicker.ColorPickerHelper;
|
||||
import org.eclipse.hawkbit.ui.layouts.UpdateTag;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.ui.Window.CloseListener;
|
||||
|
||||
/**
|
||||
* Layout for the pop-up window which is created when updating a Software Module
|
||||
* Type on the Upload View.
|
||||
*
|
||||
*/
|
||||
public class UpdateSoftwareModuleTypeLayout extends AbstractSoftwareModuleTypeLayout implements UpdateTag {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String selectedTypeName;
|
||||
|
||||
private final CloseListener closeListener;
|
||||
|
||||
/**
|
||||
* Constructor for initializing the pop-up window for updating a software
|
||||
* module type. The form fields are filled with the current data of the
|
||||
* selected software module type.
|
||||
*
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param entityFactory
|
||||
* EntityFactory
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param permChecker
|
||||
* SpPermissionChecker
|
||||
* @param uiNotification
|
||||
* UINotification
|
||||
* @param softwareModuleTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
* @param selectedTypeName
|
||||
* The name of the selected software module type to update
|
||||
* @param closeListener
|
||||
* CloseListener which describes the action to do when closing
|
||||
* the window
|
||||
*/
|
||||
public UpdateSoftwareModuleTypeLayout(final VaadinMessageSource i18n, final EntityFactory entityFactory,
|
||||
final UIEventBus eventBus, final SpPermissionChecker permChecker, final UINotification uiNotification,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement, final String selectedTypeName,
|
||||
final CloseListener closeListener) {
|
||||
super(i18n, entityFactory, eventBus, permChecker, uiNotification, softwareModuleTypeManagement);
|
||||
this.selectedTypeName = selectedTypeName;
|
||||
this.closeListener = closeListener;
|
||||
initUpdatePopup();
|
||||
}
|
||||
|
||||
private void initUpdatePopup() {
|
||||
setTagDetails(selectedTypeName);
|
||||
getWindow().addCloseListener(closeListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getWindowCaption() {
|
||||
return getI18n().getMessage("caption.update", getI18n().getMessage("caption.type"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveEntity() {
|
||||
updateSWModuleType(findEntityByName()
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, getTagName().getValue())));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildLayout() {
|
||||
super.buildLayout();
|
||||
disableFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void disableFields() {
|
||||
getTagName().setEnabled(false);
|
||||
getTypeKey().setEnabled(false);
|
||||
getAssignOptiongroup().setEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTagDetails(final String selectedEntity) {
|
||||
getSoftwareModuleTypeManagement().getByName(selectedEntity).ifPresent(selectedTypeTag -> {
|
||||
getTagName().setValue(selectedTypeTag.getName());
|
||||
getTagDesc().setValue(selectedTypeTag.getDescription());
|
||||
getTypeKey().setValue(selectedTypeTag.getKey());
|
||||
if (selectedTypeTag.getMaxAssignments() == 1) {
|
||||
getAssignOptiongroup().setValue(getSingleAssignStr());
|
||||
} else {
|
||||
getAssignOptiongroup().setValue(getMultiAssignStr());
|
||||
}
|
||||
setColorPickerComponentsColor(selectedTypeTag.getColour());
|
||||
});
|
||||
disableFields();
|
||||
}
|
||||
|
||||
private void updateSWModuleType(final SoftwareModuleType existingType) {
|
||||
getSoftwareModuleTypeManagement().update(getEntityFactory().softwareModuleType().update(existingType.getId())
|
||||
.description(getTagDesc().getValue())
|
||||
.colour(ColorPickerHelper.getColorPickedString(getColorPickerLayout().getSelPreview())));
|
||||
getUiNotification().displaySuccess(getI18n().getMessage("message.update.success", existingType.getName()));
|
||||
getEventBus().publish(this,
|
||||
new SoftwareModuleTypeEvent(SoftwareModuleTypeEnum.UPDATE_SOFTWARE_MODULE_TYPE, existingType));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isUpdateAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype.filter;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.RefreshSoftwareModuleByFilterEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.common.filterlayout.AbstractFilterSingleButtonClick;
|
||||
import org.vaadin.spring.events.EventBus;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.ui.Button;
|
||||
|
||||
/**
|
||||
* Single button click behavior of filter buttons layout for software module
|
||||
* table on the Upload view.
|
||||
*/
|
||||
public class SMTypeFilterButtonClick extends AbstractFilterSingleButtonClick {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final transient EventBus.UIEventBus eventBus;
|
||||
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
|
||||
private final transient SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
|
||||
SMTypeFilterButtonClick(final UIEventBus eventBus, final ArtifactUploadState artifactUploadState,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement) {
|
||||
this.eventBus = eventBus;
|
||||
this.artifactUploadState = artifactUploadState;
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void filterUnClicked(final Button clickedButton) {
|
||||
artifactUploadState.getSoftwareModuleFilters().setSoftwareModuleType(null);
|
||||
eventBus.publish(this, new RefreshSoftwareModuleByFilterEvent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void filterClicked(final Button clickedButton) {
|
||||
softwareModuleTypeManagement.getByName(clickedButton.getData().toString()).ifPresent(softwareModuleType -> {
|
||||
artifactUploadState.getSoftwareModuleFilters().setSoftwareModuleType(softwareModuleType);
|
||||
eventBus.publish(this, new RefreshSoftwareModuleByFilterEvent());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,190 +8,115 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype.filter;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleTypeEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleTypeEvent.SoftwareModuleTypeEnum;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.smtype.UpdateSoftwareModuleTypeLayout;
|
||||
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.common.SoftwareModuleTypeBeanQuery;
|
||||
import org.eclipse.hawkbit.ui.common.event.FilterHeaderEvent.FilterHeaderEnum;
|
||||
import org.eclipse.hawkbit.ui.common.event.SoftwareModuleTypeFilterHeaderEvent;
|
||||
import org.eclipse.hawkbit.ui.common.filterlayout.AbstractFilterButtons;
|
||||
import org.eclipse.hawkbit.ui.dd.criteria.UploadViewClientCriterion;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
import org.eclipse.hawkbit.ui.artifacts.smtype.SmTypeWindowBuilder;
|
||||
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 org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.addons.lazyquerycontainer.BeanQueryFactory;
|
||||
import org.vaadin.addons.lazyquerycontainer.LazyQueryContainer;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
import org.vaadin.spring.events.EventScope;
|
||||
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
|
||||
|
||||
import com.vaadin.event.dd.DragAndDropEvent;
|
||||
import com.vaadin.event.dd.DropHandler;
|
||||
import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
|
||||
import com.vaadin.ui.Button.ClickEvent;
|
||||
import com.vaadin.ui.Window;
|
||||
|
||||
/**
|
||||
* Software module type filter buttons.
|
||||
*
|
||||
*/
|
||||
public class SMTypeFilterButtons extends AbstractFilterButtons {
|
||||
|
||||
public class SMTypeFilterButtons extends AbstractTypeFilterButtons {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
|
||||
private final UploadViewClientCriterion uploadViewClientCriterion;
|
||||
|
||||
private final transient SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
private final transient SmTypeWindowBuilder smTypeWindowBuilder;
|
||||
|
||||
private final transient EntityFactory entityFactory;
|
||||
|
||||
private final SpPermissionChecker permChecker;
|
||||
|
||||
private final UINotification uiNotification;
|
||||
private final EventView view;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param artifactUploadState
|
||||
* ArtifactUploadState
|
||||
* @param uploadViewClientCriterion
|
||||
* UploadViewClientCriterion
|
||||
* @param softwareModuleTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param entityFactory
|
||||
* EntityFactory
|
||||
* @param permChecker
|
||||
* SpPermissionChecker
|
||||
* @param uiNotification
|
||||
* UINotification
|
||||
* @param smTypeWindowBuilder
|
||||
* SmTypeWindowBuilder
|
||||
* @param typeFilterLayoutUiState
|
||||
* TypeFilterLayoutUiState
|
||||
* @param view
|
||||
* EventView
|
||||
*/
|
||||
public SMTypeFilterButtons(final UIEventBus eventBus, final ArtifactUploadState artifactUploadState,
|
||||
final UploadViewClientCriterion uploadViewClientCriterion,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement, final VaadinMessageSource i18n,
|
||||
final EntityFactory entityFactory, final SpPermissionChecker permChecker,
|
||||
final UINotification uiNotification) {
|
||||
super(eventBus, new SMTypeFilterButtonClick(eventBus, artifactUploadState, softwareModuleTypeManagement), i18n);
|
||||
this.artifactUploadState = artifactUploadState;
|
||||
this.uploadViewClientCriterion = uploadViewClientCriterion;
|
||||
public SMTypeFilterButtons(final UIEventBus eventBus, final VaadinMessageSource i18n,
|
||||
final UINotification uiNotification, final SpPermissionChecker permChecker,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement,
|
||||
final SmTypeWindowBuilder smTypeWindowBuilder, final TypeFilterLayoutUiState typeFilterLayoutUiState,
|
||||
final EventView view) {
|
||||
super(eventBus, i18n, uiNotification, permChecker, typeFilterLayoutUiState);
|
||||
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
this.entityFactory = entityFactory;
|
||||
this.permChecker = permChecker;
|
||||
this.uiNotification = uiNotification;
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final SoftwareModuleTypeEvent event) {
|
||||
if (event.getSoftwareModuleType() != null
|
||||
&& EnumSet.allOf(SoftwareModuleTypeEnum.class).contains(event.getSoftwareModuleTypeEnum())) {
|
||||
refreshTable();
|
||||
}
|
||||
|
||||
if (isUpdate(event)) {
|
||||
getEventBus().publish(this, new SoftwareModuleTypeFilterHeaderEvent(FilterHeaderEnum.SHOW_MENUBAR));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isUpdate(final SoftwareModuleTypeEvent event) {
|
||||
return event.getSoftwareModuleTypeEnum() == SoftwareModuleTypeEnum.UPDATE_SOFTWARE_MODULE_TYPE;
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final UploadArtifactUIEvent event) {
|
||||
if (event == UploadArtifactUIEvent.DELETED_ALL_SOFTWARE_TYPE) {
|
||||
refreshTable();
|
||||
}
|
||||
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
|
||||
protected String getButtonsTableId() {
|
||||
public String getGridId() {
|
||||
return UIComponentIdProvider.SW_MODULE_TYPE_TABLE_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LazyQueryContainer createButtonsLazyQueryContainer() {
|
||||
return HawkbitCommonUtil.createLazyQueryContainer(new BeanQueryFactory<>(SoftwareModuleTypeBeanQuery.class));
|
||||
protected String getFilterButtonsType() {
|
||||
return i18n.getMessage("caption.entity.software.module.type");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isClickedByDefault(final String typeName) {
|
||||
return artifactUploadState.getSoftwareModuleFilters().getSoftwareModuleType()
|
||||
.map(type -> type.getName().equals(typeName)).orElse(false);
|
||||
protected String getFilterButtonIdPrefix() {
|
||||
return UIComponentIdProvider.SOFTWARE_MODULE_TYPE_ID_PREFIXS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String createButtonId(final String name) {
|
||||
return UIComponentIdProvider.SM_TYPE_FILTER_BTN_ID + name;
|
||||
protected boolean isDefaultType(final ProxyType type) {
|
||||
// We do not have default type for software module
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DropHandler getFilterButtonDropHandler() {
|
||||
return new DropHandler() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public AcceptCriterion getAcceptCriterion() {
|
||||
return uploadViewClientCriterion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drop(final DragAndDropEvent event) {
|
||||
/* Not required */
|
||||
}
|
||||
};
|
||||
protected Class<? extends ProxyIdentifiableEntity> getFilterMasterEntityType() {
|
||||
return ProxySoftwareModule.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getButttonWrapperIdPrefix() {
|
||||
return UIComponentIdProvider.UPLOAD_TYPE_BUTTON_PREFIX;
|
||||
protected EventView getView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getButtonWrapperData() {
|
||||
return null;
|
||||
protected void deleteType(final ProxyType typeToDelete) {
|
||||
softwareModuleTypeManagement.delete(typeToDelete.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addEditButtonClickListener(final ClickEvent event) {
|
||||
new UpdateSoftwareModuleTypeLayout(getI18n(), entityFactory, getEventBus(), permChecker, uiNotification,
|
||||
softwareModuleTypeManagement, getEntityId(event), getCloseListenerForEditAndDeleteTag(
|
||||
new SoftwareModuleTypeFilterHeaderEvent(FilterHeaderEnum.SHOW_MENUBAR)));
|
||||
protected Window getUpdateWindow(final ProxyType clickedFilter) {
|
||||
return smTypeWindowBuilder.getWindowForUpdate(clickedFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDeleteButtonClickListener(final ClickEvent event) {
|
||||
openConfirmationWindowForDeletion(getEntityId(event),
|
||||
getI18n().getMessage("caption.entity.software.module.type"),
|
||||
new SoftwareModuleTypeFilterHeaderEvent(FilterHeaderEnum.SHOW_MENUBAR));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deleteEntity(final String entityToDelete) {
|
||||
final Optional<SoftwareModuleType> swmTypeToDelete = softwareModuleTypeManagement.getByName(entityToDelete);
|
||||
swmTypeToDelete.ifPresent(tag -> {
|
||||
if (artifactUploadState.getSoftwareModuleFilters().getSoftwareModuleType().equals(swmTypeToDelete)) {
|
||||
uiNotification.displayValidationError(getI18n().getMessage("message.tag.delete", entityToDelete));
|
||||
removeUpdateAndDeleteColumn();
|
||||
} else {
|
||||
softwareModuleTypeManagement.delete(swmTypeToDelete.get().getId());
|
||||
getEventBus().publish(this, UploadArtifactUIEvent.DELETED_ALL_SOFTWARE_TYPE);
|
||||
uiNotification.displaySuccess(getI18n().getMessage("message.delete.success", entityToDelete));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,122 +8,96 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype.filter;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.smtype.CreateSoftwareModuleTypeLayout;
|
||||
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.common.event.FilterHeaderEvent.FilterHeaderEnum;
|
||||
import org.eclipse.hawkbit.ui.common.event.SoftwareModuleTypeFilterHeaderEvent;
|
||||
import org.eclipse.hawkbit.ui.common.filterlayout.AbstractFilterHeader;
|
||||
import org.eclipse.hawkbit.ui.artifacts.smtype.SmTypeWindowBuilder;
|
||||
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 org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
import org.vaadin.spring.events.EventScope;
|
||||
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
|
||||
|
||||
import com.vaadin.ui.Button.ClickEvent;
|
||||
import com.vaadin.ui.MenuBar.Command;
|
||||
import com.vaadin.ui.Window;
|
||||
|
||||
/**
|
||||
* Software module type filter buttons header.
|
||||
*/
|
||||
public class SMTypeFilterHeader extends AbstractFilterHeader {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
private final TypeFilterLayoutUiState smTypeFilterLayoutUiState;
|
||||
|
||||
private final transient EntityFactory entityFactory;
|
||||
private final transient SmTypeWindowBuilder smTypeWindowBuilder;
|
||||
|
||||
private final UINotification uiNotification;
|
||||
private final EventView view;
|
||||
|
||||
private final transient SoftwareModuleTypeManagement softwareModuleTypeManagement;
|
||||
/**
|
||||
* Constructor for SMTypeFilterHeader
|
||||
*
|
||||
* @param eventBus
|
||||
* UIEventBus
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param permChecker
|
||||
* SpPermissionChecker
|
||||
* @param smTypeWindowBuilder
|
||||
* SmTypeWindowBuilder
|
||||
* @param smTypeFilterLayoutUiState
|
||||
* TypeFilterLayoutUiState
|
||||
* @param view
|
||||
* EventView
|
||||
*/
|
||||
public SMTypeFilterHeader(final UIEventBus eventBus, final VaadinMessageSource i18n,
|
||||
final SpPermissionChecker permChecker, final SmTypeWindowBuilder smTypeWindowBuilder,
|
||||
final TypeFilterLayoutUiState smTypeFilterLayoutUiState, final EventView view) {
|
||||
super(i18n, permChecker, eventBus);
|
||||
|
||||
private final SMTypeFilterButtons smTypeFilterButtons;
|
||||
this.smTypeFilterLayoutUiState = smTypeFilterLayoutUiState;
|
||||
this.smTypeWindowBuilder = smTypeWindowBuilder;
|
||||
this.view = view;
|
||||
|
||||
SMTypeFilterHeader(final VaadinMessageSource i18n, final SpPermissionChecker permChecker, final UIEventBus eventBus,
|
||||
final ArtifactUploadState artifactUploadState, final EntityFactory entityFactory,
|
||||
final UINotification uiNotification, final SoftwareModuleTypeManagement softwareModuleTypeManagement,
|
||||
final SMTypeFilterButtons smTypeFilterButtons) {
|
||||
super(permChecker, eventBus, i18n);
|
||||
this.artifactUploadState = artifactUploadState;
|
||||
this.entityFactory = entityFactory;
|
||||
this.uiNotification = uiNotification;
|
||||
this.softwareModuleTypeManagement = softwareModuleTypeManagement;
|
||||
this.smTypeFilterButtons = smTypeFilterButtons;
|
||||
buildHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTitle() {
|
||||
return getI18n().getMessage(UIMessageIdProvider.CAPTION_FILTER_BY_TYPE);
|
||||
protected String getHeaderCaptionMsgKey() {
|
||||
return UIMessageIdProvider.CAPTION_FILTER_BY_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean dropHitsRequired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void hideFilterButtonLayout() {
|
||||
artifactUploadState.setSwTypeFilterClosed(true);
|
||||
getEventBus().publish(this, UploadArtifactUIEvent.HIDE_FILTER_BY_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getConfigureFilterButtonId() {
|
||||
return UIComponentIdProvider.ADD_SOFTWARE_MODULE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getHideButtonId() {
|
||||
return UIComponentIdProvider.SM_SHOW_FILTER_BUTTON_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAddTagRequired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Command getAddButtonCommand() {
|
||||
return command -> new CreateSoftwareModuleTypeLayout(getI18n(), entityFactory, getEventBus(), getPermChecker(),
|
||||
uiNotification, softwareModuleTypeManagement);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Command getDeleteButtonCommand() {
|
||||
return command -> {
|
||||
smTypeFilterButtons.addDeleteColumn();
|
||||
getEventBus().publish(this, new SoftwareModuleTypeFilterHeaderEvent(FilterHeaderEnum.SHOW_CANCEL_BUTTON));
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Command getUpdateButtonCommand() {
|
||||
return command -> {
|
||||
smTypeFilterButtons.addUpdateColumn();
|
||||
getEventBus().publish(this, new SoftwareModuleTypeFilterHeaderEvent(FilterHeaderEnum.SHOW_CANCEL_BUTTON));
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancelUpdateOrDeleteTag(final ClickEvent event) {
|
||||
super.cancelUpdateOrDeleteTag(event);
|
||||
smTypeFilterButtons.removeUpdateAndDeleteColumn();
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
private void onEvent(final SoftwareModuleTypeFilterHeaderEvent event) {
|
||||
processFilterHeaderEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMenuBarId() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,32 +8,46 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.smtype.filter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.EntityFactory;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.artifacts.smtype.SmTypeWindowBuilder;
|
||||
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 org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
import org.vaadin.spring.events.EventScope;
|
||||
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
|
||||
|
||||
import com.vaadin.ui.ComponentContainer;
|
||||
|
||||
/**
|
||||
* Software module type filter buttons layout.
|
||||
*/
|
||||
public class SMTypeFilterLayout extends AbstractFilterLayout {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
private final SMTypeFilterHeader smTypeFilterHeader;
|
||||
private final SMTypeFilterButtons smTypeFilterButtons;
|
||||
|
||||
private final transient GridActionsVisibilityListener gridActionsVisibilityListener;
|
||||
private final transient EntityModifiedListener<ProxyType> entityModifiedListener;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param artifactUploadState
|
||||
* ArtifactUploadState
|
||||
* @param i18n
|
||||
* VaadinMessageSource
|
||||
* @param permChecker
|
||||
@@ -46,32 +60,59 @@ public class SMTypeFilterLayout extends AbstractFilterLayout {
|
||||
* UINotification
|
||||
* @param softwareModuleTypeManagement
|
||||
* SoftwareModuleTypeManagement
|
||||
* @param sMTypeFilterButtons
|
||||
* SMTypeFilterButtons
|
||||
* @param smTypeFilterLayoutUiState
|
||||
* SMTypeFilterLayoutUiState
|
||||
*/
|
||||
public SMTypeFilterLayout(final ArtifactUploadState artifactUploadState, final VaadinMessageSource i18n,
|
||||
final SpPermissionChecker permChecker, final UIEventBus eventBus, final EntityFactory entityFactory,
|
||||
final UINotification uiNotification, final SoftwareModuleTypeManagement softwareModuleTypeManagement,
|
||||
final SMTypeFilterButtons sMTypeFilterButtons) {
|
||||
super(new SMTypeFilterHeader(i18n, permChecker, eventBus, artifactUploadState, entityFactory, uiNotification,
|
||||
softwareModuleTypeManagement, sMTypeFilterButtons), sMTypeFilterButtons, eventBus);
|
||||
this.artifactUploadState = artifactUploadState;
|
||||
restoreState();
|
||||
public SMTypeFilterLayout(final VaadinMessageSource i18n, final SpPermissionChecker permChecker,
|
||||
final UIEventBus eventBus, final EntityFactory entityFactory, final UINotification uiNotification,
|
||||
final SoftwareModuleTypeManagement softwareModuleTypeManagement,
|
||||
final TypeFilterLayoutUiState smTypeFilterLayoutUiState) {
|
||||
final SmTypeWindowBuilder smTypeWindowBuilder = new SmTypeWindowBuilder(i18n, entityFactory, eventBus,
|
||||
uiNotification, softwareModuleTypeManagement);
|
||||
|
||||
this.smTypeFilterHeader = new SMTypeFilterHeader(eventBus, i18n, permChecker, smTypeWindowBuilder,
|
||||
smTypeFilterLayoutUiState, EventView.UPLOAD);
|
||||
this.smTypeFilterButtons = new SMTypeFilterButtons(eventBus, i18n, uiNotification, permChecker,
|
||||
softwareModuleTypeManagement, smTypeWindowBuilder, smTypeFilterLayoutUiState, EventView.UPLOAD);
|
||||
|
||||
this.gridActionsVisibilityListener = new GridActionsVisibilityListener(eventBus,
|
||||
new EventLayoutViewAware(EventLayout.SM_TYPE_FILTER, EventView.UPLOAD),
|
||||
smTypeFilterButtons::hideActionColumns, smTypeFilterButtons::showEditColumn,
|
||||
smTypeFilterButtons::showDeleteColumn);
|
||||
this.entityModifiedListener = new EntityModifiedListener.Builder<>(eventBus, ProxyType.class)
|
||||
.entityModifiedAwareSupports(getEntityModifiedAwareSupports())
|
||||
.parentEntityType(ProxySoftwareModule.class).build();
|
||||
|
||||
buildLayout();
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final UploadArtifactUIEvent event) {
|
||||
if (event == UploadArtifactUIEvent.HIDE_FILTER_BY_TYPE) {
|
||||
setVisible(false);
|
||||
}
|
||||
if (event == UploadArtifactUIEvent.SHOW_FILTER_BY_TYPE) {
|
||||
setVisible(true);
|
||||
}
|
||||
private List<EntityModifiedAwareSupport> getEntityModifiedAwareSupports() {
|
||||
return Arrays.asList(EntityModifiedGridRefreshAwareSupport.of(smTypeFilterButtons::refreshAll),
|
||||
EntityModifiedGenericSupport.of(null, null, smTypeFilterButtons::resetFilterOnTypesDeleted));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean onLoadIsTypeFilterIsClosed() {
|
||||
return artifactUploadState.isSwTypeFilterClosed();
|
||||
protected SMTypeFilterHeader getFilterHeader() {
|
||||
return smTypeFilterHeader;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ComponentContainer getFilterContent() {
|
||||
return wrapFilterContent(smTypeFilterButtons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is called when view is shown to the user
|
||||
*/
|
||||
public void restoreState() {
|
||||
smTypeFilterButtons.restoreState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe the events listeners
|
||||
*/
|
||||
public void unsubscribeListener() {
|
||||
gridActionsVisibilityListener.unsubscribe();
|
||||
entityModifiedListener.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.state;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
|
||||
import com.vaadin.spring.annotation.SpringComponent;
|
||||
import com.vaadin.spring.annotation.VaadinSessionScope;
|
||||
|
||||
/**
|
||||
* Software module filters.
|
||||
*
|
||||
*
|
||||
*/
|
||||
@VaadinSessionScope
|
||||
@SpringComponent
|
||||
public class SoftwareModuleFilters implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -5251492630546463593L;
|
||||
|
||||
private SoftwareModuleType softwareModuleType;
|
||||
|
||||
private String searchText;
|
||||
|
||||
public Optional<SoftwareModuleType> getSoftwareModuleType() {
|
||||
return Optional.ofNullable(softwareModuleType);
|
||||
}
|
||||
|
||||
public void setSoftwareModuleType(final SoftwareModuleType softwareModuleType) {
|
||||
this.softwareModuleType = softwareModuleType;
|
||||
}
|
||||
|
||||
public Optional<String> getSearchText() {
|
||||
return Optional.ofNullable(searchText);
|
||||
}
|
||||
|
||||
public void setSearchText(final String searchText) {
|
||||
this.searchText = searchText;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,10 +12,9 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.RegexCharacterCollection;
|
||||
import org.eclipse.hawkbit.repository.RegexCharacterCollection.RegexChar;
|
||||
@@ -28,15 +27,18 @@ 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.event.SoftwareModuleEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent.SoftwareModuleEventType;
|
||||
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
|
||||
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.SpringContextHelper;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
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;
|
||||
|
||||
@@ -101,9 +103,8 @@ public abstract class AbstractFileTransferHandler implements Serializable {
|
||||
|
||||
protected void startTransferToRepositoryThread(final InputStream inputStream, final FileUploadId fileUploadId,
|
||||
final String mimeType) {
|
||||
SpringContextHelper.getBean("asyncExecutor", ExecutorService.class)
|
||||
.execute(new TransferArtifactToRepositoryRunnable(inputStream, fileUploadId, mimeType, UI.getCurrent(),
|
||||
uploadLock));
|
||||
SpringContextHelper.getBean("uiExecutor", Executor.class).execute(new TransferArtifactToRepositoryRunnable(
|
||||
inputStream, fileUploadId, mimeType, UI.getCurrent(), uploadLock));
|
||||
}
|
||||
|
||||
private void interruptUploadAndSetReason(final String failureReason) {
|
||||
@@ -152,7 +153,7 @@ public abstract class AbstractFileTransferHandler implements Serializable {
|
||||
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
|
||||
FileUploadStatus.UPLOAD_STARTED);
|
||||
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
|
||||
eventBus.publish(this, fileUploadProgress);
|
||||
eventBus.publish(EventTopics.FILE_UPLOAD_CHANGED, this, fileUploadProgress);
|
||||
}
|
||||
|
||||
protected void publishUploadProgressEvent(final FileUploadId fileUploadId, final long bytesReceived,
|
||||
@@ -164,14 +165,14 @@ public abstract class AbstractFileTransferHandler implements Serializable {
|
||||
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
|
||||
FileUploadStatus.UPLOAD_IN_PROGRESS, bytesReceived, fileSize);
|
||||
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
|
||||
eventBus.publish(this, 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(this, fileUploadProgress);
|
||||
eventBus.publish(EventTopics.FILE_UPLOAD_CHANGED, this, fileUploadProgress);
|
||||
}
|
||||
|
||||
protected void publishUploadSucceeded(final FileUploadId fileUploadId, final long fileSize) {
|
||||
@@ -179,21 +180,21 @@ public abstract class AbstractFileTransferHandler implements Serializable {
|
||||
final FileUploadProgress fileUploadProgress = new FileUploadProgress(fileUploadId,
|
||||
FileUploadStatus.UPLOAD_SUCCESSFUL, fileSize, fileSize);
|
||||
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
|
||||
eventBus.publish(this, 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.isBlank(failureReason) ? i18n.getMessage(MESSAGE_UPLOAD_FAILED) : failureReason);
|
||||
StringUtils.hasText(failureReason) ? failureReason : i18n.getMessage(MESSAGE_UPLOAD_FAILED));
|
||||
artifactUploadState.updateFileUploadProgress(fileUploadId, fileUploadProgress);
|
||||
eventBus.publish(this, fileUploadProgress);
|
||||
eventBus.publish(EventTopics.FILE_UPLOAD_CHANGED, this, fileUploadProgress);
|
||||
}
|
||||
|
||||
protected void publishArtifactsChanged(final FileUploadId fileUploadId) {
|
||||
eventBus.publish(this,
|
||||
new SoftwareModuleEvent(SoftwareModuleEventType.ARTIFACTS_CHANGED, fileUploadId.getSoftwareModuleId()));
|
||||
eventBus.publish(EventTopics.ENTITY_MODIFIED, this, new EntityModifiedEventPayload(
|
||||
EntityModifiedEventType.ENTITY_UPDATED, ProxySoftwareModule.class, fileUploadId.getSoftwareModuleId()));
|
||||
}
|
||||
|
||||
protected void publishUploadFailedAndFinishedEvent(final FileUploadId fileUploadId) {
|
||||
@@ -236,6 +237,20 @@ public abstract class AbstractFileTransferHandler implements Serializable {
|
||||
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;
|
||||
@@ -285,6 +300,7 @@ public abstract class AbstractFileTransferHandler implements Serializable {
|
||||
LOG.debug("Transfering file {} directly to repository", filename);
|
||||
final Artifact artifact = uploadArtifact(filename);
|
||||
if (isUploadInterrupted()) {
|
||||
LOG.warn("Upload of {} was interrupted", filename);
|
||||
handleUploadFailure(artifact);
|
||||
publishUploadFinishedEvent(fileUploadId);
|
||||
return;
|
||||
|
||||
@@ -24,8 +24,6 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.vaadin.server.StreamVariable;
|
||||
import com.vaadin.ui.Upload.FinishedEvent;
|
||||
import com.vaadin.ui.Upload.SucceededEvent;
|
||||
|
||||
/**
|
||||
* {@link StreamVariable} implementation to read and upload a file. One instance
|
||||
@@ -61,12 +59,19 @@ public class FileTransferHandlerStreamVariable extends AbstractFileTransferHandl
|
||||
publishUploadStarted(fileUploadId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for duplication and invalid file name during feil 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);
|
||||
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(),
|
||||
@@ -75,6 +80,11 @@ public class FileTransferHandlerStreamVariable extends AbstractFileTransferHandl
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the output stream of uploaded file
|
||||
*
|
||||
* @return OutputStream
|
||||
*/
|
||||
@Override
|
||||
public final OutputStream getOutputStream() {
|
||||
if (isUploadInterrupted()) {
|
||||
@@ -134,8 +144,7 @@ public class FileTransferHandlerStreamVariable extends AbstractFileTransferHandl
|
||||
|
||||
/**
|
||||
* Upload finished for {@link StreamVariable} variant. Called only in good
|
||||
* case. So a combination of {@link #uploadSucceeded(SucceededEvent)} and
|
||||
* {@link #uploadFinished(FinishedEvent)}.
|
||||
* case.
|
||||
*
|
||||
* @see com.vaadin.server.StreamVariable#streamingFinished(com.vaadin.server.StreamVariable.StreamingEndEvent)
|
||||
*/
|
||||
@@ -161,6 +170,11 @@ public class FileTransferHandlerStreamVariable extends AbstractFileTransferHandl
|
||||
publishUploadFailedAndFinishedEvent(fileUploadId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if upload process is interrupted
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
@Override
|
||||
public boolean isInterrupted() {
|
||||
return isUploadInterrupted();
|
||||
|
||||
@@ -59,6 +59,7 @@ public class FileTransferHandlerVaadinUpload extends AbstractFileTransferHandler
|
||||
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;
|
||||
}
|
||||
@@ -91,7 +92,8 @@ public class FileTransferHandlerVaadinUpload extends AbstractFileTransferHandler
|
||||
interruptUploadDueToIllegalFilename();
|
||||
event.getUpload().interruptUpload();
|
||||
} else if (isFileAlreadyContainedInSoftwareModule(fileUploadId, softwareModule)) {
|
||||
LOG.debug("File {} already contained in Software Module {}", fileUploadId.getFilename(), softwareModule);
|
||||
LOG.debug("File {} already contained in Software Module {}", fileUploadId.getFilename(),
|
||||
softwareModule);
|
||||
interruptUploadDueToDuplicateFile();
|
||||
event.getUpload().interruptUpload();
|
||||
}
|
||||
@@ -99,12 +101,9 @@ public class FileTransferHandlerVaadinUpload extends AbstractFileTransferHandler
|
||||
}
|
||||
|
||||
private SoftwareModule getSelectedSoftwareModule() {
|
||||
if (getUploadState().isMoreThanOneSoftwareModulesSelected()) {
|
||||
throw new IllegalStateException("More than one SoftwareModul selected but only one is allowed");
|
||||
}
|
||||
final long selectedId = getUploadState().getSelectedBaseSwModuleId()
|
||||
.orElseThrow(() -> new IllegalStateException("No SoftwareModul selected"));
|
||||
return softwareModuleManagement.get(selectedId)
|
||||
final Long lastSelectedSmId = getUploadState().getSmGridLayoutUiState().getSelectedEntityId();
|
||||
|
||||
return softwareModuleManagement.get(lastSelectedSmId)
|
||||
.orElseThrow(() -> new IllegalStateException("SoftwareModul with unknown ID selected"));
|
||||
}
|
||||
|
||||
|
||||
@@ -101,18 +101,38 @@ public class FileUploadId implements Serializable {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the uploaded file name
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the software module name
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String getSoftwareModuleName() {
|
||||
return softwareModuleName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the software module version
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public String getSoftwareModuleVersion() {
|
||||
return softwareModuleVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the software module ID
|
||||
*
|
||||
* @return Long
|
||||
*/
|
||||
public Long getSoftwareModuleId() {
|
||||
return softwareModuleId;
|
||||
}
|
||||
|
||||
@@ -137,26 +137,55 @@ public class FileUploadProgress implements Serializable {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -8,70 +8,54 @@
|
||||
*/
|
||||
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.event.SoftwareModuleEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType;
|
||||
import org.eclipse.hawkbit.ui.dd.criteria.ServerItemIdClientCriterion;
|
||||
import org.eclipse.hawkbit.ui.dd.criteria.ServerItemIdClientCriterion.Mode;
|
||||
import org.eclipse.hawkbit.ui.artifacts.ArtifactUploadState;
|
||||
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 org.vaadin.spring.events.EventBus;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
import org.vaadin.spring.events.EventScope;
|
||||
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
|
||||
|
||||
import com.vaadin.event.dd.DragAndDropEvent;
|
||||
import com.vaadin.event.dd.DropHandler;
|
||||
import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
|
||||
import com.vaadin.event.dd.acceptcriteria.Not;
|
||||
import com.vaadin.server.FontAwesome;
|
||||
import com.vaadin.shared.ui.label.ContentMode;
|
||||
import com.vaadin.ui.AbstractComponent;
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.DragAndDropWrapper;
|
||||
import com.vaadin.ui.DragAndDropWrapper.WrapperTransferable;
|
||||
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.UI;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
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 AbstractComponent {
|
||||
|
||||
public class UploadDropAreaLayout extends CustomComponent implements MasterEntityAwareComponent<ProxySoftwareModule> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static AcceptCriterion acceptAllExceptBlacklisted = new Not(new ServerItemIdClientCriterion(Mode.PREFIX,
|
||||
UIComponentIdProvider.UPLOAD_SOFTWARE_MODULE_TABLE, UIComponentIdProvider.UPLOAD_TYPE_BUTTON_PREFIX));
|
||||
|
||||
private DragAndDropWrapper dropAreaWrapper;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
|
||||
private final UINotification uiNotification;
|
||||
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
|
||||
private final transient MultipartConfigElement multipartConfigElement;
|
||||
|
||||
private final transient ArtifactManagement artifactManagement;
|
||||
private final transient SoftwareModuleManagement softwareManagement;
|
||||
|
||||
private final transient ArtifactManagement artifactManagement;
|
||||
private final transient MultipartConfigElement multipartConfigElement;
|
||||
private final transient Lock uploadLock = new ReentrantLock();
|
||||
|
||||
private final UploadProgressButtonLayout uploadButtonLayout;
|
||||
|
||||
private final transient Lock uploadLock = new ReentrantLock();
|
||||
private VerticalLayout dropAreaLayout;
|
||||
|
||||
/**
|
||||
* Creates a new {@link UploadDropAreaLayout} instance.
|
||||
@@ -103,84 +87,112 @@ public class UploadDropAreaLayout extends AbstractComponent {
|
||||
this.multipartConfigElement = multipartConfigElement;
|
||||
this.softwareManagement = softwareManagement;
|
||||
this.artifactManagement = artifactManagement;
|
||||
|
||||
this.uploadButtonLayout = new UploadProgressButtonLayout(i18n, eventBus, artifactUploadState,
|
||||
multipartConfigElement, artifactManagement, softwareManagement, uploadLock);
|
||||
|
||||
buildLayout();
|
||||
|
||||
eventBus.subscribe(this);
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final SoftwareModuleEvent event) {
|
||||
final BaseEntityEventType eventType = event.getEventType();
|
||||
if (eventType == BaseEntityEventType.SELECTED_ENTITY) {
|
||||
UI.getCurrent().access(() -> {
|
||||
if (artifactUploadState.isNoSoftwareModuleSelected()
|
||||
|| artifactUploadState.isMoreThanOneSoftwareModulesSelected()) {
|
||||
dropAreaWrapper.setEnabled(false);
|
||||
} else if (artifactUploadState.areAllUploadsFinished()) {
|
||||
dropAreaWrapper.setEnabled(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void buildLayout() {
|
||||
dropAreaWrapper = new DragAndDropWrapper(createDropAreaLayout());
|
||||
dropAreaWrapper.setDropHandler(new DropAreaHandler());
|
||||
}
|
||||
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();
|
||||
|
||||
private VerticalLayout createDropAreaLayout() {
|
||||
final VerticalLayout dropAreaLayout = new VerticalLayout();
|
||||
final Label dropHereLabel = new Label(i18n.getMessage(UIMessageIdProvider.LABEL_DROP_AREA_UPLOAD));
|
||||
dropHereLabel.setWidth(null);
|
||||
|
||||
final Label dropIcon = new Label(FontAwesome.ARROW_DOWN.getHtml(), ContentMode.HTML);
|
||||
final Label dropIcon = new Label(VaadinIcons.ARROW_DOWN.getHtml(), ContentMode.HTML);
|
||||
dropIcon.addStyleName("drop-icon");
|
||||
dropIcon.setWidth(null);
|
||||
|
||||
dropAreaLayout.addComponent(dropIcon);
|
||||
dropAreaLayout.setComponentAlignment(dropIcon, Alignment.TOP_CENTER);
|
||||
|
||||
final Label dropHereLabel = new Label(i18n.getMessage(UIMessageIdProvider.LABEL_DROP_AREA_UPLOAD));
|
||||
dropHereLabel.setWidth(null);
|
||||
dropAreaLayout.addComponent(dropHereLabel);
|
||||
dropAreaLayout.setComponentAlignment(dropHereLabel, Alignment.TOP_CENTER);
|
||||
|
||||
uploadButtonLayout.setWidth(null);
|
||||
uploadButtonLayout.addStyleName("upload-button");
|
||||
dropAreaLayout.addComponent(uploadButtonLayout);
|
||||
dropAreaLayout.setComponentAlignment(uploadButtonLayout, Alignment.BOTTOM_CENTER);
|
||||
|
||||
dropAreaLayout.setSizeFull();
|
||||
dropAreaLayout.setStyleName("upload-drop-area-layout-info");
|
||||
dropAreaLayout.setSpacing(false);
|
||||
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;
|
||||
}
|
||||
|
||||
public DragAndDropWrapper getDropAreaWrapper() {
|
||||
return dropAreaWrapper;
|
||||
/**
|
||||
* Get File upload button layout
|
||||
*
|
||||
* @return UploadProgressButtonLayout
|
||||
*/
|
||||
public UploadProgressButtonLayout getUploadButtonLayout() {
|
||||
return uploadButtonLayout;
|
||||
}
|
||||
|
||||
private class DropAreaHandler implements DropHandler {
|
||||
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 AcceptCriterion getAcceptCriterion() {
|
||||
return acceptAllExceptBlacklisted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drop(final DragAndDropEvent event) {
|
||||
public void drop(final FileDropEvent<VerticalLayout> event) {
|
||||
if (validate(event)) {
|
||||
final Html5File[] files = ((WrapperTransferable) event.getTransferable()).getFiles();
|
||||
// selected software module at the time of file drop is
|
||||
// considered for upload
|
||||
artifactUploadState.getSelectedBaseSwModuleId()
|
||||
.ifPresent(selectedSwId -> uploadFilesForSoftwareModule(files, selectedSwId));
|
||||
final Long lastSelectedSmId = artifactUploadState.getSmGridLayoutUiState().getSelectedEntityId();
|
||||
if (lastSelectedSmId != null) {
|
||||
uploadFilesForSoftwareModule(event.getFiles(), lastSelectedSmId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void uploadFilesForSoftwareModule(final Html5File[] files, final Long softwareModuleId) {
|
||||
private void uploadFilesForSoftwareModule(final Collection<Html5File> files, final Long softwareModuleId) {
|
||||
final SoftwareModule softwareModule = softwareManagement.get(softwareModuleId).orElse(null);
|
||||
|
||||
boolean duplicateFound = false;
|
||||
@@ -199,7 +211,7 @@ public class UploadDropAreaLayout extends AbstractComponent {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean validate(final DragAndDropEvent event) {
|
||||
private boolean validate(final FileDropEvent<VerticalLayout> event) {
|
||||
// check if drop is valid.If valid ,check if software module is
|
||||
// selected.
|
||||
if (!isFilesDropped(event)) {
|
||||
@@ -209,29 +221,19 @@ public class UploadDropAreaLayout extends AbstractComponent {
|
||||
return validateSoftwareModuleSelection();
|
||||
}
|
||||
|
||||
private boolean isFilesDropped(final DragAndDropEvent event) {
|
||||
if (event.getTransferable() instanceof WrapperTransferable) {
|
||||
final Html5File[] files = ((WrapperTransferable) event.getTransferable()).getFiles();
|
||||
return files != null;
|
||||
}
|
||||
return false;
|
||||
private boolean isFilesDropped(final FileDropEvent<VerticalLayout> event) {
|
||||
return event.getFiles() != null;
|
||||
}
|
||||
|
||||
private boolean validateSoftwareModuleSelection() {
|
||||
if (artifactUploadState.isNoSoftwareModuleSelected()) {
|
||||
final Long lastSelectedSmId = artifactUploadState.getSmGridLayoutUiState().getSelectedEntityId();
|
||||
|
||||
if (lastSelectedSmId == null) {
|
||||
uiNotification.displayValidationError(i18n.getMessage("message.error.noSwModuleSelected"));
|
||||
return false;
|
||||
}
|
||||
if (artifactUploadState.isMoreThanOneSoftwareModulesSelected()) {
|
||||
uiNotification.displayValidationError(i18n.getMessage("message.error.multiSwModuleSelected"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public UploadProgressButtonLayout getUploadButtonLayout() {
|
||||
return uploadButtonLayout;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,6 +27,9 @@ public class UploadFixed extends Upload {
|
||||
|
||||
private boolean uploadInterrupted;
|
||||
|
||||
/**
|
||||
* Stops the file upload
|
||||
*/
|
||||
@Override
|
||||
public void interruptUpload() {
|
||||
super.interruptUpload();
|
||||
@@ -42,6 +45,12 @@ public class UploadFixed extends Upload {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final StreamVariable originalStreamVariable;
|
||||
|
||||
/**
|
||||
* Constructor for StreamVariableFixed
|
||||
*
|
||||
* @param originalStreamVariable
|
||||
* StreamVariable
|
||||
*/
|
||||
public StreamVariableFixed(final StreamVariable originalStreamVariable) {
|
||||
this.originalStreamVariable = originalStreamVariable;
|
||||
}
|
||||
|
||||
@@ -8,56 +8,47 @@
|
||||
*/
|
||||
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.event.SoftwareModuleEvent;
|
||||
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
|
||||
import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType;
|
||||
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 org.vaadin.spring.events.EventScope;
|
||||
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
|
||||
|
||||
import com.vaadin.ui.Button;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.Upload;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
/**
|
||||
* Container for upload and progress button.
|
||||
*/
|
||||
public class UploadProgressButtonLayout extends VerticalLayout {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final UploadProgressInfoWindow uploadInfoWindow;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
|
||||
private final transient MultipartConfigElement multipartConfigElement;
|
||||
|
||||
private final UI ui;
|
||||
|
||||
private Button uploadProgressButton;
|
||||
|
||||
private final transient SoftwareModuleManagement softwareModuleManagement;
|
||||
|
||||
private final UploadFixed upload;
|
||||
|
||||
private final transient ArtifactManagement artifactManagement;
|
||||
|
||||
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.
|
||||
*
|
||||
@@ -76,14 +67,16 @@ public class UploadProgressButtonLayout extends VerticalLayout {
|
||||
* the {@link ArtifactManagement} for storing the uploaded
|
||||
* artifacts
|
||||
* @param uploadLock
|
||||
* A common upload lock that enforced sequential upload within an UI instance
|
||||
* 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) {
|
||||
final ArtifactManagement artifactManagement, final SoftwareModuleManagement softwareManagement,
|
||||
final Lock uploadLock) {
|
||||
this.artifactUploadState = artifactUploadState;
|
||||
this.artifactManagement = artifactManagement;
|
||||
this.uploadInfoWindow = new UploadProgressInfoWindow(eventBus, artifactUploadState, i18n);
|
||||
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
|
||||
@@ -99,25 +92,34 @@ public class UploadProgressButtonLayout extends VerticalLayout {
|
||||
|
||||
createComponents();
|
||||
buildLayout();
|
||||
restoreState();
|
||||
ui = UI.getCurrent();
|
||||
|
||||
eventBus.subscribe(this);
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final FileUploadProgress fileUploadProgress) {
|
||||
/**
|
||||
* 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.access(this::onStartOfUpload);
|
||||
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.access(this::onUploadFinished);
|
||||
UI.getCurrent().access(() -> {
|
||||
onUploadFinished();
|
||||
uploadInfoWindow.onUploadFinished();
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Enum " + FileUploadProgress.FileUploadStatus.class.getSimpleName()
|
||||
@@ -125,35 +127,28 @@ public class UploadProgressButtonLayout extends VerticalLayout {
|
||||
}
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final SoftwareModuleEvent event) {
|
||||
final BaseEntityEventType eventType = event.getEventType();
|
||||
if (eventType == BaseEntityEventType.SELECTED_ENTITY) {
|
||||
ui.access(() -> {
|
||||
if (artifactUploadState.isNoSoftwareModuleSelected()
|
||||
|| artifactUploadState.isMoreThanOneSoftwareModulesSelected()) {
|
||||
upload.setEnabled(false);
|
||||
} else if (artifactUploadState.areAllUploadsFinished()) {
|
||||
upload.setEnabled(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 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.setIcon(null);
|
||||
uploadProgressButton.setHtmlContentAllowed(true);
|
||||
uploadProgressButton.addClickListener(event -> onClickOfUploadProgressButton());
|
||||
uploadProgressButton.addClickListener(event -> showUploadInfoWindow());
|
||||
}
|
||||
|
||||
private void buildLayout() {
|
||||
final FileTransferHandlerVaadinUpload uploadHandler = new FileTransferHandlerVaadinUpload(
|
||||
multipartConfigElement.getMaxFileSize(), softwareModuleManagement, artifactManagement, i18n, uploadLock);
|
||||
multipartConfigElement.getMaxFileSize(), softwareModuleManagement, artifactManagement, i18n,
|
||||
uploadLock);
|
||||
upload.setButtonCaption(i18n.getMessage("upload.file"));
|
||||
upload.setImmediate(true);
|
||||
upload.setReceiver(uploadHandler);
|
||||
upload.addSucceededListener(uploadHandler);
|
||||
upload.addFailedListener(uploadHandler);
|
||||
@@ -163,7 +158,8 @@ public class UploadProgressButtonLayout extends VerticalLayout {
|
||||
upload.setId(UIComponentIdProvider.UPLOAD_BUTTON);
|
||||
|
||||
addComponent(upload);
|
||||
setSpacing(true);
|
||||
setSizeFull();
|
||||
setMargin(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,7 +190,10 @@ public class UploadProgressButtonLayout extends VerticalLayout {
|
||||
}
|
||||
}
|
||||
|
||||
private void onClickOfUploadProgressButton() {
|
||||
/**
|
||||
* Maximize the file upload view
|
||||
*/
|
||||
public void showUploadInfoWindow() {
|
||||
uploadInfoWindow.maximizeWindow();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.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));
|
||||
}
|
||||
}
|
||||
@@ -8,76 +8,52 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.artifacts.upload;
|
||||
|
||||
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
|
||||
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.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 org.springframework.util.StringUtils;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
import org.vaadin.spring.events.EventScope;
|
||||
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
|
||||
|
||||
import com.vaadin.data.Container.Indexed;
|
||||
import com.vaadin.data.Item;
|
||||
import com.vaadin.data.util.IndexedContainer;
|
||||
import com.vaadin.server.FontAwesome;
|
||||
import com.vaadin.icons.VaadinIcons;
|
||||
import com.vaadin.shared.ui.window.WindowMode;
|
||||
import com.vaadin.ui.Button;
|
||||
import com.vaadin.ui.Grid;
|
||||
import com.vaadin.ui.Grid.SelectionMode;
|
||||
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.renderers.HtmlRenderer;
|
||||
import com.vaadin.ui.renderers.ProgressBarRenderer;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
import elemental.json.JsonValue;
|
||||
|
||||
/**
|
||||
* Window that shows the progress of all uploads.
|
||||
*/
|
||||
public class UploadProgressInfoWindow extends Window {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String COLUMN_PROGRESS = UIMessageIdProvider.CAPTION_ARTIFACT_UPLOAD_PROGRESS;
|
||||
private static final String COLUMN_FILE_NAME = UIMessageIdProvider.CAPTION_ARTIFACT_FILENAME;
|
||||
private static final String COLUMN_STATUS = UIMessageIdProvider.CAPTION_ARTIFACT_UPLOAD_STATUS;
|
||||
private static final String COLUMN_REASON = UIMessageIdProvider.CAPTION_ARTIFACT_UPLOAD_REASON;
|
||||
private static final String COLUMN_SOFTWARE_MODULE = UIMessageIdProvider.CAPTION_SOFTWARE_MODULE;
|
||||
|
||||
private static final String STATUS_INPROGRESS = "InProgress";
|
||||
private static final String STATUS_FINISHED = "Finished";
|
||||
private static final String STATUS_FAILED = "Failed";
|
||||
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
|
||||
private final Grid grid;
|
||||
|
||||
private final IndexedContainer uploads;
|
||||
private final ArtifactUploadState artifactUploadState;
|
||||
|
||||
private final UploadProgressGrid uploadProgressGrid;
|
||||
private final VerticalLayout mainLayout;
|
||||
|
||||
private final UI ui;
|
||||
|
||||
private Label windowCaption;
|
||||
|
||||
private Button closeButton;
|
||||
|
||||
UploadProgressInfoWindow(final UIEventBus eventBus, final ArtifactUploadState artifactUploadState,
|
||||
final VaadinMessageSource i18n) {
|
||||
this.artifactUploadState = artifactUploadState;
|
||||
private final List<ProxyUploadProgress> uploads;
|
||||
|
||||
UploadProgressInfoWindow(final VaadinMessageSource i18n, final ArtifactUploadState artifactUploadState) {
|
||||
this.i18n = i18n;
|
||||
this.artifactUploadState = artifactUploadState;
|
||||
|
||||
setPopupProperties();
|
||||
createStatusPopupHeaderComponents();
|
||||
@@ -87,44 +63,84 @@ public class UploadProgressInfoWindow extends Window {
|
||||
mainLayout.setSizeUndefined();
|
||||
setPopupSizeInMinMode();
|
||||
|
||||
uploads = getGridContainer();
|
||||
grid = createGrid();
|
||||
setGridColumnProperties();
|
||||
uploads = new ArrayList<>();
|
||||
uploadProgressGrid = new UploadProgressGrid(i18n);
|
||||
uploadProgressGrid.setItems(uploads);
|
||||
|
||||
mainLayout.addComponents(getCaptionLayout(), grid);
|
||||
mainLayout.setExpandRatio(grid, 1.0F);
|
||||
mainLayout.addComponents(getCaptionLayout(), uploadProgressGrid);
|
||||
mainLayout.setExpandRatio(uploadProgressGrid, 1.0F);
|
||||
setContent(mainLayout);
|
||||
eventBus.subscribe(this);
|
||||
ui = UI.getCurrent();
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final FileUploadProgress fileUploadProgress) {
|
||||
switch (fileUploadProgress.getFileUploadStatus()) {
|
||||
case UPLOAD_STARTED:
|
||||
ui.access(() -> onUploadStarted(fileUploadProgress));
|
||||
break;
|
||||
case UPLOAD_IN_PROGRESS:
|
||||
case UPLOAD_FAILED:
|
||||
case UPLOAD_SUCCESSFUL:
|
||||
ui.access(() -> updateUploadProgressInfoRowObject(fileUploadProgress));
|
||||
break;
|
||||
case UPLOAD_FINISHED:
|
||||
ui.access(this::onUploadFinished);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
private void onUploadStarted(final FileUploadProgress fileUploadProgress) {
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
grid.scrollTo(fileUploadProgress.getFileUploadId());
|
||||
}
|
||||
|
||||
private boolean isWindowNotAlreadyAttached() {
|
||||
@@ -132,8 +148,7 @@ public class UploadProgressInfoWindow extends Window {
|
||||
}
|
||||
|
||||
private void restoreState() {
|
||||
final Indexed container = grid.getContainerDataSource();
|
||||
container.removeAllItems();
|
||||
uploads.clear();
|
||||
for (final FileUploadProgress fileUploadProgress : artifactUploadState
|
||||
.getAllFileUploadProgressValuesFromOverallUploadProcessList()) {
|
||||
updateUploadProgressInfoRowObject(fileUploadProgress);
|
||||
@@ -143,48 +158,13 @@ public class UploadProgressInfoWindow extends Window {
|
||||
private void setPopupProperties() {
|
||||
setId(UIComponentIdProvider.UPLOAD_STATUS_POPUP_ID);
|
||||
addStyleName(SPUIStyleDefinitions.UPLOAD_INFO);
|
||||
setImmediate(true);
|
||||
|
||||
setResizable(false);
|
||||
setDraggable(true);
|
||||
setClosable(false);
|
||||
setModal(true);
|
||||
}
|
||||
|
||||
private void setGridColumnProperties() {
|
||||
grid.getColumn(COLUMN_STATUS).setRenderer(new StatusRenderer());
|
||||
grid.getColumn(COLUMN_PROGRESS).setRenderer(new ProgressBarRenderer());
|
||||
grid.setColumnOrder(COLUMN_STATUS, COLUMN_PROGRESS, COLUMN_FILE_NAME, COLUMN_SOFTWARE_MODULE,
|
||||
COLUMN_REASON);
|
||||
setColumnWidth();
|
||||
grid.getColumn(COLUMN_STATUS).setHeaderCaption(i18n.getMessage(COLUMN_STATUS));
|
||||
grid.getColumn(COLUMN_PROGRESS).setHeaderCaption(i18n.getMessage(COLUMN_PROGRESS));
|
||||
grid.getColumn(COLUMN_FILE_NAME).setHeaderCaption(i18n.getMessage(COLUMN_FILE_NAME));
|
||||
grid.getColumn(COLUMN_SOFTWARE_MODULE).setHeaderCaption(i18n.getMessage(COLUMN_SOFTWARE_MODULE));
|
||||
grid.getColumn(COLUMN_REASON).setHeaderCaption(i18n.getMessage(COLUMN_REASON));
|
||||
grid.setFrozenColumnCount(5);
|
||||
}
|
||||
|
||||
private Grid createGrid() {
|
||||
final Grid statusGrid = new Grid(uploads);
|
||||
statusGrid.addStyleName(SPUIStyleDefinitions.UPLOAD_STATUS_GRID);
|
||||
statusGrid.setId(UIComponentIdProvider.UPLOAD_STATUS_POPUP_GRID);
|
||||
statusGrid.setSelectionMode(SelectionMode.NONE);
|
||||
statusGrid.setHeaderVisible(true);
|
||||
statusGrid.setImmediate(true);
|
||||
statusGrid.setSizeFull();
|
||||
return statusGrid;
|
||||
}
|
||||
|
||||
private static IndexedContainer getGridContainer() {
|
||||
final IndexedContainer uploadContainer = new IndexedContainer();
|
||||
uploadContainer.addContainerProperty(COLUMN_STATUS, String.class, "Active");
|
||||
uploadContainer.addContainerProperty(COLUMN_FILE_NAME, String.class, null);
|
||||
uploadContainer.addContainerProperty(COLUMN_PROGRESS, Double.class, 0D);
|
||||
uploadContainer.addContainerProperty(COLUMN_REASON, String.class, "");
|
||||
uploadContainer.addContainerProperty(COLUMN_SOFTWARE_MODULE, String.class, "");
|
||||
return uploadContainer;
|
||||
}
|
||||
|
||||
private HorizontalLayout getCaptionLayout() {
|
||||
final HorizontalLayout captionLayout = new HorizontalLayout();
|
||||
captionLayout.setSizeFull();
|
||||
@@ -200,43 +180,6 @@ public class UploadProgressInfoWindow extends Window {
|
||||
closeButton = getCloseButton();
|
||||
}
|
||||
|
||||
private void setColumnWidth() {
|
||||
grid.getColumn(COLUMN_STATUS).setWidth(60);
|
||||
grid.getColumn(COLUMN_PROGRESS).setWidth(150);
|
||||
grid.getColumn(COLUMN_FILE_NAME).setWidth(200);
|
||||
grid.getColumn(COLUMN_REASON).setWidth(290);
|
||||
grid.getColumn(COLUMN_SOFTWARE_MODULE).setWidth(200);
|
||||
}
|
||||
|
||||
private static class StatusRenderer extends HtmlRenderer {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public JsonValue encode(final String value) {
|
||||
if (value == null) {
|
||||
return super.encode(getNullRepresentation());
|
||||
}
|
||||
|
||||
final String result;
|
||||
switch (value) {
|
||||
case STATUS_FINISHED:
|
||||
result = "<div class=\"statusIconGreen\">" + FontAwesome.CHECK_CIRCLE.getHtml() + "</div>";
|
||||
break;
|
||||
case STATUS_FAILED:
|
||||
result = "<div class=\"statusIconRed\">" + FontAwesome.EXCLAMATION_CIRCLE.getHtml() + "</div>";
|
||||
break;
|
||||
case STATUS_INPROGRESS:
|
||||
result = "<div class=\"statusIconActive\"></div>";
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Argument " + value + " wasn't expected.");
|
||||
}
|
||||
|
||||
return super.encode(result);
|
||||
}
|
||||
}
|
||||
|
||||
private void openWindow() {
|
||||
UI.getCurrent().addWindow(this);
|
||||
center();
|
||||
@@ -260,7 +203,7 @@ public class UploadProgressInfoWindow extends Window {
|
||||
/**
|
||||
* Called for every finished (succeeded or failed) upload.
|
||||
*/
|
||||
private void onUploadFinished() {
|
||||
public void onUploadFinished() {
|
||||
if (artifactUploadState.areAllUploadsFinished() && artifactUploadState.isStatusPopupMinimized()) {
|
||||
if (artifactUploadState.getFilesInFailedState().isEmpty()) {
|
||||
cleanupStates();
|
||||
@@ -272,7 +215,7 @@ public class UploadProgressInfoWindow extends Window {
|
||||
}
|
||||
|
||||
private void cleanupStates() {
|
||||
uploads.removeAllItems();
|
||||
uploads.clear();
|
||||
artifactUploadState.clearUploadTempData();
|
||||
}
|
||||
|
||||
@@ -283,7 +226,7 @@ public class UploadProgressInfoWindow extends Window {
|
||||
|
||||
private Button getCloseButton() {
|
||||
final Button closeBtn = SPUIComponentProvider.getButton(
|
||||
UIComponentIdProvider.UPLOAD_STATUS_POPUP_CLOSE_BUTTON_ID, "", "", "", true, FontAwesome.TIMES,
|
||||
UIComponentIdProvider.UPLOAD_STATUS_POPUP_CLOSE_BUTTON_ID, "", "", "", true, VaadinIcons.CLOSE,
|
||||
SPUIButtonStyleNoBorder.class);
|
||||
closeBtn.addStyleName(ValoTheme.BUTTON_BORDERLESS);
|
||||
closeBtn.addClickListener(event -> onClose());
|
||||
@@ -301,56 +244,7 @@ public class UploadProgressInfoWindow extends Window {
|
||||
|
||||
private void closeWindow() {
|
||||
setWindowMode(WindowMode.NORMAL);
|
||||
setColumnWidth();
|
||||
setPopupSizeInMinMode();
|
||||
this.close();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void updateUploadProgressInfoRowObject(final FileUploadProgress fileUploadProgress) {
|
||||
final FileUploadId fileUploadId = fileUploadProgress.getFileUploadId();
|
||||
Item item = uploads.getItem(fileUploadId);
|
||||
if (item == null) {
|
||||
item = grid.getContainerDataSource().addItem(fileUploadId);
|
||||
item.getItemProperty(COLUMN_FILE_NAME).setValue(fileUploadId.getFilename());
|
||||
item.getItemProperty(COLUMN_SOFTWARE_MODULE).setValue(HawkbitCommonUtil.getFormattedNameVersion(
|
||||
fileUploadId.getSoftwareModuleName(), fileUploadId.getSoftwareModuleVersion()));
|
||||
}
|
||||
|
||||
final String status;
|
||||
final FileUploadStatus uploadStatus = fileUploadProgress.getFileUploadStatus();
|
||||
if (uploadStatus == FileUploadStatus.UPLOAD_FAILED) {
|
||||
status = STATUS_FAILED;
|
||||
} else if (uploadStatus == FileUploadStatus.UPLOAD_SUCCESSFUL) {
|
||||
status = STATUS_FINISHED;
|
||||
} else {
|
||||
status = STATUS_INPROGRESS;
|
||||
}
|
||||
item.getItemProperty(COLUMN_STATUS).setValue(status);
|
||||
item.getItemProperty(COLUMN_REASON).setValue(getFailureReason(fileUploadId));
|
||||
|
||||
final long bytesRead = fileUploadProgress.getBytesRead();
|
||||
final long fileSize = fileUploadProgress.getContentLength();
|
||||
if (bytesRead > 0 && fileSize > 0) {
|
||||
item.getItemProperty(COLUMN_PROGRESS).setValue((double) bytesRead / (double) fileSize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.colorpicker;
|
||||
|
||||
import com.vaadin.shared.ui.colorpicker.Color;
|
||||
|
||||
/**
|
||||
* Provides color constants for the ColorPickerLayout
|
||||
*
|
||||
*/
|
||||
public final class ColorPickerConstants {
|
||||
|
||||
public static final String DEFAULT_COLOR = "rgb(44,151,32)";
|
||||
|
||||
public static final Color START_COLOR = new Color(0, 146, 58);
|
||||
|
||||
private ColorPickerConstants() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.colorpicker;
|
||||
|
||||
import org.eclipse.hawkbit.ui.management.tag.SpColorPickerPreview;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.vaadin.shared.ui.colorpicker.Color;
|
||||
import com.vaadin.ui.Slider.ValueOutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Contains helper methods for the ColorPickerLayout to handle the ColorPicker
|
||||
*
|
||||
*/
|
||||
public final class ColorPickerHelper {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ColorPickerHelper.class);
|
||||
|
||||
private ColorPickerHelper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get color picked value as string.
|
||||
*
|
||||
* @param preview
|
||||
* the color picker preview
|
||||
* @return String of color picked value.
|
||||
*/
|
||||
public static String getColorPickedString(final SpColorPickerPreview preview) {
|
||||
|
||||
final Color color = preview.getColor();
|
||||
return "rgb(" + color.getRed() + "," + color.getGreen() + "," + color.getBlue() + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Covert RGB code to {@link Color}.
|
||||
*
|
||||
* @param value
|
||||
* RGB vale
|
||||
* @return Color
|
||||
*/
|
||||
public static Color rgbToColorConverter(final String value) {
|
||||
|
||||
if (StringUtils.isEmpty(value) || (!StringUtils.isEmpty(value) && !value.startsWith("rgb"))) {
|
||||
throw new IllegalArgumentException(
|
||||
"String to convert is empty or of invalid format - value: '" + value + "'");
|
||||
}
|
||||
|
||||
// RGB color format rgb/rgba(255,255,255,0.1)
|
||||
final String[] colors = value.substring(value.indexOf('(') + 1, value.length() - 1).split(",");
|
||||
final int red = Integer.parseInt(colors[0]);
|
||||
final int green = Integer.parseInt(colors[1]);
|
||||
final int blue = Integer.parseInt(colors[2]);
|
||||
if (colors.length > 3) {
|
||||
final int alpha = (int) (Double.parseDouble(colors[3]) * 255D);
|
||||
return new Color(red, green, blue, alpha);
|
||||
}
|
||||
return new Color(red, green, blue);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Gets the selectedColor in the ColorPickerLayout and sets the slider
|
||||
* values
|
||||
*
|
||||
* @param colorPickerLayout
|
||||
* colorPickerLayout
|
||||
*/
|
||||
public static void setRgbSliderValues(final ColorPickerLayout colorPickerLayout) {
|
||||
|
||||
try {
|
||||
final double redColorValue = colorPickerLayout.getSelectedColor().getRed();
|
||||
colorPickerLayout.getRedSlider().setValue(Double.valueOf(redColorValue));
|
||||
final double blueColorValue = colorPickerLayout.getSelectedColor().getBlue();
|
||||
colorPickerLayout.getBlueSlider().setValue(Double.valueOf(blueColorValue));
|
||||
final double greenColorValue = colorPickerLayout.getSelectedColor().getGreen();
|
||||
colorPickerLayout.getGreenSlider().setValue(Double.valueOf(greenColorValue));
|
||||
} catch (final ValueOutOfBoundsException e) {
|
||||
LOG.error("Unable to set RGB color value to " + colorPickerLayout.getSelectedColor().getRed() + ","
|
||||
+ colorPickerLayout.getSelectedColor().getGreen() + ","
|
||||
+ colorPickerLayout.getSelectedColor().getBlue(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.colorpicker;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.CoordinatesToColor;
|
||||
import org.eclipse.hawkbit.ui.management.tag.SpColorPickerPreview;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
|
||||
import com.vaadin.shared.ui.colorpicker.Color;
|
||||
import com.vaadin.ui.AbstractColorPicker.Coordinates2Color;
|
||||
import com.vaadin.ui.GridLayout;
|
||||
import com.vaadin.ui.Slider;
|
||||
import com.vaadin.ui.components.colorpicker.ColorPickerGradient;
|
||||
import com.vaadin.ui.components.colorpicker.ColorSelector;
|
||||
|
||||
/**
|
||||
*
|
||||
* Defines the Layout for the ColorPicker
|
||||
*
|
||||
*/
|
||||
public class ColorPickerLayout extends GridLayout {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private SpColorPickerPreview selPreview;
|
||||
|
||||
private ColorPickerGradient colorSelect;
|
||||
|
||||
private Set<ColorSelector> selectors;
|
||||
|
||||
private Color selectedColor;
|
||||
|
||||
/** RGB color converter. */
|
||||
private final Coordinates2Color rgbConverter = new CoordinatesToColor();
|
||||
|
||||
private Slider redSlider;
|
||||
|
||||
private Slider greenSlider;
|
||||
|
||||
private Slider blueSlider;
|
||||
|
||||
public ColorPickerLayout() {
|
||||
|
||||
setColumns(2);
|
||||
setRows(4);
|
||||
setId(UIComponentIdProvider.COLOR_PICKER_LAYOUT);
|
||||
|
||||
init();
|
||||
|
||||
setStyleName("rgb-vertical-layout");
|
||||
|
||||
addComponent(redSlider, 0, 1);
|
||||
addComponent(greenSlider, 0, 2);
|
||||
addComponent(blueSlider, 0, 3);
|
||||
|
||||
addComponent(selPreview, 1, 0);
|
||||
addComponent(colorSelect, 1, 1, 1, 3);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
|
||||
selectors = new HashSet<>();
|
||||
selectedColor = getDefaultColor();
|
||||
selPreview = new SpColorPickerPreview(selectedColor);
|
||||
|
||||
colorSelect = new ColorPickerGradient("rgb-gradient", rgbConverter);
|
||||
colorSelect.setColor(selectedColor);
|
||||
colorSelect.setWidth("220px");
|
||||
|
||||
redSlider = createRGBSlider("", "red");
|
||||
redSlider.setId(UIComponentIdProvider.COLOR_PICKER_RED_SLIDER);
|
||||
greenSlider = createRGBSlider("", "green");
|
||||
blueSlider = createRGBSlider("", "blue");
|
||||
|
||||
selectors.add(colorSelect);
|
||||
}
|
||||
|
||||
private static Slider createRGBSlider(final String caption, final String styleName) {
|
||||
final Slider slider = new Slider(caption, 0, 255);
|
||||
slider.setImmediate(true);
|
||||
slider.setWidth("150px");
|
||||
slider.addStyleName(styleName);
|
||||
return slider;
|
||||
}
|
||||
|
||||
public SpColorPickerPreview getSelPreview() {
|
||||
return selPreview;
|
||||
}
|
||||
|
||||
public void setSelPreview(final SpColorPickerPreview selPreview) {
|
||||
this.selPreview = selPreview;
|
||||
}
|
||||
|
||||
public ColorPickerGradient getColorSelect() {
|
||||
return colorSelect;
|
||||
}
|
||||
|
||||
public void setColorSelect(final ColorPickerGradient colorSelect) {
|
||||
this.colorSelect = colorSelect;
|
||||
}
|
||||
|
||||
public Set<ColorSelector> getSelectors() {
|
||||
return selectors;
|
||||
}
|
||||
|
||||
public Color getSelectedColor() {
|
||||
return selectedColor;
|
||||
}
|
||||
|
||||
public void setSelectedColor(final Color selectedColor) {
|
||||
this.selectedColor = selectedColor;
|
||||
}
|
||||
|
||||
public Coordinates2Color getRgbConverter() {
|
||||
return rgbConverter;
|
||||
}
|
||||
|
||||
public Color getDefaultColor() {
|
||||
return new Color(44, 151, 32);
|
||||
}
|
||||
|
||||
public Slider getRedSlider() {
|
||||
return redSlider;
|
||||
}
|
||||
|
||||
public void setRedSlider(final Slider redSlider) {
|
||||
this.redSlider = redSlider;
|
||||
}
|
||||
|
||||
public Slider getGreenSlider() {
|
||||
return greenSlider;
|
||||
}
|
||||
|
||||
public void setGreenSlider(final Slider greenSlider) {
|
||||
this.greenSlider = greenSlider;
|
||||
}
|
||||
|
||||
public Slider getBlueSlider() {
|
||||
return blueSlider;
|
||||
}
|
||||
|
||||
public void setBlueSlider(final Slider blueSlider) {
|
||||
this.blueSlider = blueSlider;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common;
|
||||
|
||||
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 VaadinMessageSource i18n;
|
||||
|
||||
protected AbstractEntityWindowBuilder(final VaadinMessageSource i18n) {
|
||||
this.i18n = i18n;
|
||||
}
|
||||
|
||||
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(i18n)
|
||||
.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;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user