Migration of Action History to vaadin grid (#420)
* Migration of Action History to vaadin Grid Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
committed by
Kai Zimmermann
parent
081c3cccbf
commit
c8db41ff85
@@ -96,7 +96,7 @@ public final class MgmtRestConstants {
|
||||
/**
|
||||
* The tag URL mapping rest resource.
|
||||
*/
|
||||
public static final String TARGET_TAG_TAGERTS_REQUEST_MAPPING = "/{targetTagId}/targets";
|
||||
public static final String TARGET_TAG_TARGETS_REQUEST_MAPPING = "/{targetTagId}/targets";
|
||||
|
||||
/**
|
||||
* The tag URL mapping rest resource.
|
||||
|
||||
@@ -121,7 +121,7 @@ public interface MgmtTargetTagRestApi {
|
||||
*
|
||||
* @return the list of assigned targets.
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.GET, value = MgmtRestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING, produces = {
|
||||
@RequestMapping(method = RequestMethod.GET, value = MgmtRestConstants.TARGET_TAG_TARGETS_REQUEST_MAPPING, produces = {
|
||||
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE })
|
||||
ResponseEntity<List<MgmtTarget>> getAssignedTargets(@PathVariable("targetTagId") final Long targetTagId);
|
||||
|
||||
@@ -136,7 +136,7 @@ public interface MgmtTargetTagRestApi {
|
||||
*
|
||||
* @return the list of assigned targets and unassigned targets.
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.POST, value = MgmtRestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING
|
||||
@RequestMapping(method = RequestMethod.POST, value = MgmtRestConstants.TARGET_TAG_TARGETS_REQUEST_MAPPING
|
||||
+ "/toggleTagAssignment", consumes = { MediaTypes.HAL_JSON_VALUE,
|
||||
MediaType.APPLICATION_JSON_VALUE }, produces = { MediaTypes.HAL_JSON_VALUE,
|
||||
MediaType.APPLICATION_JSON_VALUE })
|
||||
@@ -154,7 +154,7 @@ public interface MgmtTargetTagRestApi {
|
||||
*
|
||||
* @return the list of assigned targets.
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.POST, value = MgmtRestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING, consumes = {
|
||||
@RequestMapping(method = RequestMethod.POST, value = MgmtRestConstants.TARGET_TAG_TARGETS_REQUEST_MAPPING, consumes = {
|
||||
MediaTypes.HAL_JSON_VALUE, MediaType.APPLICATION_JSON_VALUE }, produces = { MediaTypes.HAL_JSON_VALUE,
|
||||
MediaType.APPLICATION_JSON_VALUE })
|
||||
ResponseEntity<List<MgmtTarget>> assignTargets(@PathVariable("targetTagId") final Long targetTagId,
|
||||
@@ -167,7 +167,7 @@ public interface MgmtTargetTagRestApi {
|
||||
* the ID of the target tag to retrieve
|
||||
* @return http status code
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.DELETE, value = MgmtRestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING)
|
||||
@RequestMapping(method = RequestMethod.DELETE, value = MgmtRestConstants.TARGET_TAG_TARGETS_REQUEST_MAPPING)
|
||||
ResponseEntity<Void> unassignTargets(@PathVariable("targetTagId") final Long targetTagId);
|
||||
|
||||
/**
|
||||
@@ -179,7 +179,7 @@ public interface MgmtTargetTagRestApi {
|
||||
* the ID of the target to unassign
|
||||
* @return http status code
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.DELETE, value = MgmtRestConstants.TARGET_TAG_TAGERTS_REQUEST_MAPPING
|
||||
@RequestMapping(method = RequestMethod.DELETE, value = MgmtRestConstants.TARGET_TAG_TARGETS_REQUEST_MAPPING
|
||||
+ "/{controllerId}")
|
||||
ResponseEntity<Void> unassignTarget(@PathVariable("targetTagId") final Long targetTagId,
|
||||
@PathVariable("controllerId") final String controllerId);
|
||||
|
||||
@@ -62,7 +62,7 @@ public interface DeploymentManagement {
|
||||
* @throws IncompleteDistributionSetException
|
||||
* if mandatory {@link SoftwareModuleType} are not assigned as
|
||||
* define by the {@link DistributionSetType}.
|
||||
*
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if either provided {@link DistributionSet} or {@link Target}s
|
||||
* do not exist
|
||||
@@ -84,7 +84,7 @@ public interface DeploymentManagement {
|
||||
* @throws IncompleteDistributionSetException
|
||||
* if mandatory {@link SoftwareModuleType} are not assigned as
|
||||
* define by the {@link DistributionSetType}.
|
||||
*
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if either provided {@link DistributionSet} or {@link Target}s
|
||||
* do not exist
|
||||
@@ -108,7 +108,7 @@ public interface DeploymentManagement {
|
||||
* @throws IncompleteDistributionSetException
|
||||
* if mandatory {@link SoftwareModuleType} are not assigned as
|
||||
* define by the {@link DistributionSetType}.
|
||||
*
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if either provided {@link DistributionSet} or {@link Target}s
|
||||
* do not exist
|
||||
@@ -145,7 +145,7 @@ public interface DeploymentManagement {
|
||||
* @param controllerId
|
||||
* the target associated to the actions to count
|
||||
* @return the count value of found actions associated to the target
|
||||
*
|
||||
*
|
||||
* @throws RSQLParameterUnsupportedFieldException
|
||||
* if a field in the RSQL string is used but not provided by the
|
||||
* given {@code fieldNameProvider}
|
||||
@@ -290,6 +290,19 @@ public interface DeploymentManagement {
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
Page<ActionStatus> findActionStatusByActionWithMessages(@NotNull Pageable pageable, @NotNull Long actionId);
|
||||
|
||||
/**
|
||||
* Retrieves all messages for an {@link ActionStatus}.
|
||||
*
|
||||
*
|
||||
* @param pageable
|
||||
* the page request parameter for paging and sorting the result
|
||||
* @param actionStatusId
|
||||
* the id of {@link ActionStatus} to retrieve the messages from
|
||||
* @return a page of messages by a specific {@link ActionStatus} id
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
Page<String> findMessagesByActionStatusId(@NotNull Pageable pageable, @NotNull Long actionStatusId);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s of a specific target ordered by action ID.
|
||||
*
|
||||
@@ -297,7 +310,7 @@ public interface DeploymentManagement {
|
||||
* the target associated with the actions
|
||||
* @return a list of actions associated with the given target ordered by
|
||||
* action ID
|
||||
*
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if target with given ID does not exist
|
||||
*/
|
||||
@@ -392,7 +405,7 @@ public interface DeploymentManagement {
|
||||
|
||||
/**
|
||||
* All {@link ActionStatus} entries in the repository.
|
||||
*
|
||||
*
|
||||
* @param pageable
|
||||
* the pagination parameter
|
||||
* @return {@link Page} of {@link ActionStatus} entries
|
||||
|
||||
@@ -78,6 +78,17 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
*/
|
||||
Slice<Action> findByTargetControllerId(Pageable pageable, String controllerId);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s which are referring the given targetId
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
* @param targetId
|
||||
* the target to find assigned actions for
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
Page<Action> findByTargetId(Pageable pageable, Long targetId);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s which are active and referring to the given
|
||||
* {@link Target} order by ID ascending.
|
||||
@@ -93,14 +104,14 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
/**
|
||||
* Retrieves the oldest {@link Action} that is active and referring to the
|
||||
* given {@link Target}.
|
||||
*
|
||||
*
|
||||
* @param sort
|
||||
* order
|
||||
* @param controllerId
|
||||
* the target to find assigned actions
|
||||
* @param active
|
||||
* the action active flag
|
||||
*
|
||||
*
|
||||
* @return the found {@link Action}
|
||||
*/
|
||||
@EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD)
|
||||
@@ -209,6 +220,15 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
*/
|
||||
Long countByTargetControllerId(String controllerId);
|
||||
|
||||
/**
|
||||
* Counts all {@link Action}s referring to the given targetId.
|
||||
*
|
||||
* @param targetId
|
||||
* the target to count the {@link Action}s
|
||||
* @return the count of actions referring to the given target
|
||||
*/
|
||||
Long countByTargetId(Long targetId);
|
||||
|
||||
/**
|
||||
* Counts all {@link Action}s referring to the given DistributionSet.
|
||||
*
|
||||
|
||||
@@ -40,8 +40,8 @@ public interface ActionStatusRepository
|
||||
|
||||
/**
|
||||
* Retrieves all {@link ActionStatus} entries from repository of given
|
||||
* {@link Action}.
|
||||
*
|
||||
* ActionId.
|
||||
*
|
||||
* @param pageReq
|
||||
* parameters
|
||||
* @param actionId
|
||||
@@ -64,5 +64,4 @@ public interface ActionStatusRepository
|
||||
*/
|
||||
@EntityGraph(value = "ActionStatus.withMessages", type = EntityGraphType.LOAD)
|
||||
Page<ActionStatus> getByActionId(Pageable pageReq, Long actionId);
|
||||
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionWithStatusCount;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
@@ -656,6 +657,29 @@ public class JpaDeploymentManagement implements DeploymentManagement {
|
||||
return actionStatusRepository.getByActionId(pageReq, actionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<String> findMessagesByActionStatusId(final Pageable pageable, final Long actionStatusId) {
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
|
||||
final CriteriaQuery<Long> countMsgQuery = cb.createQuery(Long.class);
|
||||
final Root<JpaActionStatus> countMsgQueryFrom = countMsgQuery.distinct(true).from(JpaActionStatus.class);
|
||||
final ListJoin<JpaActionStatus, String> cJoin = countMsgQueryFrom.joinList("messages", JoinType.LEFT);
|
||||
countMsgQuery.select(cb.count(cJoin))
|
||||
.where(cb.equal(countMsgQueryFrom.get(JpaActionStatus_.id), actionStatusId));
|
||||
final Long totalCount = entityManager.createQuery(countMsgQuery).getSingleResult();
|
||||
|
||||
final CriteriaQuery<String> msgQuery = cb.createQuery(String.class);
|
||||
final Root<JpaActionStatus>as = msgQuery.from(JpaActionStatus.class);
|
||||
final ListJoin<JpaActionStatus, String> join = as.joinList("messages", JoinType.LEFT);
|
||||
final CriteriaQuery<String> selMsgQuery = msgQuery.select(join);
|
||||
selMsgQuery.where(cb.equal(as.get(JpaActionStatus_.id), actionStatusId));
|
||||
|
||||
final List<String> result = entityManager.createQuery(selMsgQuery).setFirstResult(pageable.getOffset())
|
||||
.setMaxResults(pageable.getPageSize()).getResultList().stream().collect(Collectors.toList());
|
||||
|
||||
return new PageImpl<>(result, pageable, totalCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<ActionStatus> findActionStatusAll(final Pageable pageable) {
|
||||
return convertAcSPage(actionStatusRepository.findAll(pageable), pageable);
|
||||
|
||||
@@ -30,13 +30,12 @@ import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedExcepti
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.ActionWithStatusCount;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetAssignmentResult;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
@@ -53,6 +52,7 @@ import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
@@ -148,24 +148,65 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Test verifies that the custom query to find all actions include the count of action status is working correctly")
|
||||
public void findActionsWithStatusCountByTarget() {
|
||||
@Description("Test verifies that actions of a target are found by using id-based search.")
|
||||
public void findActionByTargetId() {
|
||||
final DistributionSet testDs = testdataFactory.createDistributionSet("TestDs", "1.0",
|
||||
new ArrayList<DistributionSetTag>());
|
||||
final List<Target> testTarget = testdataFactory.createTargets(1);
|
||||
// one action with one action status is generated
|
||||
final Action action = deploymentManagement
|
||||
.findActionWithDetails(assignDistributionSet(testDs, testTarget).getActions().get(0)).get();
|
||||
// save 2 action status
|
||||
actionStatusRepository.save(new JpaActionStatus(action, Status.RETRIEVED, System.currentTimeMillis()));
|
||||
actionStatusRepository.save(new JpaActionStatus(action, Status.RUNNING, System.currentTimeMillis()));
|
||||
final Long actionId = assignDistributionSet(testDs, testTarget).getActions().get(0);
|
||||
|
||||
final List<ActionWithStatusCount> findActionsWithStatusCountByTarget = deploymentManagement
|
||||
.findActionsWithStatusCountByTargetOrderByIdDesc(testTarget.get(0).getControllerId());
|
||||
// act
|
||||
final Slice<Action> actions = deploymentManagement.findActionsByTarget(testTarget.get(0).getControllerId(),
|
||||
pageReq);
|
||||
final Long count = deploymentManagement.countActionsByTarget(testTarget.get(0).getControllerId());
|
||||
|
||||
assertThat(findActionsWithStatusCountByTarget).as("wrong action size").hasSize(1);
|
||||
assertThat(findActionsWithStatusCountByTarget.get(0).getActionStatusCount()).as("wrong action status size")
|
||||
.isEqualTo(3);
|
||||
assertThat(count).as("One Action for target").isEqualTo(1L).isEqualTo(actions.getContent().size());
|
||||
assertThat(actions.getContent().get(0).getId()).as("Action of target").isEqualTo(actionId);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Test verifies that action-states of an action are found by using id-based search.")
|
||||
public void findActionStatusByActionId() {
|
||||
final DistributionSet testDs = testdataFactory.createDistributionSet("TestDs", "1.0",
|
||||
new ArrayList<DistributionSetTag>());
|
||||
final List<Target> testTarget = testdataFactory.createTargets(1);
|
||||
// one action with one action status is generated
|
||||
final Long actionId = assignDistributionSet(testDs, testTarget).getActions().get(0);
|
||||
final Slice<Action> actions = deploymentManagement.findActionsByTarget(testTarget.get(0).getControllerId(),
|
||||
pageReq);
|
||||
final ActionStatus expectedActionStatus = actions.getContent().get(0).getActionStatus().get(0);
|
||||
|
||||
// act
|
||||
final Page<ActionStatus> actionStates = deploymentManagement.findActionStatusByAction(pageReq, actionId);
|
||||
|
||||
assertThat(actionStates.getContent()).hasSize(1);
|
||||
assertThat(actionStates.getContent().get(0)).as("Action-status of action").isEqualTo(expectedActionStatus);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Test verifies that messages of an action-status are found by using id-based search.")
|
||||
public void findMessagesByActionStatusId() {
|
||||
final DistributionSet testDs = testdataFactory.createDistributionSet("TestDs", "1.0",
|
||||
new ArrayList<DistributionSetTag>());
|
||||
final List<Target> testTarget = testdataFactory.createTargets(1);
|
||||
// one action with one action status is generated
|
||||
final Long actionId = assignDistributionSet(testDs, testTarget).getActions().get(0);
|
||||
// create action-status entry with one message
|
||||
controllerManagement.addUpdateActionStatus(entityFactory.actionStatus().create(actionId)
|
||||
.status(Action.Status.FINISHED).messages(Lists.newArrayList("finished message")));
|
||||
final Page<ActionStatus> actionStates = deploymentManagement.findActionStatusByAction(pageReq, actionId);
|
||||
// find newly created action-status entry with message
|
||||
final ActionStatus actionStatusWithMessage = actionStates.getContent().stream()
|
||||
.filter(entry -> entry.getMessages() != null && entry.getMessages().size() > 0).findFirst().get();
|
||||
final String expectedMsg = actionStatusWithMessage.getMessages().get(0);
|
||||
|
||||
// act
|
||||
final Page<String> messages = deploymentManagement.findMessagesByActionStatusId(pageReq,
|
||||
actionStatusWithMessage.getId());
|
||||
|
||||
assertThat(actionStates.getTotalElements()).as("Two action-states in total").isEqualTo(2L);
|
||||
assertThat(messages.getContent().get(0)).as("Message of action-status").isEqualTo(expectedMsg);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -176,7 +217,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
|
||||
assignDS.add(testdataFactory.createDistributionSet("DS" + i, "1.0", Collections.emptyList()).getId());
|
||||
}
|
||||
// not exists
|
||||
assignDS.add(Long.valueOf(100));
|
||||
assignDS.add(100L);
|
||||
|
||||
final DistributionSetTag tag = tagManagement
|
||||
.createDistributionSetTag(entityFactory.tag().create().name("Tag1"));
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -28,7 +26,6 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.vaadin.spring.events.EventBus;
|
||||
|
||||
import com.vaadin.annotations.Title;
|
||||
@@ -44,7 +41,6 @@ import com.vaadin.spring.navigator.SpringViewProvider;
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.Component;
|
||||
import com.vaadin.ui.CssLayout;
|
||||
import com.vaadin.ui.CustomLayout;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.Panel;
|
||||
@@ -84,6 +80,8 @@ public class HawkbitUI extends DefaultHawkbitUI implements DetachListener {
|
||||
@Autowired
|
||||
private NotificationUnreadButton notificationUnreadButton;
|
||||
|
||||
private Label viewTitle;
|
||||
|
||||
/**
|
||||
* Constructor taking the push strategy.
|
||||
*
|
||||
@@ -120,47 +118,22 @@ public class HawkbitUI extends DefaultHawkbitUI implements DetachListener {
|
||||
rootLayout.setSizeFull();
|
||||
|
||||
dashboardMenu.init();
|
||||
dashboardMenu.setResponsive(Boolean.TRUE);
|
||||
dashboardMenu.setResponsive(true);
|
||||
|
||||
final VerticalLayout contentVerticalLayout = new VerticalLayout();
|
||||
contentVerticalLayout.addComponent(buildHeader());
|
||||
contentVerticalLayout.setSizeFull();
|
||||
contentVerticalLayout.setStyleName("main-content");
|
||||
contentVerticalLayout.addComponent(buildHeader());
|
||||
contentVerticalLayout.addComponent(buildViewTitle());
|
||||
|
||||
final Panel content = buildContent();
|
||||
contentVerticalLayout.addComponent(content);
|
||||
contentVerticalLayout.setExpandRatio(content, 1);
|
||||
|
||||
rootLayout.addComponent(dashboardMenu);
|
||||
rootLayout.addComponent(contentVerticalLayout);
|
||||
|
||||
final HorizontalLayout viewHeadercontent = new HorizontalLayout();
|
||||
contentVerticalLayout.addComponent(viewHeadercontent);
|
||||
viewHeadercontent.setWidth("100%");
|
||||
viewHeadercontent.setHeight("43px");
|
||||
viewHeadercontent.addStyleName("view-header-layout");
|
||||
|
||||
final Label viewHeader = new Label();
|
||||
viewHeader.setWidth("100%");
|
||||
viewHeader.setStyleName("header-content");
|
||||
viewHeadercontent.addComponent(viewHeader);
|
||||
|
||||
viewHeadercontent.addComponent(notificationUnreadButton);
|
||||
viewHeadercontent.setComponentAlignment(notificationUnreadButton, Alignment.MIDDLE_RIGHT);
|
||||
|
||||
final Panel content = new Panel();
|
||||
content.setSizeFull();
|
||||
content.setStyleName("view-content");
|
||||
contentVerticalLayout.addComponent(content);
|
||||
|
||||
rootLayout.setExpandRatio(contentVerticalLayout, 1.0F);
|
||||
contentVerticalLayout.setStyleName("main-content");
|
||||
contentVerticalLayout.setExpandRatio(content, 1.0F);
|
||||
rootLayout.setExpandRatio(contentVerticalLayout, 1);
|
||||
setContent(rootLayout);
|
||||
final Resource resource = context
|
||||
.getResource("classpath:/VAADIN/themes/" + UI.getCurrent().getTheme() + "/layouts/footer.html");
|
||||
try (InputStream resourceStream = resource.getInputStream()) {
|
||||
final CustomLayout customLayout = new CustomLayout(resourceStream);
|
||||
customLayout.setSizeUndefined();
|
||||
contentVerticalLayout.addComponent(customLayout);
|
||||
} catch (final IOException ex) {
|
||||
LOG.error("Footer file cannot be loaded", ex);
|
||||
}
|
||||
|
||||
final Navigator navigator = new Navigator(this, content);
|
||||
navigator.addViewChangeListener(new ViewChangeListener() {
|
||||
@@ -176,10 +149,10 @@ public class HawkbitUI extends DefaultHawkbitUI implements DetachListener {
|
||||
final DashboardMenuItem view = dashboardMenu.getByViewName(event.getViewName());
|
||||
dashboardMenu.postViewChange(new PostViewChangeEvent(view));
|
||||
if (view == null) {
|
||||
viewHeader.setCaption(null);
|
||||
viewTitle.setCaption(null);
|
||||
return;
|
||||
}
|
||||
viewHeader.setCaption(view.getDashboardCaptionLong());
|
||||
viewTitle.setCaption(view.getDashboardCaptionLong());
|
||||
notificationUnreadButton.setCurrentView(event.getNewView());
|
||||
}
|
||||
});
|
||||
@@ -200,6 +173,28 @@ public class HawkbitUI extends DefaultHawkbitUI implements DetachListener {
|
||||
LOG.info("Current locale of the application is : {}", HawkbitCommonUtil.getLocale());
|
||||
}
|
||||
|
||||
private Panel buildContent() {
|
||||
final Panel content = new Panel();
|
||||
content.setSizeFull();
|
||||
content.setStyleName("view-content");
|
||||
return content;
|
||||
}
|
||||
|
||||
private HorizontalLayout buildViewTitle() {
|
||||
final HorizontalLayout viewHeadercontent = new HorizontalLayout();
|
||||
viewHeadercontent.setWidth("100%");
|
||||
viewHeadercontent.addStyleName("view-header-layout");
|
||||
|
||||
viewTitle = new Label();
|
||||
viewTitle.setWidth("100%");
|
||||
viewTitle.setStyleName("header-content");
|
||||
viewHeadercontent.addComponent(viewTitle);
|
||||
|
||||
viewHeadercontent.addComponent(notificationUnreadButton);
|
||||
viewHeadercontent.setComponentAlignment(notificationUnreadButton, Alignment.MIDDLE_RIGHT);
|
||||
return viewHeadercontent;
|
||||
}
|
||||
|
||||
private Component buildHeader() {
|
||||
final CssLayout cssLayout = new CssLayout();
|
||||
cssLayout.setStyleName("view-header");
|
||||
|
||||
@@ -467,12 +467,12 @@ public class ArtifactDetailsLayout extends VerticalLayout {
|
||||
}
|
||||
|
||||
private void showMinIcon() {
|
||||
maxMinButton.togleIcon(FontAwesome.COMPRESS);
|
||||
maxMinButton.toggleIcon(FontAwesome.COMPRESS);
|
||||
maxMinButton.setData(Boolean.TRUE);
|
||||
}
|
||||
|
||||
private void showMaxIcon() {
|
||||
maxMinButton.togleIcon(FontAwesome.EXPAND);
|
||||
maxMinButton.toggleIcon(FontAwesome.EXPAND);
|
||||
maxMinButton.setData(Boolean.FALSE);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,40 +8,70 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.common.grid;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.components.RefreshableContainer;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.addons.lazyquerycontainer.LazyQueryContainer;
|
||||
import org.vaadin.spring.events.EventBus;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.data.Container;
|
||||
import com.vaadin.data.Container.Indexed;
|
||||
import com.vaadin.data.util.GeneratedPropertyContainer;
|
||||
import com.vaadin.data.util.converter.Converter;
|
||||
import com.vaadin.ui.Grid;
|
||||
|
||||
/**
|
||||
* Abstract table class.
|
||||
* Abstract grid that offers various capabilities (aka support) to offer
|
||||
* convenient enhancements to the vaadin standard grid.
|
||||
*
|
||||
* @param <T>
|
||||
* The container-type used by the grid
|
||||
*/
|
||||
public abstract class AbstractGrid extends Grid implements RefreshableContainer {
|
||||
|
||||
private static final long serialVersionUID = 4856562746502217630L;
|
||||
public abstract class AbstractGrid<T extends Indexed> extends Grid implements RefreshableContainer {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected final VaadinMessageSource i18n;
|
||||
|
||||
protected final transient EventBus.UIEventBus eventBus;
|
||||
|
||||
protected final SpPermissionChecker permissionChecker;
|
||||
|
||||
protected AbstractGrid(final VaadinMessageSource i18n, final UIEventBus eventBus, final SpPermissionChecker permissionChecker) {
|
||||
private transient AbstractMaximizeSupport maximizeSupport;
|
||||
private transient AbstractGeneratedPropertySupport generatedPropertySupport;
|
||||
private transient SingleSelectionSupport singleSelectionSupport;
|
||||
private transient DetailsSupport detailsSupport;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param i18n
|
||||
* @param eventBus
|
||||
* @param permissionChecker
|
||||
*/
|
||||
protected AbstractGrid(final VaadinMessageSource i18n, final UIEventBus eventBus,
|
||||
final SpPermissionChecker permissionChecker) {
|
||||
this.i18n = i18n;
|
||||
this.eventBus = eventBus;
|
||||
this.permissionChecker = permissionChecker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the grid.
|
||||
* <p>
|
||||
*
|
||||
* <b>NOTE:</b> Sub-classes should configure the grid before calling this
|
||||
* method (this means: set all support-classes needed, and then call init).
|
||||
*/
|
||||
protected void init() {
|
||||
setSizeFull();
|
||||
setImmediate(true);
|
||||
setId(getGridId());
|
||||
setSelectionMode(SelectionMode.NONE);
|
||||
if (!hasSingleSelectionSupport()) {
|
||||
setSelectionMode(SelectionMode.NONE);
|
||||
}
|
||||
setColumnReorderingAllowed(true);
|
||||
addNewContainerDS();
|
||||
eventBus.subscribe(this);
|
||||
@@ -52,56 +82,593 @@ public abstract class AbstractGrid extends Grid implements RefreshableContainer
|
||||
*/
|
||||
@Override
|
||||
public void refreshContainer() {
|
||||
final Container container = getContainerDataSource();
|
||||
if (!(container instanceof LazyQueryContainer)) {
|
||||
final Indexed container = getContainerDataSource();
|
||||
if (hasGeneratedPropertySupport()
|
||||
&& getGeneratedPropertySupport().getRawContainer() instanceof LazyQueryContainer) {
|
||||
((LazyQueryContainer) getGeneratedPropertySupport().getRawContainer()).refresh();
|
||||
return;
|
||||
}
|
||||
((LazyQueryContainer) container).refresh();
|
||||
|
||||
if (container instanceof LazyQueryContainer) {
|
||||
((LazyQueryContainer) container).refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void addNewContainerDS() {
|
||||
final Container container = createContainer();
|
||||
setContainerDataSource((Indexed) container);
|
||||
/**
|
||||
* Creates a new container instance by calling the required
|
||||
* template-methods.
|
||||
* <p>
|
||||
* A new container is created on initialization as well as when container
|
||||
* content fundamentally changes (e.g. if container content depends on a
|
||||
* selection as common in master-details relations)
|
||||
*/
|
||||
protected void addNewContainerDS() {
|
||||
final T container = createContainer();
|
||||
Indexed indexedContainer = container;
|
||||
if (hasGeneratedPropertySupport()) {
|
||||
indexedContainer = getGeneratedPropertySupport().decorate(container);
|
||||
setContainerDataSource(indexedContainer);
|
||||
getGeneratedPropertySupport().addGeneratedContainerProperties();
|
||||
} else {
|
||||
setContainerDataSource(indexedContainer);
|
||||
}
|
||||
addContainerProperties();
|
||||
setColumnExpandRatio();
|
||||
|
||||
setColumnProperties();
|
||||
setColumnHeaderNames();
|
||||
setColumnsHidable();
|
||||
addColumnRenderes();
|
||||
setColumnExpandRatio();
|
||||
|
||||
setHiddenColumns();
|
||||
|
||||
final CellDescriptionGenerator cellDescriptionGenerator = getDescriptionGenerator();
|
||||
if (getDescriptionGenerator() != null) {
|
||||
setCellDescriptionGenerator(cellDescriptionGenerator);
|
||||
}
|
||||
|
||||
// Allow column hiding
|
||||
for (final Column c : getColumns()) {
|
||||
c.setHidable(true);
|
||||
}
|
||||
setHiddenColumns();
|
||||
int size = 0;
|
||||
if (container != null) {
|
||||
size = container.size();
|
||||
}
|
||||
if (size == 0) {
|
||||
if (indexedContainer != null && indexedContainer.size() == 0) {
|
||||
setData(SPUIDefinitions.NO_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Container createContainer();
|
||||
/**
|
||||
* Sets the standard behavior of columns to be hidable. If implementors
|
||||
* needs other behavior they have to concern about it.
|
||||
*/
|
||||
protected void setColumnsHidable() {
|
||||
// Allow column hiding
|
||||
for (final Column c : getColumns()) {
|
||||
c.setHidable(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables maximize-support for the grid by setting a MaximizeSupport
|
||||
* implementation.
|
||||
*
|
||||
* @param maximizeSupport
|
||||
* encapsulates behavior for minimize and maximize.
|
||||
*/
|
||||
protected void setMaximizeSupport(final AbstractMaximizeSupport maximizeSupport) {
|
||||
this.maximizeSupport = maximizeSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MaximizeSupport implementation describing behavior for minimize
|
||||
* and maximize.
|
||||
*
|
||||
* @return maximizeSupport that encapsulates behavior for minimize and
|
||||
* maximize.
|
||||
*/
|
||||
protected AbstractMaximizeSupport getMaximizeSupport() {
|
||||
return maximizeSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether maximize-support is enabled.
|
||||
*
|
||||
* @return <code>true</code> if maximize-support is enabled, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
protected boolean hasMaximizeSupport() {
|
||||
return maximizeSupport != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables support for generated properties. This implies that the
|
||||
* standard-container has to be decorated and the generators have to be
|
||||
* registered for the generated (aka virtual) properties.
|
||||
*
|
||||
* @param generatedPropertySupport
|
||||
* that encapsulates behavior for generated properties
|
||||
*/
|
||||
protected void setGeneratedPropertySupport(final AbstractGeneratedPropertySupport generatedPropertySupport) {
|
||||
this.generatedPropertySupport = generatedPropertySupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the GeneratedPropertySupport implementation describing generated
|
||||
* properties by registering their generators and attaching them to a
|
||||
* wrapper-container.
|
||||
*
|
||||
* @return generatedPropertySupport that encapsulates registration of
|
||||
* generated properties.
|
||||
*/
|
||||
protected AbstractGeneratedPropertySupport getGeneratedPropertySupport() {
|
||||
return generatedPropertySupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether support for generated properties is enabled.
|
||||
*
|
||||
* @return <code>true</code> if support for generated properties is enabled,
|
||||
* otherwise <code>false</code>
|
||||
*/
|
||||
protected boolean hasGeneratedPropertySupport() {
|
||||
return generatedPropertySupport != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables single-selection-support for the grid by setting
|
||||
* SingleSelectionSupport configuration.
|
||||
*
|
||||
* @param singleSelectionSupport
|
||||
* encapsulates behavior for single-selection and offers some
|
||||
* convenient functionality.
|
||||
*/
|
||||
protected void setSingleSelectionSupport(final SingleSelectionSupport singleSelectionSupport) {
|
||||
this.singleSelectionSupport = singleSelectionSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SingleSelectionSupport implementation configuring
|
||||
* single-selection.
|
||||
*
|
||||
* @return singleSelectionSupport that configures single-selection.
|
||||
*/
|
||||
protected SingleSelectionSupport getSingleSelectionSupport() {
|
||||
return singleSelectionSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether single-selection-support is enabled.
|
||||
*
|
||||
* @return <code>true</code> if single-selection-support is enabled,
|
||||
* otherwise <code>false</code>
|
||||
*/
|
||||
protected boolean hasSingleSelectionSupport() {
|
||||
return singleSelectionSupport != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables details-support for the grid by setting DetailsSupport
|
||||
* configuration. If details-support is enabled, the grid handles
|
||||
* details-data that depends on a master-selection.
|
||||
*
|
||||
* @param detailsSupport
|
||||
* encapsulates behavior for changes of master-selection.
|
||||
*/
|
||||
protected void setDetailsSupport(final DetailsSupport detailsSupport) {
|
||||
this.detailsSupport = detailsSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the DetailsSupport implementation configuring master-details
|
||||
* relation.
|
||||
*
|
||||
* @return detailsSupport that configures master-details relation.
|
||||
*/
|
||||
public DetailsSupport getDetailsSupport() {
|
||||
return detailsSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether details-support is enabled.
|
||||
*
|
||||
* @return <code>true</code> if details-support is enabled, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean hasDetailsSupport() {
|
||||
return detailsSupport != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method invoked by {@link this#addNewContainerDS()} for creating
|
||||
* a container instance.
|
||||
*
|
||||
* @return new container instance used by the grid.
|
||||
*/
|
||||
protected abstract T createContainer();
|
||||
|
||||
/**
|
||||
* Template method invoked by {@link this#addNewContainerDS()} for adding
|
||||
* properties to the container (usually by invoing
|
||||
* {@link Container#addContainerProperty(Object, Class, Object))})
|
||||
*/
|
||||
protected abstract void addContainerProperties();
|
||||
|
||||
/**
|
||||
* Template method invoked by {@link this#addNewContainerDS()} for setting
|
||||
* the expand ratio of the columns.
|
||||
*/
|
||||
protected abstract void setColumnExpandRatio();
|
||||
|
||||
/**
|
||||
* Template method invoked by {@link this#addNewContainerDS()} for setting
|
||||
* the column names.
|
||||
*/
|
||||
protected abstract void setColumnHeaderNames();
|
||||
|
||||
protected abstract String getGridId();
|
||||
|
||||
/**
|
||||
* Template method invoked by {@link this#addNewContainerDS()} for setting
|
||||
* the column properties to the grid.
|
||||
*/
|
||||
protected abstract void setColumnProperties();
|
||||
|
||||
/**
|
||||
* Template method invoked by {@link this#addNewContainerDS()} for adding
|
||||
* special column renderers if needed.
|
||||
*/
|
||||
protected abstract void addColumnRenderes();
|
||||
|
||||
/**
|
||||
* Template method invoked by {@link this#addNewContainerDS()} that hides
|
||||
* columns. If a column is hidable and hidden, it can be made visible via
|
||||
* grid column menu.
|
||||
*/
|
||||
protected abstract void setHiddenColumns();
|
||||
|
||||
/**
|
||||
* Template method invoked by {@link this#addNewContainerDS()} for adding a
|
||||
* CellDescriptionGenerator to the grid.
|
||||
*/
|
||||
protected abstract CellDescriptionGenerator getDescriptionGenerator();
|
||||
|
||||
/**
|
||||
* Gets id of the grid.
|
||||
*
|
||||
* @return id of the grid
|
||||
*/
|
||||
protected abstract String getGridId();
|
||||
|
||||
/**
|
||||
* Resets the default row of the header. This means the current default row
|
||||
* is removed and replaced with a newly created one.
|
||||
*
|
||||
* @return the new and clean header row.
|
||||
*/
|
||||
protected HeaderRow resetHeaderDefaultRow() {
|
||||
getHeader().removeRow(getHeader().getDefaultRow());
|
||||
final HeaderRow newHeaderRow = getHeader().appendRow();
|
||||
getHeader().setDefaultRow(newHeaderRow);
|
||||
return newHeaderRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for master-details relation for grid. This means that grid
|
||||
* content (=details) is updated as soon as master-data changes.
|
||||
*/
|
||||
public class DetailsSupport {
|
||||
|
||||
private Long master;
|
||||
|
||||
/**
|
||||
* Set selected master-data as member of this grid-support (as all
|
||||
* presented grid-data is related to this master-data) and re-calculate
|
||||
* grid-container-content.
|
||||
*
|
||||
* @param master
|
||||
* id of selected action
|
||||
*/
|
||||
public void populateMasterDataAndRecalculateContainer(final Long master) {
|
||||
this.master = master;
|
||||
recalculateContainer();
|
||||
populateSelection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set selected master-data as member of this grid-support (as all
|
||||
* presented grid-data is related to this master-data) and re-create
|
||||
* grid-container.
|
||||
*
|
||||
* @param master
|
||||
* id of selected action
|
||||
*/
|
||||
public void populateMasterDataAndRecreateContainer(final Long master) {
|
||||
this.master = master;
|
||||
recreateContainer();
|
||||
populateSelection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagates the selection if needed.
|
||||
*
|
||||
*/
|
||||
public void populateSelection() {
|
||||
if (!hasSingleSelectionSupport()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (master == null) {
|
||||
getSingleSelectionSupport().clearSelection();
|
||||
return;
|
||||
}
|
||||
getSingleSelectionSupport().selectFirstRow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the master-data id.
|
||||
*
|
||||
* @return master-data id
|
||||
*/
|
||||
public Long getMasterDataId() {
|
||||
return master;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates container-data (but reused container) and refreshes it
|
||||
* with new details-data for the new selected master-data.
|
||||
*/
|
||||
private void recalculateContainer() {
|
||||
clearSortOrder();
|
||||
refreshContainer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates container and replace it with a fresh instance for the
|
||||
* new selected master-data.
|
||||
*/
|
||||
private void recreateContainer() {
|
||||
removeAllColumns();
|
||||
clearSortOrder();
|
||||
addNewContainerDS();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Via implementations of this support capability an expand-mode is provided
|
||||
* that maximizes the grid size.
|
||||
*/
|
||||
protected abstract class AbstractMaximizeSupport {
|
||||
|
||||
/**
|
||||
* Renews the content for maximized layout.
|
||||
*/
|
||||
public void createMaximizedContent() {
|
||||
setMaximizedColumnProperties();
|
||||
setMaximizedHiddenColumns();
|
||||
setMaximizedHeaders();
|
||||
setMaximizedColumnExpandRatio();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renews the content for minimized layout.
|
||||
*/
|
||||
public void createMinimizedContent() {
|
||||
setColumnProperties();
|
||||
setHiddenColumns();
|
||||
setColumnExpandRatio();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the column properties for maximized-state.
|
||||
*/
|
||||
protected abstract void setMaximizedColumnProperties();
|
||||
|
||||
/**
|
||||
* Sets the hidden columns for maximized-state.
|
||||
*/
|
||||
protected abstract void setMaximizedHiddenColumns();
|
||||
|
||||
/**
|
||||
* Sets additional headers for maximized-state.
|
||||
*/
|
||||
protected abstract void setMaximizedHeaders();
|
||||
|
||||
/**
|
||||
* Sets column expand ratio for maximized-state.
|
||||
*/
|
||||
protected abstract void setMaximizedColumnExpandRatio();
|
||||
}
|
||||
|
||||
/**
|
||||
* Grids that are used in conjunction with
|
||||
* {@link GeneratedPropertyContainer}, might use
|
||||
* {@link AbstractGeneratedPropertySupport} to get type-save access to the
|
||||
* raw container as well as the decorated container.
|
||||
*/
|
||||
protected abstract class AbstractGeneratedPropertySupport {
|
||||
|
||||
/**
|
||||
* Gives type-save access to the wrapper container the grid works on.
|
||||
* This wrapper container attaches generated properties that are not
|
||||
* part of the raw container that encapsulates the database access.
|
||||
*
|
||||
* @return decorated container that includes the generated properties as
|
||||
* well as the native properties.
|
||||
*/
|
||||
public abstract GeneratedPropertyContainer getDecoratedContainer();
|
||||
|
||||
/**
|
||||
* Gives type-save access to the wrapped container that binds to the
|
||||
* database. The grid does not work directly with this container but
|
||||
* with a container that wraps and decorates it with generated
|
||||
* properties.
|
||||
*
|
||||
* @return raw container that gives access to the native properties.
|
||||
*/
|
||||
public abstract T getRawContainer();
|
||||
|
||||
/**
|
||||
* Adds the generated properties to the decorated container. Each
|
||||
* generated property has to be associated with a property generator
|
||||
* that is capable to calculate the value of the generated (aka virtual)
|
||||
* property.
|
||||
*
|
||||
* @return decorated container that includes the generated properties
|
||||
*/
|
||||
protected abstract GeneratedPropertyContainer addGeneratedContainerProperties();
|
||||
|
||||
/**
|
||||
* Decorates the raw-container by wrapping it.
|
||||
*
|
||||
* @param container
|
||||
* raw-container to be wrapped.
|
||||
* @return decorated container.
|
||||
*/
|
||||
protected GeneratedPropertyContainer decorate(final T container) {
|
||||
return new GeneratedPropertyContainer(container);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for single selection on the grid.
|
||||
*/
|
||||
protected class SingleSelectionSupport {
|
||||
|
||||
public SingleSelectionSupport() {
|
||||
enable();
|
||||
}
|
||||
|
||||
public final void enable() {
|
||||
setSelectionMode(SelectionMode.SINGLE);
|
||||
}
|
||||
|
||||
public final void disable() {
|
||||
setSelectionMode(SelectionMode.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the first row if available and enabled.
|
||||
*/
|
||||
public void selectFirstRow() {
|
||||
if (!isSingleSelectionModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Indexed container = getContainerDataSource();
|
||||
final int size = container.size();
|
||||
if (size > 0) {
|
||||
refreshRows(getContainerDataSource().firstItemId());
|
||||
getSingleSelectionModel().select(getContainerDataSource().firstItemId());
|
||||
} else {
|
||||
getSingleSelectionModel().select(null);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSingleSelectionModel() {
|
||||
return getSelectionModel() instanceof SelectionModel.Single;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the selection.
|
||||
*/
|
||||
public void clearSelection() {
|
||||
if (!isSingleSelectionModel()) {
|
||||
return;
|
||||
}
|
||||
getSingleSelectionModel().select(null);
|
||||
}
|
||||
|
||||
private SelectionModel.Single getSingleSelectionModel() {
|
||||
return (SelectionModel.Single) getSelectionModel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CellStyleGenerator that concerns about alignment in the grid cells.
|
||||
*/
|
||||
protected static class AlignCellStyleGenerator implements CellStyleGenerator {
|
||||
private static final long serialVersionUID = 5573570647129792429L;
|
||||
|
||||
private final String[] left;
|
||||
private final String[] center;
|
||||
private final String[] right;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param left
|
||||
* list of propertyIds that should be left-aligned
|
||||
* @param center
|
||||
* list of propertyIds that should be center-aligned
|
||||
* @param right
|
||||
* list of propertyIds that should be right-aligned
|
||||
*/
|
||||
public AlignCellStyleGenerator(final String[] left, final String[] center, final String[] right) {
|
||||
this.left = left;
|
||||
this.center = center;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStyle(final CellReference cellReference) {
|
||||
if (ArrayUtils.contains(center, cellReference.getPropertyId())) {
|
||||
return "centeralign";
|
||||
} else if (ArrayUtils.contains(right, cellReference.getPropertyId())) {
|
||||
return "rightalign";
|
||||
} else if (ArrayUtils.contains(left, cellReference.getPropertyId())) {
|
||||
return "leftalign";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tooltip to the 'Date and time' column in detailed format.
|
||||
*/
|
||||
public static class ModifiedTimeTooltipGenerator implements CellDescriptionGenerator {
|
||||
private static final long serialVersionUID = -6617911967167729195L;
|
||||
|
||||
private final String datePropertyId;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param datePropertyId
|
||||
*/
|
||||
public ModifiedTimeTooltipGenerator(final String datePropertyId) {
|
||||
this.datePropertyId = datePropertyId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription(final CellReference cell) {
|
||||
if (!datePropertyId.equals(cell.getPropertyId())) {
|
||||
return null;
|
||||
}
|
||||
final Long timestamp = (Long) cell.getItem().getItemProperty(datePropertyId).getValue();
|
||||
return SPDateTimeUtil.getFormattedDate(timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converter that gets time-data as input of type <code>Long</code> and
|
||||
* converts to a formatted date string.
|
||||
*/
|
||||
public class LongToFormattedDateStringConverter implements Converter<String, Long> {
|
||||
private static final long serialVersionUID = 1247513913478717845L;
|
||||
|
||||
@Override
|
||||
public Long convertToModel(final String value, final Class<? extends Long> targetType, final Locale locale) {
|
||||
// not needed
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertToPresentation(final Long value, final Class<? extends String> targetType,
|
||||
final Locale locale) {
|
||||
return SPDateTimeUtil.getFormattedDate(value, SPUIDefinitions.LAST_QUERY_DATE_FORMAT_SHORT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Long> getModelType() {
|
||||
return Long.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<String> getPresentationType() {
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* 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.grid;
|
||||
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.ui.AbstractOrderedLayout;
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.Grid;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.Layout;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
/**
|
||||
* Abstract grid layout class which builds layout with grid {@link AbstractGrid}
|
||||
* and grid header {@link DefaultGridHeader}.
|
||||
*/
|
||||
public abstract class AbstractGridComponentLayout extends VerticalLayout {
|
||||
private static final long serialVersionUID = -3766179797384539821L;
|
||||
|
||||
protected final transient EventBus.UIEventBus eventBus;
|
||||
protected final VaadinMessageSource i18n;
|
||||
|
||||
private AbstractOrderedLayout gridHeader;
|
||||
private Grid grid;
|
||||
|
||||
private transient AbstractFooterSupport footerSupport;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param i18n
|
||||
* @param deploymentManagement
|
||||
* @param eventBus
|
||||
* @param notification
|
||||
* @param managementUIState
|
||||
*/
|
||||
public AbstractGridComponentLayout(final VaadinMessageSource i18n, final UIEventBus eventBus) {
|
||||
super();
|
||||
this.i18n = i18n;
|
||||
this.eventBus = eventBus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this layout that presents a header and a grid.
|
||||
*/
|
||||
protected void init() {
|
||||
this.gridHeader = createGridHeader();
|
||||
this.grid = createGrid();
|
||||
buildLayout();
|
||||
setSizeFull();
|
||||
setImmediate(true);
|
||||
eventBus.subscribe(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Layouts header, grid and optional footer.
|
||||
*/
|
||||
protected void buildLayout() {
|
||||
setSizeFull();
|
||||
setSpacing(true);
|
||||
setMargin(false);
|
||||
setStyleName("group");
|
||||
final VerticalLayout gridHeaderLayout = new VerticalLayout();
|
||||
gridHeaderLayout.setSizeFull();
|
||||
gridHeaderLayout.setSpacing(false);
|
||||
gridHeaderLayout.setMargin(false);
|
||||
|
||||
gridHeaderLayout.setStyleName("table-layout");
|
||||
gridHeaderLayout.addComponent(gridHeader);
|
||||
|
||||
gridHeaderLayout.setComponentAlignment(gridHeader, Alignment.TOP_CENTER);
|
||||
gridHeaderLayout.addComponent(grid);
|
||||
gridHeaderLayout.setComponentAlignment(grid, Alignment.TOP_CENTER);
|
||||
gridHeaderLayout.setExpandRatio(grid, 1.0F);
|
||||
|
||||
addComponent(gridHeaderLayout);
|
||||
setComponentAlignment(gridHeaderLayout, Alignment.TOP_CENTER);
|
||||
setExpandRatio(gridHeaderLayout, 1.0F);
|
||||
if (hasFooterSupport()) {
|
||||
final Layout footerLayout = getFooterSupport().createFooterMessageComponent();
|
||||
addComponent(footerLayout);
|
||||
setComponentAlignment(footerLayout, Alignment.BOTTOM_CENTER);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the selection of this grid as master for another grid that
|
||||
* displays the details.
|
||||
*
|
||||
* @param details
|
||||
* the details of another grid the selection of this grid should
|
||||
* be registered for as master.
|
||||
*/
|
||||
public void registerDetails(final AbstractGrid<?>.DetailsSupport details) {
|
||||
grid.addSelectionListener(event -> {
|
||||
final Long masterId = (Long) event.getSelected().stream().findFirst().orElse(null);
|
||||
details.populateMasterDataAndRecalculateContainer(masterId);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the grid instance displayed and owned by the layout.
|
||||
*
|
||||
* @return grid instance displayed and owned by the layout.
|
||||
*/
|
||||
public Grid getGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the grid-header instance displayed and owned by the layout.
|
||||
*
|
||||
* @return grid-header instance displayed and owned by the layout.
|
||||
*/
|
||||
public AbstractOrderedLayout getHeader() {
|
||||
return gridHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the grid-header instance the layout is responsible for.
|
||||
*
|
||||
* @return newly created grid-header instance displayed and owned by the
|
||||
* layout.
|
||||
*/
|
||||
public abstract AbstractOrderedLayout createGridHeader();
|
||||
|
||||
/**
|
||||
* Creates the grid instance the layout is responsible for.
|
||||
*
|
||||
* @return newly created grid instance displayed and owned by the layout.
|
||||
*/
|
||||
public abstract Grid createGrid();
|
||||
|
||||
/**
|
||||
* Enables footer-support for the grid by setting a FooterSupport
|
||||
* implementation.
|
||||
*
|
||||
* @param footerSupport
|
||||
* encapsulates footer layout.
|
||||
*/
|
||||
public void setFooterSupport(final AbstractFooterSupport footerSupport) {
|
||||
this.footerSupport = footerSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the FooterSupport implementation describing footer layout.
|
||||
*
|
||||
* @return footerSupport that encapsulates footer layout.
|
||||
*/
|
||||
public AbstractFooterSupport getFooterSupport() {
|
||||
return footerSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether footer-support is enabled.
|
||||
*
|
||||
* @return <code>true</code> if footer-support is enabled, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean hasFooterSupport() {
|
||||
return footerSupport != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If footer support is enabled, the footer is placed below the component
|
||||
*/
|
||||
public abstract class AbstractFooterSupport {
|
||||
|
||||
/**
|
||||
* Creates a sub-layout for the footer.
|
||||
*
|
||||
* @return the footer sub-layout.
|
||||
*/
|
||||
private Layout createFooterMessageComponent() {
|
||||
final HorizontalLayout footerLayout = new HorizontalLayout();
|
||||
footerLayout.addComponent(getFooterMessageLabel());
|
||||
footerLayout.setStyleName(SPUIStyleDefinitions.FOOTER_LAYOUT);
|
||||
footerLayout.setWidth(100, Unit.PERCENTAGE);
|
||||
return footerLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the count message label.
|
||||
*
|
||||
* @return count message
|
||||
*/
|
||||
protected abstract Label getFooterMessageLabel();
|
||||
}
|
||||
}
|
||||
@@ -152,7 +152,7 @@ public abstract class AbstractGridHeader extends VerticalLayout {
|
||||
|
||||
private void openSearchTextField() {
|
||||
searchResetIcon.addStyleName(SPUIDefinitions.FILTER_RESET_ICON);
|
||||
searchResetIcon.togleIcon(FontAwesome.TIMES);
|
||||
searchResetIcon.toggleIcon(FontAwesome.TIMES);
|
||||
searchResetIcon.setData(Boolean.TRUE);
|
||||
searchField.removeStyleName(SPUIDefinitions.FILTER_BOX_HIDE);
|
||||
searchField.setVisible(true);
|
||||
@@ -164,7 +164,7 @@ public abstract class AbstractGridHeader extends VerticalLayout {
|
||||
searchField.addStyleName(SPUIDefinitions.FILTER_BOX_HIDE);
|
||||
searchField.setVisible(false);
|
||||
searchResetIcon.removeStyleName(SPUIDefinitions.FILTER_RESET_ICON);
|
||||
searchResetIcon.togleIcon(FontAwesome.SEARCH);
|
||||
searchResetIcon.toggleIcon(FontAwesome.SEARCH);
|
||||
searchResetIcon.setData(Boolean.FALSE);
|
||||
|
||||
resetSearchText();
|
||||
|
||||
@@ -1,96 +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.grid;
|
||||
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
/**
|
||||
*
|
||||
* Abstract grid layout class which builds layout with grid {@link AbstractGrid}
|
||||
* and table header {@link AbstractGridHeader}.
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractGridLayout extends VerticalLayout {
|
||||
|
||||
private static final long serialVersionUID = 8611248179949245460L;
|
||||
|
||||
private final AbstractGridHeader tableHeader;
|
||||
|
||||
protected final AbstractGrid grid;
|
||||
|
||||
protected AbstractGridLayout(final AbstractGridHeader tableHeader, final AbstractGrid grid) {
|
||||
this.tableHeader = tableHeader;
|
||||
this.grid = grid;
|
||||
}
|
||||
|
||||
protected void buildLayout() {
|
||||
setSizeFull();
|
||||
setSpacing(true);
|
||||
setMargin(false);
|
||||
setStyleName("group");
|
||||
final VerticalLayout tableHeaderLayout = new VerticalLayout();
|
||||
tableHeaderLayout.setSizeFull();
|
||||
tableHeaderLayout.setSpacing(false);
|
||||
tableHeaderLayout.setMargin(false);
|
||||
|
||||
tableHeaderLayout.setStyleName("table-layout");
|
||||
tableHeaderLayout.addComponent(tableHeader);
|
||||
|
||||
tableHeaderLayout.setComponentAlignment(tableHeader, Alignment.TOP_CENTER);
|
||||
tableHeaderLayout.addComponent(grid);
|
||||
tableHeaderLayout.setComponentAlignment(grid, Alignment.TOP_CENTER);
|
||||
tableHeaderLayout.setExpandRatio(grid, 1.0F);
|
||||
|
||||
addComponent(tableHeaderLayout);
|
||||
setComponentAlignment(tableHeaderLayout, Alignment.TOP_CENTER);
|
||||
setExpandRatio(tableHeaderLayout, 1.0F);
|
||||
if (hasCountMessage()) {
|
||||
final HorizontalLayout rolloutGroupTargetsCountLayout = createCountMessageComponent();
|
||||
addComponent(rolloutGroupTargetsCountLayout);
|
||||
setComponentAlignment(rolloutGroupTargetsCountLayout, Alignment.BOTTOM_CENTER);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private HorizontalLayout createCountMessageComponent() {
|
||||
final HorizontalLayout rolloutGroupTargetsCountLayout = new HorizontalLayout();
|
||||
final Label countMessageLabel = getCountMessageLabel();
|
||||
countMessageLabel.setId(UIComponentIdProvider.ROLLOUT_GROUP_TARGET_LABEL);
|
||||
rolloutGroupTargetsCountLayout.addComponent(getCountMessageLabel());
|
||||
rolloutGroupTargetsCountLayout.setStyleName(SPUIStyleDefinitions.FOOTER_LAYOUT);
|
||||
rolloutGroupTargetsCountLayout.setWidth("100%");
|
||||
return rolloutGroupTargetsCountLayout;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Only in rollout group targets view count message is displayed.
|
||||
*
|
||||
* @return true if count message has to be displayed
|
||||
*/
|
||||
protected abstract boolean hasCountMessage();
|
||||
|
||||
/**
|
||||
* Get the count message label.
|
||||
*
|
||||
* @return count message
|
||||
*/
|
||||
protected abstract Label getCountMessageLabel();
|
||||
|
||||
public AbstractGrid getGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
/**
|
||||
* 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.grid;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.hawkbit.ui.common.builder.LabelBuilder;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIButton;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder;
|
||||
import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
|
||||
|
||||
import com.vaadin.server.FontAwesome;
|
||||
import com.vaadin.shared.ui.label.ContentMode;
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
/**
|
||||
* Abstract grid header placed on top of a grid.
|
||||
*/
|
||||
public class DefaultGridHeader extends VerticalLayout {
|
||||
private static final long serialVersionUID = 1921798400953670917L;
|
||||
|
||||
private final ManagementUIState managementUIState;
|
||||
|
||||
private final String titleText;
|
||||
private Label title;
|
||||
private HorizontalLayout titleLayout;
|
||||
private transient AbstractHeaderMaximizeSupport maximizeSupport;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param managementUIState
|
||||
*/
|
||||
public DefaultGridHeader(final ManagementUIState managementUIState) {
|
||||
this(managementUIState, StringUtils.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param managementUIState
|
||||
* @param titleText
|
||||
*/
|
||||
public DefaultGridHeader(final ManagementUIState managementUIState, final String titleText) {
|
||||
this.managementUIState = managementUIState;
|
||||
this.titleText = titleText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the header.
|
||||
*
|
||||
* @return this DefaultGridHeader in order to allow method chaining
|
||||
*/
|
||||
public DefaultGridHeader init() {
|
||||
buildTitleLabel();
|
||||
buildTitleLayout();
|
||||
buildComponent();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the title label.
|
||||
*
|
||||
* @return title-label
|
||||
*/
|
||||
protected Label buildTitleLabel() {
|
||||
// create default title - even shown when no data is available
|
||||
title = new LabelBuilder().name(titleText).buildCaptionLabel();
|
||||
title.setImmediate(true);
|
||||
title.setContentMode(ContentMode.HTML);
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the title layout.
|
||||
*
|
||||
* @return title-layout
|
||||
*/
|
||||
protected HorizontalLayout buildTitleLayout() {
|
||||
titleLayout = new HorizontalLayout();
|
||||
titleLayout.addStyleName(SPUIStyleDefinitions.WIDGET_TITLE);
|
||||
titleLayout.setSpacing(false);
|
||||
titleLayout.setMargin(false);
|
||||
titleLayout.setSizeFull();
|
||||
titleLayout.addComponent(title);
|
||||
titleLayout.setComponentAlignment(title, Alignment.TOP_LEFT);
|
||||
titleLayout.setExpandRatio(title, 0.8F);
|
||||
|
||||
if (hasHeaderMaximizeSupport()) {
|
||||
titleLayout.addComponents(getHeaderMaximizeSupport().maxMinButton);
|
||||
titleLayout.setComponentAlignment(getHeaderMaximizeSupport().maxMinButton, Alignment.TOP_RIGHT);
|
||||
titleLayout.setExpandRatio(getHeaderMaximizeSupport().maxMinButton, 0.2F);
|
||||
}
|
||||
|
||||
return titleLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the layout for the header component.
|
||||
*/
|
||||
protected void buildComponent() {
|
||||
addComponent(titleLayout);
|
||||
setComponentAlignment(titleLayout, Alignment.TOP_LEFT);
|
||||
setWidth(100, Unit.PERCENTAGE);
|
||||
setImmediate(true);
|
||||
addStyleName("action-history-header");
|
||||
addStyleName("bordered-layout");
|
||||
addStyleName("no-border-bottom");
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables maximize-support for the header by setting a
|
||||
* HeaderMaximizeSupport implementation.
|
||||
*
|
||||
* @param maximizeSupport
|
||||
* encapsulates layout of min-max-button and behavior for
|
||||
* minimize and maximize.
|
||||
*/
|
||||
public void setHeaderMaximizeSupport(final AbstractHeaderMaximizeSupport maximizeSupport) {
|
||||
this.maximizeSupport = maximizeSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the HeaderMaximizeSupport implementation describing behavior for
|
||||
* minimize and maximize.
|
||||
*
|
||||
* @return maximizeSupport that encapsulates behavior for minimize and
|
||||
* maximize.
|
||||
*/
|
||||
public AbstractHeaderMaximizeSupport getHeaderMaximizeSupport() {
|
||||
return maximizeSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether maximize-support is enabled.
|
||||
*
|
||||
* @return <code>true</code> if maximize-support is enabled, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean hasHeaderMaximizeSupport() {
|
||||
return maximizeSupport != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the title of the header.
|
||||
*
|
||||
* @param newTitle
|
||||
*/
|
||||
public void updateTitle(final String newTitle) {
|
||||
title.setValue(newTitle);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Implemented capability offers a button that triggers minimization and
|
||||
* maximization.
|
||||
*/
|
||||
public abstract class AbstractHeaderMaximizeSupport {
|
||||
|
||||
private final SPUIButton maxMinButton;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param maximizeButtonId
|
||||
*/
|
||||
protected AbstractHeaderMaximizeSupport(final String maximizeButtonId) {
|
||||
maxMinButton = createMinMaxButton(maximizeButtonId);
|
||||
// listener for maximizing action history
|
||||
maxMinButton.addClickListener(event -> maxMinButtonClicked());
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when min-max-button is pressed.
|
||||
*/
|
||||
private void maxMinButtonClicked() {
|
||||
final Boolean flag = (Boolean) maxMinButton.getData();
|
||||
if (flag == null || Boolean.FALSE.equals(flag)) {
|
||||
// Clicked on max Icon
|
||||
showMinIcon();
|
||||
maximize();
|
||||
managementUIState.setActionHistoryMaximized(true);
|
||||
} else {
|
||||
// Clicked on min icon
|
||||
showMaxIcon();
|
||||
minimize();
|
||||
managementUIState.setActionHistoryMaximized(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional actions for maximize operation might be performed by this
|
||||
* method.
|
||||
*/
|
||||
protected abstract void maximize();
|
||||
|
||||
/**
|
||||
* Additional actions for minimize operation might be performed by this
|
||||
* method.
|
||||
*/
|
||||
protected abstract void minimize();
|
||||
|
||||
/**
|
||||
* Creates a min-max-button instance.
|
||||
*
|
||||
* @param buttonId
|
||||
* the button id for the min-max-button
|
||||
* @return newly cretaed min-max-button
|
||||
*/
|
||||
protected SPUIButton createMinMaxButton(final String buttonId) {
|
||||
return (SPUIButton) SPUIComponentProvider.getButton(buttonId, "", "Maximize", null, true,
|
||||
FontAwesome.EXPAND, SPUIButtonStyleSmallNoBorder.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Styles min-max-button icon with minimize decoration
|
||||
*/
|
||||
public void showMinIcon() {
|
||||
maxMinButton.toggleIcon(FontAwesome.COMPRESS);
|
||||
maxMinButton.setDescription("Minimize");
|
||||
maxMinButton.setData(Boolean.TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Styles min-max-button icon with maximize decoration
|
||||
*/
|
||||
public void showMaxIcon() {
|
||||
maxMinButton.toggleIcon(FontAwesome.EXPAND);
|
||||
maxMinButton.setDescription("Maximize");
|
||||
maxMinButton.setData(Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,7 +258,7 @@ public abstract class AbstractTableHeader extends VerticalLayout {
|
||||
|
||||
private void openSearchTextField() {
|
||||
searchResetIcon.addStyleName(SPUIDefinitions.FILTER_RESET_ICON);
|
||||
searchResetIcon.togleIcon(FontAwesome.TIMES);
|
||||
searchResetIcon.toggleIcon(FontAwesome.TIMES);
|
||||
searchResetIcon.setData(Boolean.TRUE);
|
||||
searchField.removeStyleName(SPUIDefinitions.FILTER_BOX_HIDE);
|
||||
searchField.focus();
|
||||
@@ -268,7 +268,7 @@ public abstract class AbstractTableHeader extends VerticalLayout {
|
||||
searchField.setValue("");
|
||||
searchField.addStyleName(SPUIDefinitions.FILTER_BOX_HIDE);
|
||||
searchResetIcon.removeStyleName(SPUIDefinitions.FILTER_RESET_ICON);
|
||||
searchResetIcon.togleIcon(FontAwesome.SEARCH);
|
||||
searchResetIcon.toggleIcon(FontAwesome.SEARCH);
|
||||
searchResetIcon.setData(Boolean.FALSE);
|
||||
resetSearchText();
|
||||
}
|
||||
@@ -297,12 +297,12 @@ public abstract class AbstractTableHeader extends VerticalLayout {
|
||||
}
|
||||
|
||||
private void showMinIcon() {
|
||||
maxMinIcon.togleIcon(FontAwesome.COMPRESS);
|
||||
maxMinIcon.toggleIcon(FontAwesome.COMPRESS);
|
||||
maxMinIcon.setData(Boolean.TRUE);
|
||||
}
|
||||
|
||||
private void showMaxIcon() {
|
||||
maxMinIcon.togleIcon(FontAwesome.EXPAND);
|
||||
maxMinIcon.toggleIcon(FontAwesome.EXPAND);
|
||||
maxMinIcon.setData(Boolean.FALSE);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ public class BaseUIEntityEvent<T extends BaseEntity> {
|
||||
|
||||
/**
|
||||
* Base entity event
|
||||
*
|
||||
*
|
||||
* @param eventType
|
||||
* the event type
|
||||
* @param entity
|
||||
@@ -55,7 +55,7 @@ public class BaseUIEntityEvent<T extends BaseEntity> {
|
||||
|
||||
/**
|
||||
* Base entity event
|
||||
*
|
||||
*
|
||||
* @param eventType
|
||||
* the event type
|
||||
* @param entityIds
|
||||
@@ -74,6 +74,10 @@ public class BaseUIEntityEvent<T extends BaseEntity> {
|
||||
return entity;
|
||||
}
|
||||
|
||||
public Collection<Long> getEntityIds() {
|
||||
return entityIds;
|
||||
}
|
||||
|
||||
public BaseEntityEventType getEventType() {
|
||||
return eventType;
|
||||
}
|
||||
@@ -81,7 +85,7 @@ public class BaseUIEntityEvent<T extends BaseEntity> {
|
||||
/**
|
||||
* Checks if the remote event is the same as this UI event. Then maybe you
|
||||
* can skip the remote event because it is already executed.
|
||||
*
|
||||
*
|
||||
* @param tenantAwareEvent
|
||||
* the remote event
|
||||
* @return {@code true} match ; {@code false} not match
|
||||
|
||||
@@ -93,7 +93,7 @@ public class NotificationUnreadButton extends Button {
|
||||
notificationsWindow.setClosable(true);
|
||||
notificationsWindow.setResizable(false);
|
||||
notificationsWindow.setDraggable(false);
|
||||
notificationsWindow.setId(UIComponentIdProvider.NOTIFICATION_UNREAD_POPUP_id);
|
||||
notificationsWindow.setId(UIComponentIdProvider.NOTIFICATION_UNREAD_POPUP_ID);
|
||||
notificationsWindow.addCloseListener(event -> refreshCaption());
|
||||
notificationsWindow.addBlurListener(this::closeWindow);
|
||||
}
|
||||
|
||||
@@ -27,12 +27,12 @@ public class SPUIButton extends Button {
|
||||
}
|
||||
|
||||
/**
|
||||
* Toogle Icon on action.
|
||||
*
|
||||
* Toggle Icon on action.
|
||||
*
|
||||
* @param icon
|
||||
* as Resource
|
||||
*/
|
||||
public void togleIcon(final Resource icon) {
|
||||
public void toggleIcon(final Resource icon) {
|
||||
setIcon(icon);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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.customrenderers.client;
|
||||
|
||||
import org.eclipse.hawkbit.ui.customrenderers.client.renderers.FontIconData;
|
||||
|
||||
import com.google.web.bindery.event.shared.HandlerRegistration;
|
||||
import com.vaadin.client.connectors.ClickableRendererConnector;
|
||||
import com.vaadin.client.renderers.ClickableRenderer.RendererClickHandler;
|
||||
import com.vaadin.shared.ui.Connect;
|
||||
|
||||
import elemental.json.JsonObject;
|
||||
|
||||
/**
|
||||
* A connector for {@link GridButtonRenderer }.
|
||||
*
|
||||
*/
|
||||
@Connect(org.eclipse.hawkbit.ui.customrenderers.renderers.GridButtonRenderer.class)
|
||||
public class GridButtonRendererConnector extends ClickableRendererConnector<FontIconData> {
|
||||
private static final long serialVersionUID = 7987417436367399331L;
|
||||
|
||||
@Override
|
||||
public org.eclipse.hawkbit.ui.customrenderers.client.renderers.GridButtonRenderer getRenderer() {
|
||||
return (org.eclipse.hawkbit.ui.customrenderers.client.renderers.GridButtonRenderer) super.getRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HandlerRegistration addClickHandler(final RendererClickHandler<JsonObject> handler) {
|
||||
return getRenderer().addClickHandler(handler);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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.customrenderers.client.renderers;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Data class that transports the icon meta-data to client-side renderer.
|
||||
*/
|
||||
public class FontIconData implements Serializable {
|
||||
|
||||
/** serialVersionUID. */
|
||||
private static final long serialVersionUID = 5823318280700107049L;
|
||||
private String fontIconHtml;
|
||||
private String style;
|
||||
private String title;
|
||||
private String id;
|
||||
private boolean disabled;
|
||||
|
||||
/**
|
||||
* Gets the html representing the icon.
|
||||
*
|
||||
* @return the html representing the icon
|
||||
*/
|
||||
public String getFontIconHtml() {
|
||||
return fontIconHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the html representing the icon.
|
||||
*
|
||||
* @param fontIconHtml
|
||||
* html representing the icon
|
||||
*/
|
||||
public void setFontIconHtml(String fontIconHtml) {
|
||||
this.fontIconHtml = fontIconHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the style.
|
||||
*
|
||||
* @return the style
|
||||
*/
|
||||
public String getStyle() {
|
||||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the style.
|
||||
*
|
||||
* @param style
|
||||
* icon style
|
||||
*/
|
||||
public void setStyle(String style) {
|
||||
this.style = style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the title shown as tooltip.
|
||||
*
|
||||
* @return the title shown as tooltip.
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the title shown as tooltip.
|
||||
*
|
||||
* @param title
|
||||
* shown as tooltip.
|
||||
*/
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id for direct access.
|
||||
*
|
||||
* @return the id for direct access.
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the id for direct access.
|
||||
*
|
||||
* @param id
|
||||
* for direct access.
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the disabled-state of the icon.
|
||||
*
|
||||
* @return the disabled-state of the icon.
|
||||
*/
|
||||
public boolean isDisabled() {
|
||||
return disabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the disabled-state of the icon.
|
||||
*
|
||||
* @param disabled
|
||||
* disabled-state of the icon.
|
||||
*/
|
||||
public void setDisabled(boolean disabled) {
|
||||
this.disabled = disabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 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.customrenderers.client.renderers;
|
||||
|
||||
import com.google.gwt.core.shared.GWT;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.vaadin.client.renderers.ClickableRenderer;
|
||||
import com.vaadin.client.ui.VButton;
|
||||
import com.vaadin.client.widget.grid.RendererCellReference;
|
||||
|
||||
/**
|
||||
* Renders button with provided HTML content. Used to display button with icons.
|
||||
*/
|
||||
public class GridButtonRenderer extends ClickableRenderer<FontIconData, Button> {
|
||||
|
||||
@Override
|
||||
public Button createWidget() {
|
||||
Button b = GWT.create(Button.class);
|
||||
b.addClickHandler(this);
|
||||
b.setStylePrimaryName("v-nativebutton");
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(final RendererCellReference cell, final FontIconData iconMetadata, final Button button) {
|
||||
if (iconMetadata.getFontIconHtml() != null) {
|
||||
button.setHTML(iconMetadata.getFontIconHtml());
|
||||
}
|
||||
applyStyles(button, iconMetadata.isDisabled(), iconMetadata.getStyle());
|
||||
button.getElement().setId(iconMetadata.getId());
|
||||
button.getElement().setTitle(iconMetadata.getTitle());
|
||||
button.setEnabled(!iconMetadata.isDisabled());
|
||||
// this is to allow the button to disappear, if the text is null
|
||||
button.setVisible(iconMetadata.getFontIconHtml() != null);
|
||||
}
|
||||
|
||||
private static void applyStyles(final Button button, final boolean buttonDisabled, final String additionalStyle) {
|
||||
|
||||
button.setStyleName(VButton.CLASSNAME);
|
||||
button.addStyleName(getStyle("tiny"));
|
||||
button.addStyleName(getStyle("borderless"));
|
||||
button.addStyleName(getStyle("button-no-border"));
|
||||
button.addStyleName(getStyle("action-type-padding"));
|
||||
button.addStyleName(getStyle(additionalStyle));
|
||||
|
||||
if (buttonDisabled) {
|
||||
button.addStyleName("v-disabled");
|
||||
}
|
||||
}
|
||||
|
||||
private static String getStyle(final String style) {
|
||||
return new StringBuilder(style).append(" ").append(VButton.CLASSNAME).append("-").append(style).toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,7 +17,7 @@ import com.vaadin.client.ui.VLabel;
|
||||
import com.vaadin.client.widget.grid.RendererCellReference;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Renders label with provided value and style.
|
||||
*
|
||||
*/
|
||||
@@ -33,6 +33,7 @@ public class HtmlLabelRenderer extends WidgetRenderer<String, VLabel> {
|
||||
Map<String, String> map = formatInput(input);
|
||||
String value = map.containsKey("value") ? map.get("value") : null;
|
||||
String style = map.containsKey("style") ? map.get("style") : null;
|
||||
String title = map.containsKey("title") ? map.get("title") : null;
|
||||
String id = map.containsKey("id") ? map.get("id") : null;
|
||||
|
||||
if (value != null) {
|
||||
@@ -42,6 +43,7 @@ public class HtmlLabelRenderer extends WidgetRenderer<String, VLabel> {
|
||||
}
|
||||
applyStyle(label, style);
|
||||
label.getElement().setId(id);
|
||||
label.getElement().setTitle(title);
|
||||
}
|
||||
|
||||
private void applyStyle(VLabel label, String style) {
|
||||
@@ -57,7 +59,7 @@ public class HtmlLabelRenderer extends WidgetRenderer<String, VLabel> {
|
||||
return new StringBuilder(style).append(" ").append(VLabel.CLASSNAME).append("-").append(style).toString();
|
||||
}
|
||||
|
||||
private Map<String, String> formatInput(String input) {
|
||||
private static Map<String, String> formatInput(String input) {
|
||||
Map<String, String> details = new HashMap<>();
|
||||
String[] tempData = input.split(",");
|
||||
for (String statusWithCount : tempData) {
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* 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.customrenderers.renderers;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.hawkbit.ui.customrenderers.client.renderers.FontIconData;
|
||||
import org.eclipse.hawkbit.ui.rollout.StatusFontIcon;
|
||||
|
||||
import com.vaadin.data.util.converter.Converter;
|
||||
|
||||
/**
|
||||
* Converter that adapts to a model and converts to a grid-button presentation.
|
||||
*
|
||||
* @param <T>
|
||||
* The type the converter adapts to
|
||||
*/
|
||||
public abstract class AbstractGridButtonConverter<T> implements Converter<FontIconData, T> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private GridButtonAdapter<T> adapter;
|
||||
|
||||
@Override
|
||||
public T convertToModel(final FontIconData meta, final Class<? extends T> targetType, final Locale locale) {
|
||||
// not needed
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FontIconData convertToPresentation(final T status, final Class<? extends FontIconData> targetType,
|
||||
final Locale locale) {
|
||||
if (adapter == null) {
|
||||
throw new IllegalStateException(
|
||||
"Adapter must be set before usage! Convertion without adapter is not possible!");
|
||||
}
|
||||
return createFontIconData(adapter.adapt(status));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a data transport object for the icon meta data.
|
||||
*
|
||||
* @param meta
|
||||
* icon metadata
|
||||
* @return icon metadata transport object
|
||||
*/
|
||||
private static FontIconData createFontIconData(StatusFontIcon meta) {
|
||||
FontIconData result = new FontIconData();
|
||||
result.setFontIconHtml(meta.getFontIcon().getHtml());
|
||||
result.setTitle(meta.getTitle());
|
||||
result.setStyle(meta.getStyle());
|
||||
result.setId(meta.getId());
|
||||
result.setDisabled(meta.isDisabled());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<FontIconData> getPresentationType() {
|
||||
return FontIconData.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an appropriate adapter to the converter. The adapter is mandatory
|
||||
* for the converter.
|
||||
*
|
||||
* @param adapter
|
||||
* label-adapter that converts from model to label-presentation.
|
||||
* @return self for method-chaining
|
||||
*/
|
||||
public AbstractGridButtonConverter<T> addAdapter(GridButtonAdapter<T> adapter) {
|
||||
this.adapter = adapter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts from model data to presentation data.
|
||||
*
|
||||
* @param <T>
|
||||
* The type to adapt to
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface GridButtonAdapter<T> extends Serializable {
|
||||
|
||||
/**
|
||||
* @param status
|
||||
* model data
|
||||
* @return meta representation that is used as input for label
|
||||
* generation.
|
||||
*/
|
||||
StatusFontIcon adapt(final T status);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* 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.customrenderers.renderers;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.hawkbit.ui.rollout.StatusFontIcon;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.vaadin.data.util.converter.Converter;
|
||||
|
||||
/**
|
||||
* Converter that adapts to a model and converts to a label presentation.
|
||||
*
|
||||
* @param <T>
|
||||
* The type the converter adapts to
|
||||
*/
|
||||
public abstract class AbstractHtmlLabelConverter<T> implements Converter<String, T> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private LabelAdapter<T> adapter;
|
||||
|
||||
@Override
|
||||
public T convertToModel(final String value, final Class<? extends T> targetType, final Locale locale) {
|
||||
// not needed
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertToPresentation(final T status, final Class<? extends String> targetType, final Locale locale) {
|
||||
return convert(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<String> getPresentationType() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an appropriate adapter to the converter. The adapter is mandatory
|
||||
* for the converter.
|
||||
*
|
||||
* @param adapter
|
||||
* label-adapter that converts from model to label-presentation.
|
||||
* @return self for method-chaining
|
||||
*/
|
||||
public AbstractHtmlLabelConverter<T> addAdapter(LabelAdapter<T> adapter) {
|
||||
this.adapter = adapter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the model data to a string representation of the presentation
|
||||
* label that is used on client-side to style the label.
|
||||
*
|
||||
* @param status
|
||||
* model data
|
||||
* @return string representation of label
|
||||
*/
|
||||
private String convert(final T status) {
|
||||
if (adapter == null) {
|
||||
throw new IllegalStateException(
|
||||
"Adapter must be set before usage! Convertion without adapter is not possible!");
|
||||
}
|
||||
final StatusFontIcon statusProps = adapter.adapt(status);
|
||||
// fail fast
|
||||
if (statusProps == null) {
|
||||
return "";
|
||||
}
|
||||
final String codePoint = getCodePoint(statusProps);
|
||||
final String title = statusProps.getTitle();
|
||||
return getStatusLabelDetailsInString(codePoint, statusProps.getStyle(), title, statusProps.getId(),
|
||||
statusProps.isDisabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a key:value map represented by a comma-separated list.
|
||||
*
|
||||
* @param fontIcon
|
||||
* the font representing the icon
|
||||
* @param style
|
||||
* the style
|
||||
* @param title
|
||||
* the title shown as tooltip
|
||||
* @param id
|
||||
* the id for direct access
|
||||
* @param disabled
|
||||
* disabled-state of the icon
|
||||
* @return string representation of key:value map
|
||||
*/
|
||||
private static String getStatusLabelDetailsInString(final String value, final String style, final String title,
|
||||
final String id, boolean disabled) {
|
||||
final StringBuilder val = new StringBuilder();
|
||||
if (!Strings.isNullOrEmpty(value)) {
|
||||
val.append("value:").append(value).append(",");
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(style)) {
|
||||
val.append("style:").append(style).append(",");
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(title)) {
|
||||
val.append("title:").append(title).append(",");
|
||||
}
|
||||
if (disabled) {
|
||||
val.append("disabled:true").append(",");
|
||||
}
|
||||
return val.append("id:").append(id).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the codepoint from the font-icon.
|
||||
*
|
||||
* @param statusFontIcon
|
||||
* the label-metadata that holds the font-icon
|
||||
*
|
||||
*/
|
||||
private static String getCodePoint(final StatusFontIcon statusFontIcon) {
|
||||
return statusFontIcon.getFontIcon() != null ? Integer.toString(statusFontIcon.getFontIcon().getCodepoint())
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts from model data to presentation data.
|
||||
*
|
||||
* @param <T>
|
||||
* The type to adapt to
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface LabelAdapter<T> extends Serializable {
|
||||
|
||||
/**
|
||||
* @param status
|
||||
* model data
|
||||
* @return meta representation that is used as input for label
|
||||
* generation.
|
||||
*/
|
||||
StatusFontIcon adapt(final T status);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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.customrenderers.renderers;
|
||||
|
||||
import org.eclipse.hawkbit.ui.customrenderers.client.renderers.FontIconData;
|
||||
import com.vaadin.ui.renderers.ClickableRenderer;
|
||||
import elemental.json.JsonValue;
|
||||
|
||||
/**
|
||||
* Renders buttons for a grid with provided HTML content based on meta-data.
|
||||
* Used to display button with icons.
|
||||
*/
|
||||
public class GridButtonRenderer extends ClickableRenderer<FontIconData> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public GridButtonRenderer() {
|
||||
super(FontIconData.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new custom object renderer and adds the given click listener to
|
||||
* it.
|
||||
*
|
||||
* @param listener
|
||||
* the click listener to register
|
||||
*/
|
||||
public GridButtonRenderer(final RendererClickListener listener) {
|
||||
this();
|
||||
addClickListener(listener);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Initialize custom object renderer with the given type.
|
||||
*
|
||||
* @param presentationType
|
||||
* Class<CustomObject>
|
||||
*/
|
||||
|
||||
public GridButtonRenderer(final Class<FontIconData> presentationType) {
|
||||
super(presentationType);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JsonValue encode(final FontIconData resource) {
|
||||
return super.encode(resource, FontIconData.class);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ package org.eclipse.hawkbit.ui.customrenderers.renderers;
|
||||
import com.vaadin.ui.Grid.AbstractRenderer;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Renders label with provided value and style.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -154,7 +154,7 @@ public class TargetFilterHeader extends VerticalLayout {
|
||||
|
||||
private void openSearchTextField() {
|
||||
searchResetIcon.addStyleName(SPUIDefinitions.FILTER_RESET_ICON);
|
||||
searchResetIcon.togleIcon(FontAwesome.TIMES);
|
||||
searchResetIcon.toggleIcon(FontAwesome.TIMES);
|
||||
searchResetIcon.setData(Boolean.TRUE);
|
||||
searchField.removeStyleName(SPUIDefinitions.FILTER_BOX_HIDE);
|
||||
searchField.setVisible(true);
|
||||
@@ -165,7 +165,7 @@ public class TargetFilterHeader extends VerticalLayout {
|
||||
searchField.setValue("");
|
||||
searchField.addStyleName(SPUIDefinitions.FILTER_BOX_HIDE);
|
||||
searchResetIcon.removeStyleName(SPUIDefinitions.FILTER_RESET_ICON);
|
||||
searchResetIcon.togleIcon(FontAwesome.SEARCH);
|
||||
searchResetIcon.toggleIcon(FontAwesome.SEARCH);
|
||||
searchResetIcon.setData(Boolean.FALSE);
|
||||
resetSearchText();
|
||||
|
||||
|
||||
@@ -28,7 +28,11 @@ import org.eclipse.hawkbit.ui.components.AbstractNotificationView;
|
||||
import org.eclipse.hawkbit.ui.components.NotificationUnreadButton;
|
||||
import org.eclipse.hawkbit.ui.components.RefreshableContainer;
|
||||
import org.eclipse.hawkbit.ui.dd.criteria.ManagementViewClientCriterion;
|
||||
import org.eclipse.hawkbit.ui.management.actionhistory.ActionHistoryComponent;
|
||||
import org.eclipse.hawkbit.ui.management.actionhistory.ActionHistoryLayout;
|
||||
import org.eclipse.hawkbit.ui.management.actionhistory.ActionStatusGrid;
|
||||
import org.eclipse.hawkbit.ui.management.actionhistory.ActionStatusLayout;
|
||||
import org.eclipse.hawkbit.ui.management.actionhistory.ActionStatusMsgGrid;
|
||||
import org.eclipse.hawkbit.ui.management.actionhistory.ActionStatusMsgLayout;
|
||||
import org.eclipse.hawkbit.ui.management.dstable.DistributionTableLayout;
|
||||
import org.eclipse.hawkbit.ui.management.dstag.DistributionTagLayout;
|
||||
import org.eclipse.hawkbit.ui.management.event.DistributionTableEvent;
|
||||
@@ -89,7 +93,11 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
|
||||
|
||||
private final ManagementUIState managementUIState;
|
||||
|
||||
private final ActionHistoryComponent actionHistoryComponent;
|
||||
private final ActionHistoryLayout actionHistoryLayout;
|
||||
|
||||
private final ActionStatusLayout actionStatusLayout;
|
||||
|
||||
private final ActionStatusMsgLayout actionStatusMsgLayout;
|
||||
|
||||
private final TargetTagFilterLayout targetTagFilterLayout;
|
||||
|
||||
@@ -97,7 +105,7 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
|
||||
|
||||
private final DistributionTagLayout distributionTagLayout;
|
||||
|
||||
private final DistributionTableLayout distributionTableLayoutNew;
|
||||
private final DistributionTableLayout distributionTableLayout;
|
||||
|
||||
private final DeleteActionsLayout deleteAndActionsLayout;
|
||||
|
||||
@@ -121,8 +129,10 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
|
||||
this.i18n = i18n;
|
||||
this.uiNotification = uiNotification;
|
||||
this.managementUIState = managementUIState;
|
||||
this.actionHistoryComponent = new ActionHistoryComponent(i18n, deploymentManagement, eventBus, uiNotification,
|
||||
this.actionHistoryLayout = new ActionHistoryLayout(i18n, deploymentManagement, eventBus, uiNotification,
|
||||
managementUIState);
|
||||
this.actionStatusLayout = new ActionStatusLayout(i18n, eventBus, managementUIState);
|
||||
this.actionStatusMsgLayout = new ActionStatusMsgLayout(i18n, eventBus, managementUIState);
|
||||
final CreateUpdateTargetTagLayoutWindow createUpdateTargetTagLayout = new CreateUpdateTargetTagLayoutWindow(
|
||||
i18n, tagManagement, entityFactory, eventBus, permChecker, uiNotification);
|
||||
this.targetTagFilterLayout = new TargetTagFilterLayout(i18n, createUpdateTargetTagLayout, managementUIState,
|
||||
@@ -139,7 +149,7 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
|
||||
this.distributionTagLayout = new DistributionTagLayout(eventbus, managementUIState, i18n, permChecker, eventBus,
|
||||
tagManagement, entityFactory, uiNotification, distFilterParameters, distributionSetManagement,
|
||||
managementViewClientCriterion);
|
||||
this.distributionTableLayoutNew = new DistributionTableLayout(i18n, eventBus, permChecker, managementUIState,
|
||||
this.distributionTableLayout = new DistributionTableLayout(i18n, eventBus, permChecker, managementUIState,
|
||||
distributionSetManagement, managementViewClientCriterion, entityFactory, uiNotification, tagManagement,
|
||||
systemManagement, targetManagement, deploymentManagement);
|
||||
this.deleteAndActionsLayout = new DeleteActionsLayout(i18n, permChecker, eventBus, uiNotification,
|
||||
@@ -147,6 +157,9 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
|
||||
deploymentManagement, distributionSetManagement);
|
||||
|
||||
this.deploymentViewMenuItem = deploymentViewMenuItem;
|
||||
|
||||
actionHistoryLayout.registerDetails(((ActionStatusGrid) actionStatusLayout.getGrid()).getDetailsSupport());
|
||||
actionStatusLayout.registerDetails(((ActionStatusMsgGrid) actionStatusMsgLayout.getGrid()).getDetailsSupport());
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
@@ -238,11 +251,13 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
|
||||
mainLayout.setRows(2);
|
||||
mainLayout.addComponent(targetTagFilterLayout, 0, 0);
|
||||
mainLayout.addComponent(targetTableLayout, 1, 0);
|
||||
mainLayout.addComponent(actionHistoryComponent, 4, 0);
|
||||
mainLayout.addComponent(distributionTableLayoutNew, 2, 0);
|
||||
mainLayout.addComponent(distributionTableLayout, 2, 0);
|
||||
mainLayout.addComponent(distributionTagLayout, 3, 0);
|
||||
mainLayout.addComponent(actionHistoryLayout, 4, 0);
|
||||
mainLayout.setColumnExpandRatio(0, 0F);
|
||||
mainLayout.setColumnExpandRatio(1, 0.275F);
|
||||
mainLayout.setColumnExpandRatio(2, 0.275F);
|
||||
mainLayout.setColumnExpandRatio(3, 0F);
|
||||
mainLayout.setColumnExpandRatio(4, 0.45F);
|
||||
if (showFooterLayout()) {
|
||||
mainLayout.addComponent(deleteAndActionsLayout, 1, 1, 2, 1);
|
||||
@@ -253,7 +268,7 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
|
||||
private void displayDistributionWidgetsOnly() {
|
||||
mainLayout.setColumns(2);
|
||||
mainLayout.setRows(2);
|
||||
mainLayout.addComponent(distributionTableLayoutNew, 0, 0);
|
||||
mainLayout.addComponent(distributionTableLayout, 0, 0);
|
||||
mainLayout.addComponent(distributionTagLayout, 1, 0);
|
||||
mainLayout.setColumnExpandRatio(0, 1F);
|
||||
if (showFooterLayout()) {
|
||||
@@ -280,7 +295,7 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
|
||||
mainLayout.setRows(2);
|
||||
mainLayout.addComponent(targetTagFilterLayout, 0, 0);
|
||||
mainLayout.addComponent(targetTableLayout, 1, 0);
|
||||
mainLayout.addComponent(actionHistoryComponent, 2, 0);
|
||||
mainLayout.addComponent(actionHistoryLayout, 2, 0);
|
||||
mainLayout.setColumnExpandRatio(1, 0.4F);
|
||||
mainLayout.setColumnExpandRatio(2, 0.6F);
|
||||
if (showFooterLayout()) {
|
||||
@@ -291,10 +306,10 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
|
||||
|
||||
private void maximizeTargetTable() {
|
||||
if (permChecker.hasReadDistributionPermission()) {
|
||||
mainLayout.removeComponent(distributionTableLayoutNew);
|
||||
mainLayout.removeComponent(distributionTableLayout);
|
||||
mainLayout.removeComponent(distributionTagLayout);
|
||||
}
|
||||
mainLayout.removeComponent(actionHistoryComponent);
|
||||
mainLayout.removeComponent(actionHistoryLayout);
|
||||
mainLayout.removeComponent(deleteAndActionsLayout);
|
||||
mainLayout.setColumnExpandRatio(1, 1F);
|
||||
mainLayout.setColumnExpandRatio(2, 0F);
|
||||
@@ -306,7 +321,7 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
|
||||
if (permChecker.hasTargetReadPermission()) {
|
||||
mainLayout.removeComponent(targetTagFilterLayout);
|
||||
mainLayout.removeComponent(targetTableLayout);
|
||||
mainLayout.removeComponent(actionHistoryComponent);
|
||||
mainLayout.removeComponent(actionHistoryLayout);
|
||||
}
|
||||
mainLayout.removeComponent(deleteAndActionsLayout);
|
||||
mainLayout.setColumnExpandRatio(0, 0F);
|
||||
@@ -316,20 +331,16 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
|
||||
}
|
||||
|
||||
private void maximizeActionHistory() {
|
||||
mainLayout.setSpacing(false);
|
||||
mainLayout.removeComponent(targetTagFilterLayout);
|
||||
mainLayout.removeComponent(targetTableLayout);
|
||||
if (permChecker.hasReadDistributionPermission()) {
|
||||
mainLayout.removeComponent(distributionTableLayoutNew);
|
||||
mainLayout.removeComponent(distributionTagLayout);
|
||||
}
|
||||
mainLayout.setColumnExpandRatio(0, 0F);
|
||||
mainLayout.setColumnExpandRatio(1, 0F);
|
||||
mainLayout.setColumnExpandRatio(2, 0F);
|
||||
mainLayout.setColumnExpandRatio(3, 0F);
|
||||
mainLayout.setColumnExpandRatio(4, 1F);
|
||||
mainLayout.removeComponent(deleteAndActionsLayout);
|
||||
mainLayout.setComponentAlignment(actionHistoryComponent, Alignment.TOP_LEFT);
|
||||
mainLayout.removeAllComponents();
|
||||
mainLayout.setColumns(3);
|
||||
mainLayout.setRows(1);
|
||||
mainLayout.addComponent(actionHistoryLayout, 0, 0);
|
||||
mainLayout.addComponent(actionStatusLayout, 1, 0);
|
||||
mainLayout.addComponent(actionStatusMsgLayout, 2, 0);
|
||||
mainLayout.setColumnExpandRatio(0, 0.55F);
|
||||
mainLayout.setColumnExpandRatio(1, 0.18F);
|
||||
mainLayout.setColumnExpandRatio(2, 0.27F);
|
||||
mainLayout.setComponentAlignment(actionHistoryLayout, Alignment.TOP_LEFT);
|
||||
}
|
||||
|
||||
private void minimizeTargetTable() {
|
||||
@@ -342,7 +353,6 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
|
||||
|
||||
private void minimizeActionHistory() {
|
||||
layoutWidgets();
|
||||
mainLayout.setSpacing(true);
|
||||
}
|
||||
|
||||
private void checkNoDataAvaialble() {
|
||||
@@ -362,7 +372,7 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
|
||||
targetTagFilterLayout.setVisible(false);
|
||||
targetTableLayout.setShowFilterButtonVisible(true);
|
||||
distributionTagLayout.setVisible(false);
|
||||
distributionTableLayoutNew.setShowFilterButtonVisible(true);
|
||||
distributionTableLayout.setShowFilterButtonVisible(true);
|
||||
} else {
|
||||
if (!managementUIState.isTargetTagFilterClosed()) {
|
||||
targetTagFilterLayout.setVisible(true);
|
||||
@@ -371,7 +381,7 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
|
||||
}
|
||||
if (!managementUIState.isDistTagFilterClosed()) {
|
||||
distributionTagLayout.setVisible(true);
|
||||
distributionTableLayoutNew.setShowFilterButtonVisible(false);
|
||||
distributionTableLayout.setShowFilterButtonVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -383,8 +393,8 @@ public class DeploymentView extends AbstractNotificationView implements BrowserW
|
||||
supportedEvents.put(TargetCreatedEventContainer.class, targetTableLayout.getTable());
|
||||
supportedEvents.put(TargetDeletedEventContainer.class, targetTableLayout.getTable());
|
||||
|
||||
supportedEvents.put(DistributionCreatedEventContainer.class, distributionTableLayoutNew.getTable());
|
||||
supportedEvents.put(DistributionDeletedEventContainer.class, distributionTableLayoutNew.getTable());
|
||||
supportedEvents.put(DistributionCreatedEventContainer.class, distributionTableLayout.getTable());
|
||||
supportedEvents.put(DistributionDeletedEventContainer.class, distributionTableLayout.getTable());
|
||||
|
||||
supportedEvents.put(TargetTagCreatedEventContainer.class, targetTagFilterLayout);
|
||||
supportedEvents.put(TargetTagDeletedEventContainer.class, targetTagFilterLayout);
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* 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.management.actionhistory;
|
||||
|
||||
import static org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil.isNotNullOrEmpty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.ui.management.actionhistory.ProxyAction.IsActiveDecoration;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.SpringContextHelper;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Slice;
|
||||
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
|
||||
* {@link ProxyAction} batch of beans.
|
||||
*
|
||||
*/
|
||||
public class ActionBeanQuery extends AbstractBeanQuery<ProxyAction> {
|
||||
private static final long serialVersionUID = 3596912494728552516L;
|
||||
|
||||
private Sort sort = new Sort(Direction.DESC, ProxyAction.PXY_ACTION_ID);
|
||||
private transient DeploymentManagement deploymentManagement;
|
||||
|
||||
private String currentSelectedConrollerId;
|
||||
private transient Slice<Action> firstPageActions;
|
||||
|
||||
/**
|
||||
* Parametric Constructor.
|
||||
*
|
||||
* @param definition
|
||||
* QueryDefinition contains the query properties.
|
||||
* @param queryConfig
|
||||
* Implementation specific configuration.
|
||||
* @param sortPropertyIds
|
||||
* The properties participating in sort.
|
||||
* @param sortStates
|
||||
* The ascending or descending state of sort properties.
|
||||
*/
|
||||
public ActionBeanQuery(final QueryDefinition definition, final Map<String, Object> queryConfig,
|
||||
final Object[] sortPropertyIds, final boolean[] sortStates) {
|
||||
super(definition, queryConfig, sortPropertyIds, sortStates);
|
||||
|
||||
if (isNotNullOrEmpty(queryConfig)) {
|
||||
currentSelectedConrollerId = (String) queryConfig.get(SPUIDefinitions.ACTIONS_BY_TARGET);
|
||||
}
|
||||
|
||||
if (ArrayUtils.isEmpty(sortStates)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize sort
|
||||
sort = new Sort(sortStates[0] ? Direction.ASC : Direction.DESC, (String) sortPropertyIds[0]);
|
||||
// Add sort
|
||||
for (int distId = 1; distId < sortPropertyIds.length; distId++) {
|
||||
sort.and(new Sort(sortStates[distId] ? Direction.ASC : Direction.DESC, (String) sortPropertyIds[distId]));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProxyAction constructBean() {
|
||||
return new ProxyAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ProxyAction> loadBeans(final int startIndex, final int count) {
|
||||
Slice<Action> actionBeans;
|
||||
if (startIndex == 0) {
|
||||
if (firstPageActions == null) {
|
||||
firstPageActions = getDeploymentManagement().findActionsByTarget(currentSelectedConrollerId,
|
||||
new PageRequest(0, SPUIDefinitions.PAGE_SIZE, sort));
|
||||
}
|
||||
actionBeans = firstPageActions;
|
||||
} else {
|
||||
actionBeans = getDeploymentManagement().findActionsByTarget(currentSelectedConrollerId,
|
||||
new PageRequest(startIndex / SPUIDefinitions.PAGE_SIZE, SPUIDefinitions.PAGE_SIZE, sort));
|
||||
}
|
||||
return createProxyActions(actionBeans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of {@link ProxyAction}s for presentation layer from slice
|
||||
* of {@link Action}s.
|
||||
*
|
||||
* @param actionBeans
|
||||
* slice of {@link Action}s
|
||||
* @return list of {@link ProxyAction}s
|
||||
*/
|
||||
private static List<ProxyAction> createProxyActions(final Slice<Action> actionBeans) {
|
||||
final List<ProxyAction> proxyActions = new ArrayList<>();
|
||||
for (final Action action : actionBeans) {
|
||||
final ProxyAction proxyAction = new ProxyAction();
|
||||
final String dsNameVersion = action.getDistributionSet().getName() + ":"
|
||||
+ action.getDistributionSet().getVersion();
|
||||
proxyAction.setActive(action.isActive());
|
||||
proxyAction.setIsActiveDecoration(buildIsActiveDecoration(action));
|
||||
proxyAction.setDsNameVersion(dsNameVersion);
|
||||
proxyAction.setAction(action);
|
||||
proxyAction.setId(action.getId());
|
||||
proxyAction.setLastModifiedAt(action.getLastModifiedAt());
|
||||
proxyAction.setRolloutName(action.getRollout() != null ? action.getRollout().getName() : "");
|
||||
proxyAction.setStatus(action.getStatus());
|
||||
|
||||
proxyActions.add(proxyAction);
|
||||
}
|
||||
return proxyActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a virtual IsActiveDecoration for the presentation layer that is
|
||||
* calculated from {@link Action#isActive()} and
|
||||
* {@link Action#getActionStatus()}.
|
||||
*
|
||||
* @param action
|
||||
* the action combined IsActiveDecoration is calculated from
|
||||
* @return IsActiveDecoration combined decoration for the presentation
|
||||
* layer.
|
||||
*/
|
||||
private static IsActiveDecoration buildIsActiveDecoration(final Action action) {
|
||||
final Action.Status status = action.getStatus();
|
||||
|
||||
if (status == Action.Status.SCHEDULED) {
|
||||
return IsActiveDecoration.SCHEDULED;
|
||||
} else if (status == Action.Status.ERROR) {
|
||||
return IsActiveDecoration.IN_ACTIVE_ERROR;
|
||||
}
|
||||
|
||||
return action.isActive() ? IsActiveDecoration.ACTIVE : IsActiveDecoration.IN_ACTIVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveBeans(final List<ProxyAction> addedBeans, final List<ProxyAction> modifiedBeans,
|
||||
final List<ProxyAction> removedBeans) {
|
||||
// CRUD operations on Target will be done through repository methods
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
long size = 0;
|
||||
|
||||
if (currentSelectedConrollerId != null) {
|
||||
size = getDeploymentManagement().countActionsByTarget(currentSelectedConrollerId);
|
||||
}
|
||||
if (size > Integer.MAX_VALUE) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy gets deploymentManagement.
|
||||
*
|
||||
* @return the deploymentManagement
|
||||
*/
|
||||
public DeploymentManagement getDeploymentManagement() {
|
||||
if (null == deploymentManagement) {
|
||||
deploymentManagement = SpringContextHelper.getBean(DeploymentManagement.class);
|
||||
}
|
||||
return deploymentManagement;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,85 +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.management.actionhistory;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType;
|
||||
import org.eclipse.hawkbit.ui.management.event.TargetTableEvent;
|
||||
import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
import org.vaadin.spring.events.EventScope;
|
||||
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
|
||||
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class ActionHistoryComponent extends VerticalLayout {
|
||||
private static final long serialVersionUID = -3766179797384539821L;
|
||||
|
||||
private final ActionHistoryHeader actionHistoryHeader;
|
||||
private final ActionHistoryTable actionHistoryTable;
|
||||
|
||||
public ActionHistoryComponent(final VaadinMessageSource i18n, final DeploymentManagement deploymentManagement,
|
||||
final UIEventBus eventBus, final UINotification notification, final ManagementUIState managementUIState) {
|
||||
this.actionHistoryHeader = new ActionHistoryHeader(eventBus, managementUIState);
|
||||
this.actionHistoryTable = new ActionHistoryTable(i18n, deploymentManagement, eventBus, notification,
|
||||
managementUIState);
|
||||
buildLayout();
|
||||
setSizeFull();
|
||||
setImmediate(true);
|
||||
eventBus.subscribe(this);
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final TargetTableEvent targetUIEvent) {
|
||||
if (BaseEntityEventType.SELECTED_ENTITY == targetUIEvent.getEventType()) {
|
||||
setData(SPUIDefinitions.DATA_AVAILABLE);
|
||||
UI.getCurrent().access(() -> populateActionHistoryDetails(targetUIEvent.getEntity()));
|
||||
}
|
||||
}
|
||||
|
||||
private void buildLayout() {
|
||||
setSizeFull();
|
||||
setSpacing(false);
|
||||
setMargin(false);
|
||||
addStyleName("table-layout");
|
||||
addComponents(actionHistoryHeader, actionHistoryTable);
|
||||
setComponentAlignment(actionHistoryHeader, Alignment.TOP_CENTER);
|
||||
setComponentAlignment(actionHistoryTable, Alignment.TOP_CENTER);
|
||||
setExpandRatio(actionHistoryTable, 1.0F);
|
||||
}
|
||||
|
||||
/**
|
||||
* populate action header and table for the target.
|
||||
*
|
||||
* @param target
|
||||
* the target
|
||||
*/
|
||||
public void populateActionHistoryDetails(final Target target) {
|
||||
if (null != target) {
|
||||
actionHistoryHeader.populateHeader(target.getName());
|
||||
actionHistoryTable.setAlreadyHasMessages(false);
|
||||
actionHistoryTable.populateTableData(target);
|
||||
} else {
|
||||
actionHistoryHeader.updateActionHistoryHeader(" ");
|
||||
actionHistoryTable.setAlreadyHasMessages(false);
|
||||
actionHistoryTable.clearContainerData();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,792 @@
|
||||
/**
|
||||
* 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.management.actionhistory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.ui.common.ConfirmationDialog;
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGrid;
|
||||
import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType;
|
||||
import org.eclipse.hawkbit.ui.customrenderers.renderers.AbstractGridButtonConverter;
|
||||
import org.eclipse.hawkbit.ui.customrenderers.renderers.AbstractHtmlLabelConverter;
|
||||
import org.eclipse.hawkbit.ui.customrenderers.renderers.GridButtonRenderer;
|
||||
import org.eclipse.hawkbit.ui.customrenderers.renderers.HtmlLabelRenderer;
|
||||
import org.eclipse.hawkbit.ui.management.actionhistory.ProxyAction.IsActiveDecoration;
|
||||
import org.eclipse.hawkbit.ui.management.event.ManagementUIEvent;
|
||||
import org.eclipse.hawkbit.ui.management.event.PinUnpinEvent;
|
||||
import org.eclipse.hawkbit.ui.management.event.TargetTableEvent;
|
||||
import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
|
||||
import org.eclipse.hawkbit.ui.rollout.StatusFontIcon;
|
||||
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.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.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.Item;
|
||||
import com.vaadin.data.util.GeneratedPropertyContainer;
|
||||
import com.vaadin.data.util.PropertyValueGenerator;
|
||||
import com.vaadin.server.FontAwesome;
|
||||
import com.vaadin.ui.UI;
|
||||
|
||||
/**
|
||||
* This grid presents the action history for a selected target.
|
||||
*/
|
||||
public class ActionHistoryGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
private static final long serialVersionUID = 4324796883957831443L;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ActionHistoryGrid.class);
|
||||
private static final String BUTTON_CANCEL = "button.cancel";
|
||||
private static final String BUTTON_OK = "button.ok";
|
||||
private static final double FIXED_PIX_MIN = 29F;
|
||||
private static final double FIXED_PIX_MAX = 32F;
|
||||
|
||||
private static final String STATUS_ICON_GREEN = "statusIconGreen";
|
||||
private static final String STATUS_ICON_RED = "statusIconRed";
|
||||
private static final String STATUS_ICON_ORANGE = "statusIconOrange";
|
||||
private static final String STATUS_ICON_PENDING = "statusIconPending";
|
||||
private static final String STATUS_ICON_NEUTRAL = "statusIconNeutral";
|
||||
private static final String STATUS_ICON_ACTIVE = "statusIconActive";
|
||||
private static final String STATUS_ICON_FORCED = "statusIconForced";
|
||||
|
||||
private static final String VIRT_PROP_FORCED = "forced";
|
||||
private static final String VIRT_PROP_TIMEFORCED = "timeForced";
|
||||
private static final String VIRT_PROP_ACTION_CANCEL = "cancel-aciton";
|
||||
private static final String VIRT_PROP_ACTION_FORCE = "force-action";
|
||||
private static final String VIRT_PROP_ACTION_FORCE_QUIT = "force-quit-action";
|
||||
|
||||
private static final Object[] maxColumnOrder = new Object[] { ProxyAction.PXY_ACTION_IS_ACTIVE_DECO,
|
||||
ProxyAction.PXY_ACTION_ID, ProxyAction.PXY_ACTION_DS_NAME_VERSION, ProxyAction.PXY_ACTION_LAST_MODIFIED_AT,
|
||||
ProxyAction.PXY_ACTION_STATUS, ProxyAction.PXY_ACTION_ROLLOUT_NAME, VIRT_PROP_FORCED, VIRT_PROP_TIMEFORCED,
|
||||
VIRT_PROP_ACTION_CANCEL, VIRT_PROP_ACTION_FORCE, VIRT_PROP_ACTION_FORCE_QUIT };
|
||||
|
||||
private static final Object[] minColumnOrder = new Object[] { ProxyAction.PXY_ACTION_IS_ACTIVE_DECO,
|
||||
ProxyAction.PXY_ACTION_DS_NAME_VERSION, ProxyAction.PXY_ACTION_LAST_MODIFIED_AT,
|
||||
ProxyAction.PXY_ACTION_STATUS, VIRT_PROP_FORCED, VIRT_PROP_TIMEFORCED, VIRT_PROP_ACTION_CANCEL,
|
||||
VIRT_PROP_ACTION_FORCE, VIRT_PROP_ACTION_FORCE_QUIT };
|
||||
|
||||
private static final String[] leftAlignedColumns = new String[] { VIRT_PROP_TIMEFORCED };
|
||||
|
||||
private static final String[] centerAlignedColumns = new String[] { ProxyAction.PXY_ACTION_IS_ACTIVE_DECO,
|
||||
ProxyAction.PXY_ACTION_STATUS };
|
||||
|
||||
private static final String[] rightAlignedColumns = new String[] { VIRT_PROP_FORCED, ProxyAction.PXY_ACTION_ID };
|
||||
|
||||
private final transient DeploymentManagement deploymentManagement;
|
||||
private final UINotification notification;
|
||||
private final ManagementUIState managementUIState;
|
||||
|
||||
private Target selectedTarget;
|
||||
private final AlignCellStyleGenerator alignGenerator;
|
||||
private final ModifiedTimeTooltipGenerator modTimetooltipGenerator;
|
||||
|
||||
private final Map<Action.Status, StatusFontIcon> states;
|
||||
private final Map<IsActiveDecoration, StatusFontIcon> activeStates;
|
||||
|
||||
private final BeanQueryFactory<ActionBeanQuery> targetQF = new BeanQueryFactory<>(ActionBeanQuery.class);
|
||||
|
||||
boolean forceClientRefreshToggle = true;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param i18n
|
||||
* @param deploymentManagement
|
||||
* @param eventBus
|
||||
* @param notification
|
||||
* @param managementUIState
|
||||
*/
|
||||
protected ActionHistoryGrid(final VaadinMessageSource i18n, final DeploymentManagement deploymentManagement,
|
||||
final UIEventBus eventBus, final UINotification notification, final ManagementUIState managementUIState) {
|
||||
super(i18n, eventBus, null);
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
this.notification = notification;
|
||||
this.managementUIState = managementUIState;
|
||||
|
||||
setMaximizeSupport(new ActionHistoryMaximizeSupport());
|
||||
setSingleSelectionSupport(new SingleSelectionSupport());
|
||||
|
||||
if (!managementUIState.isActionHistoryMaximized()) {
|
||||
getSingleSelectionSupport().disable();
|
||||
}
|
||||
|
||||
setGeneratedPropertySupport(new ActionHistoryGeneratedPropertySupport());
|
||||
setDetailsSupport(new DetailsSupport());
|
||||
|
||||
final LabelConfig conf = new LabelConfig();
|
||||
states = conf.createStatusLabelConfig(i18n, UIComponentIdProvider.ACTION_HISTORY_TABLE_STATUS_LABEL_ID);
|
||||
activeStates = conf
|
||||
.createActiveStatusLabelConfig(UIComponentIdProvider.ACTION_HISTORY_TABLE_ACTIVESTATE_LABEL_ID);
|
||||
alignGenerator = new AlignCellStyleGenerator(leftAlignedColumns, centerAlignedColumns, rightAlignedColumns);
|
||||
modTimetooltipGenerator = new ModifiedTimeTooltipGenerator(ProxyAction.PXY_ACTION_LAST_MODIFIED_AT);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final ManagementUIEvent mgmtUIEvent) {
|
||||
if (mgmtUIEvent == ManagementUIEvent.MAX_ACTION_HISTORY) {
|
||||
UI.getCurrent().access(this::createMaximizedContent);
|
||||
}
|
||||
if (mgmtUIEvent == ManagementUIEvent.MIN_ACTION_HISTORY) {
|
||||
UI.getCurrent().access(this::createMinimizedContent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
restorePreviousState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set target as member of this grid (as all presented grid-data is related
|
||||
* to this target) and recalculate grid-data for this target.
|
||||
*
|
||||
* @param selectedTarget
|
||||
* reference of target
|
||||
*/
|
||||
public void populateSelectedTarget(final Target selectedTarget) {
|
||||
this.selectedTarget = selectedTarget;
|
||||
getDetailsSupport()
|
||||
.populateMasterDataAndRecalculateContainer(selectedTarget != null ? selectedTarget.getId() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LazyQueryContainer createContainer() {
|
||||
configureQueryFactory();
|
||||
return new LazyQueryContainer(
|
||||
new LazyQueryDefinition(true, SPUIDefinitions.PAGE_SIZE, ProxyAction.PXY_ACTION_ID), targetQF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshContainer() {
|
||||
configureQueryFactory();
|
||||
super.refreshContainer();
|
||||
}
|
||||
|
||||
protected void configureQueryFactory() {
|
||||
// ADD all the filters to the query config
|
||||
final Map<String, Object> queryConfig = Maps.newHashMapWithExpectedSize(1);
|
||||
queryConfig.put(SPUIDefinitions.ACTIONS_BY_TARGET,
|
||||
selectedTarget != null ? selectedTarget.getControllerId() : null);
|
||||
// Create ActionBeanQuery factory with the query config.
|
||||
targetQF.setQueryConfiguration(queryConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addContainerProperties() {
|
||||
final LazyQueryContainer rawCont = getGeneratedPropertySupport().getRawContainer();
|
||||
|
||||
rawCont.addContainerProperty(ProxyAction.PXY_ACTION_IS_ACTIVE_DECO, IsActiveDecoration.class, null, true,
|
||||
false);
|
||||
rawCont.addContainerProperty(ProxyAction.PXY_ACTION, Action.class, null, true, false);
|
||||
rawCont.addContainerProperty(ProxyAction.PXY_ACTION_DS_NAME_VERSION, String.class, null, true, false);
|
||||
rawCont.addContainerProperty(ProxyAction.PXY_ACTION_LAST_MODIFIED_AT, Long.class, null, true, true);
|
||||
rawCont.addContainerProperty(ProxyAction.PXY_ACTION_STATUS, Action.Status.class, null, true, false);
|
||||
|
||||
rawCont.addContainerProperty(ProxyAction.PXY_ACTION_ID, Long.class, null, true, true);
|
||||
rawCont.addContainerProperty(ProxyAction.PXY_ACTION_ROLLOUT_NAME, String.class, null, true, true);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getGridId() {
|
||||
return UIComponentIdProvider.ACTION_HISTORY_GRID_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addColumnRenderes() {
|
||||
getColumn(ProxyAction.PXY_ACTION_LAST_MODIFIED_AT).setConverter(new LongToFormattedDateStringConverter());
|
||||
getColumn(ProxyAction.PXY_ACTION_STATUS).setRenderer(new HtmlLabelRenderer(),
|
||||
new HtmlStatusLabelConverter(this::createStatusLabelMetadata));
|
||||
getColumn(ProxyAction.PXY_ACTION_IS_ACTIVE_DECO).setRenderer(new HtmlLabelRenderer(),
|
||||
new HtmlIsActiveLabelConverter(this::createIsActiveLabelMetadata));
|
||||
getColumn(VIRT_PROP_FORCED).setRenderer(new HtmlLabelRenderer(),
|
||||
new HtmlVirtPropLabelConverter(ActionHistoryGrid::createForcedLabelMetadata));
|
||||
getColumn(VIRT_PROP_TIMEFORCED).setRenderer(new HtmlLabelRenderer(),
|
||||
new HtmlVirtPropLabelConverter(this::createTimeForcedLabelMetadata));
|
||||
getColumn(VIRT_PROP_ACTION_CANCEL).setRenderer(
|
||||
new GridButtonRenderer(clickEvent -> confirmAndCancelAction((Long) clickEvent.getItemId())),
|
||||
new ActionGridButtonConverter(this::createCancelButtonMetadata));
|
||||
getColumn(VIRT_PROP_ACTION_FORCE).setRenderer(
|
||||
new GridButtonRenderer(clickEvent -> confirmAndForceAction((Long) clickEvent.getItemId())),
|
||||
new ActionGridButtonConverter(this::createForceButtonMetadata));
|
||||
getColumn(VIRT_PROP_ACTION_FORCE_QUIT).setRenderer(
|
||||
new GridButtonRenderer(clickEvent -> confirmAndForceQuitAction((Long) clickEvent.getItemId())),
|
||||
new ActionGridButtonConverter(this::createForceQuitButtonMetadata));
|
||||
}
|
||||
|
||||
private StatusFontIcon createCancelButtonMetadata(final Action action) {
|
||||
final boolean isDisabled = !action.isActive() || action.isCancelingOrCanceled();
|
||||
return new StatusFontIcon(FontAwesome.TIMES, STATUS_ICON_NEUTRAL, i18n.getMessage("message.cancel.action"),
|
||||
UIComponentIdProvider.ACTION_HISTORY_TABLE_CANCEL_ID, isDisabled);
|
||||
}
|
||||
|
||||
private StatusFontIcon createForceButtonMetadata(final Action action) {
|
||||
final boolean isDisabled = !action.isActive() || action.isForce() || action.isCancelingOrCanceled();
|
||||
return new StatusFontIcon(FontAwesome.BOLT, STATUS_ICON_NEUTRAL, i18n.getMessage("message.force.action"),
|
||||
UIComponentIdProvider.ACTION_HISTORY_TABLE_FORCE_ID, isDisabled);
|
||||
}
|
||||
|
||||
private StatusFontIcon createForceQuitButtonMetadata(final Action action) {
|
||||
final boolean isDisabled = !action.isActive() || !action.isCancelingOrCanceled();
|
||||
return new StatusFontIcon(FontAwesome.TIMES, STATUS_ICON_RED, i18n.getMessage("message.forcequit.action"),
|
||||
UIComponentIdProvider.ACTION_HISTORY_TABLE_FORCE_QUIT_ID, isDisabled);
|
||||
}
|
||||
|
||||
private StatusFontIcon createStatusLabelMetadata(final Action.Status status) {
|
||||
return states.get(status);
|
||||
}
|
||||
|
||||
private StatusFontIcon createIsActiveLabelMetadata(final IsActiveDecoration isActiveDeco) {
|
||||
return activeStates.get(isActiveDeco);
|
||||
}
|
||||
|
||||
private static StatusFontIcon createForcedLabelMetadata(final Action action) {
|
||||
StatusFontIcon result = null;
|
||||
if (ActionType.FORCED.equals(action.getActionType()) || ActionType.TIMEFORCED.equals(action.getActionType())) {
|
||||
result = new StatusFontIcon(FontAwesome.BOLT, STATUS_ICON_FORCED, "Forced",
|
||||
UIComponentIdProvider.ACTION_HISTORY_TABLE_FORCED_LABEL_ID);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private StatusFontIcon createTimeForcedLabelMetadata(final Action action) {
|
||||
StatusFontIcon result = null;
|
||||
|
||||
if (ActionType.TIMEFORCED.equals(action.getActionType())) {
|
||||
final long currentTimeMillis = System.currentTimeMillis();
|
||||
String style;
|
||||
String title;
|
||||
if (action.isHitAutoForceTime(currentTimeMillis)) {
|
||||
style = STATUS_ICON_GREEN;
|
||||
title = "auto forced since "
|
||||
+ SPDateTimeUtil.getDurationFormattedString(action.getForcedTime(), currentTimeMillis, i18n);
|
||||
} else {
|
||||
style = STATUS_ICON_PENDING;
|
||||
title = "auto forcing in "
|
||||
+ SPDateTimeUtil.getDurationFormattedString(currentTimeMillis, action.getForcedTime(), i18n);
|
||||
}
|
||||
result = new StatusFontIcon(FontAwesome.HISTORY, style, title,
|
||||
UIComponentIdProvider.ACTION_HISTORY_TABLE_TIMEFORCED_LABEL_ID);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show confirmation window and if ok then only, force the action.
|
||||
*
|
||||
* @param actionId
|
||||
* as Id if the action needs to be forced.
|
||||
*/
|
||||
private void confirmAndForceAction(final Long actionId) {
|
||||
/* Display the confirmation */
|
||||
final ConfirmationDialog confirmDialog = new ConfirmationDialog(
|
||||
i18n.getMessage("caption.force.action.confirmbox"), i18n.getMessage("message.force.action.confirm"),
|
||||
i18n.getMessage(BUTTON_OK), i18n.getMessage(BUTTON_CANCEL), ok -> {
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
deploymentManagement.forceTargetAction(actionId);
|
||||
populateAndUpdateTargetDetails(selectedTarget);
|
||||
notification.displaySuccess(i18n.getMessage("message.force.action.success"));
|
||||
});
|
||||
UI.getCurrent().addWindow(confirmDialog.getWindow());
|
||||
|
||||
confirmDialog.getWindow().bringToFront();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show confirmation window and if ok then only, force quit action.
|
||||
*
|
||||
* @param actionId
|
||||
* as Id if the action needs to be forced.
|
||||
*/
|
||||
private void confirmAndForceQuitAction(final Long actionId) {
|
||||
/* Display the confirmation */
|
||||
final ConfirmationDialog confirmDialog = new ConfirmationDialog(
|
||||
i18n.getMessage("caption.forcequit.action.confirmbox"),
|
||||
i18n.getMessage("message.forcequit.action.confirm"), i18n.getMessage(BUTTON_OK),
|
||||
i18n.getMessage(BUTTON_CANCEL), ok -> {
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
final boolean cancelResult = forceQuitActiveAction(actionId);
|
||||
if (cancelResult) {
|
||||
populateAndUpdateTargetDetails(selectedTarget);
|
||||
notification.displaySuccess(i18n.getMessage("message.forcequit.action.success"));
|
||||
} else {
|
||||
notification.displayValidationError(i18n.getMessage("message.forcequit.action.failed"));
|
||||
}
|
||||
}, FontAwesome.WARNING);
|
||||
UI.getCurrent().addWindow(confirmDialog.getWindow());
|
||||
|
||||
confirmDialog.getWindow().bringToFront();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show confirmation window and if ok then only, cancel the action.
|
||||
*
|
||||
* @param actionId
|
||||
* as Id if the action needs to be cancelled.
|
||||
*/
|
||||
private void confirmAndCancelAction(final Long actionId) {
|
||||
if (actionId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ConfirmationDialog confirmDialog = new ConfirmationDialog(
|
||||
i18n.getMessage("caption.cancel.action.confirmbox"), i18n.getMessage("message.cancel.action.confirm"),
|
||||
i18n.getMessage(BUTTON_OK), i18n.getMessage(BUTTON_CANCEL), ok -> {
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
final boolean cancelResult = cancelActiveAction(actionId);
|
||||
if (cancelResult) {
|
||||
populateAndUpdateTargetDetails(selectedTarget);
|
||||
notification.displaySuccess(i18n.getMessage("message.cancel.action.success"));
|
||||
} else {
|
||||
notification.displayValidationError(i18n.getMessage("message.cancel.action.failed"));
|
||||
}
|
||||
});
|
||||
UI.getCurrent().addWindow(confirmDialog.getWindow());
|
||||
confirmDialog.getWindow().bringToFront();
|
||||
}
|
||||
|
||||
private void populateAndUpdateTargetDetails(final Target target) {
|
||||
// show the updated target action history details
|
||||
populateSelectedTarget(target);
|
||||
// update the target table and its pinning details
|
||||
updateTargetAndDsTable();
|
||||
}
|
||||
|
||||
private void updateTargetAndDsTable() {
|
||||
eventBus.publish(this, new TargetTableEvent(BaseEntityEventType.UPDATED_ENTITY, selectedTarget));
|
||||
updateDistributionTableStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the colors of Assigned and installed distribution set in Target
|
||||
* Pinning.
|
||||
*/
|
||||
private void updateDistributionTableStyle() {
|
||||
managementUIState.getDistributionTableFilters().getPinnedTarget().ifPresent((pinnedTarget) -> {
|
||||
if (pinnedTarget.getTargetId().equals(selectedTarget.getId())) {
|
||||
eventBus.publish(this, PinUnpinEvent.PIN_TARGET);
|
||||
}
|
||||
});
|
||||
if (!managementUIState.getDistributionTableFilters().getPinnedTarget().isPresent()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// service call to cancel the active action
|
||||
private boolean cancelActiveAction(final Long actionId) {
|
||||
if (actionId != null) {
|
||||
try {
|
||||
deploymentManagement.cancelAction(actionId);
|
||||
return true;
|
||||
} catch (final CancelActionNotAllowedException e) {
|
||||
LOG.info("Cancel action not allowed exception :{}", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// service call to cancel the active action
|
||||
private boolean forceQuitActiveAction(final Long actionId) {
|
||||
if (actionId != null) {
|
||||
try {
|
||||
deploymentManagement.forceQuitAction(actionId);
|
||||
return true;
|
||||
} catch (final CancelActionNotAllowedException e) {
|
||||
LOG.info("Force Cancel action not allowed exception :{}", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setHiddenColumns() {
|
||||
getColumn(VIRT_PROP_FORCED).setHidable(false);
|
||||
getColumn(VIRT_PROP_TIMEFORCED).setHidable(false);
|
||||
getColumn(VIRT_PROP_ACTION_CANCEL).setHidable(false);
|
||||
getColumn(VIRT_PROP_ACTION_FORCE).setHidable(false);
|
||||
getColumn(VIRT_PROP_ACTION_FORCE_QUIT).setHidable(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CellDescriptionGenerator getDescriptionGenerator() {
|
||||
return modTimetooltipGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setColumnHeaderNames() {
|
||||
final HeaderRow newHeaderRow = resetHeaderDefaultRow();
|
||||
|
||||
getColumn(ProxyAction.PXY_ACTION_IS_ACTIVE_DECO).setHeaderCaption(SPUIDefinitions.ACTION_HIS_TBL_ACTIVE);
|
||||
getColumn(ProxyAction.PXY_ACTION_DS_NAME_VERSION).setHeaderCaption(SPUIDefinitions.ACTION_HIS_TBL_DIST);
|
||||
getColumn(ProxyAction.PXY_ACTION_LAST_MODIFIED_AT).setHeaderCaption(SPUIDefinitions.ACTION_HIS_TBL_DATETIME);
|
||||
getColumn(ProxyAction.PXY_ACTION_STATUS).setHeaderCaption(SPUIDefinitions.ACTION_HIS_TBL_STATUS);
|
||||
getColumn(VIRT_PROP_FORCED).setHeaderCaption(String.valueOf(forceClientRefreshToggle));
|
||||
forceClientRefreshToggle = !forceClientRefreshToggle;
|
||||
|
||||
newHeaderRow.join(VIRT_PROP_FORCED, VIRT_PROP_TIMEFORCED).setText(SPUIDefinitions.ACTION_HIS_TBL_FORCED);
|
||||
newHeaderRow.join(VIRT_PROP_ACTION_CANCEL, VIRT_PROP_ACTION_FORCE, VIRT_PROP_ACTION_FORCE_QUIT)
|
||||
.setText(SPUIDefinitions.ACTIONS_COLUMN);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setColumnExpandRatio() {
|
||||
setColumnsSize(50.0, 50.0, ProxyAction.PXY_ACTION_IS_ACTIVE_DECO);
|
||||
setColumnsSize(107.0, 500.0, ProxyAction.PXY_ACTION_DS_NAME_VERSION);
|
||||
setColumnsSize(100.0, 120.0, ProxyAction.PXY_ACTION_LAST_MODIFIED_AT);
|
||||
setColumnsSize(53.0, 55.0, ProxyAction.PXY_ACTION_STATUS);
|
||||
setColumnsSize(FIXED_PIX_MIN, FIXED_PIX_MIN, VIRT_PROP_FORCED, VIRT_PROP_TIMEFORCED, VIRT_PROP_ACTION_CANCEL,
|
||||
VIRT_PROP_ACTION_FORCE, VIRT_PROP_ACTION_FORCE_QUIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Conveniently sets min- and max-width for a bunch of columns.
|
||||
*
|
||||
* @param min
|
||||
* minimum width
|
||||
* @param max
|
||||
* maximum width
|
||||
* @param columnPropertyIds
|
||||
* all the columns the min and max should be set for.
|
||||
*/
|
||||
private void setColumnsSize(final double min, final double max, final String... columnPropertyIds) {
|
||||
for (final String columnPropertyId : columnPropertyIds) {
|
||||
getColumn(columnPropertyId).setMinimumWidth(min);
|
||||
getColumn(columnPropertyId).setMaximumWidth(max);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the grid content for maximized-state.
|
||||
*/
|
||||
private void createMaximizedContent() {
|
||||
getSingleSelectionSupport().enable();
|
||||
getDetailsSupport().populateSelection();
|
||||
getMaximizeSupport().createMaximizedContent();
|
||||
recalculateColumnWidths();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the grid content for normal (minimized) state.
|
||||
*/
|
||||
private void createMinimizedContent() {
|
||||
getSingleSelectionSupport().disable();
|
||||
getMaximizeSupport().createMinimizedContent();
|
||||
recalculateColumnWidths();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setColumnProperties() {
|
||||
clearSortOrder();
|
||||
setColumns(minColumnOrder);
|
||||
alignColumns();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the maximized state if the action history was left in
|
||||
* maximized-state and is now re-entered.
|
||||
*/
|
||||
private void restorePreviousState() {
|
||||
if (managementUIState.isActionHistoryMaximized()) {
|
||||
createMaximizedContent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alignment cell-style-generator that handles the alignment for
|
||||
* the grid cells.
|
||||
*/
|
||||
private void alignColumns() {
|
||||
setCellStyleGenerator(alignGenerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds support for virtual properties (aka generated properties)
|
||||
*/
|
||||
class ActionHistoryGeneratedPropertySupport extends AbstractGeneratedPropertySupport {
|
||||
|
||||
@Override
|
||||
public GeneratedPropertyContainer getDecoratedContainer() {
|
||||
return (GeneratedPropertyContainer) getContainerDataSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazyQueryContainer getRawContainer() {
|
||||
return (LazyQueryContainer) (getDecoratedContainer()).getWrappedContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GeneratedPropertyContainer addGeneratedContainerProperties() {
|
||||
final GeneratedPropertyContainer decoratedContainer = getDecoratedContainer();
|
||||
|
||||
decoratedContainer.addGeneratedProperty(VIRT_PROP_FORCED, new GenericPropertyValueGenerator());
|
||||
decoratedContainer.addGeneratedProperty(VIRT_PROP_TIMEFORCED, new GenericPropertyValueGenerator());
|
||||
decoratedContainer.addGeneratedProperty(VIRT_PROP_ACTION_CANCEL, new GenericPropertyValueGenerator());
|
||||
decoratedContainer.addGeneratedProperty(VIRT_PROP_ACTION_FORCE, new GenericPropertyValueGenerator());
|
||||
decoratedContainer.addGeneratedProperty(VIRT_PROP_ACTION_FORCE_QUIT, new GenericPropertyValueGenerator());
|
||||
|
||||
return decoratedContainer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds support to maximize the grid.
|
||||
*/
|
||||
class ActionHistoryMaximizeSupport extends AbstractMaximizeSupport {
|
||||
|
||||
/**
|
||||
* Sets the property-ids available in maximized-state.
|
||||
*/
|
||||
@Override
|
||||
protected void setMaximizedColumnProperties() {
|
||||
clearSortOrder();
|
||||
setColumns(maxColumnOrder);
|
||||
alignColumns();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setMaximizedHiddenColumns() {
|
||||
getColumn(ProxyAction.PXY_ACTION_ID).setHidden(false);
|
||||
getColumn(ProxyAction.PXY_ACTION_ID).setHidable(true);
|
||||
getColumn(ProxyAction.PXY_ACTION_ROLLOUT_NAME).setHidden(false);
|
||||
getColumn(ProxyAction.PXY_ACTION_ROLLOUT_NAME).setHidable(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets additional headers for the maximized-state.
|
||||
*/
|
||||
@Override
|
||||
protected void setMaximizedHeaders() {
|
||||
getColumn(ProxyAction.PXY_ACTION_ID).setHeaderCaption(SPUIDefinitions.ACTION_HIS_TBL_ACTION_ID);
|
||||
getColumn(ProxyAction.PXY_ACTION_ROLLOUT_NAME)
|
||||
.setHeaderCaption(SPUIDefinitions.ACTION_HIS_TBL_ROLLOUT_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expand ratio for the maximized-state.
|
||||
*/
|
||||
@Override
|
||||
protected void setMaximizedColumnExpandRatio() {
|
||||
/* set messages column can expand the rest of the available space */
|
||||
setColumnsSize(50.0, 50.0, ProxyAction.PXY_ACTION_IS_ACTIVE_DECO);
|
||||
setColumnsSize(FIXED_PIX_MIN, 100.0, ProxyAction.PXY_ACTION_ID);
|
||||
setColumnsSize(107.0, 500.0, ProxyAction.PXY_ACTION_DS_NAME_VERSION);
|
||||
setColumnsSize(100.0, 150.0, ProxyAction.PXY_ACTION_LAST_MODIFIED_AT);
|
||||
setColumnsSize(53.0, 55.0, ProxyAction.PXY_ACTION_STATUS);
|
||||
setColumnsSize(FIXED_PIX_MIN, FIXED_PIX_MAX, VIRT_PROP_FORCED, VIRT_PROP_TIMEFORCED,
|
||||
VIRT_PROP_ACTION_CANCEL, VIRT_PROP_ACTION_FORCE, VIRT_PROP_ACTION_FORCE_QUIT);
|
||||
setColumnsSize(FIXED_PIX_MIN, 500.0, ProxyAction.PXY_ACTION_ROLLOUT_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete html-label converter that handles IsActiveDecoration enum.
|
||||
*/
|
||||
class HtmlIsActiveLabelConverter extends AbstractHtmlLabelConverter<IsActiveDecoration> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructor that sets the appropriate adapter.
|
||||
*
|
||||
* @param adapter
|
||||
* adapts <code>IsActiveDecoration</code> to
|
||||
* <code>String</code>
|
||||
*/
|
||||
public HtmlIsActiveLabelConverter(final LabelAdapter<IsActiveDecoration> adapter) {
|
||||
addAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<IsActiveDecoration> getModelType() {
|
||||
return IsActiveDecoration.class;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete html-label converter that handles Booleans. The converter needs
|
||||
* an appropriate adapter that must be set via
|
||||
* {@link AbstractHtmlLabelConverter#addAdapter()} to do the work.
|
||||
*/
|
||||
class HtmlBooleanLabelConverter extends AbstractHtmlLabelConverter<Boolean> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Class<Boolean> getModelType() {
|
||||
return Boolean.class;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete html-label converter that handles Actions.
|
||||
*/
|
||||
class HtmlVirtPropLabelConverter extends AbstractHtmlLabelConverter<Action> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructor that sets the appropriate adapter.
|
||||
*
|
||||
* @param adapter
|
||||
* adapts <code>Action</code> to <code>String</code>
|
||||
*/
|
||||
public HtmlVirtPropLabelConverter(final LabelAdapter<Action> adapter) {
|
||||
addAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Action> getModelType() {
|
||||
return Action.class;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Concrete grid-button converter that handles Actions.
|
||||
*/
|
||||
class ActionGridButtonConverter extends AbstractGridButtonConverter<Action> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructor that sets the appropriate adapter.
|
||||
*
|
||||
* @param adapter
|
||||
* adapts <code>Action</code> to <code>StatusFontIcon</code>
|
||||
*/
|
||||
public ActionGridButtonConverter(final GridButtonAdapter<Action> adapter) {
|
||||
addAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Action> getModelType() {
|
||||
return Action.class;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generator class responsible to retrieve an Action from the grid data in
|
||||
* order to generate a virtual property.
|
||||
*/
|
||||
class GenericPropertyValueGenerator extends PropertyValueGenerator<Action> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Action getValue(final Item item, final Object itemId, final Object propertyId) {
|
||||
return (Action) item.getItemProperty(ProxyAction.PXY_ACTION).getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Action> getType() {
|
||||
return Action.class;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generator class responsible to generate a button property value for the
|
||||
* grid.
|
||||
*/
|
||||
class ButtonPropertyValueGenerator extends PropertyValueGenerator<String> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String buttonLabel;
|
||||
|
||||
public ButtonPropertyValueGenerator(final String buttonLabel) {
|
||||
this.buttonLabel = buttonLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue(final Item item, final Object itemId, final Object propertyId) {
|
||||
return buttonLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<String> getType() {
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration that holds the styling properties for label- and
|
||||
* button-renderers that are included in grid-cells.
|
||||
*/
|
||||
public static class LabelConfig {
|
||||
|
||||
/**
|
||||
* Initializes a map with all available status label metadata.
|
||||
*
|
||||
* @param i18n
|
||||
* @param statusLabelId
|
||||
* @return the configured map
|
||||
*/
|
||||
public Map<Action.Status, StatusFontIcon> createStatusLabelConfig(final VaadinMessageSource i18n,
|
||||
final String statusLabelId) {
|
||||
final HashMap<Action.Status, StatusFontIcon> stateMap = Maps.newHashMapWithExpectedSize(9);
|
||||
stateMap.put(Action.Status.FINISHED, new StatusFontIcon(FontAwesome.CHECK_CIRCLE, STATUS_ICON_GREEN,
|
||||
i18n.getMessage("label.finished"), statusLabelId));
|
||||
stateMap.put(Action.Status.ERROR, new StatusFontIcon(FontAwesome.EXCLAMATION_CIRCLE, STATUS_ICON_RED,
|
||||
i18n.getMessage("label.error"), statusLabelId));
|
||||
stateMap.put(Action.Status.WARNING, new StatusFontIcon(FontAwesome.EXCLAMATION_CIRCLE, STATUS_ICON_ORANGE,
|
||||
i18n.getMessage("label.warning"), statusLabelId));
|
||||
stateMap.put(Action.Status.RUNNING, new StatusFontIcon(FontAwesome.ADJUST, STATUS_ICON_PENDING,
|
||||
i18n.getMessage("label.running"), statusLabelId));
|
||||
stateMap.put(Action.Status.CANCELING, new StatusFontIcon(FontAwesome.TIMES_CIRCLE, STATUS_ICON_PENDING,
|
||||
i18n.getMessage("label.cancelling"), statusLabelId));
|
||||
stateMap.put(Action.Status.CANCELED, new StatusFontIcon(FontAwesome.TIMES_CIRCLE, STATUS_ICON_GREEN,
|
||||
i18n.getMessage("label.cancelled"), statusLabelId));
|
||||
stateMap.put(Action.Status.RETRIEVED, new StatusFontIcon(FontAwesome.CIRCLE_O, STATUS_ICON_PENDING,
|
||||
i18n.getMessage("label.retrieved"), statusLabelId));
|
||||
stateMap.put(Action.Status.DOWNLOAD, new StatusFontIcon(FontAwesome.CLOUD_DOWNLOAD, STATUS_ICON_PENDING,
|
||||
i18n.getMessage("label.download"), statusLabelId));
|
||||
stateMap.put(Action.Status.SCHEDULED, new StatusFontIcon(FontAwesome.HOURGLASS_1, STATUS_ICON_PENDING,
|
||||
i18n.getMessage("label.scheduled"), statusLabelId));
|
||||
return stateMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a map with all available active-state metadata.
|
||||
*
|
||||
* @param activeStateId
|
||||
* @return the configured map
|
||||
*/
|
||||
public Map<IsActiveDecoration, StatusFontIcon> createActiveStatusLabelConfig(final String activeStateId) {
|
||||
final HashMap<IsActiveDecoration, StatusFontIcon> activeStateMap = Maps.newHashMapWithExpectedSize(4);
|
||||
activeStateMap.put(IsActiveDecoration.SCHEDULED,
|
||||
new StatusFontIcon(FontAwesome.HOURGLASS_1, STATUS_ICON_PENDING, "Scheduled", activeStateId));
|
||||
activeStateMap.put(IsActiveDecoration.ACTIVE,
|
||||
new StatusFontIcon(null, STATUS_ICON_ACTIVE, "Active", activeStateId));
|
||||
activeStateMap.put(IsActiveDecoration.IN_ACTIVE,
|
||||
new StatusFontIcon(FontAwesome.CHECK_CIRCLE, STATUS_ICON_NEUTRAL, "In-active", activeStateId));
|
||||
activeStateMap.put(IsActiveDecoration.IN_ACTIVE_ERROR,
|
||||
new StatusFontIcon(FontAwesome.CHECK_CIRCLE, STATUS_ICON_RED, "In-active", activeStateId));
|
||||
return activeStateMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,149 +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.management.actionhistory;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.builder.LabelBuilder;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIButton;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder;
|
||||
import org.eclipse.hawkbit.ui.management.event.ManagementUIEvent;
|
||||
import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
|
||||
import org.vaadin.spring.events.EventBus;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.server.FontAwesome;
|
||||
import com.vaadin.shared.ui.label.ContentMode;
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class ActionHistoryHeader extends VerticalLayout {
|
||||
private static final long serialVersionUID = -6276188234115774351L;
|
||||
|
||||
private final transient EventBus.UIEventBus eventBus;
|
||||
private final ManagementUIState managementUIState;
|
||||
|
||||
private Label titleOfActionHistory;
|
||||
private SPUIButton maxMinButton;
|
||||
|
||||
ActionHistoryHeader(final UIEventBus eventBus, final ManagementUIState managementUIState) {
|
||||
this.eventBus = eventBus;
|
||||
this.managementUIState = managementUIState;
|
||||
buildComponent();
|
||||
buildLayout();
|
||||
restorePreviousState();
|
||||
}
|
||||
|
||||
private void buildComponent() {
|
||||
// create default title - it will be shown even when no data is
|
||||
// available
|
||||
titleOfActionHistory = new LabelBuilder().name(HawkbitCommonUtil.getArtifactoryDetailsLabelId(""))
|
||||
.buildCaptionLabel();
|
||||
|
||||
titleOfActionHistory.setImmediate(true);
|
||||
titleOfActionHistory.setContentMode(ContentMode.HTML);
|
||||
|
||||
maxMinButton = (SPUIButton) SPUIComponentProvider.getButton(SPUIDefinitions.EXPAND_ACTION_HISTORY, "", "", null,
|
||||
true, FontAwesome.EXPAND, SPUIButtonStyleSmallNoBorder.class);
|
||||
// listener for maximizing action history
|
||||
maxMinButton.addClickListener(event -> maxMinButtonClicked());
|
||||
|
||||
}
|
||||
|
||||
private void buildLayout() {
|
||||
final HorizontalLayout titleMaxIconsLayout = new HorizontalLayout();
|
||||
titleMaxIconsLayout.addStyleName(SPUIStyleDefinitions.WIDGET_TITLE);
|
||||
titleMaxIconsLayout.setSpacing(false);
|
||||
titleMaxIconsLayout.setMargin(false);
|
||||
titleMaxIconsLayout.setSizeFull();
|
||||
titleMaxIconsLayout.addComponents(titleOfActionHistory, maxMinButton);
|
||||
titleMaxIconsLayout.setComponentAlignment(titleOfActionHistory, Alignment.TOP_LEFT);
|
||||
titleMaxIconsLayout.setComponentAlignment(maxMinButton, Alignment.TOP_RIGHT);
|
||||
titleMaxIconsLayout.setExpandRatio(titleOfActionHistory, 0.8f);
|
||||
titleMaxIconsLayout.setExpandRatio(maxMinButton, 0.2f);
|
||||
|
||||
// Note: here the only purpose of adding drop hints to the layout is to
|
||||
// maintain consistent
|
||||
// height for all widgets headers.
|
||||
addComponent(titleMaxIconsLayout);
|
||||
setComponentAlignment(titleMaxIconsLayout, Alignment.TOP_LEFT);
|
||||
setWidth(100, Unit.PERCENTAGE);
|
||||
setImmediate(true);
|
||||
addStyleName("action-history-header");
|
||||
addStyleName("bordered-layout");
|
||||
addStyleName("no-border-bottom");
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate Header Data for Target.
|
||||
*
|
||||
* @param targetName
|
||||
* name of the target
|
||||
*/
|
||||
public void populateHeader(final String targetName) {
|
||||
updateActionHistoryHeader(targetName);
|
||||
}
|
||||
|
||||
private void maxMinButtonClicked() {
|
||||
final Boolean flag = (Boolean) maxMinButton.getData();
|
||||
if (flag == null || Boolean.FALSE.equals(flag)) {
|
||||
// Clicked on max Icon
|
||||
maximizedTableView();
|
||||
managementUIState.setActionHistoryMaximized(Boolean.TRUE);
|
||||
} else {
|
||||
// Clicked on min icon
|
||||
minimizeTableView();
|
||||
managementUIState.setActionHistoryMaximized(Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
private void maximizedTableView() {
|
||||
showMinIcon();
|
||||
eventBus.publish(this, ManagementUIEvent.MAX_ACTION_HISTORY);
|
||||
}
|
||||
|
||||
private void minimizeTableView() {
|
||||
showMaxIcon();
|
||||
eventBus.publish(this, ManagementUIEvent.MIN_ACTION_HISTORY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates header with target name.
|
||||
*
|
||||
* @param targetName
|
||||
* name of the target
|
||||
*/
|
||||
public void updateActionHistoryHeader(final String targetName) {
|
||||
titleOfActionHistory.setValue(HawkbitCommonUtil.getActionHistoryLabelId(targetName));
|
||||
}
|
||||
|
||||
private void showMinIcon() {
|
||||
maxMinButton.togleIcon(FontAwesome.COMPRESS);
|
||||
maxMinButton.setData(Boolean.TRUE);
|
||||
}
|
||||
|
||||
private void showMaxIcon() {
|
||||
maxMinButton.togleIcon(FontAwesome.EXPAND);
|
||||
maxMinButton.setData(Boolean.FALSE);
|
||||
}
|
||||
|
||||
private void restorePreviousState() {
|
||||
if (managementUIState.isActionHistoryMaximized()) {
|
||||
showMinIcon();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* 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.management.actionhistory;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGrid;
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGridComponentLayout;
|
||||
import org.eclipse.hawkbit.ui.common.grid.DefaultGridHeader;
|
||||
import org.eclipse.hawkbit.ui.common.grid.DefaultGridHeader.AbstractHeaderMaximizeSupport;
|
||||
import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType;
|
||||
import org.eclipse.hawkbit.ui.management.event.ManagementUIEvent;
|
||||
import org.eclipse.hawkbit.ui.management.event.TargetTableEvent;
|
||||
import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
|
||||
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
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.UI;
|
||||
|
||||
/**
|
||||
* Layout responsible for action-history-grid and the corresponding header.
|
||||
*/
|
||||
public class ActionHistoryLayout extends AbstractGridComponentLayout {
|
||||
private static final long serialVersionUID = -3766179797384539821L;
|
||||
|
||||
private final transient DeploymentManagement deploymentManagement;
|
||||
private final UINotification notification;
|
||||
private final ManagementUIState managementUIState;
|
||||
|
||||
private transient AbstractGrid<?>.DetailsSupport details;
|
||||
private Long masterForDetails;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param i18n
|
||||
* @param deploymentManagement
|
||||
* @param eventBus
|
||||
* @param notification
|
||||
* @param managementUIState
|
||||
*/
|
||||
public ActionHistoryLayout(final VaadinMessageSource i18n, final DeploymentManagement deploymentManagement,
|
||||
final UIEventBus eventBus, final UINotification notification, final ManagementUIState managementUIState) {
|
||||
super(i18n, eventBus);
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
this.notification = notification;
|
||||
this.managementUIState = managementUIState;
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionHistoryHeader createGridHeader() {
|
||||
return new ActionHistoryHeader(managementUIState).init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionHistoryGrid createGrid() {
|
||||
return new ActionHistoryGrid(i18n, deploymentManagement, eventBus, notification, managementUIState);
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final TargetTableEvent targetUIEvent) {
|
||||
if (BaseEntityEventType.SELECTED_ENTITY == targetUIEvent.getEventType()) {
|
||||
setData(SPUIDefinitions.DATA_AVAILABLE);
|
||||
UI.getCurrent().access(() -> populateActionHistoryDetails(targetUIEvent.getEntity()));
|
||||
} else if (BaseEntityEventType.REMOVE_ENTITY == targetUIEvent.getEventType()
|
||||
&& targetUIEvent.getEntityIds().contains(managementUIState.getLastSelectedTargetId())) {
|
||||
setData(SPUIDefinitions.NO_DATA);
|
||||
UI.getCurrent().access(this::populateActionHistoryDetails);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override default registration for selection propagation in order to
|
||||
* interrupt update cascade in minimized state to prevent updates on
|
||||
* invisible action-status-grid and message-grid.
|
||||
* <p>
|
||||
* The master selection is stored and propagation is performed as soon as
|
||||
* the state changes to maximize and hence the dependent grids are updated.
|
||||
*/
|
||||
@Override
|
||||
public void registerDetails(final AbstractGrid<?>.DetailsSupport details) {
|
||||
this.details = details;
|
||||
getGrid().addSelectionListener(event -> {
|
||||
masterForDetails = (Long) event.getSelected().stream().findFirst().orElse(null);
|
||||
if (managementUIState.isActionHistoryMaximized()) {
|
||||
details.populateMasterDataAndRecalculateContainer(masterForDetails);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate action header and table for the target.
|
||||
*
|
||||
* @param target
|
||||
* the target
|
||||
*/
|
||||
public void populateActionHistoryDetails(final Target target) {
|
||||
if (null != target) {
|
||||
((ActionHistoryHeader) getHeader()).updateActionHistoryHeader(target.getName());
|
||||
((ActionHistoryGrid) getGrid()).populateSelectedTarget(target);
|
||||
} else {
|
||||
((ActionHistoryHeader) getHeader()).updateActionHistoryHeader(" ");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate empty action header and empty table for empty selection.
|
||||
*/
|
||||
public void populateActionHistoryDetails() {
|
||||
((ActionHistoryHeader) getHeader()).updateActionHistoryHeader(" ");
|
||||
((ActionHistoryGrid) getGrid()).populateSelectedTarget(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Header for ActionHistory with maximize-support.
|
||||
*/
|
||||
class ActionHistoryHeader extends DefaultGridHeader {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param managementUIState
|
||||
*/
|
||||
ActionHistoryHeader(final ManagementUIState managementUIState) {
|
||||
super(managementUIState);
|
||||
this.setHeaderMaximizeSupport(
|
||||
new ActionHistoryHeaderMaxSupport(this, SPUIDefinitions.EXPAND_ACTION_HISTORY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the header.
|
||||
*/
|
||||
@Override
|
||||
public ActionHistoryHeader init() {
|
||||
super.init();
|
||||
restorePreviousState();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates header with target name.
|
||||
*
|
||||
* @param targetName
|
||||
* name of the target
|
||||
*/
|
||||
public void updateActionHistoryHeader(final String targetName) {
|
||||
updateTitle(HawkbitCommonUtil.getActionHistoryLabelId(targetName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the previous min-max state.
|
||||
*/
|
||||
private void restorePreviousState() {
|
||||
if (hasHeaderMaximizeSupport() && managementUIState.isActionHistoryMaximized()) {
|
||||
getHeaderMaximizeSupport().showMinIcon();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Min-max support for header.
|
||||
*/
|
||||
class ActionHistoryHeaderMaxSupport extends AbstractHeaderMaximizeSupport {
|
||||
|
||||
private final DefaultGridHeader abstractGridHeader;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param abstractGridHeader
|
||||
* @param maximizeButtonId
|
||||
*/
|
||||
protected ActionHistoryHeaderMaxSupport(final DefaultGridHeader abstractGridHeader,
|
||||
final String maximizeButtonId) {
|
||||
abstractGridHeader.super(maximizeButtonId);
|
||||
this.abstractGridHeader = abstractGridHeader;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void maximize() {
|
||||
details.populateMasterDataAndRecreateContainer(masterForDetails);
|
||||
eventBus.publish(this, ManagementUIEvent.MAX_ACTION_HISTORY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void minimize() {
|
||||
eventBus.publish(this, ManagementUIEvent.MIN_ACTION_HISTORY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the grid header the maximize support is for.
|
||||
*
|
||||
* @return grid header
|
||||
*/
|
||||
protected DefaultGridHeader getGridHeader() {
|
||||
return abstractGridHeader;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,844 +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.management.actionhistory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ActionStatusFields;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.ActionType;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.ActionWithStatusCount;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.ui.common.ConfirmationDialog;
|
||||
import org.eclipse.hawkbit.ui.common.builder.LabelBuilder;
|
||||
import org.eclipse.hawkbit.ui.common.entity.TargetIdName;
|
||||
import org.eclipse.hawkbit.ui.common.table.BaseEntityEventType;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder;
|
||||
import org.eclipse.hawkbit.ui.management.event.ManagementUIEvent;
|
||||
import org.eclipse.hawkbit.ui.management.event.PinUnpinEvent;
|
||||
import org.eclipse.hawkbit.ui.management.event.TargetTableEvent;
|
||||
import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.eclipse.hawkbit.ui.utils.SPDateTimeUtil;
|
||||
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.UINotification;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
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.data.Container;
|
||||
import com.vaadin.data.Item;
|
||||
import com.vaadin.data.util.HierarchicalContainer;
|
||||
import com.vaadin.server.FontAwesome;
|
||||
import com.vaadin.shared.ui.label.ContentMode;
|
||||
import com.vaadin.ui.Button;
|
||||
import com.vaadin.ui.Component;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.Table;
|
||||
import com.vaadin.ui.TextArea;
|
||||
import com.vaadin.ui.TreeTable;
|
||||
import com.vaadin.ui.UI;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
/**
|
||||
* Table for {@link Target#getActions()} history.
|
||||
*
|
||||
*/
|
||||
public class ActionHistoryTable extends TreeTable {
|
||||
|
||||
private static final long serialVersionUID = -1631514704696786653L;
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ActionHistoryTable.class);
|
||||
private static final String BUTTON_CANCEL = "button.cancel";
|
||||
private static final String BUTTON_OK = "button.ok";
|
||||
|
||||
private final VaadinMessageSource i18n;
|
||||
private final transient DeploymentManagement deploymentManagement;
|
||||
private final transient EventBus.UIEventBus eventBus;
|
||||
private final UINotification notification;
|
||||
private final ManagementUIState managementUIState;
|
||||
|
||||
private Container hierarchicalContainer;
|
||||
private boolean alreadyHasMessages;
|
||||
|
||||
private Target target;
|
||||
|
||||
ActionHistoryTable(final VaadinMessageSource i18n, final DeploymentManagement deploymentManagement, final UIEventBus eventBus,
|
||||
final UINotification notification, final ManagementUIState managementUIState) {
|
||||
this.i18n = i18n;
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
this.eventBus = eventBus;
|
||||
this.notification = notification;
|
||||
this.managementUIState = managementUIState;
|
||||
|
||||
initializeTableSettings();
|
||||
buildComponent();
|
||||
restorePreviousState();
|
||||
setVisibleColumns(getVisbleColumns().toArray());
|
||||
eventBus.subscribe(this);
|
||||
setPageLength(SPUIDefinitions.PAGE_SIZE);
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
void onEvent(final ManagementUIEvent mgmtUIEvent) {
|
||||
if (mgmtUIEvent == ManagementUIEvent.MAX_ACTION_HISTORY) {
|
||||
UI.getCurrent().access(this::createTableContentForMax);
|
||||
}
|
||||
if (mgmtUIEvent == ManagementUIEvent.MIN_ACTION_HISTORY) {
|
||||
UI.getCurrent().access(this::normalActionHistoryTable);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* this method is called when the target history component is initialized
|
||||
* without any data
|
||||
*/
|
||||
private void buildComponent() {
|
||||
// create an empty container
|
||||
createContainer();
|
||||
setContainerDataSource(hierarchicalContainer);
|
||||
addGeneratedColumns();
|
||||
setColumnExpandRatioForMinimisedTable();
|
||||
}
|
||||
|
||||
private void setColumnExpandRatioForMinimisedTable() {
|
||||
setColumnExpandRatio(SPUIDefinitions.ACTION_HIS_TBL_ACTION_ID, 0.1F);
|
||||
setColumnExpandRatio(SPUIDefinitions.ACTION_HIS_TBL_DIST, 0.3F);
|
||||
setColumnExpandRatio(SPUIDefinitions.ACTION_HIS_TBL_STATUS, 0.15F);
|
||||
setColumnExpandRatio(SPUIDefinitions.ACTION_HIS_TBL_DATETIME, 0.3F);
|
||||
setColumnExpandRatio(SPUIDefinitions.ACTION_HIS_TBL_FORCED, 0.15F);
|
||||
setColumnExpandRatio(SPUIDefinitions.ACTIONS_COLUMN, 0.2F);
|
||||
}
|
||||
|
||||
private void initializeTableSettings() {
|
||||
|
||||
setId(UIComponentIdProvider.ACTION_HISTORY_TABLE_ID);
|
||||
setSelectable(false);
|
||||
setMultiSelect(false);
|
||||
setSortEnabled(true);
|
||||
setColumnReorderingAllowed(true);
|
||||
setHeight(100.0F, Unit.PERCENTAGE);
|
||||
setWidth(100.0F, Unit.PERCENTAGE);
|
||||
setImmediate(true);
|
||||
setStyleName("sp-table");
|
||||
addStyleName(ValoTheme.TABLE_NO_VERTICAL_LINES);
|
||||
addStyleName(ValoTheme.TABLE_SMALL);
|
||||
setColumnAlignment(SPUIDefinitions.ACTION_HIS_TBL_FORCED, Align.CENTER);
|
||||
setColumnAlignment(SPUIDefinitions.ACTION_HIS_TBL_STATUS, Align.CENTER);
|
||||
setColumnAlignment(SPUIDefinitions.ACTIONS_COLUMN, Align.CENTER);
|
||||
// listeners for child
|
||||
addExpandListener(event -> {
|
||||
expandParentActionRow(event.getItemId());
|
||||
managementUIState.getExpandParentActionRowId().add(event.getItemId());
|
||||
});
|
||||
addCollapseListener(event -> {
|
||||
collapseParentActionRow(event.getItemId());
|
||||
managementUIState.getExpandParentActionRowId().remove(event.getItemId());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a empty HierarchicalContainer.
|
||||
*/
|
||||
public void createContainer() {
|
||||
/* Create HierarchicalContainer container */
|
||||
hierarchicalContainer = new HierarchicalContainer();
|
||||
hierarchicalContainer.addContainerProperty(SPUIDefinitions.ACTION_HIS_TBL_ACTIVE_HIDDEN, String.class, null);
|
||||
hierarchicalContainer.addContainerProperty(SPUIDefinitions.ACTION_HIS_TBL_FORCED, Action.class, null);
|
||||
hierarchicalContainer.addContainerProperty(SPUIDefinitions.ACTION_HIS_TBL_ACTION_ID_HIDDEN, Long.class, null);
|
||||
hierarchicalContainer.addContainerProperty(SPUIDefinitions.ACTION_HIS_TBL_ACTION_ID, String.class, null);
|
||||
hierarchicalContainer.addContainerProperty(SPUIDefinitions.ACTION_HIS_TBL_DIST, String.class, null);
|
||||
hierarchicalContainer.addContainerProperty(SPUIDefinitions.ACTION_HIS_TBL_DATETIME, String.class, null);
|
||||
hierarchicalContainer.addContainerProperty(SPUIDefinitions.ACTION_HIS_TBL_STATUS_HIDDEN, Action.Status.class,
|
||||
null);
|
||||
hierarchicalContainer.addContainerProperty(SPUIDefinitions.ACTION_HIS_TBL_MSGS_HIDDEN, List.class, null);
|
||||
hierarchicalContainer.addContainerProperty(SPUIDefinitions.ACTION_HIS_TBL_ROLLOUT_NAME, String.class, null);
|
||||
|
||||
}
|
||||
|
||||
private List<Object> getVisbleColumns() {
|
||||
final List<Object> visibleColumnIds = new ArrayList<>();
|
||||
visibleColumnIds.add(SPUIDefinitions.ACTION_HIS_TBL_ACTIVE);
|
||||
visibleColumnIds.add(SPUIDefinitions.ACTION_HIS_TBL_DIST);
|
||||
visibleColumnIds.add(SPUIDefinitions.ACTION_HIS_TBL_DATETIME);
|
||||
visibleColumnIds.add(SPUIDefinitions.ACTION_HIS_TBL_STATUS);
|
||||
visibleColumnIds.add(SPUIDefinitions.ACTION_HIS_TBL_FORCED);
|
||||
visibleColumnIds.add(SPUIDefinitions.ACTIONS_COLUMN);
|
||||
|
||||
if (managementUIState.isActionHistoryMaximized()) {
|
||||
visibleColumnIds.add(SPUIDefinitions.ACTION_HIS_TBL_ROLLOUT_NAME);
|
||||
visibleColumnIds.add(SPUIDefinitions.ACTION_HIS_TBL_MSGS);
|
||||
visibleColumnIds.add(1, SPUIDefinitions.ACTION_HIS_TBL_ACTION_ID);
|
||||
}
|
||||
return visibleColumnIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch the target details using controller id, and set it globally.
|
||||
*
|
||||
* @param selectedTarget
|
||||
* reference of target
|
||||
*/
|
||||
public void populateTableData(final Target selectedTarget) {
|
||||
target = selectedTarget;
|
||||
refreshContainer();
|
||||
}
|
||||
|
||||
/* re -create the container and get the data and set it to the table */
|
||||
private void refreshContainer() {
|
||||
getcontainerData();
|
||||
// to expand parent row , if already expanded.
|
||||
expandParentRow();
|
||||
|
||||
}
|
||||
|
||||
private void getcontainerData() {
|
||||
hierarchicalContainer.removeAllItems();
|
||||
|
||||
if (target != null) {
|
||||
/* service method to create action history for target */
|
||||
final List<ActionWithStatusCount> actionHistory = deploymentManagement
|
||||
.findActionsWithStatusCountByTargetOrderByIdDesc(target.getControllerId());
|
||||
|
||||
addDetailsToContainer(actionHistory);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate Container for Action.
|
||||
*
|
||||
* @param isActiveActions
|
||||
* as flag
|
||||
* @param reversedActions
|
||||
* as action
|
||||
* @param startIdx
|
||||
* as sort
|
||||
* @param target2
|
||||
* @param actionHistoryMode
|
||||
* as either {@link ActionHistoryMode.NORMAL} or
|
||||
* {@link ActionHistoryMode.MAXIMIZED}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void addDetailsToContainer(final List<ActionWithStatusCount> actions) {
|
||||
for (final ActionWithStatusCount actionWithStatusCount : actions) {
|
||||
|
||||
final Action action = actionWithStatusCount.getAction();
|
||||
|
||||
final Item item = hierarchicalContainer.addItem(actionWithStatusCount.getAction().getId());
|
||||
|
||||
item.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_STATUS_HIDDEN)
|
||||
.setValue(actionWithStatusCount.getAction().getStatus());
|
||||
|
||||
/*
|
||||
* add action id.
|
||||
*/
|
||||
item.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_ACTION_ID)
|
||||
.setValue(actionWithStatusCount.getAction().getId().toString());
|
||||
/*
|
||||
* add active/inactive status to the item which will be used in
|
||||
* Column generator to generate respective icon
|
||||
*/
|
||||
item.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_ACTIVE_HIDDEN).setValue(
|
||||
actionWithStatusCount.getAction().isActive() ? SPUIDefinitions.ACTIVE : SPUIDefinitions.IN_ACTIVE);
|
||||
|
||||
/*
|
||||
* add action Id to the item which will be used for fetching child
|
||||
* items ( previous action status ) during expand
|
||||
*/
|
||||
item.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_ACTION_ID_HIDDEN)
|
||||
.setValue(actionWithStatusCount.getAction().getId());
|
||||
|
||||
/*
|
||||
* add distribution name to the item which will be displayed in the
|
||||
* table. The name should not exceed certain limit.
|
||||
*/
|
||||
item.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_DIST)
|
||||
.setValue(actionWithStatusCount.getDsName() + ":" + actionWithStatusCount.getDsVersion());
|
||||
item.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_FORCED).setValue(action);
|
||||
|
||||
/* Default no child */
|
||||
((Hierarchical) hierarchicalContainer).setChildrenAllowed(actionWithStatusCount.getAction().getId(), false);
|
||||
|
||||
item.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_DATETIME)
|
||||
.setValue(SPDateTimeUtil.getFormattedDate(actionWithStatusCount.getAction().getLastModifiedAt()));
|
||||
|
||||
item.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_ROLLOUT_NAME)
|
||||
.setValue(actionWithStatusCount.getRolloutName());
|
||||
|
||||
if (actionWithStatusCount.getActionStatusCount() > 0) {
|
||||
((Hierarchical) hierarchicalContainer).setChildrenAllowed(actionWithStatusCount.getAction().getId(),
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addGeneratedColumns() {
|
||||
addGeneratedColumn(SPUIDefinitions.ACTION_HIS_TBL_ACTIVE, new Table.ColumnGenerator() {
|
||||
/* Serial Verion Id */
|
||||
private static final long serialVersionUID = -8673604389011758339L;
|
||||
|
||||
@Override
|
||||
public Component generateCell(final Table source, final Object itemId, final Object columnId) {
|
||||
return getActiveColumn(itemId);
|
||||
}
|
||||
});
|
||||
addGeneratedColumn(SPUIDefinitions.ACTION_HIS_TBL_STATUS, new Table.ColumnGenerator() {
|
||||
/* Serial Verion Id */
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Component generateCell(final Table source, final Object itemId, final Object columnId) {
|
||||
return getStatusColumn(itemId);
|
||||
}
|
||||
});
|
||||
// forced
|
||||
addGeneratedColumn(SPUIDefinitions.ACTION_HIS_TBL_FORCED, new Table.ColumnGenerator() {
|
||||
/* Serial Verion Id */
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Component generateCell(final Table source, final Object itemId, final Object columnId) {
|
||||
return getForcedColumn(itemId);
|
||||
}
|
||||
});
|
||||
|
||||
addGeneratedColumn(SPUIDefinitions.ACTIONS_COLUMN, new Table.ColumnGenerator() {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Component generateCell(final Table source, final Object itemId, final Object columnId) {
|
||||
return createActionBarColumn(itemId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Component getForcedColumn(final Object itemId) {
|
||||
final Action actionWithActiveStatus = (Action) hierarchicalContainer.getItem(itemId)
|
||||
.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_FORCED).getValue();
|
||||
final Label actionLabel = new LabelBuilder().name("").buildCaptionLabel();
|
||||
actionLabel.setContentMode(ContentMode.HTML);
|
||||
actionLabel.setStyleName("action-history-table-col-forced-label");
|
||||
if (actionWithActiveStatus != null && actionWithActiveStatus.getActionType() == ActionType.FORCED) {
|
||||
actionLabel.setValue(FontAwesome.BOLT.getHtml());
|
||||
// setted Id for Forced.
|
||||
actionLabel.setId("action.history.table.forcedId");
|
||||
} else if (actionWithActiveStatus != null && actionWithActiveStatus.getActionType() == ActionType.TIMEFORCED) {
|
||||
return actionLabelWithTimeForceIcon(actionWithActiveStatus, actionLabel);
|
||||
}
|
||||
return actionLabel;
|
||||
}
|
||||
|
||||
private Component getActiveColumn(final Object itemId) {
|
||||
final Action.Status status = (Action.Status) hierarchicalContainer.getItem(itemId)
|
||||
.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_STATUS_HIDDEN).getValue();
|
||||
String activeValue;
|
||||
if (status == Action.Status.SCHEDULED) {
|
||||
activeValue = Action.Status.SCHEDULED.toString().toLowerCase();
|
||||
} else {
|
||||
activeValue = (String) hierarchicalContainer.getItem(itemId)
|
||||
.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_ACTIVE_HIDDEN).getValue();
|
||||
}
|
||||
final String distName = (String) hierarchicalContainer.getItem(itemId)
|
||||
.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_DIST).getValue();
|
||||
final Label activeStatusIcon = createActiveStatusLabel(activeValue,
|
||||
(Action.Status) hierarchicalContainer.getItem(itemId)
|
||||
.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_STATUS_HIDDEN)
|
||||
.getValue() == Action.Status.ERROR);
|
||||
activeStatusIcon.setId(new StringJoiner(".").add(distName).add(itemId.toString())
|
||||
.add(SPUIDefinitions.ACTION_HIS_TBL_ACTIVE).add(activeValue).toString());
|
||||
return activeStatusIcon;
|
||||
}
|
||||
|
||||
private HorizontalLayout createActionBarColumn(final Object itemId) {
|
||||
final HorizontalLayout actionBar = new HorizontalLayout();
|
||||
final Item item = hierarchicalContainer.getItem(itemId);
|
||||
final Long actionId = (Long) item.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_ACTION_ID_HIDDEN).getValue();
|
||||
final String activeValue = (String) item.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_ACTIVE_HIDDEN)
|
||||
.getValue();
|
||||
final Action actionWithActiveStatus = (Action) item.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_FORCED)
|
||||
.getValue();
|
||||
|
||||
if (actionWithActiveStatus == null) {
|
||||
return null;
|
||||
}
|
||||
final boolean isActionActive = target != null && SPUIDefinitions.ACTIVE.equals(activeValue);
|
||||
|
||||
final Button actionCancel = SPUIComponentProvider.getButton(
|
||||
UIComponentIdProvider.ACTION_HISTORY_TABLE_CANCEL_ID, "", i18n.getMessage("message.cancel.action"),
|
||||
ValoTheme.BUTTON_TINY, true, FontAwesome.TIMES, SPUIButtonStyleSmallNoBorder.class);
|
||||
actionCancel.setEnabled(isActionActive && !actionWithActiveStatus.isCancelingOrCanceled());
|
||||
actionCancel.addClickListener(event -> confirmAndCancelAction(actionId));
|
||||
|
||||
final Button actionForce = SPUIComponentProvider.getButton(UIComponentIdProvider.ACTION_HISTORY_TABLE_FORCE_ID,
|
||||
"", i18n.getMessage("message.force.action"), ValoTheme.BUTTON_TINY, true, FontAwesome.BOLT,
|
||||
SPUIButtonStyleSmallNoBorder.class);
|
||||
actionForce.setEnabled(
|
||||
isActionActive && !actionWithActiveStatus.isForce() && !actionWithActiveStatus.isCancelingOrCanceled());
|
||||
actionForce.addClickListener(event -> confirmAndForceAction(actionId));
|
||||
|
||||
final Button actionForceQuit = SPUIComponentProvider.getButton(
|
||||
UIComponentIdProvider.ACTION_HISTORY_TABLE_FORCE_QUIT_ID, "", i18n.getMessage("message.forcequit.action"),
|
||||
ValoTheme.BUTTON_TINY + " redicon", true, FontAwesome.TIMES, SPUIButtonStyleSmallNoBorder.class);
|
||||
actionForceQuit.setEnabled(isActionActive && actionWithActiveStatus.isCancelingOrCanceled());
|
||||
actionForceQuit.addClickListener(event -> confirmAndForceQuitAction(actionId));
|
||||
|
||||
actionBar.addComponents(actionCancel, actionForce, actionForceQuit);
|
||||
|
||||
return actionBar;
|
||||
}
|
||||
|
||||
private Component getStatusColumn(final Object itemId) {
|
||||
final Action.Status status = (Action.Status) hierarchicalContainer.getItem(itemId)
|
||||
.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_STATUS_HIDDEN).getValue();
|
||||
return getStatusIcon(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the rows of previous status history of the selected action row and
|
||||
* add it next to the selected action row.
|
||||
*
|
||||
* @param parentRowIdx
|
||||
* index of the selected action row.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void expandParentActionRow(final Object parentRowIdx) {
|
||||
/* Get the item for which the expand is made */
|
||||
final Item item = hierarchicalContainer.getItem(parentRowIdx);
|
||||
if (null != item) {
|
||||
final Long actionId = (Long) item.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_ACTION_ID_HIDDEN)
|
||||
.getValue();
|
||||
|
||||
final Optional<Action> action = deploymentManagement.findActionWithDetails(actionId);
|
||||
|
||||
if (!action.isPresent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Pageable pageReq = new PageRequest(0, 1000,
|
||||
new Sort(Direction.DESC, ActionStatusFields.ID.getFieldName()));
|
||||
final Page<ActionStatus> actionStatusList;
|
||||
if (managementUIState.isActionHistoryMaximized()) {
|
||||
actionStatusList = deploymentManagement.findActionStatusByActionWithMessages(pageReq, actionId);
|
||||
} else {
|
||||
actionStatusList = deploymentManagement.findActionStatusByAction(pageReq, actionId);
|
||||
}
|
||||
final List<ActionStatus> content = actionStatusList.getContent();
|
||||
/*
|
||||
* Since the recent action status and messages are already
|
||||
* displaying with parent item, check if more than one action status
|
||||
* available.
|
||||
*/
|
||||
int childIdx = 1;
|
||||
for (final ActionStatus actionStatus : content) {
|
||||
final String childId = parentRowIdx + " -> " + childIdx;
|
||||
final Item childItem = hierarchicalContainer.addItem(childId);
|
||||
if (null != childItem) {
|
||||
/*
|
||||
* For better UI, no need to display active/inactive icon
|
||||
* for child items.
|
||||
*/
|
||||
childItem.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_ACTIVE_HIDDEN).setValue("");
|
||||
|
||||
childItem.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_DIST)
|
||||
.setValue(action.get().getDistributionSet().getName() + ":"
|
||||
+ action.get().getDistributionSet().getVersion());
|
||||
|
||||
childItem.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_DATETIME)
|
||||
.setValue(SPDateTimeUtil.getFormattedDate(actionStatus.getCreatedAt()));
|
||||
childItem.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_STATUS_HIDDEN)
|
||||
.setValue(actionStatus.getStatus());
|
||||
showOrHideMessage(childItem, actionStatus);
|
||||
/* No further child items allowed for the child items */
|
||||
((Hierarchical) hierarchicalContainer).setChildrenAllowed(childId, false);
|
||||
/* Assign this childItem to the parent */
|
||||
((Hierarchical) hierarchicalContainer).setParent(childId, parentRowIdx);
|
||||
childIdx++;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the rows of previous status history of the selected action row.
|
||||
*
|
||||
* @param parentRowIdx
|
||||
* index of the selected action row.
|
||||
*/
|
||||
public void collapseParentActionRow(final Object parentRowIdx) {
|
||||
/* Remove all child items for the clear the memory. */
|
||||
final Collection<?> children = ((Hierarchical) hierarchicalContainer).getChildren(parentRowIdx);
|
||||
if (children != null && !children.isEmpty()) {
|
||||
String ids = children.toString().substring(1);
|
||||
ids = ids.substring(0, ids.length() - 1);
|
||||
for (final String childId : ids.split(", ")) {
|
||||
((Hierarchical) hierarchicalContainer).removeItem(childId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status icon.
|
||||
*
|
||||
* @param status
|
||||
* as Status
|
||||
* @return Label as UI
|
||||
*/
|
||||
private Label getStatusIcon(final Action.Status status) {
|
||||
final Label label = new LabelBuilder().name("").buildLabel();
|
||||
label.setContentMode(ContentMode.HTML);
|
||||
|
||||
final ActionStatusIconMapper mapping = ActionStatusIconMapper.MAPPINGS.get(status);
|
||||
|
||||
if (mapping == null) {
|
||||
label.setDescription("");
|
||||
label.setValue("");
|
||||
return label;
|
||||
}
|
||||
|
||||
label.setDescription(i18n.getMessage(mapping.getDescriptionI18N()));
|
||||
label.setStyleName(mapping.getStyleName());
|
||||
label.setValue(mapping.getIcon().getHtml());
|
||||
return label;
|
||||
|
||||
}
|
||||
|
||||
// to show forced Icon
|
||||
private Component actionLabelWithTimeForceIcon(final Action actionWithActiveStatus, final Label actionLabel) {
|
||||
final long currentTimeMillis = System.currentTimeMillis();
|
||||
|
||||
final HorizontalLayout hLayout = new HorizontalLayout();
|
||||
final Label autoForceLabel = new LabelBuilder().name("").id("action.history.table.timedforceId").buildLabel();
|
||||
|
||||
actionLabel.setValue(FontAwesome.BOLT.getHtml());
|
||||
autoForceLabel.setContentMode(ContentMode.HTML);
|
||||
autoForceLabel.setValue(FontAwesome.HISTORY.getHtml());
|
||||
|
||||
hLayout.addComponent(actionLabel);
|
||||
hLayout.addComponent(autoForceLabel);
|
||||
|
||||
if (actionWithActiveStatus.isHitAutoForceTime(currentTimeMillis)) {
|
||||
autoForceLabel.setDescription("autoforced");
|
||||
autoForceLabel.setStyleName(SPUIStyleDefinitions.STATUS_ICON_GREEN);
|
||||
autoForceLabel.setDescription("auto forced since " + SPDateTimeUtil
|
||||
.getDurationFormattedString(actionWithActiveStatus.getForcedTime(), currentTimeMillis, i18n));
|
||||
} else {
|
||||
autoForceLabel.setDescription("auto forcing in " + SPDateTimeUtil
|
||||
.getDurationFormattedString(currentTimeMillis, actionWithActiveStatus.getForcedTime(), i18n));
|
||||
autoForceLabel.setStyleName("statusIconPending");
|
||||
autoForceLabel.setValue(FontAwesome.HISTORY.getHtml());
|
||||
}
|
||||
return hLayout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Status Label.
|
||||
*
|
||||
* @param activeValue
|
||||
* as String
|
||||
* @return Labeal as UI
|
||||
*/
|
||||
private static Label createActiveStatusLabel(final String activeValue, final boolean endedWithError) {
|
||||
final Label label = new LabelBuilder().name("").buildLabel();
|
||||
label.setContentMode(ContentMode.HTML);
|
||||
if (SPUIDefinitions.SCHEDULED.equals(activeValue)) {
|
||||
label.setDescription("Scheduled");
|
||||
label.setValue(FontAwesome.HOURGLASS_1.getHtml());
|
||||
} else if (SPUIDefinitions.ACTIVE.equals(activeValue)) {
|
||||
label.setDescription("Active");
|
||||
label.setStyleName("statusIconActive");
|
||||
} else if (SPUIDefinitions.IN_ACTIVE.equals(activeValue)) {
|
||||
if (endedWithError) {
|
||||
label.setStyleName(SPUIStyleDefinitions.STATUS_ICON_RED);
|
||||
} else {
|
||||
label.setStyleName("statusIconNeutral");
|
||||
}
|
||||
label.setDescription("In-active");
|
||||
label.setValue(FontAwesome.CHECK_CIRCLE.getHtml());
|
||||
} else {
|
||||
label.setValue("");
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates full sized window for action history with message.
|
||||
*/
|
||||
private void createTableContentForMax() {
|
||||
setColumnCollapsingAllowed(true);
|
||||
if (!alreadyHasMessages) {
|
||||
/*
|
||||
* check to avoid DB call for fetching the messages again and again
|
||||
* if already available in container.
|
||||
*/
|
||||
getcontainerData();
|
||||
// to expand parent row , if already expanded.
|
||||
expandParentRow();
|
||||
alreadyHasMessages = true;
|
||||
}
|
||||
|
||||
addGeneratedColumn(SPUIDefinitions.ACTION_HIS_TBL_MSGS, new Table.ColumnGenerator() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Component generateCell(final Table source, final Object itemId, final Object columnId) {
|
||||
final List<String> messages = (List<String>) hierarchicalContainer.getItem(itemId)
|
||||
.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_MSGS_HIDDEN).getValue();
|
||||
return createMessagesBlock(messages);
|
||||
}
|
||||
});
|
||||
setVisibleColumns(getVisbleColumns().toArray());
|
||||
setColumnExpantRatioOnTableMaximize();
|
||||
}
|
||||
|
||||
private void setColumnExpantRatioOnTableMaximize() {
|
||||
/* set messages column can expand the rest of the available space */
|
||||
setColumnExpandRatio(SPUIDefinitions.ACTION_HIS_TBL_ACTIVE, 0.1F);
|
||||
setColumnExpandRatio(SPUIDefinitions.ACTION_HIS_TBL_ACTION_ID, 0.1F);
|
||||
setColumnExpandRatio(SPUIDefinitions.ACTION_HIS_TBL_STATUS, 0.1F);
|
||||
setColumnExpandRatio(SPUIDefinitions.ACTION_HIS_TBL_DIST, 0.2F);
|
||||
setColumnExpandRatio(SPUIDefinitions.ACTION_HIS_TBL_FORCED, 0.1F);
|
||||
setColumnExpandRatio(SPUIDefinitions.ACTION_HIS_TBL_ROLLOUT_NAME, 0.1F);
|
||||
setColumnExpandRatio(SPUIDefinitions.ACTION_HIS_TBL_MSGS, 0.35F);
|
||||
setColumnExpandRatio(SPUIDefinitions.ACTION_HIS_TBL_DATETIME, 0.15F);
|
||||
setColumnExpandRatio(SPUIDefinitions.ACTIONS_COLUMN, 0.2F);
|
||||
}
|
||||
|
||||
/**
|
||||
* create Message block for Actions.
|
||||
*
|
||||
* @param messages
|
||||
* as List of msg
|
||||
* @return Component as UI
|
||||
*/
|
||||
protected Component createMessagesBlock(final List<String> messages) {
|
||||
|
||||
final TextArea textArea = new TextArea();
|
||||
textArea.addStyleName(ValoTheme.TEXTAREA_BORDERLESS);
|
||||
textArea.addStyleName(ValoTheme.TEXTAREA_TINY);
|
||||
textArea.addStyleName("inline-icon");
|
||||
textArea.setSizeFull();
|
||||
int index = 1;
|
||||
final StringBuilder updateStatusMessages = new StringBuilder();
|
||||
if (messages != null && !messages.isEmpty()) {
|
||||
/* Messages are available */
|
||||
for (final String msg : messages) {
|
||||
updateStatusMessages.append('[').append(index).append("]: ").append(msg).append('\n');
|
||||
index++;
|
||||
}
|
||||
} else {
|
||||
/* Messages are not available */
|
||||
updateStatusMessages.append(i18n.getMessage("message.no.available"));
|
||||
}
|
||||
textArea.setValue(updateStatusMessages.toString());
|
||||
textArea.setReadOnly(Boolean.TRUE);
|
||||
return textArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show or hide message.
|
||||
*
|
||||
* @param actionHistoryMode
|
||||
* {@link ActionHisTableType}
|
||||
* @param childItem
|
||||
* {@link Item}
|
||||
* @param actionStatus
|
||||
* {@link ActionHisTableType}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void showOrHideMessage(final Item childItem, final ActionStatus actionStatus) {
|
||||
if (managementUIState.isActionHistoryMaximized()) {
|
||||
childItem.getItemProperty(SPUIDefinitions.ACTION_HIS_TBL_MSGS_HIDDEN).setValue(actionStatus.getMessages());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* View History Table in normal window mode.
|
||||
*/
|
||||
private void normalActionHistoryTable() {
|
||||
setColumnCollapsingAllowed(false);
|
||||
managementUIState.setActionHistoryMaximized(false);
|
||||
removeGeneratedColumn(SPUIDefinitions.ACTION_HIS_TBL_MSGS);
|
||||
setVisibleColumns(getVisbleColumns().toArray());
|
||||
setColumnExpandRatioForMinimisedTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show confirmation window and if ok then only, force the action.
|
||||
*
|
||||
* @param actionId
|
||||
* as Id if the action needs to be forced.
|
||||
*/
|
||||
private void confirmAndForceAction(final Long actionId) {
|
||||
/* Display the confirmation */
|
||||
final ConfirmationDialog confirmDialog = new ConfirmationDialog(i18n.getMessage("caption.force.action.confirmbox"),
|
||||
i18n.getMessage("message.force.action.confirm"), i18n.getMessage(BUTTON_OK), i18n.getMessage(BUTTON_CANCEL), ok -> {
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
deploymentManagement.forceTargetAction(actionId);
|
||||
populateAndupdateTargetDetails(target);
|
||||
notification.displaySuccess(i18n.getMessage("message.force.action.success"));
|
||||
});
|
||||
UI.getCurrent().addWindow(confirmDialog.getWindow());
|
||||
|
||||
confirmDialog.getWindow().bringToFront();
|
||||
}
|
||||
|
||||
private void confirmAndForceQuitAction(final Long actionId) {
|
||||
/* Display the confirmation */
|
||||
final ConfirmationDialog confirmDialog = new ConfirmationDialog(i18n.getMessage("caption.forcequit.action.confirmbox"),
|
||||
i18n.getMessage("message.forcequit.action.confirm"), i18n.getMessage(BUTTON_OK), i18n.getMessage(BUTTON_CANCEL), ok -> {
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
final boolean cancelResult = forceQuitActiveAction(actionId);
|
||||
if (cancelResult) {
|
||||
populateAndupdateTargetDetails(target);
|
||||
notification.displaySuccess(i18n.getMessage("message.forcequit.action.success"));
|
||||
} else {
|
||||
notification.displayValidationError(i18n.getMessage("message.forcequit.action.failed"));
|
||||
}
|
||||
}, FontAwesome.WARNING);
|
||||
UI.getCurrent().addWindow(confirmDialog.getWindow());
|
||||
|
||||
confirmDialog.getWindow().bringToFront();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show confirmation window and if ok then only, cancel the action.
|
||||
*
|
||||
* @param actionId
|
||||
* as Id if the action needs to be cancelled.
|
||||
*/
|
||||
private void confirmAndCancelAction(final Long actionId) {
|
||||
if (actionId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ConfirmationDialog confirmDialog = new ConfirmationDialog(i18n.getMessage("caption.cancel.action.confirmbox"),
|
||||
i18n.getMessage("message.cancel.action.confirm"), i18n.getMessage(BUTTON_OK), i18n.getMessage(BUTTON_CANCEL), ok -> {
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
final boolean cancelResult = cancelActiveAction(actionId);
|
||||
if (cancelResult) {
|
||||
populateAndupdateTargetDetails(target);
|
||||
notification.displaySuccess(i18n.getMessage("message.cancel.action.success"));
|
||||
} else {
|
||||
notification.displayValidationError(i18n.getMessage("message.cancel.action.failed"));
|
||||
}
|
||||
});
|
||||
UI.getCurrent().addWindow(confirmDialog.getWindow());
|
||||
confirmDialog.getWindow().bringToFront();
|
||||
}
|
||||
|
||||
private void populateAndupdateTargetDetails(final Target target) {
|
||||
// show the updated target action history details
|
||||
populateTableData(target);
|
||||
// update the target table and its pinning details
|
||||
updateTargetAndDsTable();
|
||||
}
|
||||
|
||||
// service call to cancel the active action
|
||||
private boolean cancelActiveAction(final Long actionId) {
|
||||
if (actionId != null) {
|
||||
try {
|
||||
deploymentManagement.cancelAction(actionId);
|
||||
return true;
|
||||
} catch (final CancelActionNotAllowedException e) {
|
||||
LOG.info("Cancel action not allowed exception :{}", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// service call to cancel the active action
|
||||
private boolean forceQuitActiveAction(final Long actionId) {
|
||||
if (actionId != null) {
|
||||
try {
|
||||
deploymentManagement.forceQuitAction(actionId);
|
||||
return true;
|
||||
} catch (final CancelActionNotAllowedException e) {
|
||||
LOG.info("Force Cancel action not allowed exception :{}", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void updateTargetAndDsTable() {
|
||||
eventBus.publish(this, new TargetTableEvent(BaseEntityEventType.UPDATED_ENTITY, target));
|
||||
updateDistributionTableStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the colors of Assigned and installed distribution set in Target
|
||||
* Pinning.
|
||||
*/
|
||||
private void updateDistributionTableStyle() {
|
||||
if (managementUIState.getDistributionTableFilters().getPinnedTarget().map(TargetIdName::getTargetId)
|
||||
.map(target.getId()::equals).orElse(false)) {
|
||||
eventBus.publish(this, PinUnpinEvent.PIN_TARGET);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* empty the container when there is no data selected in Target Table.
|
||||
*/
|
||||
public void clearContainerData() {
|
||||
getContainerDataSource().removeAllItems();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set messages false.
|
||||
*
|
||||
* @param alreadyHasMessages
|
||||
* the alreadyHasMessages to set
|
||||
*/
|
||||
public void setAlreadyHasMessages(final boolean alreadyHasMessages) {
|
||||
this.alreadyHasMessages = alreadyHasMessages;
|
||||
}
|
||||
|
||||
private void restorePreviousState() {
|
||||
if (managementUIState.isActionHistoryMaximized()) {
|
||||
createTableContentForMax();
|
||||
}
|
||||
}
|
||||
|
||||
private void expandParentRow() {
|
||||
if (null != managementUIState.getExpandParentActionRowId()
|
||||
&& !managementUIState.getExpandParentActionRowId().isEmpty()) {
|
||||
for (final Object obj : managementUIState.getExpandParentActionRowId()) {
|
||||
expandParentActionRow(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* 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.management.actionhistory;
|
||||
|
||||
import static org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil.isNotNullOrEmpty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
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.PageRequest;
|
||||
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
|
||||
* {@link ProxyActionStatus} batch of beans.
|
||||
*/
|
||||
public class ActionStatusBeanQuery extends AbstractBeanQuery<ProxyActionStatus> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Sort sort = new Sort(Direction.DESC, "id");
|
||||
private transient DeploymentManagement deploymentManagement;
|
||||
|
||||
private Long currentSelectedActionId;
|
||||
private transient Page<ActionStatus> firstPageActionStates;
|
||||
|
||||
/**
|
||||
* Parametric Constructor.
|
||||
*
|
||||
* @param definition
|
||||
* QueryDefinition contains the query properties.
|
||||
* @param queryConfig
|
||||
* Implementation specific configuration.
|
||||
* @param sortPropertyIds
|
||||
* The properties participating in sort.
|
||||
* @param sortStates
|
||||
* The ascending or descending state of sort properties.
|
||||
*/
|
||||
public ActionStatusBeanQuery(final QueryDefinition definition, final Map<String, Object> queryConfig,
|
||||
final Object[] sortPropertyIds, final boolean[] sortStates) {
|
||||
super(definition, queryConfig, sortPropertyIds, sortStates);
|
||||
|
||||
if (isNotNullOrEmpty(queryConfig)) {
|
||||
currentSelectedActionId = (Long) queryConfig.get(SPUIDefinitions.ACTIONSTATES_BY_ACTION);
|
||||
}
|
||||
|
||||
if (sortStates.length > 0) {
|
||||
// Initialize sort
|
||||
sort = new Sort(sortStates[0] ? Direction.ASC : Direction.DESC, (String) sortPropertyIds[0]);
|
||||
// Add sort
|
||||
for (int distId = 1; distId < sortPropertyIds.length; distId++) {
|
||||
sort.and(new Sort(sortStates[distId] ? Direction.ASC : Direction.DESC,
|
||||
(String) sortPropertyIds[distId]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProxyActionStatus constructBean() {
|
||||
return new ProxyActionStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ProxyActionStatus> loadBeans(final int startIndex, final int count) {
|
||||
Page<ActionStatus> actionBeans;
|
||||
if (startIndex == 0 && firstPageActionStates != null) {
|
||||
actionBeans = firstPageActionStates;
|
||||
} else {
|
||||
actionBeans = getDeploymentManagement()
|
||||
.findActionStatusByAction(
|
||||
new PageRequest(startIndex / SPUIDefinitions.PAGE_SIZE, SPUIDefinitions.PAGE_SIZE, sort),
|
||||
currentSelectedActionId);
|
||||
}
|
||||
return createProxyActionStates(actionBeans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of {@link ProxyActionStatus} for presentation layer from
|
||||
* page of {@link ActionStatus}.
|
||||
*
|
||||
* @param actionBeans
|
||||
* page of {@link ActionStatus}
|
||||
* @return list of {@link ProxyActionStatus}
|
||||
*/
|
||||
private static List<ProxyActionStatus> createProxyActionStates(final Page<ActionStatus> actionStatusBeans) {
|
||||
final List<ProxyActionStatus> proxyActionStates = new ArrayList<>();
|
||||
for (final ActionStatus actionStatus : actionStatusBeans) {
|
||||
final ProxyActionStatus proxyAS = new ProxyActionStatus();
|
||||
proxyAS.setCreatedAt(actionStatus.getCreatedAt());
|
||||
proxyAS.setStatus(actionStatus.getStatus());
|
||||
proxyAS.setId(actionStatus.getId());
|
||||
|
||||
proxyActionStates.add(proxyAS);
|
||||
}
|
||||
return proxyActionStates;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.vaadin.addons.lazyquerycontainer.AbstractBeanQuery#saveBeans(java
|
||||
* .util.List, java.util.List, java.util.List)
|
||||
*/
|
||||
@Override
|
||||
protected void saveBeans(List<ProxyActionStatus> addedBeans, List<ProxyActionStatus> modifiedBeans,
|
||||
List<ProxyActionStatus> removedBeans) {
|
||||
// CRUD operations on Target will be done through repository methods
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
long size = 0;
|
||||
|
||||
if (currentSelectedActionId != null) {
|
||||
firstPageActionStates = getDeploymentManagement().findActionStatusByAction(
|
||||
new PageRequest(0, SPUIDefinitions.PAGE_SIZE, sort), currentSelectedActionId);
|
||||
size = firstPageActionStates.getTotalElements();
|
||||
}
|
||||
if (size > Integer.MAX_VALUE) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy gets deploymentManagement.
|
||||
*
|
||||
* @return the deploymentManagement
|
||||
*/
|
||||
public DeploymentManagement getDeploymentManagement() {
|
||||
if (null == deploymentManagement) {
|
||||
deploymentManagement = SpringContextHelper.getBean(DeploymentManagement.class);
|
||||
}
|
||||
return deploymentManagement;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* 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.management.actionhistory;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGrid;
|
||||
import org.eclipse.hawkbit.ui.customrenderers.renderers.HtmlLabelRenderer;
|
||||
import org.eclipse.hawkbit.ui.management.actionhistory.ActionHistoryGrid.LabelConfig;
|
||||
import org.eclipse.hawkbit.ui.rollout.StatusFontIcon;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
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 com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* This grid presents the action states for a selected action.
|
||||
*/
|
||||
public class ActionStatusGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String[] leftAlignedColumns = new String[] { ProxyActionStatus.PXY_AS_CREATED_AT };
|
||||
|
||||
private static final String[] centerAlignedColumns = new String[] { ProxyActionStatus.PXY_AS_STATUS };
|
||||
|
||||
private final AlignCellStyleGenerator alignGenerator;
|
||||
private final ModifiedTimeTooltipGenerator modTimetooltipGenerator;
|
||||
|
||||
private final Map<Action.Status, StatusFontIcon> states;
|
||||
|
||||
private final BeanQueryFactory<ActionStatusBeanQuery> targetQF = new BeanQueryFactory<>(
|
||||
ActionStatusBeanQuery.class);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param i18n
|
||||
* @param eventBus
|
||||
*/
|
||||
protected ActionStatusGrid(final VaadinMessageSource i18n, final UIEventBus eventBus) {
|
||||
super(i18n, eventBus, null);
|
||||
|
||||
setSingleSelectionSupport(new SingleSelectionSupport());
|
||||
setDetailsSupport(new DetailsSupport());
|
||||
|
||||
final LabelConfig conf = new ActionHistoryGrid.LabelConfig();
|
||||
states = conf.createStatusLabelConfig(i18n, UIComponentIdProvider.ACTION_STATUS_GRID_STATUS_LABEL_ID);
|
||||
alignGenerator = new AlignCellStyleGenerator(leftAlignedColumns, centerAlignedColumns, null);
|
||||
modTimetooltipGenerator = new ModifiedTimeTooltipGenerator(ProxyActionStatus.PXY_AS_CREATED_AT);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LazyQueryContainer createContainer() {
|
||||
configureQueryFactory();
|
||||
return new LazyQueryContainer(
|
||||
new LazyQueryDefinition(true, SPUIDefinitions.PAGE_SIZE, ProxyActionStatus.PXY_AS_ID), targetQF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshContainer() {
|
||||
configureQueryFactory();
|
||||
super.refreshContainer();
|
||||
}
|
||||
|
||||
protected void configureQueryFactory() {
|
||||
// ADD all the filters to the query config
|
||||
final Map<String, Object> queryConfig = Maps.newHashMapWithExpectedSize(1);
|
||||
queryConfig.put(SPUIDefinitions.ACTIONSTATES_BY_ACTION, getDetailsSupport().getMasterDataId());
|
||||
// Create ActionBeanQuery factory with the query config.
|
||||
targetQF.setQueryConfiguration(queryConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets type-save access to LazyQueryContainer.
|
||||
*
|
||||
* @return LazyQueryContainer
|
||||
*/
|
||||
private LazyQueryContainer getLazyQueryContainer() {
|
||||
return (LazyQueryContainer) getContainerDataSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addContainerProperties() {
|
||||
final LazyQueryContainer lqContainer = getLazyQueryContainer();
|
||||
lqContainer.addContainerProperty(ProxyActionStatus.PXY_AS_CREATED_AT, Long.class, null, true, true);
|
||||
lqContainer.addContainerProperty(ProxyActionStatus.PXY_AS_STATUS, Action.Status.class, null, true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setColumnExpandRatio() {
|
||||
getColumn(ProxyActionStatus.PXY_AS_STATUS).setMinimumWidth(53);
|
||||
getColumn(ProxyActionStatus.PXY_AS_STATUS).setMaximumWidth(55);
|
||||
getColumn(ProxyActionStatus.PXY_AS_CREATED_AT).setMinimumWidth(100);
|
||||
getColumn(ProxyActionStatus.PXY_AS_CREATED_AT).setMaximumWidth(400);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setColumnHeaderNames() {
|
||||
getColumn(ProxyActionStatus.PXY_AS_STATUS).setHeaderCaption(SPUIDefinitions.ACTION_HIS_TBL_STATUS);
|
||||
getColumn(ProxyActionStatus.PXY_AS_CREATED_AT).setHeaderCaption(SPUIDefinitions.ACTION_HIS_TBL_DATETIME);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getGridId() {
|
||||
return UIComponentIdProvider.ACTION_HISTORY_DETAILS_GRID_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setColumnProperties() {
|
||||
clearSortOrder();
|
||||
setColumns(ProxyActionStatus.PXY_AS_STATUS, ProxyActionStatus.PXY_AS_CREATED_AT);
|
||||
alignColumns();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addColumnRenderes() {
|
||||
getColumn(ProxyActionStatus.PXY_AS_STATUS).setRenderer(new HtmlLabelRenderer(),
|
||||
new HtmlStatusLabelConverter(this::createStatusLabelMetadata));
|
||||
getColumn(ProxyActionStatus.PXY_AS_CREATED_AT).setConverter(new LongToFormattedDateStringConverter());
|
||||
}
|
||||
|
||||
private StatusFontIcon createStatusLabelMetadata(final Action.Status status) {
|
||||
return states.get(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setHiddenColumns() {
|
||||
getColumn(ProxyActionStatus.PXY_AS_STATUS).setHidable(false);
|
||||
getColumn(ProxyActionStatus.PXY_AS_CREATED_AT).setHidable(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alignment cell-style-generator that handles the alignment for
|
||||
* the grid cells.
|
||||
*/
|
||||
private void alignColumns() {
|
||||
setCellStyleGenerator(alignGenerator);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CellDescriptionGenerator getDescriptionGenerator() {
|
||||
return modTimetooltipGenerator;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 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.management.actionhistory;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGridComponentLayout;
|
||||
import org.eclipse.hawkbit.ui.common.grid.DefaultGridHeader;
|
||||
import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
/**
|
||||
* Layout responsible for action-states-grid and the corresponding header.
|
||||
*/
|
||||
public class ActionStatusLayout extends AbstractGridComponentLayout {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected final ManagementUIState managementUIState;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param i18n
|
||||
* @param eventBus
|
||||
* @param managementUIState
|
||||
*/
|
||||
public ActionStatusLayout(final VaadinMessageSource i18n, final UIEventBus eventBus,
|
||||
final ManagementUIState managementUIState) {
|
||||
super(i18n, eventBus);
|
||||
this.managementUIState = managementUIState;
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultGridHeader createGridHeader() {
|
||||
return new DefaultGridHeader(managementUIState, "Action States").init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionStatusGrid createGrid() {
|
||||
return new ActionStatusGrid(i18n, eventBus);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* 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.management.actionhistory;
|
||||
|
||||
import static org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil.isNotNullOrEmpty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
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.PageRequest;
|
||||
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;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
/**
|
||||
* Simple implementation of generic bean query which dynamically loads
|
||||
* {@link ProxyMessage} batch of beans.
|
||||
*/
|
||||
public class ActionStatusMsgBeanQuery extends AbstractBeanQuery<ProxyMessage> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Sort sort = new Sort(Direction.DESC, "id");
|
||||
private transient DeploymentManagement deploymentManagement;
|
||||
|
||||
private Long currentSelectedActionStatusId;
|
||||
private String noMessageText;
|
||||
private transient Page<String> firstPageMessages;
|
||||
|
||||
/**
|
||||
* Parametric Constructor.
|
||||
*
|
||||
* @param definition
|
||||
* QueryDefinition contains the query properties.
|
||||
* @param queryConfig
|
||||
* Implementation specific configuration.
|
||||
* @param sortPropertyIds
|
||||
* The properties participating in sort.
|
||||
* @param sortStates
|
||||
* The ascending or descending state of sort properties.
|
||||
*/
|
||||
public ActionStatusMsgBeanQuery(final QueryDefinition definition, final Map<String, Object> queryConfig,
|
||||
final Object[] sortPropertyIds, final boolean[] sortStates) {
|
||||
super(definition, queryConfig, sortPropertyIds, sortStates);
|
||||
|
||||
if (isNotNullOrEmpty(queryConfig)) {
|
||||
currentSelectedActionStatusId = (Long) queryConfig.get(SPUIDefinitions.MESSAGES_BY_ACTIONSTATUS);
|
||||
noMessageText = (String) queryConfig.get(SPUIDefinitions.NO_MSG_PROXY);
|
||||
}
|
||||
|
||||
if (sortStates.length > 0) {
|
||||
// Initialize sort
|
||||
sort = new Sort(sortStates[0] ? Direction.ASC : Direction.DESC, (String) sortPropertyIds[0]);
|
||||
// Add sort
|
||||
for (int distId = 1; distId < sortPropertyIds.length; distId++) {
|
||||
sort.and(new Sort(sortStates[distId] ? Direction.ASC : Direction.DESC,
|
||||
(String) sortPropertyIds[distId]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProxyMessage constructBean() {
|
||||
return new ProxyMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ProxyMessage> loadBeans(final int startIndex, final int count) {
|
||||
Page<String> actionBeans;
|
||||
if (startIndex == 0 && firstPageMessages != null) {
|
||||
actionBeans = firstPageMessages;
|
||||
} else {
|
||||
actionBeans = getDeploymentManagement().findMessagesByActionStatusId(
|
||||
new PageRequest(startIndex / SPUIDefinitions.PAGE_SIZE, SPUIDefinitions.PAGE_SIZE, sort),
|
||||
currentSelectedActionStatusId);
|
||||
}
|
||||
return createProxyMessages(actionBeans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of {@link ProxyActionStatus} for presentation layer from
|
||||
* page of {@link ActionStatus}.
|
||||
*
|
||||
* @param actionBeans
|
||||
* page of {@link ActionStatus}
|
||||
* @return list of {@link ProxyActionStatus}
|
||||
*/
|
||||
private List<ProxyMessage> createProxyMessages(final Page<String> messages) {
|
||||
final List<ProxyMessage> proxyMsgs = new ArrayList<>(messages.getNumberOfElements());
|
||||
|
||||
Long idx = messages.getNumber() * ((long) messages.getSize());
|
||||
for (final String msg : messages) {
|
||||
idx++;
|
||||
final ProxyMessage proxyMsg = new ProxyMessage();
|
||||
proxyMsg.setMessage(msg);
|
||||
proxyMsg.setId(String.valueOf(idx));
|
||||
proxyMsgs.add(proxyMsg);
|
||||
}
|
||||
|
||||
if (messages.getTotalElements() == 1L && Strings.isNullOrEmpty(proxyMsgs.get(0).getMessage())) {
|
||||
proxyMsgs.get(0).setMessage(noMessageText);
|
||||
}
|
||||
|
||||
return proxyMsgs;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.vaadin.addons.lazyquerycontainer.AbstractBeanQuery#saveBeans(java
|
||||
* .util.List, java.util.List, java.util.List)
|
||||
*/
|
||||
@Override
|
||||
protected void saveBeans(List<ProxyMessage> addedBeans, List<ProxyMessage> modifiedBeans,
|
||||
List<ProxyMessage> removedBeans) {
|
||||
// CRUD operations on Target will be done through repository methods
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
long size = 0;
|
||||
|
||||
if (currentSelectedActionStatusId != null) {
|
||||
firstPageMessages = getDeploymentManagement().findMessagesByActionStatusId(
|
||||
new PageRequest(0, SPUIDefinitions.PAGE_SIZE, sort), currentSelectedActionStatusId);
|
||||
size = firstPageMessages.getTotalElements();
|
||||
}
|
||||
if (size > Integer.MAX_VALUE) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy gets deploymentManagement.
|
||||
*
|
||||
* @return the deploymentManagement
|
||||
*/
|
||||
public DeploymentManagement getDeploymentManagement() {
|
||||
if (null == deploymentManagement) {
|
||||
deploymentManagement = SpringContextHelper.getBean(DeploymentManagement.class);
|
||||
}
|
||||
return deploymentManagement;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* 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.management.actionhistory;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGrid;
|
||||
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.vaadin.addons.lazyquerycontainer.BeanQueryFactory;
|
||||
import org.vaadin.addons.lazyquerycontainer.LazyQueryContainer;
|
||||
import org.vaadin.addons.lazyquerycontainer.LazyQueryDefinition;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.vaadin.data.Item;
|
||||
import com.vaadin.event.ItemClickEvent;
|
||||
import com.vaadin.event.ItemClickEvent.ItemClickListener;
|
||||
import com.vaadin.ui.Component;
|
||||
import com.vaadin.ui.TextArea;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
/**
|
||||
* This grid presents the messages for a selected action-status.
|
||||
*/
|
||||
public class ActionStatusMsgGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String[] rightAlignedColumns = new String[] { ProxyMessage.PXY_MSG_ID };
|
||||
|
||||
private final String noMsgText;
|
||||
|
||||
private final AlignCellStyleGenerator alignGenerator;
|
||||
|
||||
private final BeanQueryFactory<ActionStatusMsgBeanQuery> targetQF = new BeanQueryFactory<>(
|
||||
ActionStatusMsgBeanQuery.class);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param i18n
|
||||
* @param eventBus
|
||||
*/
|
||||
protected ActionStatusMsgGrid(final VaadinMessageSource i18n, final UIEventBus eventBus) {
|
||||
super(i18n, eventBus, null);
|
||||
noMsgText = createNoMessageProxy(i18n);
|
||||
|
||||
setSingleSelectionSupport(new SingleSelectionSupport());
|
||||
setDetailsSupport(new DetailsSupport());
|
||||
|
||||
alignGenerator = new AlignCellStyleGenerator(null, null, rightAlignedColumns);
|
||||
addStyleName(SPUIStyleDefinitions.ACTION_HISTORY_MESSAGE_GRID);
|
||||
|
||||
setDetailsGenerator(new MessageDetailsGenerator());
|
||||
|
||||
this.addItemClickListener(new ItemClickListener() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void itemClick(final ItemClickEvent event) {
|
||||
final Object itemId = event.getItemId();
|
||||
setDetailsVisible(itemId, !isDetailsVisible(itemId));
|
||||
}
|
||||
});
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LazyQueryContainer createContainer() {
|
||||
configureQueryFactory();
|
||||
return new LazyQueryContainer(new LazyQueryDefinition(true, SPUIDefinitions.PAGE_SIZE, null), targetQF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshContainer() {
|
||||
for (final Object itemId : getContainerDataSource().getItemIds()) {
|
||||
setDetailsVisible(itemId, false);
|
||||
}
|
||||
configureQueryFactory();
|
||||
super.refreshContainer();
|
||||
}
|
||||
|
||||
protected void configureQueryFactory() {
|
||||
// ADD all the filters to the query config
|
||||
final Map<String, Object> queryConfig = Maps.newHashMapWithExpectedSize(2);
|
||||
queryConfig.put(SPUIDefinitions.MESSAGES_BY_ACTIONSTATUS, getDetailsSupport().getMasterDataId());
|
||||
queryConfig.put(SPUIDefinitions.NO_MSG_PROXY, noMsgText);
|
||||
// Create ActionBeanQuery factory with the query config.
|
||||
targetQF.setQueryConfiguration(queryConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets type-save access to LazyQueryContainer.
|
||||
*
|
||||
* @return LazyQueryContainer
|
||||
*/
|
||||
private LazyQueryContainer getLazyQueryContainer() {
|
||||
return (LazyQueryContainer) getContainerDataSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addContainerProperties() {
|
||||
getLazyQueryContainer().addContainerProperty(ProxyMessage.PXY_MSG_ID, String.class, null, true, false);
|
||||
getLazyQueryContainer().addContainerProperty(ProxyMessage.PXY_MSG_VALUE, String.class, null, true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setColumnExpandRatio() {
|
||||
getColumn(ProxyMessage.PXY_MSG_ID).setExpandRatio(0);
|
||||
getColumn(ProxyMessage.PXY_MSG_VALUE).setExpandRatio(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setColumnHeaderNames() {
|
||||
getColumn(ProxyMessage.PXY_MSG_ID).setHeaderCaption("##");
|
||||
getColumn(ProxyMessage.PXY_MSG_VALUE).setHeaderCaption(SPUIDefinitions.ACTION_HIS_TBL_MSGS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getGridId() {
|
||||
return UIComponentIdProvider.ACTION_HISTORY_MESSAGE_GRID_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setColumnProperties() {
|
||||
clearSortOrder();
|
||||
setColumns(ProxyMessage.PXY_MSG_ID, ProxyMessage.PXY_MSG_VALUE);
|
||||
setFrozenColumnCount(2);
|
||||
alignColumns();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addColumnRenderes() {
|
||||
// no specific column renderers
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setHiddenColumns() {
|
||||
getColumn(ProxyMessage.PXY_MSG_ID).setHidable(false);
|
||||
getColumn(ProxyMessage.PXY_MSG_VALUE).setHidable(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CellDescriptionGenerator getDescriptionGenerator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alignment cell-style-generator that handles the alignment for
|
||||
* the grid cells.
|
||||
*/
|
||||
private void alignColumns() {
|
||||
setCellStyleGenerator(alignGenerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the default text when no message is available for action-status
|
||||
*
|
||||
* @param i18n
|
||||
* @return default text
|
||||
*/
|
||||
private static String createNoMessageProxy(final VaadinMessageSource i18n) {
|
||||
return i18n.getMessage("message.no.available");
|
||||
}
|
||||
|
||||
protected class MessageDetailsGenerator implements DetailsGenerator {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Component getDetails(final RowReference rowReference) {
|
||||
// Find the bean to generate details for
|
||||
final Item item = rowReference.getItem();
|
||||
final String message = (String) item.getItemProperty(ProxyMessage.PXY_MSG_VALUE).getValue();
|
||||
|
||||
final TextArea textArea = new TextArea();
|
||||
textArea.addStyleName(ValoTheme.TEXTAREA_BORDERLESS);
|
||||
textArea.addStyleName(ValoTheme.TEXTAREA_TINY);
|
||||
textArea.addStyleName("inline-icon");
|
||||
textArea.setHeight(120, Unit.PIXELS);
|
||||
textArea.setWidth(100, Unit.PERCENTAGE);
|
||||
textArea.setValue(message);
|
||||
textArea.setReadOnly(Boolean.TRUE);
|
||||
return textArea;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CellStyleGenerator that concerns about cutting text.
|
||||
*/
|
||||
protected static class TextCutCellStyleGenerator implements CellStyleGenerator {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public String getStyle(final CellReference cellReference) {
|
||||
if (ProxyMessage.PXY_MSG_VALUE.equals(cellReference.getPropertyId())) {
|
||||
return "text-cut";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 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.management.actionhistory;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGridComponentLayout;
|
||||
import org.eclipse.hawkbit.ui.common.grid.DefaultGridHeader;
|
||||
import org.eclipse.hawkbit.ui.management.state.ManagementUIState;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
/**
|
||||
* Layout responsible for messages-grid and the corresponding header.
|
||||
*/
|
||||
public class ActionStatusMsgLayout extends AbstractGridComponentLayout {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected final ManagementUIState managementUIState;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param i18n
|
||||
* @param eventBus
|
||||
* @param managementUIState
|
||||
*/
|
||||
public ActionStatusMsgLayout(final VaadinMessageSource i18n, final UIEventBus eventBus,
|
||||
final ManagementUIState managementUIState) {
|
||||
super(i18n, eventBus);
|
||||
this.managementUIState = managementUIState;
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultGridHeader createGridHeader() {
|
||||
return new DefaultGridHeader(managementUIState, "Messages").init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionStatusMsgGrid createGrid() {
|
||||
return new ActionStatusMsgGrid(i18n, eventBus);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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.management.actionhistory;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.ui.customrenderers.renderers.AbstractHtmlLabelConverter;
|
||||
|
||||
/**
|
||||
* Concrete html-label converter that handles Action.Status.
|
||||
*/
|
||||
public class HtmlStatusLabelConverter extends AbstractHtmlLabelConverter<Action.Status> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructor that sets the appropriate adapter.
|
||||
*
|
||||
* @param adapter
|
||||
* adapts <code>Action.Status</code> to <code>String</code>
|
||||
*/
|
||||
public HtmlStatusLabelConverter(LabelAdapter<Action.Status> adapter) {
|
||||
this.addAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Action.Status> getModelType() {
|
||||
return Action.Status.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* 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.management.actionhistory;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
|
||||
/**
|
||||
* Proxy for {@link Action}
|
||||
*/
|
||||
public class ProxyAction implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String PXY_ACTION_STATUS = "status";
|
||||
public static final String PXY_ACTION_IS_ACTIVE = "isActive";
|
||||
public static final String PXY_ACTION_IS_ACTIVE_DECO = "isActiveDecoration";
|
||||
public static final String PXY_ACTION_ID = "id";
|
||||
public static final String PXY_ACTION_DS_NAME_VERSION = "dsNameVersion";
|
||||
public static final String PXY_ACTION = "action";
|
||||
public static final String PXY_ACTION_LAST_MODIFIED_AT = "lastModifiedAt";
|
||||
public static final String PXY_ACTION_ROLLOUT_NAME = "rolloutName";
|
||||
|
||||
private Action.Status status;
|
||||
private boolean isActive;
|
||||
private IsActiveDecoration isActiveDecoration;
|
||||
private Long id;
|
||||
private String dsNameVersion;
|
||||
private Action action;
|
||||
private Long lastModifiedAt;
|
||||
private String rolloutName;
|
||||
|
||||
/**
|
||||
* Get id for the entry.
|
||||
*
|
||||
* @return id for the entry.
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the id for the entry.
|
||||
*
|
||||
* @param id
|
||||
* of the action entry.
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status literal.
|
||||
*
|
||||
* @return status literal
|
||||
*/
|
||||
public Action.Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the status literal.
|
||||
*
|
||||
* @param status
|
||||
* literal
|
||||
*/
|
||||
public void setStatus(Action.Status status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag that indicates if the action is active.
|
||||
*
|
||||
* @return <code>true</code> if the action is active, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
public boolean isActive() {
|
||||
return isActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag that indicates if the action is active.
|
||||
*
|
||||
* @param isActive
|
||||
* <code>true</code> if the action is active, otherwise
|
||||
* <code>false</code>
|
||||
*/
|
||||
public void setActive(boolean isActive) {
|
||||
this.isActive = isActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a pre-calculated literal combining <code>ProxyAction#isActive</code>
|
||||
* and <code>ProxyAction#getStatus</code> states.
|
||||
*
|
||||
* @return pre-calculated literal
|
||||
*/
|
||||
public IsActiveDecoration getIsActiveDecoration() {
|
||||
return isActiveDecoration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pre-calculated literal combining
|
||||
* <code>ProxyAction#isActive</code> and <code>ProxyAction#getStatus</code>
|
||||
* states.
|
||||
*
|
||||
* @param isActiveDecoration
|
||||
* pre-calculated literal
|
||||
*/
|
||||
public void setIsActiveDecoration(IsActiveDecoration isActiveDecoration) {
|
||||
this.isActiveDecoration = isActiveDecoration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-calculated value that is set up by distribution set name and version.
|
||||
*
|
||||
* @return pre-calculated value combining name and version
|
||||
*/
|
||||
public String getDsNameVersion() {
|
||||
return dsNameVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pre-calculated value combining distribution set name and
|
||||
* version.
|
||||
*
|
||||
* @param dsNameVersion
|
||||
* combined value
|
||||
*/
|
||||
public void setDsNameVersion(String dsNameVersion) {
|
||||
this.dsNameVersion = dsNameVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the action to be evaluated by generators of virtual properties.
|
||||
*
|
||||
* @return action
|
||||
*/
|
||||
public Action getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action to be evaluated by generators of virtual properties.
|
||||
*
|
||||
* @param action
|
||||
*/
|
||||
public void setAction(Action action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get raw long-value for lastModifiedAt-date.
|
||||
*
|
||||
* @return raw long-value for lastModifiedAt-date
|
||||
*/
|
||||
public Long getLastModifiedAt() {
|
||||
return lastModifiedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set raw long-value for lastModifiedAt-date.
|
||||
*
|
||||
* @param lastModifiedAt
|
||||
* raw long-value for lastModifiedAt-date
|
||||
*/
|
||||
public void setLastModifiedAt(Long lastModifiedAt) {
|
||||
this.lastModifiedAt = lastModifiedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rolloutName.
|
||||
*
|
||||
* @return rolloutName
|
||||
*/
|
||||
public String getRolloutName() {
|
||||
return rolloutName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the rolloutName.
|
||||
*
|
||||
* @param rolloutName
|
||||
*/
|
||||
public void setRolloutName(String rolloutName) {
|
||||
this.rolloutName = rolloutName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-calculated decoration value combining
|
||||
* <code>ProxyAction#isActive</code> and <code>ProxyAction#getStatus</code>
|
||||
* states.
|
||||
*/
|
||||
public enum IsActiveDecoration {
|
||||
/**
|
||||
* Active label decoration type for {@code ProxyAction#isActive()==true}
|
||||
*/
|
||||
ACTIVE,
|
||||
|
||||
/**
|
||||
* Active label decoration type for
|
||||
* {@code ProxyAction#isActive()==false}
|
||||
*/
|
||||
IN_ACTIVE,
|
||||
|
||||
/**
|
||||
* Active label decoration type for {@code ProxyAction#isActive()==true}
|
||||
* AND {@code ProxyAction#getStatus()==Action.Status.ERROR}
|
||||
*/
|
||||
IN_ACTIVE_ERROR,
|
||||
|
||||
/**
|
||||
* {@code ProxyAction#getStatus()==Action.Status.SCHEDULED}
|
||||
*/
|
||||
SCHEDULED,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 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.management.actionhistory;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
|
||||
/**
|
||||
* Proxy for {@link ActionStatus}
|
||||
*/
|
||||
public class ProxyActionStatus implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String PXY_AS_STATUS = "status";
|
||||
public static final String PXY_AS_CREATED_AT = "createdAt";
|
||||
public static final String PXY_AS_ID = "id";
|
||||
|
||||
private Long id;
|
||||
private Action.Status status;
|
||||
private Long createdAt;
|
||||
|
||||
/**
|
||||
* Get id for the entry.
|
||||
*
|
||||
* @return id for the entry.
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the id for the entry.
|
||||
*
|
||||
* @param id
|
||||
* of the status entry.
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status literal.
|
||||
*
|
||||
* @return status literal
|
||||
*/
|
||||
public Action.Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the status literal.
|
||||
*
|
||||
* @param status
|
||||
* literal
|
||||
*/
|
||||
public void setStatus(Action.Status status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get raw long-value for createdAt-date.
|
||||
*
|
||||
* @return raw long-value for createdAt-date
|
||||
*/
|
||||
public Long getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set raw long-value for createdAt-date.
|
||||
*
|
||||
* @param createdAt
|
||||
* raw long-value for createdAt-date
|
||||
*/
|
||||
public void setCreatedAt(Long createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 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.management.actionhistory;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
|
||||
/**
|
||||
* Proxy for an entry of {@link ActionStatus#getMessages()}
|
||||
*/
|
||||
public class ProxyMessage implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String PXY_MSG_ID = "id";
|
||||
public static final String PXY_MSG_VALUE = "message";
|
||||
|
||||
private String id;
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* Get id for the entry.
|
||||
*
|
||||
* @return id for the entry.
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the id for the entry.
|
||||
*
|
||||
* @param id
|
||||
* of the message entry.
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get message value.
|
||||
*
|
||||
* @return message value
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set message value.
|
||||
*
|
||||
* @param message
|
||||
* value
|
||||
*/
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
@@ -25,15 +25,14 @@ import org.eclipse.hawkbit.ui.UiProperties;
|
||||
import org.eclipse.hawkbit.ui.common.UserDetailsFormatter;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.menu.DashboardEvent.PostViewChangeEvent;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.vaadin.server.FontAwesome;
|
||||
import com.vaadin.server.Page;
|
||||
import com.vaadin.server.Resource;
|
||||
import com.vaadin.server.ThemeResource;
|
||||
import com.vaadin.shared.ui.label.ContentMode;
|
||||
import com.vaadin.spring.annotation.SpringComponent;
|
||||
import com.vaadin.spring.annotation.UIScope;
|
||||
import com.vaadin.ui.Alignment;
|
||||
@@ -43,7 +42,6 @@ import com.vaadin.ui.Button.ClickListener;
|
||||
import com.vaadin.ui.Component;
|
||||
import com.vaadin.ui.CssLayout;
|
||||
import com.vaadin.ui.CustomComponent;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.Link;
|
||||
import com.vaadin.ui.MenuBar;
|
||||
@@ -82,8 +80,9 @@ public final class DashboardMenu extends CustomComponent {
|
||||
private boolean accessibleViewsEmpty;
|
||||
|
||||
@Autowired
|
||||
DashboardMenu(final VaadinMessageSource i18n, final UiProperties uiProperties, final HawkbitServerProperties serverProperties,
|
||||
final PermissionService permissionService, final List<DashboardMenuItem> dashboardVaadinViews) {
|
||||
DashboardMenu(final VaadinMessageSource i18n, final UiProperties uiProperties,
|
||||
final HawkbitServerProperties serverProperties, final PermissionService permissionService,
|
||||
final List<DashboardMenuItem> dashboardVaadinViews) {
|
||||
this.i18n = i18n;
|
||||
this.uiProperties = uiProperties;
|
||||
this.serverProperties = serverProperties;
|
||||
@@ -109,7 +108,6 @@ public final class DashboardMenu extends CustomComponent {
|
||||
final VerticalLayout dashboardMenuLayout = new VerticalLayout();
|
||||
dashboardMenuLayout.setSizeFull();
|
||||
final VerticalLayout menuContent = getMenuLayout();
|
||||
menuContent.addComponent(buildTitle());
|
||||
menuContent.addComponent(buildUserMenu());
|
||||
menuContent.addComponent(buildToggleButton());
|
||||
|
||||
@@ -137,15 +135,6 @@ public final class DashboardMenu extends CustomComponent {
|
||||
return menuContent;
|
||||
}
|
||||
|
||||
private Component buildTitle() {
|
||||
final Label logo = new Label("<strong>" + i18n.getMessage("menu.title") + "</strong>", ContentMode.HTML);
|
||||
logo.setSizeUndefined();
|
||||
final HorizontalLayout logoWrapper = new HorizontalLayout(logo);
|
||||
logoWrapper.setComponentAlignment(logo, Alignment.TOP_CENTER);
|
||||
logoWrapper.addStyleName("valo-menu-title");
|
||||
return logoWrapper;
|
||||
}
|
||||
|
||||
private VerticalLayout buildLinksAndVersion() {
|
||||
final VerticalLayout links = new VerticalLayout();
|
||||
links.setSpacing(true);
|
||||
@@ -174,8 +163,8 @@ public final class DashboardMenu extends CustomComponent {
|
||||
|
||||
if (!uiProperties.getLinks().getSupport().isEmpty()) {
|
||||
final Link supportLink = SPUIComponentProvider.getLink(UIComponentIdProvider.LINK_SUPPORT,
|
||||
i18n.getMessage("link.support.name"), uiProperties.getLinks().getSupport(), FontAwesome.ENVELOPE_O, "",
|
||||
linkStyle);
|
||||
i18n.getMessage("link.support.name"), uiProperties.getLinks().getSupport(), FontAwesome.ENVELOPE_O,
|
||||
"", linkStyle);
|
||||
supportLink.setDescription(i18n.getMessage("link.support.name"));
|
||||
supportLink.setSizeFull();
|
||||
links.addComponent(supportLink);
|
||||
|
||||
@@ -8,35 +8,140 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.rollout;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.google.gwt.i18n.client.AutoDirectionHandler.Target;
|
||||
import com.vaadin.server.FontAwesome;
|
||||
|
||||
/**
|
||||
*
|
||||
* Helper class which holds the details of font icon to be displayed for
|
||||
* {@link Rollout}/ {@link RolloutGroup} / Rollout {@link Target}
|
||||
*
|
||||
*
|
||||
* Helper class which holds the details of font icon to be displayed as
|
||||
* label/button in grid:
|
||||
* <p>
|
||||
* <code>RolloutListGrid</code> / <code>RolloutGroupListGrid</code> /
|
||||
* <code>RolloutGroupTargetsListGrid</code> / <code>ActionHistoryGrid</code>
|
||||
*/
|
||||
public class StatusFontIcon {
|
||||
final FontAwesome fontIcon;
|
||||
final String style;
|
||||
public class StatusFontIcon implements Serializable {
|
||||
/** serialVersionUID. */
|
||||
private static final long serialVersionUID = 1L;
|
||||
private FontAwesome fontIcon;
|
||||
private String style;
|
||||
private String title;
|
||||
private String id;
|
||||
private boolean disabled;
|
||||
|
||||
public StatusFontIcon(final FontAwesome fontIcon, final String style) {
|
||||
super();
|
||||
this.fontIcon = fontIcon;
|
||||
this.style = style;
|
||||
/**
|
||||
* NOTE: This constructor is used for (de-)serialization only!!!
|
||||
*/
|
||||
public StatusFontIcon() {
|
||||
// empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to create icon metadata object.
|
||||
*
|
||||
* @param fontIcon
|
||||
* the font representing the icon
|
||||
* @param style
|
||||
* the style
|
||||
*/
|
||||
public StatusFontIcon(final FontAwesome fontIcon, final String style) {
|
||||
this(fontIcon, style, "", "", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to create icon metadata object.
|
||||
*
|
||||
* @param fontIcon
|
||||
* the font representing the icon
|
||||
* @param style
|
||||
* the style
|
||||
* @param title
|
||||
* the title shown as tooltip
|
||||
*/
|
||||
public StatusFontIcon(final FontAwesome fontIcon, final String style, final String title) {
|
||||
this(fontIcon, style, title, "", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to create icon metadata object.
|
||||
*
|
||||
* @param fontIcon
|
||||
* the font representing the icon
|
||||
* @param style
|
||||
* the style
|
||||
* @param title
|
||||
* the title shown as tooltip
|
||||
* @param id
|
||||
* the id for direct access
|
||||
*/
|
||||
public StatusFontIcon(final FontAwesome fontIcon, final String style, final String title, final String id) {
|
||||
this(fontIcon, style, title, id, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to create icon metadata object.
|
||||
*
|
||||
* @param fontIcon
|
||||
* the font representing the icon
|
||||
* @param style
|
||||
* the style
|
||||
* @param title
|
||||
* the title shown as tooltip
|
||||
* @param id
|
||||
* the id for direct access
|
||||
* @param disabled
|
||||
* disabled-state of the icon
|
||||
*/
|
||||
public StatusFontIcon(final FontAwesome fontIcon, final String style, final String title, final String id,
|
||||
final boolean disabled) {
|
||||
this.fontIcon = fontIcon;
|
||||
this.style = style;
|
||||
this.title = title;
|
||||
this.id = id;
|
||||
this.disabled = disabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the font representing the icon.
|
||||
*
|
||||
* @return the font representing the icon
|
||||
*/
|
||||
public FontAwesome getFontIcon() {
|
||||
return fontIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the style.
|
||||
*
|
||||
* @return the style
|
||||
*/
|
||||
public String getStyle() {
|
||||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the title shown as tooltip.
|
||||
*
|
||||
* @return the title shown as tooltip.
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id for direct access.
|
||||
*
|
||||
* @return the id for direct access.
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the disabled-state of the icon.
|
||||
*
|
||||
* @return the disabled-state of the icon.
|
||||
*/
|
||||
public boolean isDisabled() {
|
||||
return disabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ import com.vaadin.ui.renderers.HtmlRenderer;
|
||||
/**
|
||||
* Rollout list grid component.
|
||||
*/
|
||||
public class RolloutListGrid extends AbstractGrid {
|
||||
public class RolloutListGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -132,6 +132,8 @@ public class RolloutListGrid extends AbstractGrid {
|
||||
uiNotification, uiProperties, entityFactory, i18n, eventBus, targetFilterQueryManagement);
|
||||
this.uiNotification = uiNotification;
|
||||
this.rolloutUIState = rolloutUIState;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -211,7 +213,7 @@ public class RolloutListGrid extends AbstractGrid {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Container createContainer() {
|
||||
protected LazyQueryContainer createContainer() {
|
||||
final BeanQueryFactory<RolloutBeanQuery> rolloutQf = new BeanQueryFactory<>(RolloutBeanQuery.class);
|
||||
return new LazyQueryContainer(
|
||||
new LazyQueryDefinition(true, SPUIDefinitions.PAGE_SIZE, SPUILabelDefinitions.VAR_ID), rolloutQf);
|
||||
|
||||
@@ -14,43 +14,61 @@ import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.UiProperties;
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGridLayout;
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGrid;
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGridComponentLayout;
|
||||
import org.eclipse.hawkbit.ui.rollout.state.RolloutUIState;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
import org.vaadin.addons.lazyquerycontainer.LazyQueryContainer;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.AbstractOrderedLayout;
|
||||
|
||||
/**
|
||||
* Rollout list view.
|
||||
*/
|
||||
public class RolloutListView extends AbstractGridLayout {
|
||||
|
||||
public class RolloutListView extends AbstractGridComponentLayout {
|
||||
private static final long serialVersionUID = -2703552177439393208L;
|
||||
|
||||
private final transient RolloutManagement rolloutManagement;
|
||||
private final transient TargetManagement targetManagement;
|
||||
private final transient EntityFactory entityFactory;
|
||||
private final transient TargetFilterQueryManagement targetFilterQueryManagement;
|
||||
|
||||
private final SpPermissionChecker permissionChecker;
|
||||
private final RolloutUIState rolloutUIState;
|
||||
private final UINotification uiNotification;
|
||||
private final UiProperties uiProperties;
|
||||
|
||||
|
||||
public RolloutListView(final SpPermissionChecker permissionChecker, final RolloutUIState rolloutUIState,
|
||||
final UIEventBus eventBus, final RolloutManagement rolloutManagement,
|
||||
final TargetManagement targetManagement, final UINotification uiNotification,
|
||||
final UiProperties uiProperties, final EntityFactory entityFactory, final VaadinMessageSource i18n,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement) {
|
||||
super(new RolloutListHeader(permissionChecker, rolloutUIState, eventBus, rolloutManagement, targetManagement,
|
||||
uiNotification, uiProperties, entityFactory, i18n, targetFilterQueryManagement),
|
||||
new RolloutListGrid(i18n, eventBus, rolloutManagement, uiNotification, rolloutUIState,
|
||||
permissionChecker, targetManagement, entityFactory, uiProperties, targetFilterQueryManagement));
|
||||
super(i18n, eventBus);
|
||||
this.permissionChecker = permissionChecker;
|
||||
this.rolloutUIState = rolloutUIState;
|
||||
this.rolloutManagement = rolloutManagement;
|
||||
this.targetManagement = targetManagement;
|
||||
this.uiNotification = uiNotification;
|
||||
this.uiProperties = uiProperties;
|
||||
this.entityFactory = entityFactory;
|
||||
this.targetFilterQueryManagement = targetFilterQueryManagement;
|
||||
|
||||
buildLayout();
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasCountMessage() {
|
||||
return false;
|
||||
public AbstractOrderedLayout createGridHeader() {
|
||||
return new RolloutListHeader(permissionChecker, rolloutUIState, eventBus, rolloutManagement, targetManagement,
|
||||
uiNotification, uiProperties, entityFactory, i18n, targetFilterQueryManagement);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Label getCountMessageLabel() {
|
||||
|
||||
return null;
|
||||
public AbstractGrid<LazyQueryContainer> createGrid() {
|
||||
return new RolloutListGrid(i18n, eventBus, rolloutManagement, uiNotification, rolloutUIState, permissionChecker,
|
||||
targetManagement, entityFactory, uiProperties, targetFilterQueryManagement);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ import com.vaadin.ui.renderers.HtmlRenderer;
|
||||
/**
|
||||
* Rollout group list grid component.
|
||||
*/
|
||||
public class RolloutGroupListGrid extends AbstractGrid {
|
||||
public class RolloutGroupListGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
private static final long serialVersionUID = 4060904914954370524L;
|
||||
|
||||
private static final String ROLLOUT_RENDERER_DATA = "rolloutRendererData";
|
||||
@@ -98,6 +98,8 @@ public class RolloutGroupListGrid extends AbstractGrid {
|
||||
super(i18n, eventBus, permissionChecker);
|
||||
this.rolloutGroupManagement = rolloutGroupManagement;
|
||||
this.rolloutUIState = rolloutUIState;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
@@ -131,7 +133,7 @@ public class RolloutGroupListGrid extends AbstractGrid {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Container createContainer() {
|
||||
protected LazyQueryContainer createContainer() {
|
||||
final BeanQueryFactory<RolloutGroupBeanQuery> rolloutQf = new BeanQueryFactory<>(RolloutGroupBeanQuery.class);
|
||||
return new LazyQueryContainer(
|
||||
new LazyQueryDefinition(true, SPUIDefinitions.PAGE_SIZE, SPUILabelDefinitions.VAR_ID), rolloutQf);
|
||||
|
||||
@@ -10,9 +10,11 @@ package org.eclipse.hawkbit.ui.rollout.rolloutgroup;
|
||||
|
||||
import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.ui.SpPermissionChecker;
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGridLayout;
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGrid;
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGridComponentLayout;
|
||||
import org.eclipse.hawkbit.ui.rollout.state.RolloutUIState;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.addons.lazyquerycontainer.LazyQueryContainer;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.ui.Label;
|
||||
@@ -20,10 +22,14 @@ import com.vaadin.ui.Label;
|
||||
/**
|
||||
* Groups List View.
|
||||
*/
|
||||
public class RolloutGroupsListView extends AbstractGridLayout {
|
||||
public class RolloutGroupsListView extends AbstractGridComponentLayout {
|
||||
|
||||
private static final long serialVersionUID = 7252345838154270259L;
|
||||
|
||||
private final SpPermissionChecker permissionChecker;
|
||||
private final RolloutUIState rolloutUIState;
|
||||
private final transient RolloutGroupManagement rolloutGroupManagement;
|
||||
|
||||
/**
|
||||
* Constructor for RolloutGroupsListView
|
||||
*
|
||||
@@ -41,20 +47,21 @@ public class RolloutGroupsListView extends AbstractGridLayout {
|
||||
public RolloutGroupsListView(final VaadinMessageSource i18n, final UIEventBus eventBus,
|
||||
final RolloutGroupManagement rolloutGroupManagement, final RolloutUIState rolloutUIState,
|
||||
final SpPermissionChecker permissionChecker) {
|
||||
super(new RolloutGroupsListHeader(eventBus, rolloutUIState, i18n),
|
||||
new RolloutGroupListGrid(i18n, eventBus, rolloutGroupManagement, rolloutUIState, permissionChecker));
|
||||
|
||||
buildLayout();
|
||||
super(i18n, eventBus);
|
||||
this.permissionChecker = permissionChecker;
|
||||
this.rolloutUIState = rolloutUIState;
|
||||
this.rolloutGroupManagement = rolloutGroupManagement;
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasCountMessage() {
|
||||
return false;
|
||||
public RolloutGroupsListHeader createGridHeader() {
|
||||
return new RolloutGroupsListHeader(eventBus, rolloutUIState, i18n);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Label getCountMessageLabel() {
|
||||
return null;
|
||||
public AbstractGrid<LazyQueryContainer> createGrid() {
|
||||
return new RolloutGroupListGrid(i18n, eventBus, rolloutGroupManagement, rolloutUIState, permissionChecker);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ import com.vaadin.server.FontAwesome;
|
||||
/**
|
||||
* Grid component with targets of rollout group.
|
||||
*/
|
||||
public class RolloutGroupTargetsListGrid extends AbstractGrid {
|
||||
public class RolloutGroupTargetsListGrid extends AbstractGrid<LazyQueryContainer> {
|
||||
|
||||
private static final long serialVersionUID = -2244756637458984597L;
|
||||
|
||||
@@ -85,6 +85,8 @@ public class RolloutGroupTargetsListGrid extends AbstractGrid {
|
||||
final RolloutUIState rolloutUIState) {
|
||||
super(i18n, eventBus, null);
|
||||
this.rolloutUIState = rolloutUIState;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
@EventBusListenerMethod(scope = EventScope.UI)
|
||||
@@ -97,7 +99,7 @@ public class RolloutGroupTargetsListGrid extends AbstractGrid {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Container createContainer() {
|
||||
protected LazyQueryContainer createContainer() {
|
||||
final BeanQueryFactory<RolloutGroupTargetsBeanQuery> rolloutgrouBeanQueryFactory = new BeanQueryFactory<>(
|
||||
RolloutGroupTargetsBeanQuery.class);
|
||||
return new LazyQueryContainer(
|
||||
@@ -205,7 +207,7 @@ public class RolloutGroupTargetsListGrid extends AbstractGrid {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Converts {@link Status} into string with status icon details.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -8,43 +8,50 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.rollout.rolloutgrouptargets;
|
||||
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGridLayout;
|
||||
import org.eclipse.hawkbit.ui.common.grid.AbstractGridComponentLayout;
|
||||
import org.eclipse.hawkbit.ui.rollout.state.RolloutUIState;
|
||||
import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.VaadinMessageSource;
|
||||
import org.vaadin.spring.events.EventBus.UIEventBus;
|
||||
|
||||
import com.vaadin.ui.AbstractOrderedLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
|
||||
/**
|
||||
* Rollout Group Targets List View.
|
||||
*/
|
||||
public class RolloutGroupTargetsListView extends AbstractGridLayout {
|
||||
|
||||
public class RolloutGroupTargetsListView extends AbstractGridComponentLayout {
|
||||
private static final long serialVersionUID = 26089134783467012L;
|
||||
|
||||
private final RolloutGroupTargetsCountLabelMessage rolloutGroupTargetsCountLabelMessage;
|
||||
private final RolloutUIState rolloutUIState;
|
||||
|
||||
public RolloutGroupTargetsListView(final UIEventBus eventBus, final VaadinMessageSource i18n,
|
||||
final RolloutUIState rolloutUIState) {
|
||||
super(new RolloutGroupTargetsListHeader(eventBus, i18n, rolloutUIState),
|
||||
new RolloutGroupTargetsListGrid(i18n, eventBus, rolloutUIState));
|
||||
|
||||
this.rolloutGroupTargetsCountLabelMessage = new RolloutGroupTargetsCountLabelMessage(rolloutUIState,
|
||||
(RolloutGroupTargetsListGrid) grid, i18n, eventBus);
|
||||
|
||||
buildLayout();
|
||||
super(i18n, eventBus);
|
||||
this.rolloutUIState = rolloutUIState;
|
||||
this.setFooterSupport(new RolloutTargetsCountFooterSupport());
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasCountMessage() {
|
||||
|
||||
return true;
|
||||
public AbstractOrderedLayout createGridHeader() {
|
||||
return new RolloutGroupTargetsListHeader(eventBus, i18n, rolloutUIState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Label getCountMessageLabel() {
|
||||
|
||||
return rolloutGroupTargetsCountLabelMessage;
|
||||
public RolloutGroupTargetsListGrid createGrid() {
|
||||
return new RolloutGroupTargetsListGrid(i18n, eventBus, rolloutUIState);
|
||||
}
|
||||
|
||||
class RolloutTargetsCountFooterSupport extends AbstractFooterSupport {
|
||||
private static final long serialVersionUID = 3300400541786329735L;
|
||||
|
||||
@Override
|
||||
protected Label getFooterMessageLabel() {
|
||||
final RolloutGroupTargetsCountLabelMessage countMessageLabel = new RolloutGroupTargetsCountLabelMessage(
|
||||
rolloutUIState, (RolloutGroupTargetsListGrid) getGrid(), i18n, eventBus);
|
||||
countMessageLabel.setId(UIComponentIdProvider.ROLLOUT_GROUP_TARGET_LABEL);
|
||||
return countMessageLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,18 @@ public final class SPDateTimeUtil {
|
||||
return formatDate(lastQueryDate, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get formatted date with browser time zone.
|
||||
*
|
||||
* @param lastQueryDate
|
||||
* @param datePattern
|
||||
* pattern how to format the date (cp. {@code SimpleDateFormat})
|
||||
* @return String formatted date
|
||||
*/
|
||||
public static String getFormattedDate(final Long lastQueryDate, final String datePattern) {
|
||||
return formatDate(lastQueryDate, null, datePattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get formatted date 'created at' by entity.
|
||||
*
|
||||
@@ -109,20 +121,40 @@ public final class SPDateTimeUtil {
|
||||
return formatDate(baseEntity.getLastModifiedAt(), StringUtils.EMPTY);
|
||||
}
|
||||
|
||||
private static String formatDate(final Long lastQueryDate, final String defaultString) {
|
||||
/**
|
||||
* Get formatted date 'last modified at' by entity.
|
||||
*
|
||||
* @param baseEntity
|
||||
* the entity
|
||||
* @param datePattern
|
||||
* pattern how to format the date (cp. {@code SimpleDateFormat})
|
||||
* @return String formatted date
|
||||
*/
|
||||
public static String formatLastModifiedAt(final BaseEntity baseEntity, final String datePattern) {
|
||||
if (baseEntity == null) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
return formatDate(baseEntity.getLastModifiedAt(), StringUtils.EMPTY, datePattern);
|
||||
}
|
||||
|
||||
private static String formatDate(final Long lastQueryDate, final String defaultString, final String datePattern) {
|
||||
if (lastQueryDate != null) {
|
||||
final SimpleDateFormat format = new SimpleDateFormat(SPUIDefinitions.LAST_QUERY_DATE_FORMAT);
|
||||
final SimpleDateFormat format = new SimpleDateFormat(datePattern);
|
||||
format.setTimeZone(getBrowserTimeZone());
|
||||
return format.format(new Date(lastQueryDate));
|
||||
}
|
||||
return defaultString;
|
||||
}
|
||||
|
||||
private static String formatDate(final Long lastQueryDate, final String defaultString) {
|
||||
return formatDate(lastQueryDate, defaultString, SPUIDefinitions.LAST_QUERY_DATE_FORMAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a formatted string of a duration in format '1 year 2 months 3
|
||||
* days 4 hours 5 minutes 6 seconds' zero values will be ignored in the
|
||||
* formatted string.
|
||||
*
|
||||
*
|
||||
* @param startMillis
|
||||
* the start milliseconds of the duration
|
||||
* @param endMillis
|
||||
@@ -158,34 +190,34 @@ public final class SPDateTimeUtil {
|
||||
|
||||
/**
|
||||
* Enum to get the i18n key for single or plural calendar labels.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
private enum CalendarI18N {
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
YEAR("calendar.year", "calendar.years"),
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
MONTH("calendar.month", "calendar.months"),
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
DAY("calendar.days", "calendar.days"),
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
HOUR("calendar.hour", "calendar.hours"),
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
MINUTE("calendar.minute", "calendar.minutes"),
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
SECOND("calendar.second", "calendar.seconds");
|
||||
|
||||
@@ -193,7 +225,7 @@ public final class SPDateTimeUtil {
|
||||
private final String plural;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
CalendarI18N(final String single, final String plural) {
|
||||
this.single = single;
|
||||
|
||||
@@ -53,7 +53,7 @@ public final class SPUIDefinitions {
|
||||
|
||||
/**
|
||||
* Action history active hidden column. This is using to generate active
|
||||
* icons under active coloumn.
|
||||
* icons under active column.
|
||||
*/
|
||||
public static final String ACTION_HIS_TBL_ACTIVE_HIDDEN = "Active_Hidden";
|
||||
|
||||
@@ -108,6 +108,11 @@ public final class SPUIDefinitions {
|
||||
*/
|
||||
public static final String ACTION_HIS_TBL_FORCED = "Forced";
|
||||
|
||||
/**
|
||||
* Action history action type column.
|
||||
*/
|
||||
public static final String ACTION_HIS_TBL_TIMEFORCED = "Time-Forced";
|
||||
|
||||
/**
|
||||
* Action history helping constant.
|
||||
*/
|
||||
@@ -244,6 +249,22 @@ public final class SPUIDefinitions {
|
||||
* Text field style.
|
||||
*/
|
||||
public static final String TEXT_STYLE = "text-style";
|
||||
/**
|
||||
* Show actions for a target.
|
||||
*/
|
||||
public static final String ACTIONS_BY_TARGET = "ActionsByTarget";
|
||||
/**
|
||||
* Show action-states for a action.
|
||||
*/
|
||||
public static final String ACTIONSTATES_BY_ACTION = "ActionStatesByAction";
|
||||
/**
|
||||
* Show messages for a action-status.
|
||||
*/
|
||||
public static final String MESSAGES_BY_ACTIONSTATUS = "MessagesByActionStatus";
|
||||
/**
|
||||
* Key for no-message MessageProxy.
|
||||
*/
|
||||
public static final String NO_MSG_PROXY = "NoMessageProxy";
|
||||
|
||||
/**
|
||||
* Style to highlight row in orange color.
|
||||
@@ -353,6 +374,10 @@ public final class SPUIDefinitions {
|
||||
* Target last query date format .
|
||||
*/
|
||||
public static final String LAST_QUERY_DATE_FORMAT = "EEE MMM d HH:mm:ss z yyyy";
|
||||
/**
|
||||
* Target last query date format .
|
||||
*/
|
||||
public static final String LAST_QUERY_DATE_FORMAT_SHORT = "MMM d HH:mm z ''yy";
|
||||
/**
|
||||
* Item Id used in drop comparisons.
|
||||
*/
|
||||
|
||||
@@ -25,6 +25,11 @@ public final class SPUIStyleDefinitions {
|
||||
|
||||
public static final String SP_TEXTFIELD_LAYOUT_ERROR_HIGHTLIGHT = "v-textfield-error";
|
||||
|
||||
/**
|
||||
* Action history message grid style.
|
||||
*/
|
||||
public static final String ACTION_HISTORY_MESSAGE_GRID = "action-history-message-grid";
|
||||
|
||||
/**
|
||||
* Style for accordion tab button.
|
||||
*/
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
|
||||
package org.eclipse.hawkbit.ui.utils;
|
||||
|
||||
/**
|
||||
@@ -52,17 +53,14 @@ public final class UIComponentIdProvider {
|
||||
* ID-Targ.PIN.
|
||||
*/
|
||||
public static final String TARGET_PIN_ICON = "target.pin.icon.";
|
||||
|
||||
/**
|
||||
* Target search text id.
|
||||
*/
|
||||
public static final String TARGET_TEXT_FIELD = "target.search.textfield";
|
||||
|
||||
/**
|
||||
* ID for target filter search
|
||||
*/
|
||||
public static final String TARGET_FILTER_SEARCH_TEXT = "target.filter.search.text.Id";
|
||||
|
||||
/**
|
||||
* ID for add target filter icon
|
||||
*/
|
||||
@@ -121,7 +119,6 @@ public final class UIComponentIdProvider {
|
||||
* ID-Dist.PIN.
|
||||
*/
|
||||
public static final String DIST_PIN_BUTTON = "dist.pin.button";
|
||||
|
||||
/**
|
||||
* ID for distribution set tag icon
|
||||
*/
|
||||
@@ -134,27 +131,22 @@ public final class UIComponentIdProvider {
|
||||
* ID - soft.module.version.
|
||||
*/
|
||||
public static final String SOFT_MODULE_VERSION = "soft.module.version";
|
||||
|
||||
/**
|
||||
* ID - soft.module.vendor.
|
||||
*/
|
||||
public static final String SOFT_MODULE_VENDOR = "soft.module.vendor";
|
||||
|
||||
/**
|
||||
* ID - Save Assign.
|
||||
*/
|
||||
public static final String SAVE_ASSIGNMENT = "save.actions.popup.assign";
|
||||
|
||||
/**
|
||||
* ID - Discard Assign.
|
||||
*/
|
||||
public static final String DISCARD_ASSIGNMENT = "discard.actions.popup.assign";
|
||||
|
||||
/**
|
||||
* ID - Delete Distribution SetType Save.
|
||||
*/
|
||||
public static final String SAVE_DELETE_DIST_SET_TYPE = "save.actions.popup.delete.dist.set.type";
|
||||
|
||||
/**
|
||||
* ID - Discard Distribution SetType.
|
||||
*/
|
||||
@@ -163,17 +155,14 @@ public final class UIComponentIdProvider {
|
||||
* ID Delete Software Module Type save.
|
||||
*/
|
||||
public static final String SAVE_DELETE_SW_MODULE_TYPE = "save.actions.popup.delete.sw.module.type";
|
||||
|
||||
/**
|
||||
* ID - Discard SW Module Type.
|
||||
*/
|
||||
public static final String DISCARD_SW_MODULE_TYPE = "save.actions.popup.discard.sw.module.type";
|
||||
|
||||
/**
|
||||
* Action history table cancel Id.
|
||||
*/
|
||||
public static final String ACTION_DETAILS_SOFT_ID = "action.details.soft.group";
|
||||
|
||||
/**
|
||||
* Start type of rollout manual radio button
|
||||
*/
|
||||
@@ -231,24 +220,53 @@ public final class UIComponentIdProvider {
|
||||
*/
|
||||
public static final String PENDING_ACTION_BUTTON = "pending.action.button";
|
||||
/**
|
||||
* Action history table Id.
|
||||
* Action history grid Id.
|
||||
*/
|
||||
public static final String ACTION_HISTORY_TABLE_ID = "action.history.tableId";
|
||||
|
||||
public static final String ACTION_HISTORY_GRID_ID = "action.history.gridId";
|
||||
/**
|
||||
* Action history table cancel Id.
|
||||
* Action history details grid Id.
|
||||
*/
|
||||
public static final String ACTION_HISTORY_DETAILS_GRID_ID = "action.history.details.gridId";
|
||||
/**
|
||||
* Action history message grid Id.
|
||||
*/
|
||||
public static final String ACTION_HISTORY_MESSAGE_GRID_ID = "action.history.message.gridId";
|
||||
/**
|
||||
* Action history table cancel button Id.
|
||||
*/
|
||||
public static final String ACTION_HISTORY_TABLE_CANCEL_ID = "action.history.table.action.cancel";
|
||||
|
||||
/**
|
||||
* Action history table force Id.
|
||||
* Action history table force button Id.
|
||||
*/
|
||||
public static final String ACTION_HISTORY_TABLE_FORCE_ID = "action.history.table.action.force";
|
||||
|
||||
/**
|
||||
* Action history table force quit Id.
|
||||
* Action history table force quit button Id.
|
||||
*/
|
||||
public static final String ACTION_HISTORY_TABLE_FORCE_QUIT_ID = "action.history.table.action.force.quit";
|
||||
/**
|
||||
* Action history table forced label Id.
|
||||
*/
|
||||
public static final String ACTION_HISTORY_TABLE_FORCED_LABEL_ID = "action.history.table.forcedId";
|
||||
|
||||
/**
|
||||
* Action history table time-forced label Id.
|
||||
*/
|
||||
public static final String ACTION_HISTORY_TABLE_TIMEFORCED_LABEL_ID = "action.history.table.timedforceId";
|
||||
|
||||
/**
|
||||
* Action history table status label Id.
|
||||
*/
|
||||
public static final String ACTION_HISTORY_TABLE_STATUS_LABEL_ID = "action.history.table.statusId";
|
||||
|
||||
/**
|
||||
* Action history table active-state label Id.
|
||||
*/
|
||||
public static final String ACTION_HISTORY_TABLE_ACTIVESTATE_LABEL_ID = "action.history.table.activeStateId";
|
||||
|
||||
/**
|
||||
* Action status grid status label Id.
|
||||
*/
|
||||
public static final String ACTION_STATUS_GRID_STATUS_LABEL_ID = "action.status.grid.statusId";
|
||||
|
||||
/**
|
||||
* ID for option group save timeforced
|
||||
@@ -985,7 +1003,7 @@ public final class UIComponentIdProvider {
|
||||
/**
|
||||
* Id of the unread notification popup
|
||||
*/
|
||||
public static final String NOTIFICATION_UNREAD_POPUP_id = "notification.unread.popup";
|
||||
public static final String NOTIFICATION_UNREAD_POPUP_ID = "notification.unread.popup";
|
||||
|
||||
/**
|
||||
* Id of the unread notification icon in the menu
|
||||
|
||||
@@ -18,9 +18,21 @@
|
||||
padding-bottom: 25px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
//Color of forced label
|
||||
.action-history-table-col-forced-label {
|
||||
color: $hawkbit-primary-color;
|
||||
|
||||
.action-history-message-grid {
|
||||
.v-grid-cell {
|
||||
border: none !important;
|
||||
cursor: move;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
-o-text-overflow: ellipsis;
|
||||
-icab-text-overflow: ellipsis;
|
||||
-khtml-text-overflow: ellipsis;
|
||||
-moz-text-overflow: ellipsis;
|
||||
-webkit-text-overflow: ellipsis;
|
||||
font-size: $v-font-size--small !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
}
|
||||
|
||||
.view-header-layout{
|
||||
width: 100%;
|
||||
width: 100% !important;
|
||||
padding-right: 20px;
|
||||
padding-bottom: 0.3em
|
||||
}
|
||||
|
||||
.v-ui {
|
||||
@@ -51,10 +52,10 @@
|
||||
padding-right: 20px;
|
||||
padding-left: 20px;
|
||||
min-width: 1000px;
|
||||
min-height: 400px;
|
||||
min-height: 500px;
|
||||
border: 0px;
|
||||
background-color: transparent;
|
||||
box-shadow: none;
|
||||
box-shadow: none
|
||||
}
|
||||
|
||||
//View background styles
|
||||
@@ -65,7 +66,7 @@
|
||||
background-position: bottom;
|
||||
background-repeat: no-repeat;
|
||||
border-left: 0 solid #fff;
|
||||
padding-top: 80px;
|
||||
padding-top: 70px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@@ -76,7 +77,7 @@
|
||||
font-weight: bold;
|
||||
height: 32px;
|
||||
line-height: 50px;
|
||||
padding-bottom: 5px;
|
||||
padding-bottom: 0px;
|
||||
padding-left: 15px;
|
||||
padding-top: 0;
|
||||
position: absolute;
|
||||
@@ -103,7 +104,7 @@
|
||||
background: $logo-image no-repeat right top;
|
||||
background-position: $logo-position;
|
||||
content: "";
|
||||
height: 80px;
|
||||
height: 70px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
@@ -316,5 +317,11 @@
|
||||
.form-lastrow {
|
||||
padding-bottom: 12px !important;
|
||||
}
|
||||
|
||||
.text-cut {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@mixin grid {
|
||||
.v-grid-cell.centeralign {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.v-grid-cell.leftalign {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.v-grid-cell.rightalign {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.v-grid-cell {
|
||||
font-size: $v-font-size--small !important
|
||||
}
|
||||
|
||||
.v-grid-cell.frozen{
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.v-grid-cell.frozen + th {
|
||||
border-left: $v-grid-border-size solid $widget-border-color ;
|
||||
}
|
||||
}
|
||||
@@ -92,7 +92,7 @@
|
||||
}
|
||||
|
||||
//Pin style - when hovered on pin and when row is selected
|
||||
tr.v-selected .v-button-targetStatusPinToggle:hover:after {
|
||||
widget-bg .v-button-targetStatusPinToggle:hover:after {
|
||||
background-color: $widget-bg;
|
||||
color: $hawkbit-primary-color !important;
|
||||
}
|
||||
@@ -195,56 +195,97 @@
|
||||
content: "\f08d";
|
||||
color: $widget-bg;
|
||||
}
|
||||
|
||||
.statusIconPending {
|
||||
|
||||
// pending status label not selected
|
||||
tr:not(.v-selected) .statusIconForced:after {
|
||||
color: $hawkbit-primary-color;
|
||||
}
|
||||
|
||||
.statusIconActive {
|
||||
// pending status label selected
|
||||
tr.v-selected .statusIconForced:after {
|
||||
color: $widget-bg;
|
||||
}
|
||||
|
||||
// pending status label not selected
|
||||
tr:not(.v-selected) .statusIconPending:after {
|
||||
color: $hawkbit-primary-color;
|
||||
}
|
||||
|
||||
// pending status label selected
|
||||
tr.v-selected .statusIconPending:after {
|
||||
color: $widget-bg;
|
||||
}
|
||||
|
||||
// active status label not selected
|
||||
tr:not(.v-grid-row-selected) .statusIconActive {
|
||||
@include valo-spinner($size:16px,$speed:1200ms);
|
||||
color: $hawkbit-primary-color;
|
||||
}
|
||||
|
||||
.statusIconNeutral {
|
||||
color: $hawkbit-primary-color;
|
||||
// active status label selected
|
||||
tr.v-grid-row-selected .statusIconActive {
|
||||
@include valo-spinner($size:16px,$speed:1200ms,$color: $grey-light);
|
||||
color: $grey-light;
|
||||
}
|
||||
|
||||
// neutral status label not selected
|
||||
tr:not(.v-selected) .statusIconNeutral:after {
|
||||
color: $hawkbit-primary-color;
|
||||
}
|
||||
|
||||
// neutral status label selected
|
||||
tr.v-selected .statusIconNeutral:after {
|
||||
color: $widget-bg;
|
||||
}
|
||||
|
||||
// red status label not selected
|
||||
tr:not(.v-selected) .borderless.statusIconRed:after {
|
||||
color: $hawkbit-primary-color;
|
||||
content: '';
|
||||
}
|
||||
|
||||
// red status label not selected
|
||||
tr.v-selected .borderless.statusIconRed:after {
|
||||
color: $widget-bg;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.redSpinner{
|
||||
@include valo-spinner($size: $v-font-size--small,$color: $red-color);
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
.greySpinner{
|
||||
@include valo-spinner($size: $v-font-size--small,$color: $grey-color);
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
.greySpinner{
|
||||
@include valo-spinner($size: $v-font-size--small,$color: $grey-color);
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
.yellowSpinner{
|
||||
@include valo-spinner($size: $v-font-size--small,$color: $signal-yellow-color);
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
.blueSpinner{
|
||||
@include valo-spinner($size: $v-font-size--small,$color: $signal-light-blue-color);
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
.yellowSpinner{
|
||||
@include valo-spinner($size: $v-font-size--small,$color: $signal-yellow-color);
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
.blueSpinner{
|
||||
@include valo-spinner($size: $v-font-size--small,$color: $signal-light-blue-color);
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
// Disabled row style when distribution is incomplete
|
||||
.v-table-row-incomplete-distribution {
|
||||
color: $disabled-row-color-grey !important;
|
||||
}
|
||||
.v-table-row-incomplete-distribution {
|
||||
color: $disabled-row-color-grey !important;
|
||||
}
|
||||
|
||||
.v-link {
|
||||
text-decoration: none;
|
||||
padding-right: 10px;
|
||||
font-weight: 300;
|
||||
}
|
||||
.v-link {
|
||||
text-decoration: none;
|
||||
padding-right: 10px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.v-tooltip{
|
||||
max-width:43em;
|
||||
}
|
||||
.v-tooltip{
|
||||
max-width:43em;
|
||||
}
|
||||
|
||||
.breadcrumbPaddingLeft{
|
||||
.breadcrumbPaddingLeft{
|
||||
padding-left: 3px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,97 +7,76 @@
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
@mixin rollout {
|
||||
.rollout-option-group {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.rollout-action-type-layout {
|
||||
.v-caption-padding-right-style {
|
||||
padding-right: 0px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.v-context-menu .v-context-menu-item-basic-icon-container {
|
||||
height: 0px !important;
|
||||
width: 0px !important;
|
||||
}
|
||||
|
||||
.v-context-menu .v-context-menu-item-basic {
|
||||
background-color: #feffff !important;
|
||||
border-radius: 4px;
|
||||
font-family: $app-font-family;
|
||||
font-size: $app-text-font-size;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.v-context-menu {
|
||||
background-color: #feffff !important;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.v-context-menu .v-context-menu-item-basic:focus, .v-context-menu .v-context-menu-item-basic-submenu:focus, .v-context-menu .v-context-menu-item-basic-open {
|
||||
@include valo-gradient($color: $hawkbit-primary-color);
|
||||
background-color: $hawkbit-primary-color !important;
|
||||
color: #e8eef3;
|
||||
height: 30px;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.disable-action-type-layout {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.action-type-padding {
|
||||
padding: 0 0px !important;
|
||||
}
|
||||
|
||||
.rollout-caption-links {
|
||||
font-weight: 400;
|
||||
height: 25px;
|
||||
padding: 0px 4px;
|
||||
}
|
||||
|
||||
.rollout-target-count-message {
|
||||
color: $info-message-color-grey;
|
||||
}
|
||||
|
||||
.rollout-table {
|
||||
.v-table-cell-wrapper {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
.v-grid-cell.centeralign {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.v-grid-cell {
|
||||
font-size: $v-font-size--small !important;
|
||||
height: 34px !important;
|
||||
}
|
||||
|
||||
.v-grid-row {
|
||||
height: 34px !important;
|
||||
}
|
||||
|
||||
.v-grid-cell.frozen {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.v-grid-cell.frozen + th {
|
||||
border-left: $v-grid-border-size solid $widget-border-color;
|
||||
}
|
||||
|
||||
.v-button-boldhide {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.groups-pie-chart {
|
||||
.rollout-option-group{
|
||||
font-size:12px;
|
||||
font-weight:400;
|
||||
margin-left:8px;
|
||||
}
|
||||
|
||||
.rollout-action-type-layout {
|
||||
.v-caption-padding-right-style{
|
||||
padding-right:0px !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.v-context-menu .v-context-menu-item-basic-icon-container{
|
||||
height:0px !important;
|
||||
width:0px !important;
|
||||
}
|
||||
|
||||
.v-context-menu .v-context-menu-item-basic{
|
||||
background-color: #feffff !important;
|
||||
border-radius: 4px;
|
||||
font-family : $app-font-family;
|
||||
font-size : $app-text-font-size;
|
||||
font-weight : normal;
|
||||
font-style : normal;
|
||||
}
|
||||
|
||||
|
||||
.v-context-menu{
|
||||
background-color: #feffff !important;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.v-context-menu .v-context-menu-item-basic:focus, .v-context-menu .v-context-menu-item-basic-submenu:focus, .v-context-menu .v-context-menu-item-basic-open {
|
||||
@include valo-gradient($color: $hawkbit-primary-color);
|
||||
background-color: $hawkbit-primary-color !important;
|
||||
color: #e8eef3;
|
||||
height: 30px;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.disable-action-type-layout{
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.action-type-padding{
|
||||
padding: 0 0px !important;
|
||||
}
|
||||
|
||||
.rollout-caption-links{
|
||||
font-weight: 400;
|
||||
height: 25px ;
|
||||
padding: 0px 4px ;
|
||||
}
|
||||
|
||||
.rollout-target-count-message{
|
||||
color: $info-message-color-grey;
|
||||
}
|
||||
|
||||
.rollout-table{
|
||||
.v-table-cell-wrapper {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
.v-button-boldhide{
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
.groups-pie-chart {
|
||||
float: right;
|
||||
|
||||
svg {
|
||||
@@ -209,5 +188,6 @@
|
||||
.v-slot:nth-child(16n+15) .rollout-group-count { border-left-color: #BBDE8F }
|
||||
.v-slot:nth-child(16n+16) .rollout-group-count { border-left-color: #7FB0A4 }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
}
|
||||
|
||||
.v-table-resizer {
|
||||
height: 37px !important;
|
||||
margin-left: -8px !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,10 +38,13 @@ $v-grid-cell-horizontal-border: 0px ;
|
||||
$v-grid-cell-focused-border: 0px ;
|
||||
$v-grid-cell-padding-horizontal:6px;
|
||||
|
||||
$v-table-row-height: 31px;
|
||||
|
||||
$v-animations-enabled: true;
|
||||
|
||||
@import '../valo/valo';
|
||||
@import 'customstyles/table';
|
||||
@import 'customstyles/grid';
|
||||
@import 'customstyles/filter-status';
|
||||
@import 'customstyles/colorpicker';
|
||||
@import 'customstyles/tags';
|
||||
@@ -79,6 +82,7 @@ $v-included-components: remove($v-included-components, form);
|
||||
@include valo;
|
||||
@include generic-styles;
|
||||
@include table;
|
||||
@include grid;
|
||||
@include filter-status;
|
||||
@include colorpicker;
|
||||
@include tags;
|
||||
|
||||
@@ -213,7 +213,6 @@ textfield.vendor = Vendor
|
||||
textfield.description = Description
|
||||
textfield.customfiltername = Filter name
|
||||
textfield.value = Value
|
||||
ui.version = Powered by Bosch IoT Software Provisioning
|
||||
prompt.target.id = Controller ID
|
||||
|
||||
|
||||
|
||||
20
pom.xml
20
pom.xml
@@ -105,7 +105,7 @@
|
||||
<snapshotDependencyAllowed>true</snapshotDependencyAllowed>
|
||||
|
||||
<!-- Spring boot version overrides (should be reviewed with every boot upgrade) - START -->
|
||||
<!-- Newer versions needed than defined in Boot -->
|
||||
<!-- Newer versions needed than defined in Boot -->
|
||||
<spring-hateoas.version>0.23.0.RELEASE</spring-hateoas.version>
|
||||
<assertj.version>3.6.2</assertj.version>
|
||||
<!-- Older versions needed than defined in Boot -->
|
||||
@@ -152,7 +152,7 @@
|
||||
<feign.extension.version>9.3.1</feign.extension.version>
|
||||
<jayway.awaitility.version>1.7.0</jayway.awaitility.version>
|
||||
<io-protostuff.version>1.5.2</io-protostuff.version>
|
||||
|
||||
|
||||
<!-- Misc libraries versions - END -->
|
||||
|
||||
<!-- Release - START -->
|
||||
@@ -218,7 +218,7 @@
|
||||
<version>1.4.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<!-- Make sure that only non-snapshot versions are used for the dependencies. Only active when property 'snapshotDependencyAllowed' is
|
||||
<!-- Make sure that only non-snapshot versions are used for the dependencies. Only active when property 'snapshotDependencyAllowed' is
|
||||
false. -->
|
||||
<id>enforce-no-snapshots</id>
|
||||
<goals>
|
||||
@@ -415,10 +415,10 @@
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<!-- Use the Nexus Staging plugin as a full replacement for the standard Maven Deploy plugin. See https://github.com/sonatype/nexus-maven-plugins/tree/master/staging/maven-plugin
|
||||
why this makes sense :-) We can control whether we want to deploy to the Eclipse repo or Maven Central by a combination of the version being a SNAPSHOT
|
||||
or RELEASE version and property skipStaging=true/false. In any case we can take advantage of the plugin's "deferred deploy" feature which makes sure that
|
||||
all artifacts of a multi-module project are deployed as a whole at the end of the build process instead of deploying each module's artifacts individually
|
||||
<!-- Use the Nexus Staging plugin as a full replacement for the standard Maven Deploy plugin. See https://github.com/sonatype/nexus-maven-plugins/tree/master/staging/maven-plugin
|
||||
why this makes sense :-) We can control whether we want to deploy to the Eclipse repo or Maven Central by a combination of the version being a SNAPSHOT
|
||||
or RELEASE version and property skipStaging=true/false. In any case we can take advantage of the plugin's "deferred deploy" feature which makes sure that
|
||||
all artifacts of a multi-module project are deployed as a whole at the end of the build process instead of deploying each module's artifacts individually
|
||||
as part of building the module. -->
|
||||
<groupId>org.sonatype.plugins</groupId>
|
||||
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||
@@ -629,7 +629,7 @@
|
||||
<artifactId>feign-jaxrs</artifactId>
|
||||
<version>${feign.extension.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Protostuff Io -->
|
||||
<dependency>
|
||||
<groupId>io.protostuff</groupId>
|
||||
@@ -641,7 +641,7 @@
|
||||
<artifactId>protostuff-runtime</artifactId>
|
||||
<version>${io-protostuff.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- RSQL / FIQL parser -->
|
||||
<dependency>
|
||||
<groupId>cz.jirutka.rsql</groupId>
|
||||
@@ -740,4 +740,4 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
Reference in New Issue
Block a user