From 9f3ff406583781b2ea1660fd9f4740718408ab35 Mon Sep 17 00:00:00 2001 From: Bondar Bogdan <36962546+bogdan-bondar@users.noreply.github.com> Date: Fri, 21 Aug 2020 16:57:00 +0200 Subject: [PATCH] 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 --- hawkbit-autoconfigure/pom.xml | 9 + .../mgmt/ui/MgmtUiAutoConfiguration.java | 27 +- .../mgmt/ui/RedirectController.java | 4 +- ...MemoryUserManagementAutoConfiguration.java | 4 +- .../SecurityManagedConfiguration.java | 97 +- .../repository/SoftwareModuleManagement.java | 17 +- .../repository/TargetTagManagement.java | 10 + .../remote/entity/AbstractActionEvent.java | 12 +- .../remote/entity/ActionCreatedEvent.java | 6 +- .../remote/entity/ActionUpdatedEvent.java | 6 +- .../SoftwareModuleTypeUpdatedEvent.java | 4 +- .../model/AssignedSoftwareModule.java | 11 +- .../repository/model/DistributionSetType.java | 40 +- .../repository/model/SoftwareModuleType.java | 28 +- .../model/TargetWithActionStatus.java | 8 +- .../hawkbit/repository/model/Type.java | 42 + ...stractDistributionSetTypeUpdateCreate.java | 8 - .../jpa/DefaultRolloutApprovalStrategy.java | 62 +- .../jpa/JpaDistributionSetManagement.java | 11 +- .../jpa/JpaDistributionSetTypeManagement.java | 51 +- .../repository/jpa/JpaRolloutManagement.java | 7 +- .../jpa/JpaSoftwareModuleManagement.java | 105 +- .../repository/jpa/JpaTargetManagement.java | 39 +- .../jpa/JpaTargetTagManagement.java | 5 + .../repository/jpa/TargetTagRepository.java | 5 + .../repository/jpa/model/JpaAction.java | 10 +- .../DistributionSetSpecification.java | 40 +- .../specifications/TargetSpecifications.java | 33 +- .../entity/AbstractRemoteEntityEventTest.java | 32 +- .../event/remote/entity/ActionEventTest.java | 32 +- .../remote/entity/RolloutGroupEventTest.java | 31 +- .../java/org/eclipse/hawkbit/app/MyUI.java | 13 +- .../hawkbit-boot-starter-mgmt-ui/pom.xml | 12 - hawkbit-ui/pom.xml | 37 +- .../eclipse/hawkbit/ui/AbstractHawkbitUI.java | 68 +- .../eclipse/hawkbit/ui/AppWidgetSet.gwt.xml | 13 +- .../ui/AsyncVaadinServletConfiguration.java | 18 + .../org/eclipse/hawkbit/ui/ErrorView.java | 15 +- .../ui/HawkbitEntityEventListener.java | 176 +++ .../ui/LocalizedSystemMessagesProvider.java | 4 +- .../hawkbit/ui/SpPermissionChecker.java | 9 + .../org/eclipse/hawkbit/ui/UiProperties.java | 199 ++- .../{state => }/ArtifactUploadState.java | 216 ++-- .../ui/artifacts/UploadArtifactView.java | 334 ++--- .../artifacts/UploadArtifactViewMenuItem.java | 11 +- .../artifacts/details/ArtifactBeanQuery.java | 113 -- .../details/ArtifactDetailsGrid.java | 238 ++++ .../details/ArtifactDetailsGridHeader.java | 95 ++ .../details/ArtifactDetailsGridLayout.java | 148 +++ .../ArtifactDetailsGridLayoutUiState.java | 35 + .../details/ArtifactDetailsLayout.java | 606 --------- .../RefreshSoftwareModuleByFilterEvent.java | 20 - .../artifacts/event/SoftwareModuleEvent.java | 99 -- .../event/SoftwareModuleTypeEvent.java | 51 - .../event/UploadArtifactUIEvent.java | 19 - .../smtable/AddSmWindowController.java | 146 +++ .../smtable/BaseSwModuleBeanQuery.java | 133 -- .../smtable/ProxyBaseSoftwareModuleItem.java | 140 -- .../SmMetaDataAddUpdateWindowLayout.java | 46 + .../smtable/SmMetaDataWindowBuilder.java | 93 ++ .../smtable/SmMetaDataWindowLayout.java | 143 +++ .../ui/artifacts/smtable/SmWindowBuilder.java | 96 ++ .../ui/artifacts/smtable/SmWindowLayout.java | 105 ++ .../SmWindowLayoutComponentBuilder.java | 116 ++ .../SoftwareModuleAddUpdateWindow.java | 317 ----- .../smtable/SoftwareModuleDetails.java | 55 - .../artifacts/smtable/SoftwareModuleGrid.java | 305 +++++ .../smtable/SoftwareModuleGridHeader.java | 108 ++ .../smtable/SoftwareModuleGridLayout.java | 191 +++ .../smtable/SoftwareModuleTable.java | 255 ---- .../smtable/SoftwareModuleTableHeader.java | 97 -- .../smtable/SoftwareModuleTableLayout.java | 59 - .../smtable/UpdateSmWindowController.java | 133 ++ .../AbstractSoftwareModuleTypeLayout.java | 196 --- .../smtype/AddSmTypeWindowController.java | 121 ++ .../CreateSoftwareModuleTypeLayout.java | 92 -- .../artifacts/smtype/SmTypeWindowBuilder.java | 88 ++ .../artifacts/smtype/SmTypeWindowLayout.java | 73 ++ .../SmTypeWindowLayoutComponentBuilder.java | 76 ++ .../smtype/UpdateSmTypeWindowController.java | 162 +++ .../UpdateSoftwareModuleTypeLayout.java | 132 -- .../filter/SMTypeFilterButtonClick.java | 55 - .../smtype/filter/SMTypeFilterButtons.java | 181 +-- .../smtype/filter/SMTypeFilterHeader.java | 156 +-- .../smtype/filter/SMTypeFilterLayout.java | 97 +- .../state/SoftwareModuleFilters.java | 50 - .../upload/AbstractFileTransferHandler.java | 48 +- .../FileTransferHandlerStreamVariable.java | 24 +- .../FileTransferHandlerVaadinUpload.java | 13 +- .../ui/artifacts/upload/FileUploadId.java | 20 + .../artifacts/upload/FileUploadProgress.java | 29 + .../upload/UploadDropAreaLayout.java | 196 +-- .../ui/artifacts/upload/UploadFixed.java | 9 + .../upload/UploadProgressButtonLayout.java | 105 +- .../artifacts/upload/UploadProgressGrid.java | 85 ++ .../upload/UploadProgressInfoWindow.java | 276 ++-- .../ui/colorpicker/ColorPickerConstants.java | 26 - .../ui/colorpicker/ColorPickerHelper.java | 94 -- .../ui/colorpicker/ColorPickerLayout.java | 155 --- .../common/AbstractEntityWindowBuilder.java | 86 ++ .../AbstractEntityWindowController.java | 76 ++ .../ui/common/AbstractEntityWindowLayout.java | 54 + .../common/AbstractMetadataPopupLayout.java | 534 -------- .../AbstractMetadataPopupLayoutVersioned.java | 44 - .../hawkbit/ui/common/CommonDialogWindow.java | 460 ++----- .../hawkbit/ui/common/ConfirmationDialog.java | 306 ++--- .../hawkbit/ui/common/CoordinatesToColor.java | 15 +- .../common/DistributionSetTypeBeanQuery.java | 87 -- .../ui/common/EmptyStringValidator.java | 43 - .../hawkbit/ui/common/EntityWindowLayout.java | 36 + .../ui/common/ManagementEntityState.java | 35 - .../common/SoftwareModuleTypeBeanQuery.java | 75 -- .../ui/common/UserDetailsFormatter.java | 3 + .../builder/AbstractTextFieldBuilder.java | 69 +- .../ui/common/builder/BoundComponent.java | 78 ++ .../ui/common/builder/ComboBoxBuilder.java | 72 -- .../common/builder/FormComponentBuilder.java | 414 ++++++ .../common/builder/GridComponentBuilder.java | 429 +++++++ .../ui/common/builder/LabelBuilder.java | 9 +- .../ui/common/builder/StatusIconBuilder.java | 551 ++++++++ .../ui/common/builder/TextAreaBuilder.java | 6 +- .../ui/common/builder/TextFieldBuilder.java | 26 +- .../ui/common/builder/WindowBuilder.java | 62 +- .../confirmwindow/layout/ConfirmationTab.java | 33 - .../ui/common/data/aware/ActionTypeAware.java | 24 + .../common/data/aware/DescriptionAware.java | 18 + .../ui/common/data/aware/DsIdAware.java | 18 + .../data/aware/NameAware.java} | 14 +- .../common/data/aware/StartOptionAware.java | 24 + .../data/aware/TargetFilterQueryAware.java | 22 + .../ui/common/data/aware/TypeInfoAware.java | 20 + .../ui/common/data/aware/VersionAware.java | 18 + .../filters/DsDistributionsFilterParams.java | 80 ++ .../filters/DsManagementFilterParams.java | 124 ++ .../common/data/filters/SwFilterParams.java | 106 ++ .../filters/TargetManagementFilterParams.java | 261 ++++ ...ctNamedEntityToProxyNamedEntityMapper.java | 37 + ...ActionStatusToProxyActionStatusMapper.java | 31 + .../mappers/ActionToProxyActionMapper.java | 71 ++ ...dRolloutGroupDefinitionToCreateMapper.java | 60 + .../ArtifactToProxyArtifactMapper.java | 36 + .../AssignedSoftwareModuleToProxyMapper.java | 40 + ...tributionSetToProxyDistributionMapper.java | 43 + ...EntityToProxyIdentifiableEntityMapper.java | 35 + .../NamedEntityToProxyNamedEntityMapper.java | 36 + ...olloutGroupToAdvancedDefinitionMapper.java | 88 ++ ...RolloutGroupToProxyRolloutGroupMapper.java | 74 ++ .../mappers/RolloutToProxyRolloutMapper.java | 59 + .../mappers/SoftwareModuleToProxyMapper.java | 41 + .../data/mappers/TagToProxyTagMapper.java | 34 + ...tFilterQueryToProxyTargetFilterMapper.java | 48 + .../mappers/TargetToProxyTargetMapper.java | 66 + ...etWithActionStatusToProxyTargetMapper.java | 49 + .../data/mappers/TypeToProxyTypeMapper.java | 36 + .../data/mappers/TypeToTypeInfoMapper.java | 29 + .../AbstractGenericDataProvider.java | 88 ++ .../AbstractMetaDataDataProvider.java | 55 + .../providers/AbstractProxyDataProvider.java | 66 + .../data/providers/ActionDataProvider.java | 67 + .../providers/ActionStatusDataProvider.java | 66 + .../ActionStatusMsgDataProvider.java | 110 ++ .../data/providers/ArtifactDataProvider.java | 64 + ...tionSetDistributionsStateDataProvider.java | 73 ++ ...ibutionSetManagementStateDataProvider.java | 73 ++ .../DistributionSetStatelessDataProvider.java | 65 + .../DistributionSetTagDataProvider.java | 55 + .../DistributionSetTypeDataProvider.java | 59 + .../providers/DsMetaDataDataProvider.java | 56 + .../data/providers/RolloutDataProvider.java | 64 + .../providers/RolloutGroupDataProvider.java | 62 + .../RolloutGroupTargetsDataProvider.java | 62 + .../providers/SmMetaDataDataProvider.java | 64 + .../providers/SoftwareModuleDataProvider.java | 97 ++ .../SoftwareModuleTypeDataProvider.java | 59 + .../TargetFilterQueryDataProvider.java | 64 + .../TargetFilterQueryDetailsDataProvider.java | 63 + .../TargetFilterStateDataProvider.java | 65 + .../TargetManagementStateDataProvider.java | 111 ++ .../providers/TargetMetaDataDataProvider.java | 58 + .../data/providers/TargetTagDataProvider.java | 55 + .../data/proxies}/ProxyAction.java | 190 ++- .../data/proxies}/ProxyActionStatus.java | 30 +- .../proxies/ProxyAdvancedRolloutGroup.java | 133 ++ .../ui/common/data/proxies/ProxyArtifact.java | 140 ++ .../data/proxies/ProxyAssignmentWindow.java | 145 +++ .../data/proxies/ProxyBulkUploadWindow.java | 83 ++ .../data/proxies/ProxyDistributionSet.java | 154 +++ .../data/proxies/ProxyFilterButton.java | 47 + .../data/proxies/ProxyIdNameVersion.java | 75 ++ .../data/proxies/ProxyIdentifiableEntity.java | 93 ++ .../data/proxies/ProxyKeyValueDetails.java | 62 + .../data/proxies/ProxyLoginCredentials.java | 80 ++ .../data/proxies}/ProxyMessage.java | 32 +- .../ui/common/data/proxies/ProxyMetaData.java | 135 ++ .../common/data/proxies/ProxyNamedEntity.java | 181 +++ .../ui/common/data/proxies/ProxyRollout.java | 291 +++++ .../data/proxies/ProxyRolloutApproval.java | 62 + .../common/data/proxies/ProxyRolloutForm.java | 147 +++ .../data/proxies}/ProxyRolloutGroup.java | 235 ++-- .../data/proxies/ProxyRolloutWindow.java | 469 +++++++ .../ProxySimpleRolloutGroupsDefinition.java | 81 ++ .../data/proxies/ProxySoftwareModule.java | 132 ++ .../proxies/ProxySoftwareModuleDetails.java | 95 ++ .../data/proxies/ProxySystemConfigWindow.java | 489 +++++++ .../ui/common/data/proxies/ProxyTag.java | 92 ++ .../ui/common/data/proxies/ProxyTarget.java | 209 +++ .../proxies/ProxyTargetAttributesDetails.java | 69 + .../data/proxies/ProxyTargetFilterQuery.java | 136 ++ .../ui/common/data/proxies/ProxyType.java | 175 +++ .../ui/common/data/proxies/ProxyTypeInfo.java | 78 ++ .../data/proxies/ProxyUploadProgress.java | 115 ++ .../AbstractDistributionSetDetails.java | 229 ---- .../AbstractGridDetailsLayout.java | 176 +++ .../AbstractMetaDataWindowBuilder.java | 71 ++ .../AbstractMetaDataWindowLayout.java | 247 ++++ .../AbstractMetadataDetailsLayout.java | 98 -- ...amedVersionedEntityTableDetailsLayout.java | 38 - .../AbstractSoftwareModuleDetails.java | 176 --- .../AbstractTableDetailsLayout.java | 369 ------ .../AddMetaDataWindowController.java | 107 ++ .../ArtifactDetailsHeaderSupport.java | 80 ++ .../detailslayout/DistributionSetDetails.java | 213 ++++ .../DistributionSetDetailsHeader.java | 115 ++ .../DistributionSetMetadataDetailsLayout.java | 80 -- .../EditDetailsHeaderSupport.java | 80 ++ .../KeyValueDetailsComponent.java | 113 ++ .../MetaDataAddUpdateWindowLayout.java | 73 ++ ...AddUpdateWindowLayoutComponentBuilder.java | 98 ++ .../MetaDataDetailsHeaderSupport.java | 81 ++ .../detailslayout/MetaDataWindowGrid.java | 102 ++ .../detailslayout/MetadataDetailsGrid.java | 115 ++ .../MetadataWindowGridHeader.java | 70 + .../detailslayout/SoftwareModuleDetails.java | 130 ++ .../SoftwareModuleDetailsGrid.java | 316 +++++ .../SoftwareModuleDetailsHeader.java | 210 +++ .../SoftwareModuleDetailsTable.java | 271 ---- .../SoftwareModuleMetadataDetailsLayout.java | 84 -- .../TargetFilterQueryDetailsGrid.java | 85 ++ .../TargetFilterQueryDetailsTable.java | 97 -- .../TargetMetadataDetailsLayout.java | 79 -- .../UpdateMetaDataWindowController.java | 115 ++ .../common/entity/DistributionSetIdName.java | 100 -- .../common/entity/SoftwareModuleIdName.java | 99 -- .../ui/common/entity/TargetIdName.java | 109 -- .../event/ActionsVisibilityEventPayload.java | 47 + .../common/event/BulkUploadEventPayload.java | 163 +++ .../ui/common/event/CommandTopics.java | 23 + .../DistributionSetTagFilterHeaderEvent.java | 28 - .../DistributionSetTypeFilterHeaderEvent.java | 28 - .../event/EntityDraggingEventPayload.java | 53 + .../event/EntityModifiedEventPayload.java | 211 ++++ .../EntityModifiedEventPayloadIdentifier.java | 175 +++ .../hawkbit/ui/common/event/EventLayout.java | 16 + .../ui/common/event/EventLayoutViewAware.java | 103 ++ .../hawkbit/ui/common/event/EventTopics.java | 27 + .../event/EventView.java} | 12 +- .../ui/common/event/EventViewAware.java | 69 + .../event/FilterChangedEventPayload.java | 65 + .../ui/common/event/FilterHeaderEvent.java | 41 - .../event/FilterType.java} | 12 +- .../event/LayoutResizeEventPayload.java | 46 + .../event/LayoutVisibilityEventPayload.java | 46 + .../event/PinningChangedEventPayload.java | 69 + .../event/SelectionChangedEventPayload.java | 62 + .../ui/common/event/ShowFormEventPayload.java | 146 +++ .../SoftwareModuleTypeFilterHeaderEvent.java | 28 - .../TargetFilterTabChangedEventPayload.java} | 11 +- .../event/TargetTagFilterHeaderEvent.java | 28 - .../AbstractFilterButtonClickBehaviour.java | 48 +- .../filterlayout/AbstractFilterButtons.java | 470 ++----- .../filterlayout/AbstractFilterHeader.java | 231 ---- .../filterlayout/AbstractFilterLayout.java | 66 +- .../AbstractFilterMultiButtonClick.java | 93 +- .../AbstractFilterSingleButtonClick.java | 69 +- .../AbstractTagFilterButtons.java | 231 ++++ .../AbstractTypeFilterButtons.java | 166 +++ .../filterlayout/TagFilterButtonClick.java | 48 + .../filterlayout/TypeFilterButtonClick.java | 42 + .../ui/common/grid/AbstractDsGrid.java | 142 +++ .../hawkbit/ui/common/grid/AbstractGrid.java | 762 +++-------- .../grid/AbstractGridComponentLayout.java | 217 ---- .../ui/common/grid/AbstractGridHeader.java | 284 ----- .../ui/common/grid/DefaultGridHeader.java | 280 ---- .../header/AbstractBreadcrumbGridHeader.java | 133 ++ .../grid/header/AbstractDetailsHeader.java | 132 ++ .../grid/header/AbstractEntityGridHeader.java | 211 ++++ .../grid/header/AbstractFilterHeader.java | 126 ++ .../grid/header/AbstractGridHeader.java | 129 ++ .../header/AbstractMasterAwareGridHeader.java | 115 ++ .../grid/header/support/AddHeaderSupport.java | 92 ++ .../support/BulkUploadHeaderSupport.java | 128 ++ .../header/support/CloseHeaderSupport.java | 64 + .../header/support/CrudMenuHeaderSupport.java | 183 +++ .../DistributionSetFilterDropAreaSupport.java | 222 ++++ .../support/FilterButtonsHeaderSupport.java | 99 ++ .../grid/header/support/HeaderSupport.java | 41 + .../header/support/ResizeHeaderSupport.java | 121 ++ .../header/support/SearchHeaderSupport.java | 194 +++ .../RangeSelectionGridDragSource.java | 65 + .../RangeSelectionGridRowDragger.java | 46 + .../grid/selection/RangeSelectionModel.java | 157 +++ .../selection/RangeSelectionWidgetset.gwt.xml | 21 + .../client/RangeDragSourceConnector.java | 59 + .../client/RangeDragSourceSelectionState.java | 41 + .../client/RangeSelectionHandler.java | 129 ++ .../client/RangeSelectionModelConnector.java | 51 + .../client/RangeSelectionServerRpc.java | 38 + .../selection/client/RangeSelectionState.java | 43 + .../ui/common/grid/support/DeleteSupport.java | 180 +++ .../grid/support/DragAndDropSupport.java | 279 ++++ .../ui/common/grid/support/FilterSupport.java | 218 ++++ .../grid/support/MasterEntitySupport.java | 78 ++ .../ui/common/grid/support/PinSupport.java | 297 +++++ .../common/grid/support/SelectionSupport.java | 358 ++++++ .../support/assignment/AssignmentSupport.java | 143 +++ .../DeploymentAssignmentSupport.java | 81 ++ ...istributionSetsToTagAssignmentSupport.java | 93 ++ ...ributionSetsToTargetAssignmentSupport.java | 114 ++ ...agsToDistributionSetAssignmentSupport.java | 84 ++ ...lesToDistributionSetAssignmentSupport.java | 202 +++ .../assignment/TagsAssignmentSupport.java | 54 + ...agsToDistributionSetAssignmentSupport.java | 91 ++ .../TargetTagsToTargetAssignmentSupport.java | 80 ++ ...etsToDistributionSetAssignmentSupport.java | 91 ++ .../TargetsToTagAssignmentSupport.java | 90 ++ .../assignment/ToTagAssignmentSupport.java | 51 + .../common/layout/AbstractFooterSupport.java | 43 + .../layout/AbstractGridComponentLayout.java | 143 +++ .../layout/MasterEntityAwareComponent.java | 27 + .../listener/BulkUploadChangedListener.java | 49 + .../listener/EntityDraggingListener.java | 61 + .../listener/EntityModifiedListener.java | 226 ++++ .../listener/FilterChangedListener.java | 67 + .../layout/listener/GenericEventListener.java | 46 + .../GridActionsVisibilityListener.java | 66 + .../layout/listener/LayoutResizeListener.java | 98 ++ .../listener/LayoutViewAwareListener.java | 78 ++ .../listener/LayoutVisibilityListener.java | 98 ++ .../listener/PinningChangedListener.java | 64 + .../listener/SelectGridEntityListener.java | 53 + .../listener/SelectionChangedListener.java | 72 ++ .../ShowEntityFormLayoutListener.java | 109 ++ .../layout/listener/TopicEventListener.java | 61 + .../layout/listener/ViewAwareListener.java | 69 + .../support/EntityModifiedGenericSupport.java | 81 ++ ...EntityModifiedGridRefreshAwareSupport.java | 82 ++ .../EntityModifiedPinAwareSupport.java | 142 +++ .../EntityModifiedSelectionAwareSupport.java | 176 +++ .../EntityModifiedTagTokenAwareSupport.java | 68 + .../notification/ParallelNotification.java | 86 ++ .../ParallelNotificationWidgetset.gwt.xml | 20 + .../client/ParallelNotificationConnector.java | 105 ++ .../ui/common/state/GridLayoutUiState.java | 73 ++ .../ui/common/state/HidableLayoutUiState.java | 37 + .../common/state/TagFilterLayoutUiState.java | 57 + .../common/state/TypeFilterLayoutUiState.java | 35 + .../common/table/AbstractBaseViewFilter.java | 34 - .../AbstractDistributionSetTableHeader.java | 123 -- .../table/AbstractNamedVersionTable.java | 83 -- .../AbstractSoftwareModuleTableHeader.java | 143 --- .../ui/common/table/AbstractTable.java | 660 ---------- .../ui/common/table/AbstractTableHeader.java | 574 --------- .../ui/common/table/AbstractTableLayout.java | 151 --- .../ui/common/table/BaseUIEntityEvent.java | 107 -- .../hawkbit/ui/common/table/BaseUIEvent.java | 33 - .../common/tagdetails/AbstractTagToken.java | 198 ++- .../tagdetails/AbstractTargetTagToken.java | 72 -- .../tagdetails/DistributionTagToken.java | 142 +-- .../tagdetails/TagAssignementComboBox.java | 154 ++- .../hawkbit/ui/common/tagdetails/TagData.java | 90 -- .../ui/common/tagdetails/TagListField.java | 139 +- .../ui/common/tagdetails/TagPanelLayout.java | 71 +- .../ui/common/tagdetails/TargetTagToken.java | 118 +- .../components/AbstractNotificationView.java | 182 --- .../ui/components/ColorPickerComponent.java | 178 +++ .../hawkbit/ui/components/ConfigMenuBar.java | 116 -- .../components/DistributionSetInfoPanel.java | 93 -- .../HawkbitErrorNotificationMessage.java | 50 - .../ui/components/HawkbitUIErrorHandler.java | 36 +- .../components/NotificationUnreadButton.java | 233 ++-- .../ui/components/ProxyDistribution.java | 159 --- .../hawkbit/ui/components/ProxyTarget.java | 212 ---- .../ui/components/ProxyTargetFilter.java | 112 -- .../components/SPTargetAttributesLayout.java | 68 - .../hawkbit/ui/components/SPUIButton.java | 2 +- .../hawkbit/ui/components/SPUICheckBox.java | 70 - .../ui/components/SPUIComponentProvider.java | 368 ++---- .../hawkbit/ui/components/SPUITabSheet.java | 38 - .../CustomRendererWidgetSet.gwt.xml | 27 - .../client/GridButtonRendererConnector.java | 37 - .../client/HtmlButtonRendererConnector.java | 28 - .../client/HtmlLabelRendererConnector.java | 31 - .../client/RolloutRendererConnector.java | 38 - .../client/renderers/FontIconData.java | 120 -- .../client/renderers/GridButtonRenderer.java | 61 - .../client/renderers/HtmlButtonRenderer.java | 67 - .../client/renderers/HtmlLabelRenderer.java | 71 -- .../client/renderers/RolloutRenderer.java | 64 - .../client/renderers/RolloutRendererData.java | 59 - .../AbstractGridButtonConverter.java | 101 -- .../renderers/AbstractHtmlLabelConverter.java | 147 --- .../renderers/GridButtonRenderer.java | 59 - .../renderers/HtmlButtonRenderer.java | 37 - .../renderers/HtmlLabelRenderer.java | 28 - .../renderers/RolloutRenderer.java | 59 - .../ui/dd/CustomAcceptCriteria.gwt.xml | 38 - .../criteria/ItemIdClientCriterion.java | 64 - .../client/criteria/ViewClientCriterion.java | 310 ----- .../ViewComponentClientCriterion.java | 170 --- .../dd/criteria/AcceptCriteriaConstants.java | 91 -- .../DistributionsViewClientCriterion.java | 59 - .../ManagementViewClientCriterion.java | 79 -- .../criteria/ServerItemIdClientCriterion.java | 127 -- .../criteria/ServerViewClientCriterion.java | 89 -- .../ServerViewComponentClientCriterion.java | 208 --- .../criteria/UploadViewClientCriterion.java | 50 - .../ui/decorators/SPUIComboBoxDecorator.java | 86 -- .../ui/decorators/SPUITagButtonStyle.java | 7 +- .../ui/distributions/DistributionsView.java | 392 +++--- .../DistributionsViewMenuItem.java | 11 +- .../ui/distributions/ManageDistUIState.java | 66 + .../AbstractDistributionSetTypeLayout.java | 141 --- .../disttype/AddDsTypeWindowController.java | 123 ++ .../CreateDistributionSetTypeLayout.java | 107 -- ...tionSetTypeSoftwareModuleSelectLayout.java | 331 ----- .../disttype/DsTypeSmSelectLayout.java | 184 +++ .../disttype/DsTypeWindowBuilder.java | 87 ++ .../disttype/DsTypeWindowLayout.java | 84 ++ .../DsTypeWindowLayoutComponentBuilder.java | 62 + .../disttype/SmTypeSelectedGrid.java | 87 ++ .../disttype/SmTypeSourceGrid.java | 65 + .../UpdateDistributionSetTypeLayout.java | 213 ---- .../UpdateDsTypeWindowController.java | 203 +++ .../filter/DSTypeFilterButtonClick.java | 53 - .../disttype/filter/DSTypeFilterButtons.java | 192 +-- .../disttype/filter/DSTypeFilterHeader.java | 144 +-- .../disttype/filter/DSTypeFilterLayout.java | 105 +- .../dstable/AddDsWindowController.java | 136 ++ .../dstable/DistributionSetDetails.java | 200 --- .../dstable/DistributionSetGrid.java | 127 ++ .../dstable/DistributionSetGridHeader.java | 107 ++ .../dstable/DistributionSetGridLayout.java | 221 ++++ .../dstable/DistributionSetTable.java | 541 -------- .../dstable/DistributionSetTableHeader.java | 110 -- .../dstable/DistributionSetTableLayout.java | 74 -- .../dstable/DsMetaDataWindowBuilder.java | 93 ++ .../dstable/DsMetaDataWindowLayout.java | 137 ++ .../dstable/DsMetadataPopupLayout.java | 89 -- .../dstable/DsWindowBuilder.java | 108 ++ .../distributions/dstable/DsWindowLayout.java | 112 ++ .../DsWindowLayoutComponentBuilder.java | 120 ++ .../dstable/ManageDistBeanQuery.java | 169 --- .../dstable/UpdateDsWindowController.java | 137 ++ .../event/DistributionSetTypeEvent.java | 67 - .../event/DistributionsUIEvent.java | 21 - .../event/SaveActionWindowEvent.java | 20 - .../smtable/ProxyBaseSwModuleItem.java | 44 - .../smtable/SwMetadataPopupLayout.java | 191 --- .../smtable/SwModuleBeanQuery.java | 137 -- .../smtable/SwModuleDetails.java | 139 -- .../smtable/SwModuleGridLayout.java | 196 +++ .../distributions/smtable/SwModuleTable.java | 344 ----- .../smtable/SwModuleTableHeader.java | 93 -- .../smtable/SwModuleTableLayout.java | 64 - .../filter/DistSMTypeFilterButtonClick.java | 54 - .../filter/DistSMTypeFilterButtons.java | 209 --- .../smtype/filter/DistSMTypeFilterHeader.java | 129 -- .../smtype/filter/DistSMTypeFilterLayout.java | 109 +- .../smtype/filter/SmTypeCssStylesHandler.java | 75 ++ .../state/ManageDistFilters.java | 69 - .../state/ManageDistUIState.java | 208 --- .../state/ManageSoftwareModuleFilters.java | 62 - .../AddTargetFilterController.java | 115 ++ .../AutoAssignmentWindowBuilder.java | 97 ++ .../AutoAssignmentWindowController.java | 166 +++ .../AutoAssignmentWindowLayout.java | 89 ++ ...ssignmentWindowLayoutComponentBuilder.java | 109 ++ .../AutoCompleteTextFieldComponent.java | 293 ++--- .../CreateOrUpdateFilterHeader.java | 427 ------- .../CreateOrUpdateFilterTable.java | 248 ---- .../CustomTargetBeanQuery.java | 162 --- .../DistributionSetSelectComboBox.java | 336 ----- .../DistributionSetSelectWindow.java | 308 ----- .../FilterManagementView.java | 194 ++- .../FilterManagementViewMenuItem.java | 11 +- .../TargetFilterAddUpdateLayout.java | 219 ++++ ...FilterAddUpdateLayoutComponentBuilder.java | 124 ++ .../TargetFilterBeanQuery.java | 151 --- .../TargetFilterCountMessageLabel.java | 64 + .../TargetFilterDetailsGridHeader.java | 200 +++ .../TargetFilterDetailsLayout.java | 113 ++ .../ui/filtermanagement/TargetFilterGrid.java | 222 ++++ .../TargetFilterGridHeader.java | 104 ++ .../TargetFilterGridLayout.java | 108 ++ .../filtermanagement/TargetFilterHeader.java | 193 --- .../filtermanagement/TargetFilterTable.java | 315 ----- .../TargetFilterTargetGrid.java | 87 ++ .../TextFieldSuggestionBox.gwt.xml | 14 +- .../TextFieldSuggestionBox.java | 23 +- .../UpdateTargetFilterController.java | 139 ++ .../AutoCompleteTextFieldConnector.java | 7 +- .../client/SuggestTokenDto.java | 27 + .../client/SuggestionContextDto.java | 23 +- .../client/SuggestionsSelectList.java | 12 +- .../TextFieldSuggestionBoxServerRpc.java | 14 +- .../event/CustomFilterUIEvent.java | 19 - .../footer/TargetFilterCountMessageLabel.java | 92 -- .../state/FilterManagementUIState.java | 138 +- .../TargetFilterDetailsLayoutUiState.java | 116 ++ .../state/TargetFilterGridLayoutUiState.java | 37 + .../hawkbit/ui/layouts/AbstractTagLayout.java | 569 --------- .../ui/layouts/AbstractTypeLayout.java | 189 --- .../eclipse/hawkbit/ui/layouts/UpdateTag.java | 26 - .../ui/login/AbstractHawkbitLoginUI.java | 480 +++---- .../ui/management/CountMessageLabel.java | 236 ++-- .../hawkbit/ui/management/DeploymentView.java | 619 ++++----- .../ui/management/DeploymentViewMenuItem.java | 9 +- .../ui/management/ManagementUIState.java | 94 ++ .../TargetAssignmentOperations.java | 292 ----- .../actionhistory/ActionBeanQuery.java | 185 --- .../actionhistory/ActionHistoryGrid.java | 949 +++++--------- .../ActionHistoryGridHeader.java | 95 ++ .../ActionHistoryGridLayout.java | 123 ++ .../ActionHistoryGridLayoutUiState.java | 37 + .../actionhistory/ActionHistoryLayout.java | 250 +--- .../actionhistory/ActionStatusBeanQuery.java | 151 --- .../actionhistory/ActionStatusGrid.java | 168 +-- .../actionhistory/ActionStatusGridHeader.java | 39 + .../actionhistory/ActionStatusGridLayout.java | 109 ++ .../actionhistory/ActionStatusIconMapper.java | 77 -- .../actionhistory/ActionStatusLayout.java | 55 - .../ActionStatusMsgBeanQuery.java | 152 --- .../actionhistory/ActionStatusMsgGrid.java | 227 ++-- .../ActionStatusMsgGridHeader.java | 40 + .../ActionStatusMsgGridLayout.java | 92 ++ .../actionhistory/ActionStatusMsgLayout.java | 55 - .../HtmlStatusLabelConverter.java | 35 - .../bulkupload/BulkUploadHandler.java | 396 ++++++ .../bulkupload/BulkUploadWindowBuilder.java | 142 +++ ...ulkUploadWindowLayoutComponentBuilder.java | 83 ++ .../bulkupload/TargetBulkTokenTags.java | 90 ++ .../TargetBulkUpdateWindowLayout.java | 400 ++++++ .../bulkupload/TargetBulkUploadUiState.java | 95 ++ .../DistributionAddUpdateWindowLayout.java | 385 ------ .../dstable/DistributionBeanQuery.java | 192 --- .../dstable/DistributionDetails.java | 64 - .../management/dstable/DistributionGrid.java | 245 ++++ .../dstable/DistributionGridLayout.java | 231 ++++ .../DistributionGridLayoutUiState.java | 37 + .../management/dstable/DistributionTable.java | 755 ----------- .../dstable/DistributionTableHeader.java | 104 -- .../dstable/DistributionTableLayout.java | 73 -- .../AbstractDistributionSetTagLayout.java | 84 -- .../dstag/AddDsTagWindowController.java | 106 ++ .../dstag/CreateDistributionSetTagLayout.java | 85 -- .../management/dstag/DsTagWindowBuilder.java | 76 ++ .../dstag/UpdateDistributionSetTagLayout.java | 123 -- .../dstag/UpdateDsTagWindowController.java | 137 ++ .../filter/DistributionTagBeanQuery.java | 97 -- .../filter/DistributionTagButtonClick.java | 57 - .../dstag/filter/DistributionTagButtons.java | 194 +-- .../filter/DistributionTagFilterHeader.java | 157 +-- .../dstag/filter/DistributionTagLayout.java | 125 +- .../BulkUploadValidationMessageEvent.java | 35 - .../event/DistributionSetTagTableEvent.java | 46 - .../event/DistributionTableEvent.java | 57 - .../event/DistributionTagDropEvent.java | 165 --- .../management/event/ManagementUIEvent.java | 53 - ...RefreshDistributionTableByFilterEvent.java | 20 - .../event/SaveActionWindowEvent.java | 19 - .../event/TargetAddUpdateWindowEvent.java | 35 - .../management/event/TargetFilterEvent.java | 37 - .../ui/management/event/TargetTableEvent.java | 82 -- .../management/event/TargetTagTableEvent.java | 46 - .../AbstractActionTypeOptionGroupLayout.java | 159 +-- ...ActionTypeOptionGroupAssignmentLayout.java | 102 +- ...onTypeOptionGroupAutoAssignmentLayout.java | 24 +- .../miscs/AssignmentWindowLayout.java | 142 +++ ...ssignmentWindowLayoutComponentBuilder.java | 211 ++++ .../DeploymentAssignmentWindowController.java | 199 +++ .../miscs/MaintenanceWindowLayout.java | 304 +---- .../state/DistributionTableFilters.java | 77 -- .../management/state/ManagementUIState.java | 249 ---- .../ui/management/state/TargetBulkUpload.java | 84 -- .../management/state/TargetTableFilters.java | 179 --- .../hawkbit/ui/management/tag/ProxyTag.java | 80 -- .../management/tag/SpColorPickerPreview.java | 106 -- .../hawkbit/ui/management/tag/TagIdName.java | 47 - .../ui/management/tag/TagWindowLayout.java | 90 ++ .../tag/TagWindowLayoutComponentBuilder.java | 120 ++ .../AddTargetWindowController.java | 127 ++ .../targettable/BulkUploadHandler.java | 403 ------ .../TargetAddUpdateWindowLayout.java | 221 ---- .../TargetAttributesDetailsComponent.java | 142 +++ .../targettable/TargetBeanQuery.java | 232 ---- .../targettable/TargetBulkTokenTags.java | 84 -- .../TargetBulkUpdateWindowLayout.java | 425 ------- .../management/targettable/TargetDetails.java | 450 +++---- .../targettable/TargetDetailsHeader.java | 114 ++ .../ui/management/targettable/TargetGrid.java | 389 ++++++ .../targettable/TargetGridHeader.java | 255 ++++ .../targettable/TargetGridLayout.java | 272 ++++ .../targettable/TargetGridLayoutUiState.java | 74 ++ .../TargetMetaDataWindowBuilder.java | 93 ++ .../TargetMetaDataWindowLayout.java | 139 ++ .../TargetMetadataPopupLayout.java | 88 -- .../management/targettable/TargetTable.java | 991 --------------- .../targettable/TargetTableHeader.java | 438 ------- .../targettable/TargetTableLayout.java | 64 - .../targettable/TargetWindowBuilder.java | 82 ++ .../targettable/TargetWindowLayout.java | 80 ++ .../TargetWindowLayoutComponentBuilder.java | 87 ++ .../UpdateTargetWindowController.java | 137 ++ .../targettag/AbstractTargetTagLayout.java | 85 -- .../AddTargetTagWindowController.java | 106 ++ .../targettag/CreateTargetTagLayout.java | 86 -- .../targettag/TargetTagWindowBuilder.java | 76 ++ .../targettag/UpdateTargetTagLayout.java | 120 -- .../UpdateTargetTagWindowController.java | 136 ++ .../filter/AbstractTargetTagFilterLayout.java | 74 -- .../CustomTargetTagFilterButtonClick.java | 66 +- .../filter/FilterByStatusLayout.java | 426 +++---- .../filter/MultipleTargetFilter.java | 308 ++--- .../filter/TargetFilterQueryButtons.java | 276 ++-- .../targettag/filter/TargetTagBeanQuery.java | 103 -- .../filter/TargetTagFilterButtonClick.java | 75 -- .../filter/TargetTagFilterButtons.java | 319 +---- .../filter/TargetTagFilterHeader.java | 117 +- .../filter/TargetTagFilterLayout.java | 99 +- .../filter/TargetTagFilterLayoutUiState.java | 97 ++ ...AbstractDashboardMenuItemNotification.java | 10 +- .../hawkbit/ui/menu/DashboardMenu.java | 38 +- .../hawkbit/ui/menu/DashboardMenuItem.java | 4 - .../CancelTargetAssignmentEventContainer.java | 31 - .../ui/push/DelayedEventBusPushStrategy.java | 229 ++-- .../DistributionSetCreatedEventContainer.java | 37 - .../DistributionSetDeletedEventContainer.java | 37 - ...stributionSetTagCreatedEventContainer.java | 37 - ...stributionSetTagDeletedEventContainer.java | 37 - ...stributionSetTagUpdatedEventContainer.java | 37 - .../DistributionSetUpdatedEventContainer.java | 31 - .../hawkbit/ui/push/EventContainer.java | 40 - .../push/HawkbitEventPermissionChecker.java | 95 ++ .../hawkbit/ui/push/HawkbitEventProvider.java | 115 +- .../ui/push/RolloutChangeEventContainer.java | 31 - .../ui/push/RolloutDeletedEventContainer.java | 31 - .../RolloutGroupChangedEventContainer.java | 31 - .../SoftwareModuleCreatedEventContainer.java | 38 - .../SoftwareModuleDeletedEventContainer.java | 37 - .../SoftwareModuleUpdatedEventContainer.java | 32 - .../ui/push/TargetCreatedEventContainer.java | 38 - .../ui/push/TargetDeletedEventContainer.java | 37 - .../push/TargetTagCreatedEventContainer.java | 37 - .../push/TargetTagDeletedEventContainer.java | 37 - .../push/TargetTagUpdatedEventContainer.java | 37 - .../ui/push/TargetUpdatedEventContainer.java | 31 - .../ui/push/UIEventPermissionChecker.java | 29 + .../hawkbit/ui/push/UIEventProvider.java | 5 +- .../ui/push/event/ActionChangedEvent.java | 55 + .../event/ParentIdAwareEvent.java} | 13 +- .../ui/push/event/RolloutChangedEvent.java | 70 +- .../push/event/RolloutGroupChangedEvent.java | 93 +- .../ui/push/event/TenantAwareUiEvent.java | 67 - .../ui/rollout/DistributionBarHelper.java | 40 +- .../hawkbit/ui/rollout/ProxyFontIcon.java | 128 ++ .../ui/rollout/RolloutManagementUIState.java | 138 ++ .../hawkbit/ui/rollout/RolloutView.java | 252 ++-- .../ui/rollout/RolloutViewMenuItem.java | 11 +- .../hawkbit/ui/rollout/StatusFontIcon.java | 147 --- .../groupschart/GroupsPieChart.gwt.xml | 14 +- .../rollout/groupschart/GroupsPieChart.java | 6 +- .../client/GroupsPieChartState.java | 18 + .../client/GroupsPieChartWidget.java | 46 +- .../rollout/AddUpdateRolloutWindowLayout.java | 1121 ----------------- .../rollout/AutoStartOptionGroupLayout.java | 164 --- .../rollout/rollout/DefineGroupsLayout.java | 660 ---------- .../rollout/DistributionBeanQuery.java | 144 --- .../ui/rollout/rollout/ProxyRollout.java | 248 ---- .../ui/rollout/rollout/RolloutBeanQuery.java | 162 --- .../ui/rollout/rollout/RolloutGrid.java | 443 +++++++ .../ui/rollout/rollout/RolloutGridHeader.java | 91 ++ .../ui/rollout/rollout/RolloutGridLayout.java | 138 ++ .../ui/rollout/rollout/RolloutListGrid.java | 885 ------------- .../ui/rollout/rollout/RolloutListHeader.java | 146 --- .../ui/rollout/rollout/RolloutListView.java | 95 -- .../rolloutgroup/RolloutGroupBeanQuery.java | 197 --- .../rolloutgroup/RolloutGroupGrid.java | 217 ++++ .../rolloutgroup/RolloutGroupGridHeader.java | 83 ++ .../rolloutgroup/RolloutGroupGridLayout.java | 109 ++ .../rolloutgroup/RolloutGroupListGrid.java | 382 ------ .../rolloutgroup/RolloutGroupsListHeader.java | 168 --- .../rolloutgroup/RolloutGroupsListView.java | 71 -- .../RolloutGroupTargetGrid.java | 108 ++ .../RolloutGroupTargetGridHeader.java | 109 ++ .../RolloutGroupTargetGridLayout.java | 101 ++ .../RolloutGroupTargetsBeanQuery.java | 190 --- .../RolloutGroupTargetsCountLabelMessage.java | 94 -- .../RolloutGroupTargetsListGrid.java | 293 ----- .../RolloutGroupTargetsListHeader.java | 181 --- .../RolloutGroupTargetsListView.java | 62 - .../ui/rollout/state/RolloutUIState.java | 199 --- .../rollout/window/RolloutWindowBuilder.java | 90 ++ .../window/RolloutWindowDependencies.java | 161 +++ .../RolloutWindowLayoutComponentBuilder.java | 142 +++ .../window/components/AdvancedGroupRow.java | 214 ++++ .../components/AdvancedGroupsLayout.java | 388 ++++++ .../window/components/ApprovalLayout.java | 140 ++ .../AutoStartOptionGroupLayout.java | 144 +++ .../components}/GroupsLegendLayout.java | 110 +- .../window/components/RolloutFormLayout.java | 324 +++++ .../window/components/SimpleGroupsLayout.java | 378 ++++++ .../window/components/ValidatableLayout.java | 91 ++ .../VisualGroupDefinitionLayout.java | 177 +++ .../AddRolloutWindowController.java | 170 +++ .../ApproveRolloutWindowController.java | 65 + .../CopyRolloutWindowController.java | 114 ++ .../UpdateRolloutWindowController.java | 183 +++ .../layouts/AbstractRolloutWindowLayout.java | 129 ++ .../layouts/AddRolloutWindowLayout.java | 215 ++++ .../layouts/ApproveRolloutWindowLayout.java | 78 ++ .../layouts/UpdateRolloutWindowLayout.java | 99 ++ .../AuthenticationConfigurationView.java | 146 +-- .../DefaultDistributionSetTypeLayout.java | 118 +- .../PollingConfigurationView.java | 121 +- .../RepositoryConfigurationView.java | 169 +-- .../RolloutConfigurationView.java | 62 +- .../TenantConfigurationDashboardView.java | 246 +++- ...antConfigurationDashboardViewMenuItem.java | 11 +- ...wnloadAuthenticationConfigurationItem.java | 55 +- ...ficateAuthenticationConfigurationItem.java | 120 +- ...yTokenAuthenticationConfigurationItem.java | 151 +-- ...yTokenAuthenticationConfigurationItem.java | 59 +- ...bstractBooleanTenantConfigurationItem.java | 7 +- .../polling/DurationConfigField.java | 154 +-- .../polling/DurationField.java | 242 ++-- .../ActionAutoCleanupConfigurationItem.java | 195 +++ .../ActionAutoCloseConfigurationItem.java | 34 + .../ActionAutocleanupConfigurationItem.java | 321 ----- .../ActionAutocloseConfigurationItem.java | 65 - .../MultiAssignmentsConfigurationItem.java | 93 +- .../rollout/ApprovalConfigurationItem.java | 53 +- .../SystemConfigWindowDependencies.java | 88 ++ ...temConfigWindowLayoutComponentBuilder.java | 73 ++ .../AssignInstalledDSTooltipGenerator.java | 83 -- .../hawkbit/ui/utils/HawkbitCommonUtil.java | 550 ++------ .../hawkbit/ui/utils/NotificationMessage.java | 76 -- .../hawkbit/ui/utils/SPDateTimeUtil.java | 91 +- .../hawkbit/ui/utils/SPUIDefinitions.java | 68 +- .../ui/utils/SPUILabelDefinitions.java | 31 - .../ui/utils/SPUIStyleDefinitions.java | 79 +- .../eclipse/hawkbit/ui/utils/TableColumn.java | 62 - .../ui/utils/UIComponentIdProvider.java | 381 ++++-- .../hawkbit/ui/utils/UIMessageIdProvider.java | 58 +- .../hawkbit/ui/utils/UINotification.java | 97 +- .../hawkbit/ui/utils/VaadinMessageSource.java | 2 + .../OnlyEventsFromDeploymentViewFilter.java | 24 - ...OnlyEventsFromDistributionsViewFilter.java | 24 - ...nlyEventsFromUploadArtifactViewFilter.java | 24 - .../resources/VAADIN/js/dynamicStylesheet.js | 31 + .../hawkbit/customstyles/accordion.scss | 4 + .../hawkbit/customstyles/action-history.scss | 11 - .../hawkbit/customstyles/artifact-upload.scss | 5 +- .../themes/hawkbit/customstyles/common.scss | 11 +- .../hawkbit/customstyles/drop-hint.scss | 34 +- .../customstyles/filter-layout-styles.scss | 24 +- .../hawkbit/customstyles/generic-styles.scss | 71 +- .../themes/hawkbit/customstyles/grid.scss | 114 +- .../customstyles/hawkbitvariables.scss | 12 +- .../themes/hawkbit/customstyles/others.scss | 198 ++- .../hawkbit/customstyles/popup-common.scss | 5 +- .../hawkbit/customstyles/popup-window.scss | 98 +- .../customstyles/statusprogressbar.scss | 63 +- .../hawkbit/customstyles/systemconfig.scss | 4 + .../hawkbit/customstyles/table-common.scss | 39 +- .../customstyles/table-header-common.scss | 5 - .../themes/hawkbit/customstyles/tags.scss | 121 +- .../customstyles/target-filter-query.scss | 23 +- .../VAADIN/themes/hawkbit/hawkbittheme.scss | 12 +- .../src/main/resources/messages.properties | 234 ++-- .../state/ArtifactUploadStateTest.java | 6 +- .../client/criteria/CriterionTestHelper.java | 68 - .../criteria/ItemIdClientCriterionTest.java | 139 -- .../criteria/ViewClientCriterionTest.java | 241 ---- .../ViewComponentClientCriterionTest.java | 241 ---- .../ui/login/AbstractHawkbitLoginUITest.java | 36 - pom.xml | 81 +- 786 files changed, 49027 insertions(+), 46609 deletions(-) create mode 100644 hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Type.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEntityEventListener.java rename hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/{state => }/ArtifactUploadState.java (68%) delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactBeanQuery.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGrid.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridLayoutUiState.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/RefreshSoftwareModuleByFilterEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/SoftwareModuleEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/SoftwareModuleTypeEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadArtifactUIEvent.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/AddSmWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/BaseSwModuleBeanQuery.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/ProxyBaseSoftwareModuleItem.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataAddUpdateWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataWindowBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmWindowBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmWindowLayoutComponentBuilder.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleAddUpdateWindow.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleDetails.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGrid.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGridLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTable.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTableHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTableLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/UpdateSmWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/AbstractSoftwareModuleTypeLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/AddSmTypeWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/CreateSoftwareModuleTypeLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SmTypeWindowBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SmTypeWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SmTypeWindowLayoutComponentBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/UpdateSmTypeWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/UpdateSoftwareModuleTypeLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterButtonClick.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/SoftwareModuleFilters.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadProgressGrid.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerConstants.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerHelper.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEntityWindowBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEntityWindowController.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEntityWindowLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractMetadataPopupLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractMetadataPopupLayoutVersioned.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/DistributionSetTypeBeanQuery.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/EmptyStringValidator.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/EntityWindowLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/ManagementEntityState.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/SoftwareModuleTypeBeanQuery.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/BoundComponent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/ComboBoxBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/FormComponentBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/GridComponentBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/StatusIconBuilder.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/confirmwindow/layout/ConfirmationTab.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/aware/ActionTypeAware.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/aware/DescriptionAware.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/aware/DsIdAware.java rename hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/{artifacts/event/ArtifactDetailsEvent.java => common/data/aware/NameAware.java} (56%) create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/aware/StartOptionAware.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/aware/TargetFilterQueryAware.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/aware/TypeInfoAware.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/aware/VersionAware.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/filters/DsDistributionsFilterParams.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/filters/DsManagementFilterParams.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/filters/SwFilterParams.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/filters/TargetManagementFilterParams.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/AbstractNamedEntityToProxyNamedEntityMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/ActionStatusToProxyActionStatusMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/ActionToProxyActionMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/AdvancedRolloutGroupDefinitionToCreateMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/ArtifactToProxyArtifactMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/AssignedSoftwareModuleToProxyMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/DistributionSetToProxyDistributionMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/IdentifiableEntityToProxyIdentifiableEntityMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/NamedEntityToProxyNamedEntityMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/RolloutGroupToAdvancedDefinitionMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/RolloutGroupToProxyRolloutGroupMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/RolloutToProxyRolloutMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/SoftwareModuleToProxyMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/TagToProxyTagMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/TargetFilterQueryToProxyTargetFilterMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/TargetToProxyTargetMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/TargetWithActionStatusToProxyTargetMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/TypeToProxyTypeMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/mappers/TypeToTypeInfoMapper.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/AbstractGenericDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/AbstractMetaDataDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/AbstractProxyDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/ActionDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/ActionStatusDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/ActionStatusMsgDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/ArtifactDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/DistributionSetDistributionsStateDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/DistributionSetManagementStateDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/DistributionSetStatelessDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/DistributionSetTagDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/DistributionSetTypeDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/DsMetaDataDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/RolloutDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/RolloutGroupDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/RolloutGroupTargetsDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/SmMetaDataDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/SoftwareModuleDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/SoftwareModuleTypeDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/TargetFilterQueryDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/TargetFilterQueryDetailsDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/TargetFilterStateDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/TargetManagementStateDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/TargetMetaDataDataProvider.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/providers/TargetTagDataProvider.java rename hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/{management/actionhistory => common/data/proxies}/ProxyAction.java (58%) rename hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/{management/actionhistory => common/data/proxies}/ProxyActionStatus.java (71%) create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyAdvancedRolloutGroup.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyArtifact.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyAssignmentWindow.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyBulkUploadWindow.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyDistributionSet.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyFilterButton.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyIdNameVersion.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyIdentifiableEntity.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyKeyValueDetails.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyLoginCredentials.java rename hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/{management/actionhistory => common/data/proxies}/ProxyMessage.java (53%) create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyMetaData.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyNamedEntity.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyRollout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyRolloutApproval.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyRolloutForm.java rename hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/{rollout/rolloutgroup => common/data/proxies}/ProxyRolloutGroup.java (65%) create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyRolloutWindow.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxySimpleRolloutGroupsDefinition.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxySoftwareModule.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxySoftwareModuleDetails.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxySystemConfigWindow.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyTag.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyTarget.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyTargetAttributesDetails.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyTargetFilterQuery.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyType.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyTypeInfo.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/data/proxies/ProxyUploadProgress.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractDistributionSetDetails.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractGridDetailsLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractMetaDataWindowBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractMetaDataWindowLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractMetadataDetailsLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractNamedVersionedEntityTableDetailsLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractSoftwareModuleDetails.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AbstractTableDetailsLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/AddMetaDataWindowController.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/ArtifactDetailsHeaderSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetDetails.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetDetailsHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetMetadataDetailsLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/EditDetailsHeaderSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/KeyValueDetailsComponent.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/MetaDataAddUpdateWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/MetaDataAddUpdateWindowLayoutComponentBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/MetaDataDetailsHeaderSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/MetaDataWindowGrid.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/MetadataDetailsGrid.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/MetadataWindowGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleDetails.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleDetailsGrid.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleDetailsHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleDetailsTable.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleMetadataDetailsLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/TargetFilterQueryDetailsGrid.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/TargetFilterQueryDetailsTable.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/TargetMetadataDetailsLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/UpdateMetaDataWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/entity/DistributionSetIdName.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/entity/SoftwareModuleIdName.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/entity/TargetIdName.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/ActionsVisibilityEventPayload.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/BulkUploadEventPayload.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/CommandTopics.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/DistributionSetTagFilterHeaderEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/DistributionSetTypeFilterHeaderEvent.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/EntityDraggingEventPayload.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/EntityModifiedEventPayload.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/EntityModifiedEventPayloadIdentifier.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/EventLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/EventLayoutViewAware.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/EventTopics.java rename hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/{management/event/PinUnpinEvent.java => common/event/EventView.java} (55%) create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/EventViewAware.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/FilterChangedEventPayload.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/FilterHeaderEvent.java rename hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/{management/event/BulkUploadPopupEvent.java => common/event/FilterType.java} (52%) create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/LayoutResizeEventPayload.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/LayoutVisibilityEventPayload.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/PinningChangedEventPayload.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/SelectionChangedEventPayload.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/ShowFormEventPayload.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/SoftwareModuleTypeFilterHeaderEvent.java rename hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/{table/BaseEntityEventType.java => event/TargetFilterTabChangedEventPayload.java} (50%) delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/event/TargetTagFilterHeaderEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractFilterHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractTagFilterButtons.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/AbstractTypeFilterButtons.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/TagFilterButtonClick.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/filterlayout/TypeFilterButtonClick.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/AbstractDsGrid.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/AbstractGridComponentLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/AbstractGridHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/DefaultGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/AbstractBreadcrumbGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/AbstractDetailsHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/AbstractEntityGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/AbstractFilterHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/AbstractGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/AbstractMasterAwareGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/AddHeaderSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/BulkUploadHeaderSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/CloseHeaderSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/CrudMenuHeaderSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/DistributionSetFilterDropAreaSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/FilterButtonsHeaderSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/HeaderSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/ResizeHeaderSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/header/support/SearchHeaderSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/selection/RangeSelectionGridDragSource.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/selection/RangeSelectionGridRowDragger.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/selection/RangeSelectionModel.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/selection/RangeSelectionWidgetset.gwt.xml create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/selection/client/RangeDragSourceConnector.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/selection/client/RangeDragSourceSelectionState.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/selection/client/RangeSelectionHandler.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/selection/client/RangeSelectionModelConnector.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/selection/client/RangeSelectionServerRpc.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/selection/client/RangeSelectionState.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/DeleteSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/DragAndDropSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/FilterSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/MasterEntitySupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/PinSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/SelectionSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/assignment/AssignmentSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/assignment/DeploymentAssignmentSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/assignment/DistributionSetsToTagAssignmentSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/assignment/DistributionSetsToTargetAssignmentSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/assignment/DsTagsToDistributionSetAssignmentSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/assignment/SwModulesToDistributionSetAssignmentSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/assignment/TagsAssignmentSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/assignment/TargetTagsToDistributionSetAssignmentSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/assignment/TargetTagsToTargetAssignmentSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/assignment/TargetsToDistributionSetAssignmentSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/assignment/TargetsToTagAssignmentSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/grid/support/assignment/ToTagAssignmentSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/AbstractFooterSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/AbstractGridComponentLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/MasterEntityAwareComponent.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/BulkUploadChangedListener.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/EntityDraggingListener.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/EntityModifiedListener.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/FilterChangedListener.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/GenericEventListener.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/GridActionsVisibilityListener.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/LayoutResizeListener.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/LayoutViewAwareListener.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/LayoutVisibilityListener.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/PinningChangedListener.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/SelectGridEntityListener.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/SelectionChangedListener.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/ShowEntityFormLayoutListener.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/TopicEventListener.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/ViewAwareListener.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/support/EntityModifiedGenericSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/support/EntityModifiedGridRefreshAwareSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/support/EntityModifiedPinAwareSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/support/EntityModifiedSelectionAwareSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/layout/listener/support/EntityModifiedTagTokenAwareSupport.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/notification/ParallelNotification.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/notification/ParallelNotificationWidgetset.gwt.xml create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/notification/client/ParallelNotificationConnector.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/state/GridLayoutUiState.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/state/HidableLayoutUiState.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/state/TagFilterLayoutUiState.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/state/TypeFilterLayoutUiState.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/table/AbstractBaseViewFilter.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/table/AbstractDistributionSetTableHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/table/AbstractNamedVersionTable.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/table/AbstractSoftwareModuleTableHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/table/AbstractTable.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/table/AbstractTableHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/table/AbstractTableLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/table/BaseUIEntityEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/table/BaseUIEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/AbstractTargetTagToken.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/tagdetails/TagData.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/AbstractNotificationView.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/ColorPickerComponent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/ConfigMenuBar.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/DistributionSetInfoPanel.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/HawkbitErrorNotificationMessage.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/ProxyDistribution.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/ProxyTarget.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/ProxyTargetFilter.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/SPTargetAttributesLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/SPUICheckBox.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/SPUITabSheet.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/CustomRendererWidgetSet.gwt.xml delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/client/GridButtonRendererConnector.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/client/HtmlButtonRendererConnector.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/client/HtmlLabelRendererConnector.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/client/RolloutRendererConnector.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/client/renderers/FontIconData.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/client/renderers/GridButtonRenderer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/client/renderers/HtmlButtonRenderer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/client/renderers/HtmlLabelRenderer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/client/renderers/RolloutRenderer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/client/renderers/RolloutRendererData.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/renderers/AbstractGridButtonConverter.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/renderers/AbstractHtmlLabelConverter.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/renderers/GridButtonRenderer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/renderers/HtmlButtonRenderer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/renderers/HtmlLabelRenderer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/customrenderers/renderers/RolloutRenderer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/dd/CustomAcceptCriteria.gwt.xml delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/dd/client/criteria/ItemIdClientCriterion.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/dd/client/criteria/ViewClientCriterion.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/dd/client/criteria/ViewComponentClientCriterion.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/dd/criteria/AcceptCriteriaConstants.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/dd/criteria/DistributionsViewClientCriterion.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/dd/criteria/ManagementViewClientCriterion.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/dd/criteria/ServerItemIdClientCriterion.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/dd/criteria/ServerViewClientCriterion.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/dd/criteria/ServerViewComponentClientCriterion.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/dd/criteria/UploadViewClientCriterion.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/decorators/SPUIComboBoxDecorator.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/ManageDistUIState.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/AbstractDistributionSetTypeLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/AddDsTypeWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/CreateDistributionSetTypeLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/DistributionSetTypeSoftwareModuleSelectLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/DsTypeSmSelectLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/DsTypeWindowBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/DsTypeWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/DsTypeWindowLayoutComponentBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/SmTypeSelectedGrid.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/SmTypeSourceGrid.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/UpdateDistributionSetTypeLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/UpdateDsTypeWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/disttype/filter/DSTypeFilterButtonClick.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/AddDsWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetDetails.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetGrid.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetGridLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTableHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTableLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetaDataWindowBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetaDataWindowLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetadataPopupLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsWindowBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsWindowLayoutComponentBuilder.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/ManageDistBeanQuery.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/UpdateDsWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/event/DistributionSetTypeEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/event/DistributionsUIEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/event/SaveActionWindowEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/ProxyBaseSwModuleItem.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwMetadataPopupLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwModuleBeanQuery.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwModuleDetails.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwModuleGridLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwModuleTable.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwModuleTableHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwModuleTableLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtype/filter/DistSMTypeFilterButtonClick.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtype/filter/DistSMTypeFilterButtons.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtype/filter/DistSMTypeFilterHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtype/filter/SmTypeCssStylesHandler.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/state/ManageDistFilters.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/state/ManageDistUIState.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/state/ManageSoftwareModuleFilters.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/AddTargetFilterController.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/AutoAssignmentWindowBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/AutoAssignmentWindowController.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/AutoAssignmentWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/AutoAssignmentWindowLayoutComponentBuilder.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CreateOrUpdateFilterHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CreateOrUpdateFilterTable.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/CustomTargetBeanQuery.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/DistributionSetSelectComboBox.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/DistributionSetSelectWindow.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterAddUpdateLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterAddUpdateLayoutComponentBuilder.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterBeanQuery.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterCountMessageLabel.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterDetailsGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterDetailsLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterGrid.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterGridLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterTable.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/TargetFilterTargetGrid.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/UpdateTargetFilterController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/event/CustomFilterUIEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/footer/TargetFilterCountMessageLabel.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/state/TargetFilterDetailsLayoutUiState.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/filtermanagement/state/TargetFilterGridLayoutUiState.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/layouts/AbstractTagLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/layouts/AbstractTypeLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/layouts/UpdateTag.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/ManagementUIState.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/TargetAssignmentOperations.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionBeanQuery.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionHistoryGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionHistoryGridLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionHistoryGridLayoutUiState.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusBeanQuery.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusGridLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusIconMapper.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusMsgBeanQuery.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusMsgGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusMsgGridLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/ActionStatusMsgLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/actionhistory/HtmlStatusLabelConverter.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/bulkupload/BulkUploadHandler.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/bulkupload/BulkUploadWindowBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/bulkupload/BulkUploadWindowLayoutComponentBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/bulkupload/TargetBulkTokenTags.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/bulkupload/TargetBulkUpdateWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/bulkupload/TargetBulkUploadUiState.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionAddUpdateWindowLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionBeanQuery.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionDetails.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionGrid.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionGridLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionGridLayoutUiState.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTable.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTableHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstable/DistributionTableLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/AbstractDistributionSetTagLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/AddDsTagWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/CreateDistributionSetTagLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/DsTagWindowBuilder.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/UpdateDistributionSetTagLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/UpdateDsTagWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagBeanQuery.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/dstag/filter/DistributionTagButtonClick.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/BulkUploadValidationMessageEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/DistributionSetTagTableEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/DistributionTableEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/DistributionTagDropEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/ManagementUIEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/RefreshDistributionTableByFilterEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/SaveActionWindowEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/TargetAddUpdateWindowEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/TargetFilterEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/TargetTableEvent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/event/TargetTagTableEvent.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/miscs/AssignmentWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/miscs/AssignmentWindowLayoutComponentBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/miscs/DeploymentAssignmentWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/state/DistributionTableFilters.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/state/ManagementUIState.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/state/TargetBulkUpload.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/state/TargetTableFilters.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/tag/ProxyTag.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/tag/SpColorPickerPreview.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/tag/TagIdName.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/tag/TagWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/tag/TagWindowLayoutComponentBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/AddTargetWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/BulkUploadHandler.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetAddUpdateWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetAttributesDetailsComponent.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBeanQuery.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBulkTokenTags.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetBulkUpdateWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetDetailsHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGrid.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetGridLayoutUiState.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetMetaDataWindowBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetMetaDataWindowLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetMetadataPopupLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTable.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTableHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetTableLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetWindowBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/TargetWindowLayoutComponentBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettable/UpdateTargetWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/AbstractTargetTagLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/AddTargetTagWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/CreateTargetTagLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/TargetTagWindowBuilder.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/UpdateTargetTagLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/UpdateTargetTagWindowController.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/AbstractTargetTagFilterLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/TargetTagBeanQuery.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/TargetTagFilterButtonClick.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/management/targettag/filter/TargetTagFilterLayoutUiState.java rename hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/{management => menu}/AbstractDashboardMenuItemNotification.java (84%) delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/CancelTargetAssignmentEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/DistributionSetCreatedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/DistributionSetDeletedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/DistributionSetTagCreatedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/DistributionSetTagDeletedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/DistributionSetTagUpdatedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/DistributionSetUpdatedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/EventContainer.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/HawkbitEventPermissionChecker.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/RolloutChangeEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/RolloutDeletedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/RolloutGroupChangedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/SoftwareModuleCreatedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/SoftwareModuleDeletedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/SoftwareModuleUpdatedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/TargetCreatedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/TargetDeletedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/TargetTagCreatedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/TargetTagDeletedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/TargetTagUpdatedEventContainer.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/TargetUpdatedEventContainer.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/UIEventPermissionChecker.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/event/ActionChangedEvent.java rename hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/{components/RefreshableContainer.java => push/event/ParentIdAwareEvent.java} (51%) delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/push/event/TenantAwareUiEvent.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/ProxyFontIcon.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/RolloutManagementUIState.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/StatusFontIcon.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/AddUpdateRolloutWindowLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/AutoStartOptionGroupLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/DefineGroupsLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/DistributionBeanQuery.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/ProxyRollout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutBeanQuery.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutGrid.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutGridLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutListGrid.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutListHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rollout/RolloutListView.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupBeanQuery.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupGrid.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupGridLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupListGrid.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupsListHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgroup/RolloutGroupsListView.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetGrid.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetGridHeader.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetGridLayout.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsBeanQuery.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsCountLabelMessage.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsListGrid.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsListHeader.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/rolloutgrouptargets/RolloutGroupTargetsListView.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/state/RolloutUIState.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/RolloutWindowBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/RolloutWindowDependencies.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/RolloutWindowLayoutComponentBuilder.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/components/AdvancedGroupRow.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/components/AdvancedGroupsLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/components/ApprovalLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/components/AutoStartOptionGroupLayout.java rename hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/{rollout => window/components}/GroupsLegendLayout.java (70%) create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/components/RolloutFormLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/components/SimpleGroupsLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/components/ValidatableLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/components/VisualGroupDefinitionLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/controllers/AddRolloutWindowController.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/controllers/ApproveRolloutWindowController.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/controllers/CopyRolloutWindowController.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/controllers/UpdateRolloutWindowController.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/layouts/AbstractRolloutWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/layouts/AddRolloutWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/layouts/ApproveRolloutWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/rollout/window/layouts/UpdateRolloutWindowLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/repository/ActionAutoCleanupConfigurationItem.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/repository/ActionAutoCloseConfigurationItem.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/repository/ActionAutocleanupConfigurationItem.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/repository/ActionAutocloseConfigurationItem.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/window/SystemConfigWindowDependencies.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/window/SystemConfigWindowLayoutComponentBuilder.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/AssignInstalledDSTooltipGenerator.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/NotificationMessage.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/utils/TableColumn.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/filter/OnlyEventsFromDeploymentViewFilter.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/filter/OnlyEventsFromDistributionsViewFilter.java delete mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/view/filter/OnlyEventsFromUploadArtifactViewFilter.java create mode 100644 hawkbit-ui/src/main/resources/VAADIN/js/dynamicStylesheet.js delete mode 100644 hawkbit-ui/src/test/java/org/eclipse/hawkbit/ui/dd/client/criteria/CriterionTestHelper.java delete mode 100644 hawkbit-ui/src/test/java/org/eclipse/hawkbit/ui/dd/client/criteria/ItemIdClientCriterionTest.java delete mode 100644 hawkbit-ui/src/test/java/org/eclipse/hawkbit/ui/dd/client/criteria/ViewClientCriterionTest.java delete mode 100644 hawkbit-ui/src/test/java/org/eclipse/hawkbit/ui/dd/client/criteria/ViewComponentClientCriterionTest.java delete mode 100644 hawkbit-ui/src/test/java/org/eclipse/hawkbit/ui/login/AbstractHawkbitLoginUITest.java diff --git a/hawkbit-autoconfigure/pom.xml b/hawkbit-autoconfigure/pom.xml index 1cd89aa38..a2c0ede90 100644 --- a/hawkbit-autoconfigure/pom.xml +++ b/hawkbit-autoconfigure/pom.xml @@ -91,5 +91,14 @@ protostuff-runtime true + + org.vaadin.spring.extensions + vaadin-spring-ext-security + + + javax.servlet + javax.servlet-api + provided + diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/MgmtUiAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/MgmtUiAutoConfiguration.java index a14657b32..3c3a210d9 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/MgmtUiAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/MgmtUiAutoConfiguration.java @@ -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; } diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/RedirectController.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/RedirectController.java index 3871dad01..9fd9049e3 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/RedirectController.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/mgmt/ui/RedirectController.java @@ -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/"); } diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/InMemoryUserManagementAutoConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/InMemoryUserManagementAutoConfiguration.java index 6ecf9c1f6..4e5c68237 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/InMemoryUserManagementAutoConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/InMemoryUserManagementAutoConfiguration.java @@ -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"; diff --git a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java index 655a8bc1c..1bb4ae651 100644 --- a/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java +++ b/hawkbit-autoconfigure/src/main/java/org/eclipse/hawkbit/autoconfigure/security/SecurityManagedConfiguration.java @@ -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 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 { diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleManagement.java index 00b4d4c7d..5e83a0424 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/SoftwareModuleManagement.java @@ -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 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()} diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTagManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTagManagement.java index 6376f06b4..a4fc90e62 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTagManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetTagManagement.java @@ -155,6 +155,16 @@ public interface TargetTagManagement { @PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET) Optional 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 get(@NotEmpty Collection ids); + /** * updates the {@link TargetTag}. * diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/AbstractActionEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/AbstractActionEvent.java index 386016337..583e78a09 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/AbstractActionEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/AbstractActionEvent.java @@ -16,6 +16,7 @@ import org.eclipse.hawkbit.repository.model.Action; public abstract class AbstractActionEvent extends RemoteEntityEvent { 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 { * * @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 { * @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; } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionCreatedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionCreatedEvent.java index 859e90615..681fd987f 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionCreatedEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionCreatedEvent.java @@ -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); } } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionUpdatedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionUpdatedEvent.java index e3a9fae93..6ebfda76a 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionUpdatedEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionUpdatedEvent.java @@ -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); } } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/SoftwareModuleTypeUpdatedEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/SoftwareModuleTypeUpdatedEvent.java index fc3a6c207..ca4f07b71 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/SoftwareModuleTypeUpdatedEvent.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/entity/SoftwareModuleTypeUpdatedEvent.java @@ -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 { +public class SoftwareModuleTypeUpdatedEvent extends RemoteEntityEvent + implements EntityUpdatedEvent { private static final long serialVersionUID = 1L; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/AssignedSoftwareModule.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/AssignedSoftwareModule.java index 9215fe46f..94e5a72af 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/AssignedSoftwareModule.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/AssignedSoftwareModule.java @@ -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 { - 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(); + } + } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetType.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetType.java index 6f011be68..1b36d8927 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetType.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/DistributionSetType.java @@ -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 true 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 true 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(); - } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleType.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleType.java index a8ce522e1..12e7a1444 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleType.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/SoftwareModuleType.java @@ -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 true 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(); - } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetWithActionStatus.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetWithActionStatus.java index 9193b47ef..41f7ccbc2 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetWithActionStatus.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/TargetWithActionStatus.java @@ -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 { private Target target; @@ -46,4 +47,9 @@ public class TargetWithActionStatus { this.status = status; } + @Override + public Long getId() { + return target.getId(); + } + } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Type.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Type.java new file mode 100644 index 000000000..90c0134b2 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/model/Type.java @@ -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 true 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(); + +} diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/AbstractDistributionSetTypeUpdateCreate.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/AbstractDistributionSetTypeUpdateCreate.java index 0d81ec878..dd6c8d459 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/AbstractDistributionSetTypeUpdateCreate.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/builder/AbstractDistributionSetTypeUpdateCreate.java @@ -41,18 +41,10 @@ public abstract class AbstractDistributionSetTypeUpdateCreate extends Abstrac } public Optional> getMandatory() { - if (CollectionUtils.isEmpty(mandatory)) { - return Optional.empty(); - } - return Optional.ofNullable(mandatory); } public Optional> getOptional() { - if (CollectionUtils.isEmpty(optional)) { - return Optional.empty(); - } - return Optional.ofNullable(optional); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DefaultRolloutApprovalStrategy.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DefaultRolloutApprovalStrategy.java index 6fe288128..485d168fa 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DefaultRolloutApprovalStrategy.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/DefaultRolloutApprovalStrategy.java @@ -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 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(); } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java index 12174e745..abc9465fd 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetManagement.java @@ -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; } /** diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetTypeManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetTypeManagement.java index 48f34deaa..390ac3c12 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetTypeManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaDistributionSetTypeManagement.java @@ -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 currentMandatorySmTypeIds = type.getMandatoryModuleTypes().stream() + .map(SoftwareModuleType::getId).collect(Collectors.toSet()); + final Collection currentOptionalSmTypeIds = type.getOptionalModuleTypes().stream() + .map(SoftwareModuleType::getId).collect(Collectors.toSet()); + final Collection currentSmTypeIds = Stream + .concat(currentMandatorySmTypeIds.stream(), currentOptionalSmTypeIds.stream()) + .collect(Collectors.toSet()); + + final Collection updatedMandatorySmTypeIds = update.getMandatory().orElse(currentMandatorySmTypeIds); + final Collection updatedOptionalSmTypeIds = update.getOptional().orElse(currentOptionalSmTypeIds); + final Collection 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 currentSmTypeIds, final Collection updatedSmTypeIds, + final Function addModuleTypeCallback) { + final Set 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 currentSmTypeIds, + final Collection updatedSmTypeIds, + final LongFunction removeModuleTypeCallback) { + final Set 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(); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java index 26a31d931..6d2134542 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaRolloutManagement.java @@ -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)); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareModuleManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareModuleManagement.java index 860265f5b..ea85e11f6 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareModuleManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSoftwareModuleManagement.java @@ -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 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 query = cb.createTupleQuery(); + final Root smRoot = query.from(JpaSoftwareModule.class); + + final ListJoin assignedDsList = smRoot + .join(JpaSoftwareModule_.assignedTo, JoinType.LEFT); + + final Expression assignedCaseMax = cb.max( + cb. 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 smWithAssignedFlagList = entityManager.createQuery(query) + .setFirstResult((int) pageable.getOffset()).setMaxResults(pageSize).getResultList(); + final boolean hasNext = smWithAssignedFlagList.size() > pageSize; final List resultList = new ArrayList<>(); - final int pageSize = pageable.getPageSize(); - final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - // get the assigned software modules - final CriteriaQuery assignedQuery = cb.createQuery(JpaSoftwareModule.class); - final Root assignedRoot = assignedQuery.from(JpaSoftwareModule.class); - assignedQuery.distinct(true); - final ListJoin 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 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 unassignedQuery = cb.createQuery(JpaSoftwareModule.class); - unassignedQuery.distinct(true); - final Root 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 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> 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 = { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java index 4cb23df05..8e1450480 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetManagement.java @@ -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 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 findByCriteriaAPI(final Pageable pageable, final List> 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 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 getControllerAttributes(final String controllerId) { - final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId); + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + final CriteriaQuery query = cb.createQuery(Object[].class); - return target.getControllerAttributes(); + final Root targetRoot = query.from(JpaTarget.class); + query.where(cb.equal(targetRoot.get(JpaTarget_.controllerId), controllerId)); + + final MapJoin attributes = targetRoot.join(JpaTarget_.controllerAttributes); + query.multiselect(attributes.key(), attributes.value()); + query.orderBy(cb.asc(attributes.key())); + + final List 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 diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetTagManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetTagManagement.java index eb5fa5265..3bad1eab3 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetTagManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTargetTagManagement.java @@ -142,6 +142,11 @@ public class JpaTargetTagManagement implements TargetTagManagement { return targetTagRepository.findById(id).map(tt -> (TargetTag) tt); } + @Override + public List get(final Collection ids) { + return Collections.unmodifiableList(targetTagRepository.findAllById(ids)); + } + @Override public Page findAll(final Pageable pageable) { return convertTPage(targetTagRepository.findAll(pageable), pageable); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetTagRepository.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetTagRepository.java index b242865af..4570ddb0c 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetTagRepository.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/TargetTagRepository.java @@ -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 findAllById(Iterable ids); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java index 3b86ba46a..6879f0a66 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaAction.java @@ -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 diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/DistributionSetSpecification.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/DistributionSetSpecification.java index 828554271..953b304f4 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/DistributionSetSpecification.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/DistributionSetSpecification.java @@ -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 hasTags(final Collection tagNames, final Boolean selectDSWithNoTag) { return (targetRoot, query, cb) -> { - final SetJoin 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 tags, - final Collection tagNames, final Boolean selectDSWithNoTag, final CriteriaBuilder cb) { - tags.get(JpaDistributionSetTag_.name); + private static Predicate getHasTagsPredicate(final Root targetRoot, final CriteriaBuilder cb, + final Boolean selectDSWithNoTag, final Collection tagNames) { + final SetJoin tags = targetRoot.join(JpaDistributionSet_.tags, + JoinType.LEFT); final Path 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 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 tagNames) { + return !CollectionUtils.isEmpty(tagNames); } /** diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/TargetSpecifications.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/TargetSpecifications.java index 52fd2b798..5e92e5d41 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/TargetSpecifications.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/specifications/TargetSpecifications.java @@ -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 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 targetRoot, final CriteriaBuilder cb, + private static Predicate getHasTagsPredicate(final Root targetRoot, final CriteriaBuilder cb, final Boolean selectTargetWithNoTag, final String[] tagNames) { final SetJoin tags = targetRoot.join(JpaTarget_.tags, JoinType.LEFT); final Path 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 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; } /** diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/AbstractRemoteEntityEventTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/AbstractRemoteEntityEventTest.java index f43afc8df..7cf096045 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/AbstractRemoteEntityEventTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/AbstractRemoteEntityEventTest.java @@ -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 extends AbstractRemoteEve protected RemoteEntityEvent createRemoteEvent(final E baseEntity, final Class> 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> 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); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionEventTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionEventTest.java index b782a32e6..57c8953a7 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionEventTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/ActionEventTest.java @@ -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 { } @Override - protected RemoteEntityEvent createRemoteEvent(final Action baseEntity, - final Class> 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 { 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); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/RolloutGroupEventTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/RolloutGroupEventTest.java index f155aaeb3..7a7e64977 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/RolloutGroupEventTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/event/remote/entity/RolloutGroupEventTest.java @@ -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 createRemoteEvent(final RolloutGroup baseEntity, - final Class> 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${project.version} - - - - com.vaadin - vaadin-client - - - com.vaadin.external.gwt - gwt-elemental - - - \ No newline at end of file diff --git a/hawkbit-ui/pom.xml b/hawkbit-ui/pom.xml index b0dbc3ac0..c19f550f2 100644 --- a/hawkbit-ui/pom.xml +++ b/hawkbit-ui/pom.xml @@ -25,7 +25,7 @@ vaadin-maven-plugin ${vaadin.plugin.version} - -Xmx1g -Xss1024k + -Xmx2g -Xss1024k src/main/resources/VAADIN/widgetsets src/main/resources/VAADIN/widgetsets @@ -78,24 +78,6 @@ - - org.apache.maven.plugins - maven-jar-plugin - - - true - - true - true - - - CustomRenderers - 1 - org.eclipse.hawkbit.ui.customrenderers.CustomRendererWidgetSet - - - - @@ -205,14 +187,6 @@ com.vaadin vaadin-themes - - org.vaadin.addons.lazyquerycontainer - vaadin-lazyquerycontainer - - - org.vaadin.addons - flexibleoptiongroup - org.vaadin.alump.distributionbar dbar-addon @@ -233,6 +207,10 @@ com.cronutils cron-utils + + com.github.ben-manes.caffeine + caffeine + @@ -246,11 +224,6 @@ spring-boot-starter-test test - - com.google.gwt.gwtmockito - gwtmockito - test - io.qameta.allure allure-junit4 diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AbstractHawkbitUI.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AbstractHawkbitUI.java index 619f92d15..92b0664a4 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AbstractHawkbitUI.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AbstractHawkbitUI.java @@ -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 diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AppWidgetSet.gwt.xml b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AppWidgetSet.gwt.xml index ad1e153c2..f17be5817 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AppWidgetSet.gwt.xml +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AppWidgetSet.gwt.xml @@ -13,17 +13,12 @@ - - - - - - - - - + + diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AsyncVaadinServletConfiguration.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AsyncVaadinServletConfiguration.java index f69e442a8..88c7f43a7 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AsyncVaadinServletConfiguration.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/AsyncVaadinServletConfiguration.java @@ -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() { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/ErrorView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/ErrorView.java index 0ad65009d..bdd3cae62 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/ErrorView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/ErrorView.java @@ -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())); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEntityEventListener.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEntityEventListener.java new file mode 100644 index 000000000..57999a22e --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/HawkbitEntityEventListener.java @@ -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> uiOriginatedEventsCache; + private final List 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 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 getEventPayloadIdentifierFromProvider( + final EntityModifiedEventPayload eventPayload) { + return eventProvider.getEvents().values().stream().filter(providedIdentifier -> providedIdentifier + .equals(EntityModifiedEventPayloadIdentifier.of(eventPayload))).findAny(); + } + + private Collection getRemotelyModifiedEntityIds( + final EntityModifiedEventPayloadIdentifier eventPayloadIdentifier, + final Collection remoteEventEntityIds) { + final Collection cachedEventEntityIds = uiOriginatedEventsCache.getIfPresent(eventPayloadIdentifier); + + if (CollectionUtils.isEmpty(cachedEventEntityIds)) { + return remoteEventEntityIds; + } + + final Collection commonEntityIds = getCommonEntityIds(cachedEventEntityIds, remoteEventEntityIds); + if (!commonEntityIds.isEmpty()) { + updateCache(eventPayloadIdentifier, cachedEventEntityIds, commonEntityIds); + remoteEventEntityIds.removeAll(commonEntityIds); + } + + return remoteEventEntityIds; + } + + private Collection getCommonEntityIds(final Collection cachedEventEntityIds, + final Collection remoteEventEntityIds) { + final List commonEntityIds = new ArrayList<>(cachedEventEntityIds); + commonEntityIds.retainAll(remoteEventEntityIds); + + return commonEntityIds; + } + + private void updateCache(final EntityModifiedEventPayloadIdentifier eventPayloadIdentifier, + final Collection cachedEventEntityIds, final Collection commonEntityIds) { + final List updatedCachedEventEntityIds = new ArrayList<>(cachedEventEntityIds); + updatedCachedEventEntityIds.removeAll(commonEntityIds); + + if (updatedCachedEventEntityIds.isEmpty()) { + uiOriginatedEventsCache.invalidate(eventPayloadIdentifier); + } else { + uiOriginatedEventsCache.put(eventPayloadIdentifier, updatedCachedEventEntityIds); + } + } + } + + void unsubscribeListeners() { + eventListeners.forEach(eventBus::unsubscribe); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/LocalizedSystemMessagesProvider.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/LocalizedSystemMessagesProvider.java index c45c8d48d..c8b1986ab 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/LocalizedSystemMessagesProvider.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/LocalizedSystemMessagesProvider.java @@ -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 diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SpPermissionChecker.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SpPermissionChecker.java index 15f290a71..9093c7d2d 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SpPermissionChecker.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SpPermissionChecker.java @@ -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. * diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java index 2b2e8595a..c342b077f 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/UiProperties.java @@ -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 availableLocals = Collections.singletonList(Locale.ENGLISH); + /** + * @return Default locale + */ public Locale getDefaultLocal() { return defaultLocal; } + /** + * @return List of available locale + */ public List 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 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; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/ArtifactUploadState.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/ArtifactUploadState.java similarity index 68% rename from hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/ArtifactUploadState.java rename to hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/ArtifactUploadState.java index 5b960cb55..e1663ffd9 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/ArtifactUploadState.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/ArtifactUploadState.java @@ -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 deleteSofwareModules = new HashMap<>(); - - private transient Optional selectedBaseSwModuleId = Optional.empty(); - - private Set selectedSoftwareModules = Collections.emptySet(); - - private boolean swTypeFilterClosed; - - private boolean swModuleTableMaximized; - - private boolean artifactDetailsMaximized; - - private final Set 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 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 getDeleteSoftwareModules() { - return deleteSofwareModules; + /** + * Get the Software module grid UI state + * + * @return GridLayoutUiState + */ + public GridLayoutUiState getSmGridLayoutUiState() { + return smGridLayoutUiState; } - public Optional getSelectedBaseSwModuleId() { - return selectedBaseSwModuleId; - } - - public Set getSelectedSoftwareModules() { - return selectedSoftwareModules; - } - - @Override - public void setLastSelectedEntityId(final Long value) { - this.selectedBaseSwModuleId = Optional.ofNullable(value); - } - - @Override - public void setSelectedEnitities(final Set 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 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 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 getAllFileUploadIdsFromOverallUploadProcessList() { return Collections.unmodifiableSet(getOverallFilesInUploadProcessMap().keySet()); } + /** + * Get file upload progress values from process list + * + * @return List of FileUploadProgress + */ public Collection 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 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; } - } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/UploadArtifactView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/UploadArtifactView.java index c5aae1a3a..f3c722752 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/UploadArtifactView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/UploadArtifactView.java @@ -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 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 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(); + } + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/UploadArtifactViewMenuItem.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/UploadArtifactViewMenuItem.java index dae2cedc6..9f943d4b2 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/UploadArtifactViewMenuItem.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/UploadArtifactViewMenuItem.java @@ -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 diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactBeanQuery.java deleted file mode 100644 index 2b605d4c6..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactBeanQuery.java +++ /dev/null @@ -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 { - private static final long serialVersionUID = 1L; - private Sort sort = new Sort(Direction.DESC, "filename"); - private transient ArtifactManagement artifactManagement; - private transient Page 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 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 loadBeans(final int startIndex, final int count) { - Page 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 addedTargets, final List modifiedTargets, - final List 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; - } -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGrid.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGrid.java new file mode 100644 index 000000000..dd0b74639 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGrid.java @@ -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 { + 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 artifactDeleteSupport; + private final transient MasterEntitySupport 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(). 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 artifactsToBeDeleted) { + final Collection 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 addFilenameColumn() { + return GridComponentBuilder.addColumn(this, ProxyArtifact::getFilename).setId(ARTIFACT_NAME_ID) + .setCaption(i18n.getMessage("artifact.filename.caption")); + } + + private Column addSizeColumn() { + return GridComponentBuilder.addColumn(this, ProxyArtifact::getSize).setId(ARTIFACT_SIZE_ID) + .setCaption(i18n.getMessage("artifact.filesize.bytes.caption")); + } + + protected Column addModifiedDateColumn() { + return GridComponentBuilder.addColumn(this, ProxyArtifact::getModifiedDate).setId(ARTIFACT_MODIFIED_DATE_ID) + .setCaption(i18n.getMessage("upload.last.modified.date")); + } + + private Column 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 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 addSha1Column() { + return GridComponentBuilder.addColumn(this, ProxyArtifact::getSha1Hash).setId(ARTIFACT_SHA1_ID) + .setCaption(i18n.getMessage("upload.sha1")); + } + + private Column addMd5Column() { + return GridComponentBuilder.addColumn(this, ProxyArtifact::getMd5Hash).setId(ARTIFACT_MD5_ID) + .setCaption(i18n.getMessage("upload.md5")); + } + + private Column addSha256Column() { + return GridComponentBuilder.addColumn(this, ProxyArtifact::getSha256Hash).setId(ARTIFACT_SHA256_ID) + .setCaption(i18n.getMessage("upload.sha256")); + } + + /** + * @return software module entity + */ + public MasterEntitySupport getMasterEntitySupport() { + return masterEntitySupport; + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridHeader.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridHeader.java new file mode 100644 index 000000000..588be81f3 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridHeader.java @@ -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 { + 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(); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridLayout.java new file mode 100644 index 000000000..7b9357cb6 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridLayout.java @@ -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 selectionChangedListener; + private final transient GenericEventListener 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> 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(); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridLayoutUiState.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridLayoutUiState.java new file mode 100644 index 000000000..0eef4d8c5 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsGridLayoutUiState.java @@ -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; + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsLayout.java deleted file mode 100644 index b613f6b24..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/details/ArtifactDetailsLayout.java +++ /dev/null @@ -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 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 findSelectedSoftwareModule() { - final Optional 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 queryConfig) { - - final BeanQueryFactory 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 = this.artifactManagement.get(id); - if (artifact.isPresent()) { - Optional 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 = 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 getVisbleColumns() { - final List 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 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 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(); - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/RefreshSoftwareModuleByFilterEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/RefreshSoftwareModuleByFilterEvent.java deleted file mode 100644 index 88afbe741..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/RefreshSoftwareModuleByFilterEvent.java +++ /dev/null @@ -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 { - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/SoftwareModuleEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/SoftwareModuleEvent.java deleted file mode 100644 index 8b8c6791f..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/SoftwareModuleEvent.java +++ /dev/null @@ -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 { - - /** - * 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 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; - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/SoftwareModuleTypeEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/SoftwareModuleTypeEvent.java deleted file mode 100644 index 25dd93a73..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/SoftwareModuleTypeEvent.java +++ /dev/null @@ -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; - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadArtifactUIEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadArtifactUIEvent.java deleted file mode 100644 index 8f4f526c6..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/event/UploadArtifactUIEvent.java +++ /dev/null @@ -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 -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/AddSmWindowController.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/AddSmWindowController.java new file mode 100644 index 000000000..0f6b5369c --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/AddSmWindowController.java @@ -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 { + 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 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; + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/BaseSwModuleBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/BaseSwModuleBeanQuery.java deleted file mode 100644 index 53592acb6..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/BaseSwModuleBeanQuery.java +++ /dev/null @@ -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 { - 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 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 loadBeans(final int startIndex, final int count) { - final Slice 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 addedBeans, - final List modifiedBeans, - final List removedBeans) { - // save of the entity not required from this method - } - - private SoftwareModuleManagement getSoftwareManagementService() { - if (softwareManagementService == null) { - softwareManagementService = SpringContextHelper.getBean(SoftwareModuleManagement.class); - } - return softwareManagementService; - } -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/ProxyBaseSoftwareModuleItem.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/ProxyBaseSoftwareModuleItem.java deleted file mode 100644 index 5dd5bc521..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/ProxyBaseSoftwareModuleItem.java +++ /dev/null @@ -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; - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataAddUpdateWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataAddUpdateWindowLayout.java new file mode 100644 index 000000000..b80748c27 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataAddUpdateWindowLayout.java @@ -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; + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataWindowBuilder.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataWindowBuilder.java new file mode 100644 index 000000000..25803455a --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataWindowBuilder.java @@ -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 { + 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); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataWindowLayout.java new file mode 100644 index 000000000..2c6d9a8ca --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmMetaDataWindowLayout.java @@ -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 { + private static final long serialVersionUID = 1L; + + private final transient SoftwareModuleManagement smManagement; + private final transient EntityFactory entityFactory; + + private final MetaDataWindowGrid 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 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)); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmWindowBuilder.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmWindowBuilder.java new file mode 100644 index 000000000..91aead49b --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmWindowBuilder.java @@ -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 { + 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))); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmWindowLayout.java new file mode 100644 index 000000000..0c78afbd7 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmWindowLayout.java @@ -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 { + private final SmWindowLayoutComponentBuilder smComponentBuilder; + + private final ComboBox 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 smTypeDataProvider = new SoftwareModuleTypeDataProvider<>( + smTypeManagement, new TypeToTypeInfoMapper()); + this.smComponentBuilder = new SmWindowLayoutComponentBuilder(i18n, smTypeDataProvider); + + this.smTypeSelect = smComponentBuilder.createSoftwareModuleTypeCombo(binder); + this.smName = smComponentBuilder.createNameField(binder); + this.smVersion = smComponentBuilder.createVersionField(binder); + this.smVendor = smComponentBuilder.createVendorField(binder); + this.smDescription = smComponentBuilder.createDescription(binder); + } + + /** + * @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); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmWindowLayoutComponentBuilder.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmWindowLayoutComponentBuilder.java new file mode 100644 index 000000000..21f63022e --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SmWindowLayoutComponentBuilder.java @@ -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 smTypeDataProvider; + + /** + * Constructor for SmWindowLayoutComponentBuilder + * + * @param i18n + * VaadinMessageSource + * @param smTypeDataProvider + * SoftwareModuleTypeDataProvider + */ + public SmWindowLayoutComponentBuilder(final VaadinMessageSource i18n, + final SoftwareModuleTypeDataProvider 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 createSoftwareModuleTypeCombo(final Binder 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 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 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 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 binder) { + return FormComponentBuilder + .createDescriptionInput(binder, i18n, UIComponentIdProvider.ADD_SW_MODULE_DESCRIPTION).getComponent(); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleAddUpdateWindow.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleAddUpdateWindow.java deleted file mode 100644 index f5bab1e8d..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleAddUpdateWindow.java +++ /dev/null @@ -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 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 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 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; - } - - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleDetails.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleDetails.java deleted file mode 100644 index ded36197c..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleDetails.java +++ /dev/null @@ -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)); - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGrid.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGrid.java new file mode 100644 index 000000000..618611786 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGrid.java @@ -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 { + 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 swModuleDeleteSupport; + private transient MasterEntitySupport masterEntitySupport; + + private final Map 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(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 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 swModulesToBeDeleted) { + final Collection 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 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 addNameColumn() { + return GridComponentBuilder.addNameColumn(this, i18n, SM_NAME_ID); + } + + private Column addVersionColumn() { + return GridComponentBuilder.addVersionColumn(this, i18n, ProxySoftwareModule::getVersion, SM_VERSION_ID); + } + + private Column 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 addDescriptionColumn() { + return GridComponentBuilder.addDescriptionColumn(this, i18n, SM_DESC_ID); + } + + private Column addVendorColumn() { + return GridComponentBuilder.addColumn(this, ProxySoftwareModule::getVendor).setId(SM_VENDOR_ID) + .setCaption(i18n.getMessage("header.vendor")); + } + + /** + * @return ProxyDistributionSet of master entity type + */ + public MasterEntitySupport getMasterEntitySupport() { + return masterEntitySupport; + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGridHeader.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGridHeader.java new file mode 100644 index 000000000..997951f83 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGridHeader.java @@ -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 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; + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGridLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGridLayout.java new file mode 100644 index 000000000..ad5cbf95c --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleGridLayout.java @@ -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 smFilterListener; + private final transient SelectionChangedListener masterSmChangedListener; + private final transient SelectGridEntityListener selectSmListener; + private final transient EntityModifiedListener smModifiedListener; + private final transient GenericEventListener 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> getMasterSmAwareComponents() { + return Arrays.asList(softwareModuleDetailsHeader, softwareModuleDetails); + } + + private List 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(); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTable.java deleted file mode 100644 index 624397235..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTable.java +++ /dev/null @@ -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 { - - 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 queryConfiguration = prepareQueryConfigFilters(); - - final BeanQueryFactory swQF = new BeanQueryFactory<>(BaseSwModuleBeanQuery.class); - swQF.setQueryConfiguration(queryConfiguration); - - return new LazyQueryContainer( - new LazyQueryDefinition(true, SPUIDefinitions.PAGE_SIZE, SPUILabelDefinitions.VAR_SWM_ID), swQF); - } - - private Map prepareQueryConfigFilters() { - final Map 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 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 visibleItemIds = (List) 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 getTableVisibleColumns() { - final List 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 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 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 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 = softwareModuleManagement.get(entityId); - return softwareModule.map(module -> module.getName() + ":" + module.getVersion()).orElse(""); - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTableHeader.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTableHeader.java deleted file mode 100644 index 57856c6dd..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTableHeader.java +++ /dev/null @@ -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; - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTableLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTableLayout.java deleted file mode 100644 index 92d50c55d..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTableLayout.java +++ /dev/null @@ -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 { - - 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; - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/UpdateSmWindowController.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/UpdateSmWindowController.java new file mode 100644 index 000000000..70bae8341 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/UpdateSmWindowController.java @@ -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 { + 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 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; + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/AbstractSoftwareModuleTypeLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/AbstractSoftwareModuleTypeLayout.java deleted file mode 100644 index da9b09830..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/AbstractSoftwareModuleTypeLayout.java +++ /dev/null @@ -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 { - - 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 findEntityByKey() { - return softwareModuleTypeManagement.getByKey(getTypeKey().getValue()); - } - - @Override - protected Optional 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 optionValues = new ArrayList<>(); - optionValues.add(singleAssign.getValue()); - optionValues.add(multiAssign.getValue()); - assignOptionGroupByValues(optionValues); - } - - private void assignOptionGroupByValues(final List 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)); - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/AddSmTypeWindowController.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/AddSmTypeWindowController.java new file mode 100644 index 000000000..5dccbc604 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/AddSmTypeWindowController.java @@ -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 { + 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 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; + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/CreateSoftwareModuleTypeLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/CreateSoftwareModuleTypeLayout.java deleted file mode 100644 index 435b894c5..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/CreateSoftwareModuleTypeLayout.java +++ /dev/null @@ -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; - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SmTypeWindowBuilder.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SmTypeWindowBuilder.java new file mode 100644 index 000000000..94118f4df --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SmTypeWindowBuilder.java @@ -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 { + 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))); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SmTypeWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SmTypeWindowLayout.java new file mode 100644 index 000000000..211b165b1 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SmTypeWindowLayout.java @@ -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 { + private final SmTypeWindowLayoutComponentBuilder smTypeComponentBuilder; + + private final TextField typeKey; + private final RadioButtonGroup 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); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SmTypeWindowLayoutComponentBuilder.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SmTypeWindowLayoutComponentBuilder.java new file mode 100644 index 000000000..77622a52e --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/SmTypeWindowLayoutComponentBuilder.java @@ -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 createSmTypeAssignOptionGroup(final Binder binder) { + final RadioButtonGroup 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; + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/UpdateSmTypeWindowController.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/UpdateSmTypeWindowController.java new file mode 100644 index 000000000..cc7063b68 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/UpdateSmTypeWindowController.java @@ -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 { + 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 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; + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/UpdateSoftwareModuleTypeLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/UpdateSoftwareModuleTypeLayout.java deleted file mode 100644 index 22b4ee633..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/UpdateSoftwareModuleTypeLayout.java +++ /dev/null @@ -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; - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterButtonClick.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterButtonClick.java deleted file mode 100644 index b1ac11259..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterButtonClick.java +++ /dev/null @@ -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()); - }); - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterButtons.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterButtons.java index e2fd1b1f3..5d3ee04ec 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterButtons.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterButtons.java @@ -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 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 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)); - } - }); - } - } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterHeader.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterHeader.java index 01d9c1190..0f5d6313c 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterHeader.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterHeader.java @@ -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; + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterLayout.java index e5ebd1844..62be0fbdb 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtype/filter/SMTypeFilterLayout.java @@ -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 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 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(); + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/SoftwareModuleFilters.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/SoftwareModuleFilters.java deleted file mode 100644 index 4ea48f7c2..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/state/SoftwareModuleFilters.java +++ /dev/null @@ -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 getSoftwareModuleType() { - return Optional.ofNullable(softwareModuleType); - } - - public void setSoftwareModuleType(final SoftwareModuleType softwareModuleType) { - this.softwareModuleType = softwareModuleType; - } - - public Optional getSearchText() { - return Optional.ofNullable(searchText); - } - - public void setSearchText(final String searchText) { - this.searchText = searchText; - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/AbstractFileTransferHandler.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/AbstractFileTransferHandler.java index 4f84d6a23..e2cb74e89 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/AbstractFileTransferHandler.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/AbstractFileTransferHandler.java @@ -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; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileTransferHandlerStreamVariable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileTransferHandlerStreamVariable.java index 878ba82f0..87b73e844 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileTransferHandlerStreamVariable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileTransferHandlerStreamVariable.java @@ -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(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileTransferHandlerVaadinUpload.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileTransferHandlerVaadinUpload.java index f933ec16e..f007a8861 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileTransferHandlerVaadinUpload.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileTransferHandlerVaadinUpload.java @@ -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")); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileUploadId.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileUploadId.java index fd23e398f..339075b14 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileUploadId.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileUploadId.java @@ -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; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileUploadProgress.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileUploadProgress.java index b4652dabf..ad9cb04fa 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileUploadProgress.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/FileUploadProgress.java @@ -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; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadDropAreaLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadDropAreaLayout.java index a6b89b7f5..f6124d6f5 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadDropAreaLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadDropAreaLayout.java @@ -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 { 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 { 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 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 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 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 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; - } - } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadFixed.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadFixed.java index 576dac6a9..56e4ab9b2 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadFixed.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadFixed.java @@ -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; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadProgressButtonLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadProgressButtonLayout.java index 9848e4696..f0b5bbe44 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadProgressButtonLayout.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadProgressButtonLayout.java @@ -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(); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadProgressGrid.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadProgressGrid.java new file mode 100644 index 000000000..a421ad190 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadProgressGrid.java @@ -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 { + 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 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)); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadProgressInfoWindow.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadProgressInfoWindow.java index 10f94ceab..356d897fe 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadProgressInfoWindow.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/upload/UploadProgressInfoWindow.java @@ -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 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 null. + * + * @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 = "
" + FontAwesome.CHECK_CIRCLE.getHtml() + "
"; - break; - case STATUS_FAILED: - result = "
" + FontAwesome.EXCLAMATION_CIRCLE.getHtml() + "
"; - break; - case STATUS_INPROGRESS: - result = "
"; - 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 null. - * - * @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(); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerConstants.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerConstants.java deleted file mode 100644 index 546cd04c7..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerConstants.java +++ /dev/null @@ -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() { - - } -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerHelper.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerHelper.java deleted file mode 100644 index cc208beee..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerHelper.java +++ /dev/null @@ -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); - } - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerLayout.java deleted file mode 100644 index b9b67eac1..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/colorpicker/ColorPickerLayout.java +++ /dev/null @@ -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 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 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; - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEntityWindowBuilder.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEntityWindowBuilder.java new file mode 100644 index 000000000..90af792dc --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEntityWindowBuilder.java @@ -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 + * Generic type entity + */ +public abstract class AbstractEntityWindowBuilder { + protected final VaadinMessageSource i18n; + + protected AbstractEntityWindowBuilder(final VaadinMessageSource i18n) { + this.i18n = i18n; + } + + protected CommonDialogWindow getWindowForNewEntity(final AbstractEntityWindowController controller) { + return getWindowForEntity(null, controller); + } + + protected CommonDialogWindow getWindowForNewEntity(final AbstractEntityWindowController controller, + final Component windowContent) { + return getWindowForEntity(null, controller, windowContent); + } + + protected CommonDialogWindow getWindowForEntity(final T proxyEntity, + final AbstractEntityWindowController controller) { + return getWindowForEntity(proxyEntity, controller, controller.getLayout().getRootComponent()); + } + + protected CommonDialogWindow getWindowForEntity(final T proxyEntity, + final AbstractEntityWindowController 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; + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEntityWindowController.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEntityWindowController.java new file mode 100644 index 000000000..f6380f075 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEntityWindowController.java @@ -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.common; + +import org.eclipse.hawkbit.ui.common.CommonDialogWindow.SaveDialogCloseListener; + +/** + * Controller for abstract entity window + * + * @param + * Generic type entity + * @param + * Generic type entity + */ +public abstract class AbstractEntityWindowController { + + /** + * Populate entity with data + * + * @param proxyEntity + * Generic type entity + */ + public void populateWithData(final T proxyEntity) { + getLayout().setEntity(buildEntityFromProxy(proxyEntity)); + + adaptLayout(proxyEntity); + } + + /** + * @return layout + */ + public abstract EntityWindowLayout getLayout(); + + protected abstract E buildEntityFromProxy(final T proxyEntity); + + protected void adaptLayout(final T proxyEntity) { + // can be overriden to adapt layout components (e.g. disable/enable + // fields, adapt bindings, etc.) + } + + /** + * @return Save dialog close listener + */ + public SaveDialogCloseListener getSaveDialogCloseListener() { + return new SaveDialogCloseListener() { + @Override + public void saveOrUpdate() { + persistEntity(getLayout().getEntity()); + } + + @Override + public boolean canWindowSaveOrUpdate() { + return isEntityValid(getLayout().getEntity()); + } + + @Override + public boolean canWindowClose() { + return closeWindowAfterSave(); + } + }; + } + + protected abstract void persistEntity(final E entity); + + protected abstract boolean isEntityValid(final E entity); + + protected boolean closeWindowAfterSave() { + return true; + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEntityWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEntityWindowLayout.java new file mode 100644 index 000000000..51a8c9a21 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractEntityWindowLayout.java @@ -0,0 +1,54 @@ +/** + * 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 java.util.Optional; +import java.util.function.Consumer; + +import com.vaadin.data.Binder; + +/** + * Abstract class for entity window layout + * + * @param + * Generic type entity + */ +public abstract class AbstractEntityWindowLayout implements EntityWindowLayout { + + protected final Binder binder; + + protected Consumer validationCallback; + + protected AbstractEntityWindowLayout() { + this.binder = new Binder<>(); + } + + @Override + public void setEntity(final T proxyEntity) { + binder.setBean(proxyEntity); + } + + @Override + public T getEntity() { + return binder.getBean(); + } + + @Override + public void addValidationListener(final Consumer validationCallback) { + binder.addStatusChangeListener(event -> validationCallback.accept(event.getBinder().isValid())); + this.validationCallback = validationCallback; + } + + /** + * @return Validation callback event + */ + public Optional> getValidationCallback() { + return Optional.ofNullable(validationCallback); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractMetadataPopupLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractMetadataPopupLayout.java deleted file mode 100644 index b9c225f26..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractMetadataPopupLayout.java +++ /dev/null @@ -1,534 +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.common; - -import java.util.List; -import java.util.Set; - -import org.eclipse.hawkbit.repository.model.MetaData; -import org.eclipse.hawkbit.repository.model.NamedEntity; -import org.eclipse.hawkbit.ui.SpPermissionChecker; -import org.eclipse.hawkbit.ui.common.CommonDialogWindow.SaveDialogCloseListener; -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.components.SPUIComponentProvider; -import org.eclipse.hawkbit.ui.customrenderers.renderers.HtmlButtonRenderer; -import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorder; -import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; -import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; -import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider; -import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider; -import org.eclipse.hawkbit.ui.utils.UINotification; -import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; -import org.vaadin.spring.events.EventBus; -import org.vaadin.spring.events.EventBus.UIEventBus; - -import com.vaadin.data.Item; -import com.vaadin.data.util.IndexedContainer; -import com.vaadin.event.FieldEvents.TextChangeEvent; -import com.vaadin.event.SelectionEvent; -import com.vaadin.server.FontAwesome; -import com.vaadin.ui.AbstractTextField.TextChangeEventMode; -import com.vaadin.ui.Alignment; -import com.vaadin.ui.Button; -import com.vaadin.ui.CustomComponent; -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.TextArea; -import com.vaadin.ui.TextField; -import com.vaadin.ui.UI; -import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.renderers.ClickableRenderer.RendererClickEvent; - -/** - * - * Abstract pop up layout - * - * @param - * E id the entity for which metadata is displayed - * @param - * M is the metadata - * - */ -public abstract class AbstractMetadataPopupLayout extends CustomComponent { - private static final long serialVersionUID = 1L; - - private static final String DELETE_BUTTON = "DELETE_BUTTON"; - private static final int INPUT_DEBOUNCE_TIMEOUT = 250; - - protected static final String VALUE = "value"; - protected static final String KEY = "key"; - protected static final int MAX_METADATA_QUERY = 500; - - protected VaadinMessageSource i18n; - private final UINotification uiNotification; - protected transient EventBus.UIEventBus eventBus; - - private TextField keyTextField; - private TextArea valueTextArea; - private Button addIcon; - private Grid metaDataGrid; - private Label headerCaption; - private CommonDialogWindow metadataWindow; - - private E selectedEntity; - - private HorizontalLayout mainLayout; - protected SpPermissionChecker permChecker; - - protected AbstractMetadataPopupLayout(final VaadinMessageSource i18n, final UINotification uiNotification, - final UIEventBus eventBus, final SpPermissionChecker permChecker) { - this.i18n = i18n; - this.uiNotification = uiNotification; - this.eventBus = eventBus; - this.permChecker = permChecker; - - createComponents(); - buildLayout(); - } - - /** - * Save the metadata and never close the window after saving. - */ - private final class SaveOnDialogCloseListener implements SaveDialogCloseListener { - @Override - public void saveOrUpdate() { - onSave(); - } - - @Override - public boolean canWindowClose() { - return false; - } - - @Override - public boolean canWindowSaveOrUpdate() { - return true; - } - - } - - /** - * Returns metadata popup. - * - * @param entity - * entity for which metadata data is displayed - * @param metaDatakey - * metadata key to be selected - * @return {@link CommonDialogWindow} - */ - public CommonDialogWindow getWindow(final E entity, final String metaDatakey) { - selectedEntity = entity; - - metadataWindow = new WindowBuilder(SPUIDefinitions.CREATE_UPDATE_WINDOW).content(this) - .cancelButtonClickListener(event -> onCancel()).id(UIComponentIdProvider.METADATA_POPUP_ID) - .layout(mainLayout).i18n(i18n).saveDialogCloseListener(new SaveOnDialogCloseListener()) - .buildCommonDialogWindow(); - - metadataWindow.setCaptionAsHtml(false); - metadataWindow.setAssistivePrefix(i18n.getMessage("caption.metadata.popup") + " " + ""); - metadataWindow.setCaption(getElementTitle()); - metadataWindow.setAssistivePostfix(""); - - metadataWindow.setHeight(550, Unit.PIXELS); - metadataWindow.setWidth(800, Unit.PIXELS); - metadataWindow.getMainLayout().setSizeFull(); - metadataWindow.getButtonsLayout().setHeight("45px"); - setUpDetails(entity.getId(), metaDatakey); - return metadataWindow; - } - - public E getSelectedEntity() { - return selectedEntity; - } - - public void setSelectedEntity(final E selectedEntity) { - this.selectedEntity = selectedEntity; - } - - protected abstract boolean checkForDuplicate(E entity, String value); - - protected abstract M createMetadata(E entity, String key, String value); - - protected abstract M updateMetadata(E entity, String key, String value); - - protected abstract List getMetadataList(); - - protected abstract void deleteMetadata(E entity, String key); - - protected abstract boolean hasCreatePermission(); - - protected abstract boolean hasUpdatePermission(); - - protected void createComponents() { - keyTextField = createKeyTextField(); - valueTextArea = createValueTextField(); - metaDataGrid = createMetadataGrid(); - addIcon = createAddIcon(); - headerCaption = createHeaderCaption(); - } - - private void buildLayout() { - final HorizontalLayout headerLayout = new HorizontalLayout(); - headerLayout.addStyleName(SPUIStyleDefinitions.WIDGET_TITLE); - headerLayout.setSpacing(false); - headerLayout.setMargin(false); - headerLayout.setSizeFull(); - headerLayout.addComponent(headerCaption); - if (hasCreatePermission()) { - headerLayout.addComponents(addIcon); - headerLayout.setComponentAlignment(addIcon, Alignment.MIDDLE_RIGHT); - } - headerLayout.setExpandRatio(headerCaption, 1.0F); - - final HorizontalLayout headerWrapperLayout = new HorizontalLayout(); - headerWrapperLayout.addStyleName("bordered-layout" + " " + "no-border-bottom" + " " + "metadata-table-margin"); - headerWrapperLayout.addComponent(headerLayout); - headerWrapperLayout.setWidth("100%"); - headerLayout.setHeight("30px"); - - final VerticalLayout tableLayout = new VerticalLayout(); - tableLayout.setSizeFull(); - tableLayout.setHeight("100%"); - tableLayout.addComponent(headerWrapperLayout); - tableLayout.addComponent(metaDataGrid); - tableLayout.addStyleName("table-layout"); - tableLayout.setExpandRatio(metaDataGrid, 1.0F); - - final VerticalLayout metadataFieldsLayout = createMetadataFieldsLayout(); - - mainLayout = new HorizontalLayout(); - mainLayout.addComponent(tableLayout); - mainLayout.addComponent(metadataFieldsLayout); - mainLayout.setExpandRatio(tableLayout, 0.5F); - mainLayout.setExpandRatio(metadataFieldsLayout, 0.5F); - mainLayout.setSizeFull(); - mainLayout.setSpacing(true); - setCompositionRoot(mainLayout); - setSizeFull(); - } - - protected VerticalLayout createMetadataFieldsLayout() { - final VerticalLayout metadataFieldsLayout = new VerticalLayout(); - metadataFieldsLayout.setSizeFull(); - metadataFieldsLayout.setHeight("100%"); - metadataFieldsLayout.addComponent(keyTextField); - metadataFieldsLayout.addComponent(valueTextArea); - metadataFieldsLayout.setSpacing(true); - metadataFieldsLayout.setExpandRatio(valueTextArea, 1F); - return metadataFieldsLayout; - } - - private TextField createKeyTextField() { - final TextField keyField = new TextFieldBuilder(MetaData.KEY_MAX_SIZE).caption(i18n.getMessage("textfield.key")) - .required(true, i18n).id(UIComponentIdProvider.METADATA_KEY_FIELD_ID).buildTextComponent(); - keyField.addTextChangeListener(this::onKeyChange); - keyField.setTextChangeEventMode(TextChangeEventMode.LAZY); - keyField.setTextChangeTimeout(INPUT_DEBOUNCE_TIMEOUT); - keyField.setWidth("100%"); - return keyField; - } - - private TextArea createValueTextField() { - valueTextArea = new TextAreaBuilder(MetaData.VALUE_MAX_SIZE).caption(i18n.getMessage("textfield.value")) - .required(true, i18n).id(UIComponentIdProvider.METADATA_VALUE_ID).buildTextComponent(); - valueTextArea.setSizeFull(); - valueTextArea.setHeight(100, Unit.PERCENTAGE); - valueTextArea.addTextChangeListener(this::onValueChange); - valueTextArea.setTextChangeEventMode(TextChangeEventMode.LAZY); - valueTextArea.setTextChangeTimeout(INPUT_DEBOUNCE_TIMEOUT); - return valueTextArea; - } - - protected Grid createMetadataGrid() { - final Grid metadataGrid = new Grid(); - metadataGrid.addStyleName(SPUIStyleDefinitions.METADATA_GRID); - metadataGrid.setImmediate(true); - metadataGrid.setHeight("100%"); - metadataGrid.setWidth("100%"); - metadataGrid.setId(UIComponentIdProvider.METDATA_TABLE_ID); - metadataGrid.setSelectionMode(SelectionMode.SINGLE); - metadataGrid.setColumnReorderingAllowed(true); - metadataGrid.setContainerDataSource(getMetadataContainer()); - metadataGrid.getColumn(KEY).setHeaderCaption(i18n.getMessage("header.key")); - metadataGrid.getColumn(VALUE).setHeaderCaption(i18n.getMessage("header.value")); - metadataGrid.getColumn(VALUE).setHidden(true); - metadataGrid.addSelectionListener(this::onRowClick); - metadataGrid.getColumn(DELETE_BUTTON).setHeaderCaption(""); - metadataGrid.getColumn(DELETE_BUTTON).setRenderer(new HtmlButtonRenderer(this::onDelete)); - metadataGrid.getColumn(DELETE_BUTTON).setWidth(50); - metadataGrid.getColumn(KEY).setExpandRatio(1); - return metadataGrid; - } - - private void onDelete(final RendererClickEvent event) { - final Item item = metaDataGrid.getContainerDataSource().getItem(event.getItemId()); - final String key = (String) item.getItemProperty(KEY).getValue(); - - final ConfirmationDialog confirmDialog = new ConfirmationDialog( - i18n.getMessage("caption.entity.delete.action.confirmbox"), - i18n.getMessage("message.confirm.delete.metadata", key), i18n.getMessage(UIMessageIdProvider.BUTTON_OK), - i18n.getMessage(UIMessageIdProvider.BUTTON_CANCEL), ok -> { - if (ok) { - handleOkDeleteMetadata(event, key); - } - }); - UI.getCurrent().addWindow(confirmDialog.getWindow()); - confirmDialog.getWindow().bringToFront(); - } - - private void handleOkDeleteMetadata(final RendererClickEvent event, final String key) { - deleteMetadata(getSelectedEntity(), key); - uiNotification.displaySuccess(i18n.getMessage("message.metadata.deleted.successfully", key)); - final Object selectedRow = metaDataGrid.getSelectedRow(); - metaDataGrid.getContainerDataSource().removeItem(event.getItemId()); - // force grid to refresh - metaDataGrid.clearSortOrder(); - if (!metaDataGrid.getContainerDataSource().getItemIds().isEmpty()) { - if (selectedRow != null) { - if (selectedRow.equals(event.getItemId())) { - metaDataGrid.select(metaDataGrid.getContainerDataSource().getIdByIndex(0)); - } else { - metaDataGrid.select(selectedRow); - } - } - } else { - resetFields(); - } - } - - private void resetFields() { - clearFields(); - metaDataGrid.select(null); - if (hasCreatePermission()) { - enableEditing(); - addIcon.setEnabled(false); - } - } - - private Button createAddIcon() { - addIcon = SPUIComponentProvider.getButton(UIComponentIdProvider.METADTA_ADD_ICON_ID, - i18n.getMessage("button.save"), null, null, false, FontAwesome.PLUS, SPUIButtonStyleNoBorder.class); - addIcon.addClickListener(event -> onAdd()); - return addIcon; - } - - private Label createHeaderCaption() { - return new LabelBuilder().name(i18n.getMessage("caption.metadata")).buildCaptionLabel(); - } - - private static IndexedContainer getMetadataContainer() { - final IndexedContainer swcontactContainer = new IndexedContainer(); - swcontactContainer.addContainerProperty(KEY, String.class, ""); - swcontactContainer.addContainerProperty(VALUE, String.class, ""); - swcontactContainer.addContainerProperty(DELETE_BUTTON, String.class, FontAwesome.TRASH_O.getHtml()); - return swcontactContainer; - } - - protected Item popualateKeyValue(final Object metadataCompositeKey) { - if (metadataCompositeKey != null) { - final Item item = metaDataGrid.getContainerDataSource().getItem(metadataCompositeKey); - keyTextField.setValue((String) item.getItemProperty(KEY).getValue()); - valueTextArea.setValue((String) item.getItemProperty(VALUE).getValue()); - keyTextField.setEnabled(false); - if (hasUpdatePermission()) { - valueTextArea.setEnabled(true); - } - return item; - } - - return null; - } - - private void populateGrid() { - final List metadataList = getMetadataList(); - for (final M metaData : metadataList) { - addItemToGrid(metaData); - } - } - - protected Item addItemToGrid(final M metaData) { - final IndexedContainer metadataContainer = (IndexedContainer) metaDataGrid.getContainerDataSource(); - final Item item = metadataContainer.addItem(metaData.getKey()); - item.getItemProperty(VALUE).setValue(metaData.getValue()); - item.getItemProperty(KEY).setValue(metaData.getKey()); - return item; - } - - protected Item updateItemInGrid(final String key) { - final IndexedContainer metadataContainer = (IndexedContainer) metaDataGrid.getContainerDataSource(); - final Item item = metadataContainer.getItem(key); - item.getItemProperty(VALUE).setValue(valueTextArea.getValue()); - return item; - } - - private void onAdd() { - metaDataGrid.deselect(metaDataGrid.getSelectedRow()); - clearFields(); - enableEditing(); - addIcon.setEnabled(true); - } - - protected void clearFields() { - valueTextArea.clear(); - keyTextField.clear(); - } - - protected void onSave() { - final String key = keyTextField.getValue(); - final String value = valueTextArea.getValue(); - if (mandatoryCheck()) { - final E entity = selectedEntity; - if (metaDataGrid.getSelectedRow() == null) { - if (!duplicateCheck(entity)) { - final M metadata = createMetadata(entity, key, value); - uiNotification.displaySuccess(i18n.getMessage("message.metadata.saved", metadata.getKey())); - addItemToGrid(metadata); - metaDataGrid.scrollToEnd(); - metaDataGrid.select(metadata.getKey()); - addIcon.setEnabled(true); - metadataWindow.setSaveButtonEnabled(false); - if (!hasUpdatePermission()) { - valueTextArea.setEnabled(false); - } - } - } else { - final M metadata = updateMetadata(entity, key, value); - uiNotification.displaySuccess(i18n.getMessage("message.metadata.updated", metadata.getKey())); - updateItemInGrid(metadata.getKey()); - metaDataGrid.select(metadata.getKey()); - addIcon.setEnabled(true); - metadataWindow.setSaveButtonEnabled(false); - } - } - } - - private boolean mandatoryCheck() { - if (keyTextField.getValue().isEmpty()) { - uiNotification.displayValidationError(i18n.getMessage("message.key.missing")); - return false; - } - if (valueTextArea.getValue().isEmpty()) { - uiNotification.displayValidationError(i18n.getMessage("message.value.missing")); - return false; - } - return true; - } - - private boolean duplicateCheck(final E entity) { - if (!checkForDuplicate(entity, keyTextField.getValue())) { - return false; - } - - uiNotification - .displayValidationError(i18n.getMessage("message.metadata.duplicate.check", keyTextField.getValue())); - return true; - } - - protected String getElementTitle() { - return getSelectedEntity().getName(); - } - - private void onCancel() { - metadataWindow.close(); - UI.getCurrent().removeWindow(metadataWindow); - } - - private void onKeyChange(final TextChangeEvent event) { - if (hasCreatePermission() || hasUpdatePermission()) { - if (!valueTextArea.getValue().isEmpty() && !event.getText().isEmpty()) { - metadataWindow.setSaveButtonEnabled(true); - } else { - metadataWindow.setSaveButtonEnabled(false); - } - } - } - - protected void onRowClick(final SelectionEvent event) { - final Set itemsSelected = event.getSelected(); - if (!itemsSelected.isEmpty()) { - popualateKeyValue(itemsSelected.iterator().next()); - addIcon.setEnabled(true); - } else { - clearFields(); - if (hasCreatePermission()) { - enableEditing(); - addIcon.setEnabled(false); - } else { - keyTextField.setEnabled(false); - valueTextArea.setEnabled(false); - } - } - metadataWindow.setSaveButtonEnabled(false); - } - - protected void enableEditing() { - keyTextField.setEnabled(true); - valueTextArea.setEnabled(true); - } - - private void onValueChange(final TextChangeEvent event) { - if (hasCreatePermission() || hasUpdatePermission()) { - if (!keyTextField.getValue().isEmpty() && !event.getText().isEmpty()) { - metadataWindow.setSaveButtonEnabled(true); - } else { - metadataWindow.setSaveButtonEnabled(false); - } - } - } - - private void setUpDetails(final Long swId, final String metaDatakey) { - resetDetails(); - metadataWindow.clearOriginalValues(); - if (swId != null) { - metaDataGrid.getContainerDataSource().removeAllItems(); - populateGrid(); - metaDataGrid.getSelectionModel().reset(); - if (!metaDataGrid.getContainerDataSource().getItemIds().isEmpty()) { - if (metaDatakey == null) { - metaDataGrid.select(metaDataGrid.getContainerDataSource().getIdByIndex(0)); - } else { - metaDataGrid.select(metaDatakey); - } - } else if (hasCreatePermission()) { - enableEditing(); - addIcon.setEnabled(false); - } - } - } - - private void resetDetails() { - clearFields(); - disableEditing(); - metadataWindow.setSaveButtonEnabled(false); - addIcon.setEnabled(true); - } - - protected void disableEditing() { - keyTextField.setEnabled(false); - valueTextArea.setEnabled(false); - } - - protected TextArea getValueTextArea() { - return valueTextArea; - } - - protected TextField getKeyTextField() { - return keyTextField; - } - - protected CommonDialogWindow getMetadataWindow() { - return metadataWindow; - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractMetadataPopupLayoutVersioned.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractMetadataPopupLayoutVersioned.java deleted file mode 100644 index d8d915c81..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractMetadataPopupLayoutVersioned.java +++ /dev/null @@ -1,44 +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.common; - -import org.eclipse.hawkbit.repository.model.MetaData; -import org.eclipse.hawkbit.repository.model.NamedVersionedEntity; -import org.eclipse.hawkbit.ui.SpPermissionChecker; -import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; -import org.eclipse.hawkbit.ui.utils.UINotification; -import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; -import org.vaadin.spring.events.EventBus.UIEventBus; - -/** - * - * Abstract pop up layout - * - * @param - * E id the entity for which metadata is displayed - * @param - * M is the metadata - * - */ -public abstract class AbstractMetadataPopupLayoutVersioned - extends AbstractMetadataPopupLayout { - - private static final long serialVersionUID = 1L; - - protected AbstractMetadataPopupLayoutVersioned(final VaadinMessageSource i18n, final UINotification uiNotification, - final UIEventBus eventBus, final SpPermissionChecker permChecker) { - super(i18n, uiNotification, eventBus, permChecker); - } - - @Override - protected String getElementTitle() { - return HawkbitCommonUtil.getFormattedNameVersion(getSelectedEntity().getName(), - getSelectedEntity().getVersion()); - } -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/CommonDialogWindow.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/CommonDialogWindow.java index e06a3a441..d4514a176 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/CommonDialogWindow.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/CommonDialogWindow.java @@ -8,58 +8,27 @@ */ package org.eclipse.hawkbit.ui.common; -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - -import org.eclipse.hawkbit.ui.artifacts.smtable.SoftwareModuleAddUpdateWindow; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; +import org.eclipse.hawkbit.ui.decorators.SPUIButtonDecorator; import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleNoBorderWithIcon; -import org.eclipse.hawkbit.ui.management.targettable.TargetAddUpdateWindowLayout; 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.CollectionUtils; import org.springframework.util.StringUtils; -import org.vaadin.hene.flexibleoptiongroup.FlexibleOptionGroupItemComponent; -import com.google.common.collect.Maps; -import com.vaadin.data.Container.ItemSetChangeEvent; -import com.vaadin.data.Container.ItemSetChangeListener; -import com.vaadin.data.Property.ValueChangeEvent; -import com.vaadin.data.Property.ValueChangeListener; -import com.vaadin.data.Validator; -import com.vaadin.data.validator.NullValidator; -import com.vaadin.event.FieldEvents.TextChangeEvent; -import com.vaadin.event.FieldEvents.TextChangeListener; -import com.vaadin.event.FieldEvents.TextChangeNotifier; import com.vaadin.event.ShortcutAction.KeyCode; -import com.vaadin.server.FontAwesome; +import com.vaadin.icons.VaadinIcons; import com.vaadin.ui.AbstractComponent; -import com.vaadin.ui.AbstractField; -import com.vaadin.ui.AbstractLayout; -import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; -import com.vaadin.ui.CheckBox; import com.vaadin.ui.Component; -import com.vaadin.ui.Field; import com.vaadin.ui.GridLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Link; -import com.vaadin.ui.TabSheet; -import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; import com.vaadin.ui.themes.ValoTheme; @@ -71,38 +40,36 @@ import com.vaadin.ui.themes.ValoTheme; * */ public class CommonDialogWindow extends Window { - private static final long serialVersionUID = 1L; - private final VerticalLayout mainLayout = new VerticalLayout(); + private final VaadinMessageSource i18n; + private final VerticalLayout mainLayout; private final String caption; - private final Component content; - private final String helpLink; - - private Button saveButton; - + private final ConfirmStyle confirmStyle; + private final Class buttonDecorator; + private Button confirmButton; private Button cancelButton; - private HorizontalLayout buttonsLayout; + private Label mandatoryLabel; private final ClickListener cancelButtonClickListener; - - private final ClickListener closeClickListener = this::onCloseEvent; - - private final transient Map orginalValues; - - private List> allComponents; - - private final VaadinMessageSource i18n; + private final ClickListener closeClickListener; private transient SaveDialogCloseListener closeListener; /** - * Constructor. - * + * Different kinds of confirm buttons + */ + public enum ConfirmStyle { + SAVE, OK + } + + /** + * Constructor + * * @param caption * the caption * @param content @@ -113,28 +80,34 @@ public class CommonDialogWindow extends Window { * the saveDialogCloseListener * @param cancelButtonClickListener * the cancelButtonClickListener - * @param layout - * the abstract layout + * @param confirmStyle + * what kind of button is used + * @param buttonDecorator + * to style the confirm and cancel buttons * @param i18n - * the i18n service + * internationalization */ public CommonDialogWindow(final String caption, final Component content, final String helpLink, final SaveDialogCloseListener closeListener, final ClickListener cancelButtonClickListener, - final AbstractLayout layout, final VaadinMessageSource i18n) { - checkNotNull(closeListener); + final ConfirmStyle confirmStyle, final Class buttonDecorator, + final VaadinMessageSource i18n) { this.caption = caption; this.content = content; this.helpLink = helpLink; this.closeListener = closeListener; this.cancelButtonClickListener = cancelButtonClickListener; - this.allComponents = getAllComponents(layout); - this.orginalValues = Maps.newHashMapWithExpectedSize(allComponents.size()); + this.confirmStyle = confirmStyle; + this.buttonDecorator = buttonDecorator; this.i18n = i18n; + + this.mainLayout = new VerticalLayout(); + this.closeClickListener = this::onCloseEvent; + init(); } private void onCloseEvent(final ClickEvent clickEvent) { - if (!clickEvent.getButton().equals(saveButton)) { + if (!clickEvent.getButton().equals(confirmButton)) { close(); return; } @@ -153,56 +126,13 @@ public class CommonDialogWindow extends Window { @Override public void close() { super.close(); - orginalValues.clear(); - removeListeners(); - allComponents.clear(); - this.saveButton.setEnabled(false); - } - - private void removeListeners() { - for (final AbstractField field : allComponents) { - removeTextListener(field); - removeValueChangeListener(field); - removeItemSetChangeistener(field); - } - } - - private void removeItemSetChangeistener(final AbstractField field) { - if (!(field instanceof Table)) { - return; - } - for (final Object listener : field.getListeners(ItemSetChangeEvent.class)) { - if (listener instanceof ChangeListener) { - ((Table) field).removeItemSetChangeListener((ChangeListener) listener); - } - } - } - - private void removeTextListener(final AbstractField field) { - if (!(field instanceof TextChangeNotifier)) { - return; - } - for (final Object listener : field.getListeners(TextChangeEvent.class)) { - if (listener instanceof ChangeListener) { - ((TextChangeNotifier) field).removeTextChangeListener((ChangeListener) listener); - } - } - } - - private void removeValueChangeListener(final AbstractField field) { - for (final Object listener : field.getListeners(ValueChangeEvent.class)) { - if (listener instanceof ChangeListener) { - field.removeValueChangeListener((ChangeListener) listener); - } - } + this.confirmButton.setEnabled(false); } private final void init() { + mainLayout.setMargin(false); + mainLayout.setSpacing(false); - if (content instanceof AbstractOrderedLayout) { - ((AbstractOrderedLayout) content).setSpacing(true); - ((AbstractOrderedLayout) content).setMargin(true); - } if (content instanceof GridLayout) { addStyleName("marginTop"); } @@ -218,206 +148,27 @@ public class CommonDialogWindow extends Window { mainLayout.addComponent(buttonLayout); mainLayout.setComponentAlignment(buttonLayout, Alignment.TOP_CENTER); + setCaptionAsHtml(false); setCaption(caption); - setCaptionAsHtml(true); setContent(mainLayout); setResizable(false); center(); setModal(true); addStyleName("fontsize"); - setOrginaleValues(); - addComponentListeners(); - } - - /** - * saves the original values in a Map so we can use them for detecting - * changes - */ - public final void setOrginaleValues() { - for (final AbstractField field : allComponents) { - Object value = field.getValue(); - - if (field instanceof Table) { - value = ((Table) field).getContainerDataSource().getItemIds(); - } - orginalValues.put(field, value); - } - saveButton.setEnabled(isSaveButtonEnabledAfterValueChange(null, null)); - } - - /** - * Clears the original values in case no value changed check is wished - */ - public final void clearOriginalValues() { - orginalValues.clear(); } protected void addCloseListenerForSaveButton() { - saveButton.addClickListener(closeClickListener); + confirmButton.addClickListener(closeClickListener); } protected void addCloseListenerForCancelButton() { cancelButton.addClickListener(closeClickListener); } - /** - * adds a listener to a component. Depending on the type of component a - * valueChange-, textChange- or itemSetChangeListener will be added. - */ - public void addComponentListeners() { - // avoid duplicate registration - removeListeners(); - - for (final AbstractField field : allComponents) { - if (field instanceof TextChangeNotifier) { - ((TextChangeNotifier) field).addTextChangeListener(new ChangeListener(field)); - } - - if (field instanceof Table) { - ((Table) field).addItemSetChangeListener(new ChangeListener(field)); - } - field.addValueChangeListener(new ChangeListener(field)); - } - } - - private boolean isSaveButtonEnabledAfterValueChange(final Component currentChangedComponent, - final Object newValue) { - return isMandatoryFieldNotEmptyAndValid(currentChangedComponent, newValue) - && isValuesChanged(currentChangedComponent, newValue); - } - - private boolean isValuesChanged(final Component currentChangedComponent, final Object newValue) { - for (final AbstractField field : allComponents) { - Object originalValue = orginalValues.get(field); - if (field instanceof CheckBox && originalValue == null) { - originalValue = Boolean.FALSE; - } - final Object currentValue = getCurrentValue(currentChangedComponent, newValue, field); - - if (!Objects.equals(originalValue, currentValue)) { - return true; - } - } - return false; - } - - private static Object getCurrentValue(final Component currentChangedComponent, final Object newValue, - final AbstractField field) { - Object currentValue = field.getValue(); - if (field instanceof Table) { - currentValue = ((Table) field).getContainerDataSource().getItemIds(); - } - - if (field.equals(currentChangedComponent)) { - currentValue = newValue; - } - return currentValue; - } - - private boolean shouldMandatoryLabelShown() { - for (final AbstractField field : allComponents) { - if (field.isRequired()) { - return true; - } - } - - return false; - } - - private boolean isMandatoryFieldNotEmptyAndValid(final Component currentChangedComponent, final Object newValue) { - - boolean valid = true; - final List> requiredComponents = allComponents.stream().filter(AbstractField::isRequired) - .filter(AbstractField::isEnabled).collect(Collectors.toList()); - - requiredComponents.addAll(allComponents.stream().filter(this::hasNullValidator).collect(Collectors.toList())); - - for (final AbstractField field : requiredComponents) { - Object value = getCurrentValue(currentChangedComponent, newValue, field); - - if (Set.class.equals(field.getType())) { - value = emptyToNull((Collection) value); - } - - if (value == null) { - return false; - } - - // We need to loop through all of components for validity testing. - // Otherwise the UI will only mark the first field with errors and - // then stop. Setting the value is necessary because not all - // required input fields have empty string validator, but emptiness - // is checked during isValid() call. Setting the value could be - // redundant, check if it could be removed in the future. - field.setValue(value); - if (!field.isValid()) { - valid = false; - } - } - - return valid; - } - - private static Object emptyToNull(final Collection c) { - return CollectionUtils.isEmpty(c) ? null : c; - } - - private boolean hasNullValidator(final Component component) { - - if (component instanceof AbstractField) { - final AbstractField fieldComponent = (AbstractField) component; - for (final Validator validator : fieldComponent.getValidators()) { - if (validator instanceof NullValidator) { - return true; - } - } - } - return false; - } - - private static List> getAllComponents(final AbstractLayout abstractLayout) { - final List> components = new ArrayList<>(); - - final Iterator iterate = abstractLayout.iterator(); - while (iterate.hasNext()) { - final Component c = iterate.next(); - if (c instanceof AbstractLayout) { - components.addAll(getAllComponents((AbstractLayout) c)); - } - - if (c instanceof AbstractField) { - components.add((AbstractField) c); - } - - if (c instanceof FlexibleOptionGroupItemComponent) { - components.add(((FlexibleOptionGroupItemComponent) c).getOwner()); - } - - if (c instanceof TabSheet) { - final TabSheet tabSheet = (TabSheet) c; - components.addAll(getAllComponentsFromTabSheet(tabSheet)); - } - } - return components; - } - - private static List> getAllComponentsFromTabSheet(final TabSheet tabSheet) { - final List> components = new ArrayList<>(); - for (final Iterator i = tabSheet.iterator(); i.hasNext();) { - final Component component = i.next(); - if (component instanceof AbstractLayout) { - components.addAll(getAllComponents((AbstractLayout) component)); - } - } - return components; - } - private HorizontalLayout createActionButtonsLayout() { buttonsLayout = new HorizontalLayout(); buttonsLayout.setSizeFull(); - buttonsLayout.setSpacing(true); - buttonsLayout.setSpacing(true); buttonsLayout.addStyleName("actionButtonsMargin"); createSaveButton(); @@ -430,25 +181,25 @@ public class CommonDialogWindow extends Window { private void createMandatoryLabel() { - if (!shouldMandatoryLabelShown()) { - return; - } - - final Label mandatoryLabel = new Label(i18n.getMessage("label.mandatory.field")); + mandatoryLabel = new Label(i18n.getMessage("label.mandatory.field")); mandatoryLabel.addStyleName(SPUIStyleDefinitions.SP_TEXTFIELD_ERROR + " " + ValoTheme.LABEL_TINY); - if (content instanceof TargetAddUpdateWindowLayout) { - ((TargetAddUpdateWindowLayout) content).getFormLayout().addComponent(mandatoryLabel); - } else if (content instanceof SoftwareModuleAddUpdateWindow) { - ((SoftwareModuleAddUpdateWindow) content).getFormLayout().addComponent(mandatoryLabel); - } - mainLayout.addComponent(mandatoryLabel); } + /** + * Hide the line that explains the mandatory decorator + * + */ + public void hideMandatoryExplanation() { + if (mandatoryLabel != null) { + mainLayout.removeComponent(mandatoryLabel); + } + } + private void createCancelButton() { cancelButton = SPUIComponentProvider.getButton(UIComponentIdProvider.CANCEL_BUTTON, - i18n.getMessage(UIMessageIdProvider.BUTTON_CANCEL), "", "", true, FontAwesome.TIMES, + i18n.getMessage(UIMessageIdProvider.BUTTON_CANCEL), "", "", true, VaadinIcons.CLOSE, SPUIButtonStyleNoBorderWithIcon.class); cancelButton.setSizeUndefined(); cancelButton.addStyleName("default-color"); @@ -463,17 +214,23 @@ public class CommonDialogWindow extends Window { } private void createSaveButton() { - saveButton = SPUIComponentProvider.getButton(UIComponentIdProvider.SAVE_BUTTON, - i18n.getMessage(UIMessageIdProvider.BUTTON_SAVE), "", "", true, FontAwesome.SAVE, - SPUIButtonStyleNoBorderWithIcon.class); - saveButton.setSizeUndefined(); - saveButton.addStyleName("default-color"); + if (confirmStyle == ConfirmStyle.SAVE) { + confirmButton = SPUIComponentProvider.getButton(UIComponentIdProvider.SAVE_BUTTON, + i18n.getMessage(UIMessageIdProvider.BUTTON_SAVE), "", "", true, VaadinIcons.HARDDRIVE, + buttonDecorator); + } else { + confirmButton = SPUIComponentProvider.getButton(UIComponentIdProvider.OK_BUTTON, + i18n.getMessage(UIMessageIdProvider.BUTTON_OK), "", ValoTheme.BUTTON_PRIMARY, false, null, + buttonDecorator); + } + confirmButton.setSizeUndefined(); + confirmButton.addStyleName("default-color"); addCloseListenerForSaveButton(); - saveButton.setEnabled(false); - saveButton.setClickShortcut(KeyCode.ENTER); - buttonsLayout.addComponent(saveButton); - buttonsLayout.setComponentAlignment(saveButton, Alignment.MIDDLE_RIGHT); - buttonsLayout.setExpandRatio(saveButton, 1.0F); + confirmButton.setEnabled(false); + confirmButton.setClickShortcut(KeyCode.ENTER); + buttonsLayout.addComponent(confirmButton); + buttonsLayout.setComponentAlignment(confirmButton, Alignment.MIDDLE_RIGHT); + buttonsLayout.setExpandRatio(confirmButton, 1.0F); } private void addHelpLink() { @@ -490,62 +247,35 @@ public class CommonDialogWindow extends Window { return this.buttonsLayout; } - private class ChangeListener implements ValueChangeListener, TextChangeListener, ItemSetChangeListener { - - private static final long serialVersionUID = 1L; - private final Field field; - - public ChangeListener(final Field field) { - this.field = field; - } - - @Override - public void textChange(final TextChangeEvent event) { - saveButton.setEnabled(isSaveButtonEnabledAfterValueChange(field, event.getText())); - } - - @Override - public void valueChange(final ValueChangeEvent event) { - saveButton.setEnabled(isSaveButtonEnabledAfterValueChange(field, field.getValue())); - } - - @Override - public void containerItemSetChange(final ItemSetChangeEvent event) { - if (!(field instanceof Table)) { - return; - } - final Table table = (Table) field; - saveButton.setEnabled( - isSaveButtonEnabledAfterValueChange(table, table.getContainerDataSource().getItemIds())); - } - } - - /** - * Adds the component manually to the allComponents-List and adds a - * ValueChangeListener to it. Necessary in Update Distribution Type as the - * CheckBox concerned is an ItemProperty... - * - * @param component - * AbstractField - */ - public void updateAllComponents(final AbstractField component) { - - allComponents.add(component); - component.addValueChangeListener(new ChangeListener(component)); - } - public VerticalLayout getMainLayout() { return mainLayout; } + /** + * Enables the save confirmation button + * + * @param enabled + * boolean + * + */ public void setSaveButtonEnabled(final boolean enabled) { - saveButton.setEnabled(enabled); + confirmButton.setEnabled(enabled); } public void setCancelButtonEnabled(final boolean enabled) { cancelButton.setEnabled(enabled); } + /** + * Sets the close listener in save dialog + * + * @param closeListener + * SaveDialogCloseListener + */ + public void setCloseListener(final SaveDialogCloseListener closeListener) { + this.closeListener = closeListener; + } + /** * Check if the safe action can executed. After a the save action the * listener checks if the dialog can closed. @@ -556,38 +286,24 @@ public class CommonDialogWindow extends Window { /** * Checks if the safe action can executed. * - * @return true = save action can executed - * false = cannot execute safe action . + * @return = save action can executed = cannot execute + * safe action . */ boolean canWindowSaveOrUpdate(); /** - * Checks if the window can closed after the safe action is executed + * Checks if the window can be closed after the save action is executed * - * @return true = window will close false = - * will not closed. + * @return = window will close = will not closed. */ default boolean canWindowClose() { return true; } /** - * Saves/Updates action. Is called if canWindowSaveOrUpdate is - * true. + * Saves/Updates action. Is called if canWindowSaveOrUpdate is . * */ void saveOrUpdate(); } - - /** - * Updates the field allComponents. All components existing on the given - * layout are added to the list of allComponents - * - * @param layout - * AbstractLayout - */ - public void updateAllComponents(final AbstractLayout layout) { - allComponents = getAllComponents(layout); - } - } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/ConfirmationDialog.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/ConfirmationDialog.java index fa27ec8cb..de247b6e4 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/ConfirmationDialog.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/ConfirmationDialog.java @@ -8,164 +8,90 @@ */ package org.eclipse.hawkbit.ui.common; -import org.eclipse.hawkbit.ui.common.confirmwindow.layout.ConfirmationTab; -import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; +import java.io.Serializable; +import java.util.function.Consumer; + +import org.eclipse.hawkbit.ui.common.CommonDialogWindow.ConfirmStyle; +import org.eclipse.hawkbit.ui.common.CommonDialogWindow.SaveDialogCloseListener; +import org.eclipse.hawkbit.ui.common.builder.WindowBuilder; import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleTiny; +import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; +import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; -import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider; +import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; import org.springframework.util.StringUtils; -import com.vaadin.event.ShortcutAction.KeyCode; import com.vaadin.server.Resource; -import com.vaadin.shared.ui.label.ContentMode; -import com.vaadin.ui.Alignment; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.HorizontalLayout; +import com.vaadin.server.Sizeable.Unit; +import com.vaadin.shared.ui.ContentMode; +import com.vaadin.ui.Component; import com.vaadin.ui.Label; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; -import com.vaadin.ui.themes.ValoTheme; /** * Class for the confirmation dialog which pops up when deleting, assigning... * entities. */ -public class ConfirmationDialog implements Button.ClickListener { +public class ConfirmationDialog implements Serializable { private static final long serialVersionUID = 1L; - private transient ConfirmationDialogCallback callback; + private final transient Consumer callback; - private final Button okButton; - - private final Window window; - - private boolean isImplicitClose; + private final CommonDialogWindow window; /** * Constructor for configuring confirmation dialog. * + * @param i18n + * internationalization * @param caption * the dialog caption. * @param question * the question. - * @param okLabel - * the Ok button label. - * @param cancelLabel - * the cancel button label. * @param callback * the callback. * @param tab - * ConfirmationTab which contains more information about the action - * which has to be confirmed, e.g. maintenance window + * ConfirmationTab which contains more information about the + * action which has to be confirmed, e.g. maintenance window * @param id * the id of the confirmation window */ - public ConfirmationDialog(final String caption, final String question, final String okLabel, - final String cancelLabel, final ConfirmationDialogCallback callback, final ConfirmationTab tab, - final String id) { - this(caption, question, okLabel, cancelLabel, callback, null, id, tab); + public ConfirmationDialog(final VaadinMessageSource i18n, final String caption, final String question, + final Consumer callback, final Component tab, final String id) { + this(i18n, caption, question, callback, null, id, tab); } /** * Constructor for configuring confirmation dialog. * + * @param i18n + * internationalization * @param caption * the dialog caption. * @param question * the question. - * @param okLabel - * the Ok button label. - * @param cancelLabel - * the cancel button label. - * @param callback - * the callback. - */ - public ConfirmationDialog(final String caption, final String question, final String okLabel, - final String cancelLabel, final ConfirmationDialogCallback callback) { - this(caption, question, okLabel, cancelLabel, callback, null, null, null); - } - - /** - * Constructor for configuring confirmation dialog. - * - * @param caption - * the dialog caption. - * @param question - * the question. - * @param okLabel - * the Ok button label. - * @param cancelLabel - * the cancel button label. * @param callback * the callback. * @param id * the id of the confirmation dialog */ - public ConfirmationDialog(final String caption, final String question, final String okLabel, - final String cancelLabel, final ConfirmationDialogCallback callback, final String id) { - this(caption, question, okLabel, cancelLabel, callback, null, id, null); + public ConfirmationDialog(final VaadinMessageSource i18n, final String caption, final String question, + final Consumer callback, final String id) { + this(i18n, caption, question, callback, null, id, null); } /** * Constructor for configuring confirmation dialog. * + * @param i18n + * internationalization * @param caption * the dialog caption. * @param question * the question. - * @param okLabel - * the Ok button label. - * @param cancelLabel - * the cancel button label. - * @param callback - * the callback. - * @param id - * the id of the confirmation dialog - * @param mapCloseToCancel - * Flag indicating whether or not the close event on the enclosing - * window should be mapped to a cancel event. - */ - public ConfirmationDialog(final String caption, final String question, final String okLabel, - final String cancelLabel, final ConfirmationDialogCallback callback, final String id, - final boolean mapCloseToCancel) { - this(caption, question, okLabel, cancelLabel, callback, null, id, null, mapCloseToCancel); - } - - /** - * Constructor for configuring confirmation dialog. - * - * @param caption - * the dialog caption. - * @param question - * the question. - * @param okLabel - * the Ok button label. - * @param cancelLabel - * the cancel button label. - * @param callback - * the callback. - * @param icon - * the icon of the dialog - */ - public ConfirmationDialog(final String caption, final String question, final String okLabel, - final String cancelLabel, final ConfirmationDialogCallback callback, final Resource icon) { - this(caption, question, okLabel, cancelLabel, callback, icon, null, null); - } - - /** - * Constructor for configuring confirmation dialog. - * - * @param caption - * the dialog caption. - * @param question - * the question. - * @param okLabel - * the Ok button label. - * @param cancelLabel - * the cancel button label. * @param callback * the callback. * @param icon @@ -173,154 +99,84 @@ public class ConfirmationDialog implements Button.ClickListener { * @param id * the id of the confirmation dialog * @param tab - * ConfirmationTab which contains more information about the action - * which has to be confirmed, e.g. maintenance window + * ConfirmationTab which contains more information about the + * action which has to be confirmed, e.g. maintenance window */ - public ConfirmationDialog(final String caption, final String question, final String okLabel, - final String cancelLabel, final ConfirmationDialogCallback callback, final Resource icon, final String id, - final ConfirmationTab tab) { - this(caption, question, okLabel, cancelLabel, callback, icon, id, tab, false); + public ConfirmationDialog(final VaadinMessageSource i18n, final String caption, final String question, + final Consumer callback, final Resource icon, final String id, final Component tab) { - } + final VerticalLayout content = new VerticalLayout(); + content.setMargin(false); + content.setSpacing(false); - /** - * Constructor for configuring confirmation dialog. - * - * @param caption - * the dialog caption. - * @param question - * the question. - * @param okLabel - * the Ok button label. - * @param cancelLabel - * the cancel button label. - * @param callback - * the callback. - * @param icon - * the icon of the dialog - * @param id - * the id of the confirmation dialog - * @param tab - * ConfirmationTab which contains more information about the action - * which has to be confirmed, e.g. maintenance window - * @param mapCloseToCancel - * Flag indicating whether or not the close event on the enclosing - * window should be mapped to a cancel event. - */ - public ConfirmationDialog(final String caption, final String question, final String okLabel, - final String cancelLabel, final ConfirmationDialogCallback callback, final Resource icon, final String id, - final ConfirmationTab tab, final boolean mapCloseToCancel) { - window = new Window(caption); - if (!StringUtils.isEmpty(id)) { - window.setId(id); + if (question != null) { + content.addComponent(createConfirmationQuestion(question)); } - window.addStyleName(SPUIStyleDefinitions.CONFIRMATION_WINDOW_CAPTION); + if (tab != null) { + content.addComponent(tab); + } + final WindowBuilder windowBuilder = new WindowBuilder(SPUIDefinitions.CONFIRMATION_WINDOW).caption(caption) + .content(content).cancelButtonClickListener(e -> callback.accept(false)) + .saveDialogCloseListener(getSaveDialogCloseListener()).hideMandatoryExplanation() + .buttonDecorator(SPUIButtonStyleTiny.class).confirmStyle(ConfirmStyle.OK).i18n(i18n); + + if (!StringUtils.isEmpty(id)) { + windowBuilder.id(id); + } + this.window = windowBuilder.buildCommonDialogWindow(); + window.setSaveButtonEnabled(true); + this.callback = callback; if (icon != null) { window.setIcon(icon); } - okButton = createOkButton(okLabel); - - final Button cancelButton = createCancelButton(cancelLabel); - if (mapCloseToCancel) { - window.addCloseListener(e -> { - if (!isImplicitClose) { - cancelButton.click(); - } - }); - } - window.setModal(true); window.addStyleName(SPUIStyleDefinitions.CONFIRMBOX_WINDOW_STYLE); - if (this.callback == null) { - this.callback = callback; - } - final VerticalLayout vLayout = new VerticalLayout(); - if (question != null) { - vLayout.addComponent(createConfirmationQuestion(question)); - } - if (tab != null) { - vLayout.addComponent(tab); - } + } - final HorizontalLayout hButtonLayout = createButtonLayout(cancelButton); - hButtonLayout.addStyleName("marginTop"); - vLayout.addComponent(hButtonLayout); - vLayout.setComponentAlignment(hButtonLayout, Alignment.BOTTOM_CENTER); + private SaveDialogCloseListener getSaveDialogCloseListener() { + return new SaveDialogCloseListener() { + @Override + public void saveOrUpdate() { + if (window.getParent() != null) { + UI.getCurrent().removeWindow(window); + } + callback.accept(true); + } - window.setContent(vLayout); - window.setResizable(false); + @Override + public boolean canWindowSaveOrUpdate() { + return true; + } + }; } private static Label createConfirmationQuestion(final String question) { - final Label questionLbl = new Label(question, ContentMode.TEXT); + // ContentMode.HTML is used instead of ContentMode.PREFORMATTED here due + // to no linebreaks if an entity name is very long + final String questionHtmlSave = HawkbitCommonUtil.sanitizeHtml(question); + final Label questionLbl = new Label(questionHtmlSave, ContentMode.HTML); + questionLbl.setWidth(100, Unit.PERCENTAGE); questionLbl.addStyleName(SPUIStyleDefinitions.CONFIRMBOX_QUESTION_LABEL); return questionLbl; } - private HorizontalLayout createButtonLayout(final Button cancelButton) { - final HorizontalLayout hButtonLayout = new HorizontalLayout(); - hButtonLayout.setSpacing(true); - hButtonLayout.addComponent(okButton); - hButtonLayout.addComponent(cancelButton); - hButtonLayout.setSizeUndefined(); - hButtonLayout.setComponentAlignment(okButton, Alignment.TOP_CENTER); - hButtonLayout.setComponentAlignment(cancelButton, Alignment.TOP_CENTER); - return hButtonLayout; - } - - private Button createCancelButton(final String cancelLabel) { - final Button button = SPUIComponentProvider.getButton(UIComponentIdProvider.CANCEL_BUTTON, cancelLabel, "", - null, false, null, SPUIButtonStyleTiny.class); - button.addClickListener(this); - button.setClickShortcut(KeyCode.ESCAPE); - return button; - } - - private Button createOkButton(final String okLabel) { - final Button button = SPUIComponentProvider.getButton(UIComponentIdProvider.OK_BUTTON, okLabel, "", - ValoTheme.BUTTON_PRIMARY, false, null, SPUIButtonStyleTiny.class); - button.addClickListener(this); - button.setClickShortcut(KeyCode.ENTER); - return button; + /** + * Enables the ok save button + * + * @param enabled + * boolean + */ + public void setOkButtonEnabled(final boolean enabled) { + window.setSaveButtonEnabled(enabled); } /** - * TenantAwareEvent handler for button clicks. - * - * @param event - * the click event. + * @return confirmation window */ - @Override - public void buttonClick(final ClickEvent event) { - if (window.getParent() != null) { - isImplicitClose = true; - UI.getCurrent().removeWindow(window); - } - callback.response(event.getSource().equals(okButton)); - } - public Window getWindow() { return window; } - /** - * Interface for confirmation dialog callbacks. - */ - @FunctionalInterface - public interface ConfirmationDialogCallback { - /** - * The user response. - * - * @param ok - * True if user clicked ok. - */ - void response(boolean ok); - } - - public Button getOkButton() { - return okButton; - } - } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/CoordinatesToColor.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/CoordinatesToColor.java index 09f88d655..874108bb9 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/CoordinatesToColor.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/CoordinatesToColor.java @@ -15,8 +15,7 @@ import com.vaadin.ui.AbstractColorPicker.Coordinates2Color; * Converts 2d-coordinates to a Color. */ public class CoordinatesToColor implements Coordinates2Color { - - private static final long serialVersionUID = 9145071998551210789L; + private static final long serialVersionUID = 1L; @Override public Color calculate(final int x, final int y) { @@ -26,19 +25,19 @@ public class CoordinatesToColor implements Coordinates2Color { @Override public int[] calculate(final Color color) { final float[] hsv = color.getHSV(); - final int x = Math.round(hsv[0] * 220F); + final int x = (int) Math.round(hsv[0] * 220.0); final int y = calculateYCoordinateOfColor(hsv); return new int[] { x, y }; } private static Color calculateHSVColor(final int x, final int y) { - final float h = x / 220F; + final float h = (float) (x / 220.0); float s = 1F; float v = 1F; if (y < 110) { - s = y / 110F; + s = (float) (y / 110.0); } else if (y > 110) { - v = 1F - (y - 110F) / 110F; + v = (float) (1.0 - (y - 110.0) / 110.0); } return new Color(Color.HSVtoRGB(h, s, v)); } @@ -48,9 +47,9 @@ public class CoordinatesToColor implements Coordinates2Color { // lower half /* Assuming hsv[] array value will have in the range of 0 to 1 */ if (hsv[1] < 1F) { - y = Math.round(hsv[1] * 110F); + y = (int) Math.round(hsv[1] * 110.0); } else { - y = Math.round(110F - (hsv[1] + hsv[2]) * 110F); + y = (int) Math.round(110.0 - ((double) hsv[1] + (double) hsv[2]) * 110.0); } return y; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/DistributionSetTypeBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/DistributionSetTypeBeanQuery.java deleted file mode 100644 index ea3a7057c..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/DistributionSetTypeBeanQuery.java +++ /dev/null @@ -1,87 +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.common; - -import java.util.List; -import java.util.Map; - -import org.eclipse.hawkbit.repository.DistributionSetTypeManagement; -import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; -import org.eclipse.hawkbit.repository.model.DistributionSetType; -import org.eclipse.hawkbit.ui.utils.SpringContextHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -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; - -/** - * Distribution Set Type Bean query. - * - * - * - * - */ -public class DistributionSetTypeBeanQuery extends AbstractBeanQuery { - - private static final long serialVersionUID = 1329137292955215629L; - - private static final Logger LOG = LoggerFactory.getLogger(DistributionSetTypeBeanQuery.class); - - private final Sort sort = new Sort(Direction.ASC, "name"); - private transient DistributionSetTypeManagement distributionSetTypeManagement; - - /** - * Parametric constructor. - * - * @param definition - * @param queryConfig - * @param sortIds - * @param sortStates - */ - public DistributionSetTypeBeanQuery(final QueryDefinition definition, final Map queryConfig, - final Object[] sortIds, final boolean[] sortStates) { - super(definition, queryConfig, sortIds, sortStates); - } - - @Override - protected DistributionSetType constructBean() { - return null; - } - - @Override - public int size() { - - long size = getDistributionSetManagement().count(); - if (size > Integer.MAX_VALUE) { - size = Integer.MAX_VALUE; - } - return (int) size; - } - - private DistributionSetTypeManagement getDistributionSetManagement() { - if (distributionSetTypeManagement == null) { - distributionSetTypeManagement = SpringContextHelper.getBean(DistributionSetTypeManagement.class); - } - return distributionSetTypeManagement; - } - - @Override - protected List loadBeans(final int startIndex, final int count) { - return getDistributionSetManagement().findAll(new OffsetBasedPageRequest(startIndex, count, sort)).getContent(); - } - - @Override - protected void saveBeans(final List arg0, final List arg1, - final List arg2) { - LOG.info("in side of save Bean()"); - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/EmptyStringValidator.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/EmptyStringValidator.java deleted file mode 100644 index af3029fc0..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/EmptyStringValidator.java +++ /dev/null @@ -1,43 +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.common; - -import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; - -import com.vaadin.data.validator.StringLengthValidator; - -/** - * Assures that the entered text does not contain only whitespaces. At least one - * character has to be entered. Leading and trailing whitespaces are allowed as - * they will be trimmed by the repository. - */ -public class EmptyStringValidator extends StringLengthValidator { - - private static final long serialVersionUID = 1L; - - private static final String MESSAGE_KEY = "validator.textfield.min.length"; - - /** - * Constructor for EmptyStringValidator - * - * @param i18n - * {@link VaadinMessageSource} - * @param maxLength - * max length of the textfield - */ - public EmptyStringValidator(final VaadinMessageSource i18n, final int maxLength) { - super(i18n.getMessage(MESSAGE_KEY, maxLength), 1, maxLength, false); - } - - @Override - public boolean isValidValue(final String value) { - return super.isValidValue(value != null ? value.trim() : null); - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/EntityWindowLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/EntityWindowLayout.java new file mode 100644 index 000000000..e2160eb90 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/EntityWindowLayout.java @@ -0,0 +1,36 @@ +/** + * 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 java.util.function.Consumer; + +import com.vaadin.ui.ComponentContainer; + +/** + * Interface for entity window layout + * + * @param + * Generic type entity + */ +public interface EntityWindowLayout { + + ComponentContainer getRootComponent(); + + void setEntity(final T proxyEntity); + + T getEntity(); + + /** + * Method to add validation listeners. + * + * @param validationCallback + * Validation callback event + */ + void addValidationListener(final Consumer validationCallback); +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/ManagementEntityState.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/ManagementEntityState.java deleted file mode 100644 index 63b2a220c..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/ManagementEntityState.java +++ /dev/null @@ -1,35 +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.common; - -import java.util.Set; - -/** - * Interface for all entity states UI to show the details to a entity. - */ -public interface ManagementEntityState { - - /** - * The selected entities for the detail. - * - * @param values - * the selected entities. - * - */ - void setSelectedEnitities(Set values); - - /** - * The last selected value. - * - * @param value - * the value - */ - void setLastSelectedEntityId(Long value); - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/SoftwareModuleTypeBeanQuery.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/SoftwareModuleTypeBeanQuery.java deleted file mode 100644 index 44a61361d..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/SoftwareModuleTypeBeanQuery.java +++ /dev/null @@ -1,75 +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.common; - -import java.util.List; -import java.util.Map; - -import org.eclipse.hawkbit.repository.OffsetBasedPageRequest; -import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement; -import org.eclipse.hawkbit.repository.model.SoftwareModuleType; -import org.eclipse.hawkbit.ui.utils.SpringContextHelper; -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; - -/** - * - * - */ -public class SoftwareModuleTypeBeanQuery extends AbstractBeanQuery { - private static final long serialVersionUID = 7824925429198339644L; - - private final Sort sort = new Sort(Direction.ASC, "name"); - private transient SoftwareModuleTypeManagement softwareModuleTypeManagement; - - /** - * Parametric constructor. - */ - public SoftwareModuleTypeBeanQuery(final QueryDefinition definition, final Map queryConfig, - final Object[] sortIds, final boolean[] sortStates) { - super(definition, queryConfig, sortIds, sortStates); - } - - @Override - protected SoftwareModuleType constructBean() { - return null; - } - - @Override - public int size() { - long size = getSoftwareModuleTypeManagement().count(); - if (size > Integer.MAX_VALUE) { - size = Integer.MAX_VALUE; - } - return (int) size; - } - - private SoftwareModuleTypeManagement getSoftwareModuleTypeManagement() { - if (softwareModuleTypeManagement == null) { - softwareModuleTypeManagement = SpringContextHelper.getBean(SoftwareModuleTypeManagement.class); - } - return softwareModuleTypeManagement; - } - - @Override - protected List loadBeans(final int startIndex, final int count) { - - return getSoftwareModuleTypeManagement().findAll(new OffsetBasedPageRequest(startIndex, count, sort)) - .getContent(); - } - - @Override - protected void saveBeans(final List addedBeans, final List modifiedBeans, - final List removedBeans) { - // CRUD operations on Target will be done through repository methods - } - -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java index 6aa387b02..c67202f6a 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java @@ -173,6 +173,9 @@ public final class UserDetailsFormatter { return Optional.ofNullable(userPrincipal.getEmail()); } + /** + * @return Details of currently logged-in user + */ public static UserDetails getCurrentUser() { final SecurityContext context = (SecurityContext) VaadinService.getCurrentRequest().getWrappedSession() .getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/AbstractTextFieldBuilder.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/AbstractTextFieldBuilder.java index e84dd7e73..c56cd38b9 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/AbstractTextFieldBuilder.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/AbstractTextFieldBuilder.java @@ -8,14 +8,8 @@ */ package org.eclipse.hawkbit.ui.common.builder; -import java.util.LinkedList; -import java.util.List; - -import org.eclipse.hawkbit.ui.common.EmptyStringValidator; -import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; import org.springframework.util.StringUtils; -import com.vaadin.data.Validator; import com.vaadin.ui.AbstractTextField; /** @@ -34,18 +28,17 @@ public abstract class AbstractTextFieldBuilder { private String styleName; private String prompt; private String id; - private boolean immediate = true; - private boolean required; private boolean readOnly; private boolean enabled = true; private final int maxLengthAllowed; - private final List validators = new LinkedList<>(); protected AbstractTextFieldBuilder(final int maxLengthAllowed) { this.maxLengthAllowed = maxLengthAllowed; } /** + * Add caption to text field + * * @param caption * the caption to set * @return the builder @@ -57,6 +50,8 @@ public abstract class AbstractTextFieldBuilder { } /** + * Add style to text field + * * @param style * the style to set * @return the builder * @return the builder @@ -67,6 +62,8 @@ public abstract class AbstractTextFieldBuilder { } /** + * Add style name to text field + * * @param styleName * the styleName to set * @return the builder @@ -77,21 +74,8 @@ public abstract class AbstractTextFieldBuilder { } /** - * @param required - * the required to set - * @param i18n - * to translate error message - * @return the builder - */ - public T required(final boolean required, final VaadinMessageSource i18n) { - this.required = required; - if (required) { - validators.add(new EmptyStringValidator(i18n, maxLengthAllowed)); - } - return (T) this; - } - - /** + * Add read only to text field + * * @param readOnly * the readOnly to set * @return the builder @@ -102,6 +86,8 @@ public abstract class AbstractTextFieldBuilder { } /** + * Enable the text field + * * @param enabled * the enabled to set * @return the builder @@ -112,6 +98,8 @@ public abstract class AbstractTextFieldBuilder { } /** + * Add prompt to text field + * * @param prompt * the prompt to set * @return the builder @@ -122,16 +110,8 @@ public abstract class AbstractTextFieldBuilder { } /** - * @param immediate - * the immediate to set - * @return the builder - */ - public T immediate(final boolean immediate) { - this.immediate = immediate; - return (T) this; - } - - /** + * Add id to text field + * * @param id * the id to set * @return the builder @@ -141,17 +121,6 @@ public abstract class AbstractTextFieldBuilder { return (T) this; } - /** - * - * @param validator - * the validator to set for this field - * @return the builder - */ - public T validator(final Validator validator) { - validators.add(validator); - return (T) this; - } - /** * Build a textfield * @@ -160,8 +129,6 @@ public abstract class AbstractTextFieldBuilder { public E buildTextComponent() { final E textComponent = createTextComponent(); - textComponent.setRequired(required); - textComponent.setImmediate(immediate); textComponent.setReadOnly(readOnly); textComponent.setEnabled(enabled); @@ -177,7 +144,7 @@ public abstract class AbstractTextFieldBuilder { textComponent.addStyleName(styleName); } if (!StringUtils.isEmpty(prompt)) { - textComponent.setInputPrompt(prompt); + textComponent.setPlaceholder(prompt); } if (maxLengthAllowed > 0) { @@ -188,12 +155,6 @@ public abstract class AbstractTextFieldBuilder { textComponent.setId(id); } - if (!validators.isEmpty()) { - validators.forEach(textComponent::addValidator); - } - - textComponent.setNullRepresentation(""); - return textComponent; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/BoundComponent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/BoundComponent.java new file mode 100644 index 000000000..bc06cd525 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/BoundComponent.java @@ -0,0 +1,78 @@ +/** + * 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.builder; + +import java.io.Serializable; + +import com.vaadin.data.Binder.Binding; +import com.vaadin.ui.Component; + +/** + * Holds a {@link Component} and its {@link Binding} + * + * @param + * Component type + */ +public class BoundComponent implements Serializable { + private static final long serialVersionUID = 1L; + + private final T component; + private final Binding binding; + + /** + * Constructor + * + * @param component + * component + * @param binding + * binding of the component + */ + public BoundComponent(final T component, final Binding binding) { + this.component = component; + this.binding = binding; + } + + /** + * @return The component + */ + public T getComponent() { + return component; + } + + /** + * Set to true if the component is required + * + * @param isRequired + * boolean + */ + public void setRequired(final boolean isRequired) { + binding.setAsRequiredEnabled(isRequired); + } + + /** + * @return boolean + */ + public boolean isValid() { + return !binding.validate(false).isError(); + } + + /** + * Validate binding + */ + public void validate() { + binding.validate(); + } + + /** + * unbind the component + */ + public void unbind() { + binding.unbind(); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/ComboBoxBuilder.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/ComboBoxBuilder.java deleted file mode 100644 index cc4c0134f..000000000 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/ComboBoxBuilder.java +++ /dev/null @@ -1,72 +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.common.builder; - -import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; -import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; - -import com.vaadin.data.Property; -import com.vaadin.ui.ComboBox; -import com.vaadin.ui.themes.ValoTheme; - -/** - * Builds ComboBox Elements with a commonly used properties. - */ -public class ComboBoxBuilder { - - private Property.ValueChangeListener valueChangeListener; - - private String id; - - private String prompt; - - private String caption; - - public ComboBoxBuilder setValueChangeListener(final Property.ValueChangeListener valueChangeListener) { - this.valueChangeListener = valueChangeListener; - return this; - } - - public ComboBoxBuilder setId(final String id) { - this.id = id; - return this; - } - - public ComboBoxBuilder setPrompt(final String prompt) { - this.prompt = prompt; - return this; - } - - public ComboBoxBuilder setCaption(final String caption) { - this.caption = caption; - return this; - } - - /** - * @return a new ComboBox - */ - public ComboBox buildCombBox() { - final ComboBox comboBox = SPUIComponentProvider.getComboBox(null, "", null, ValoTheme.COMBOBOX_SMALL, false, "", - prompt); - comboBox.setImmediate(true); - comboBox.setPageLength(7); - comboBox.setItemCaptionPropertyId(SPUILabelDefinitions.VAR_NAME); - comboBox.setSizeUndefined(); - if (caption != null) { - comboBox.setCaption(caption); - } - if (id != null) { - comboBox.setId(id); - } - if (valueChangeListener != null) { - comboBox.addValueChangeListener(valueChangeListener); - } - return comboBox; - } -} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/FormComponentBuilder.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/FormComponentBuilder.java new file mode 100644 index 000000000..e003c672b --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/FormComponentBuilder.java @@ -0,0 +1,414 @@ +/** + * 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.builder; + +import org.eclipse.hawkbit.repository.model.NamedEntity; +import org.eclipse.hawkbit.repository.model.NamedVersionedEntity; +import org.eclipse.hawkbit.repository.model.Type; +import org.eclipse.hawkbit.ui.common.data.aware.ActionTypeAware; +import org.eclipse.hawkbit.ui.common.data.aware.DescriptionAware; +import org.eclipse.hawkbit.ui.common.data.aware.DsIdAware; +import org.eclipse.hawkbit.ui.common.data.aware.NameAware; +import org.eclipse.hawkbit.ui.common.data.aware.StartOptionAware; +import org.eclipse.hawkbit.ui.common.data.aware.TargetFilterQueryAware; +import org.eclipse.hawkbit.ui.common.data.aware.TypeInfoAware; +import org.eclipse.hawkbit.ui.common.data.aware.VersionAware; +import org.eclipse.hawkbit.ui.common.data.providers.DistributionSetStatelessDataProvider; +import org.eclipse.hawkbit.ui.common.data.providers.AbstractProxyDataProvider; +import org.eclipse.hawkbit.ui.common.data.providers.TargetFilterQueryDataProvider; +import org.eclipse.hawkbit.ui.common.data.proxies.ProxyDistributionSet; +import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTargetFilterQuery; +import org.eclipse.hawkbit.ui.common.data.proxies.ProxyType; +import org.eclipse.hawkbit.ui.common.data.proxies.ProxyTypeInfo; +import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; +import org.eclipse.hawkbit.ui.management.miscs.ActionTypeOptionGroupAssignmentLayout; +import org.eclipse.hawkbit.ui.rollout.window.components.AutoStartOptionGroupLayout; +import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil; +import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider; +import org.eclipse.hawkbit.ui.utils.UIMessageIdProvider; +import org.eclipse.hawkbit.ui.utils.VaadinMessageSource; +import org.springframework.util.StringUtils; + +import com.vaadin.data.Binder; +import com.vaadin.data.Binder.Binding; +import com.vaadin.data.Binder.BindingBuilder; +import com.vaadin.data.Validator; +import com.vaadin.data.ValueProvider; +import com.vaadin.server.Setter; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.ComboBox; +import com.vaadin.ui.TextArea; +import com.vaadin.ui.TextField; + +/** + * Builder class for from components + */ +public final class FormComponentBuilder { + public static final String TEXTFIELD_NAME = "textfield.name"; + public static final String TEXTFIELD_VERSION = "textfield.version"; + public static final String TEXTFIELD_DESCRIPTION = "textfield.description"; + + public static final String PROMPT_DISTRIBUTION_SET = "prompt.distribution.set"; + public static final String PROMPT_TARGET_FILTER = "prompt.target.filter"; + + public static final String CAPTION_TYPE = "caption.type"; + + private FormComponentBuilder() { + } + + /** + * Create an input field for a name + * + * @param + * type of the binder + * @param binder + * that is bound to the field + * @param i18n + * message source + * @param fieldId + * id of the field + * @return the TextField with its Binding + */ + public static BoundComponent createNameInput(final Binder binder, + final VaadinMessageSource i18n, final String fieldId) { + final TextField nameInput = new TextFieldBuilder(NamedEntity.NAME_MAX_SIZE).id(fieldId) + .caption(i18n.getMessage(TEXTFIELD_NAME)).prompt(i18n.getMessage(TEXTFIELD_NAME)).buildTextComponent(); + nameInput.setSizeUndefined(); + + final Binding binding = binder.forField(nameInput) + .asRequired(i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_NAMEREQUIRED)) + .bind(NameAware::getName, NameAware::setName); + + return new BoundComponent<>(nameInput, binding); + } + + /** + * Create a required input field for a version + * + * @param + * type of the binder + * @param binder + * that is bound to the field + * @param i18n + * message source + * @param fieldId + * id of the field + * @return the TextField + */ + public static BoundComponent createVersionInput(final Binder binder, + final VaadinMessageSource i18n, final String fieldId) { + final TextField versionInput = new TextFieldBuilder(NamedVersionedEntity.VERSION_MAX_SIZE).id(fieldId) + .caption(i18n.getMessage(TEXTFIELD_VERSION)).prompt(i18n.getMessage(TEXTFIELD_VERSION)) + .buildTextComponent(); + versionInput.setSizeUndefined(); + + final Binding binding = binder.forField(versionInput) + .asRequired(i18n.getMessage(UIMessageIdProvider.MESSAGE_ERROR_VERSIONREQUIRED)) + .bind(VersionAware::getVersion, VersionAware::setVersion); + + return new BoundComponent<>(versionInput, binding); + } + + /** + * Create an optional input field for a description + * + * @param + * type of the binder + * @param binder + * that is bound to the field + * @param i18n + * message source + * @param fieldId + * id of the field + * @return the TextArea + */ + public static BoundComponent