From 176e2d52c1bf7bfe3d66a9e9ccfa9a8c2089fec1 Mon Sep 17 00:00:00 2001 From: Kai Zimmermann Date: Wed, 22 Jun 2016 13:13:54 +0200 Subject: [PATCH] Metadata management for SM and DS in Management UI. Conflicts: hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTable.java Signed-off-by: Kai Zimmermann --- .../smtable/SoftwareModuleTable.java | 1 + .../common/AbstractMetadataPopupLayout.java | 492 ++++++++++++++++++ .../DistributionSetMetadatadetailslayout.java | 190 +++++++ .../SoftwareModuleMetadatadetailslayout.java | 169 ++++++ .../dstable/DistributionSetTable.java | 45 ++ .../dstable/DsMetadataPopupLayout.java | 83 +++ .../ui/distributions/event/MetadataEvent.java | 52 ++ .../smtable/SwMetadataPopupLayout.java | 90 ++++ 8 files changed, 1122 insertions(+) create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractMetadataPopupLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetMetadatadetailslayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleMetadatadetailslayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetadataPopupLayout.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/event/MetadataEvent.java create mode 100644 hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwMetadataPopupLayout.java diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTable.java index 0104509eb..a27ab6682 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/artifacts/smtable/SoftwareModuleTable.java @@ -15,6 +15,7 @@ import java.util.Map; import org.eclipse.hawkbit.repository.SoftwareManagement; import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; import org.eclipse.hawkbit.ui.artifacts.event.SMFilterEvent; import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent; import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractMetadataPopupLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractMetadataPopupLayout.java new file mode 100644 index 000000000..67c6680a7 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/AbstractMetadataPopupLayout.java @@ -0,0 +1,492 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.ui.common; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.PostConstruct; + +import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; +import org.eclipse.hawkbit.repository.model.MetaData; +import org.eclipse.hawkbit.repository.model.NamedVersionedEntity; +import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; +import org.eclipse.hawkbit.ui.customrenderers.renderers.HtmlButtonRenderer; +import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder; +import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; +import org.eclipse.hawkbit.ui.utils.I18N; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; +import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; +import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; +import org.eclipse.hawkbit.ui.utils.UINotification; +import org.springframework.beans.factory.annotation.Autowired; +import org.vaadin.spring.events.EventBus; + +import com.vaadin.data.Item; +import com.vaadin.data.util.IndexedContainer; +import com.vaadin.event.FieldEvents.TextChangeEvent; +import com.vaadin.event.SelectionEvent; +import com.vaadin.server.FontAwesome; +import com.vaadin.shared.ui.window.WindowMode; +import com.vaadin.ui.AbstractTextField.TextChangeEventMode; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.CustomComponent; +import com.vaadin.ui.Grid; +import com.vaadin.ui.Grid.SelectionMode; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.TextArea; +import com.vaadin.ui.TextField; +import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.Window.WindowModeChangeEvent; +import com.vaadin.ui.renderers.ClickableRenderer.RendererClickEvent; +import com.vaadin.ui.themes.ValoTheme; + +/** + * + * Abstract pop up layout + * + * @param + * E id the entity for which metadata is displayed + * @param + * M is the metadata + * + */ +public abstract class AbstractMetadataPopupLayout extends + CustomComponent { + + private static final String DELETE_BUTTON = "DELETE_BUTTON"; + + private static final long serialVersionUID = -1491218218453167613L; + + private static final String VALUE = "value"; + + private static final String KEY = "key"; + + @Autowired + protected I18N i18n; + + @Autowired + private UINotification uiNotification; + + @Autowired + protected transient EventBus.SessionEventBus eventBus; + + private TextField keyTextField; + + private TextArea valueTextArea; + + private Button addIcon; + + private Grid metaDataGrid; + + private Label headerCaption; + + private CommonDialogWindow metadataWindow; + + private E selectedEntity; + + @PostConstruct + private void init() { + createComponents(); + buildLayout(); + + } + + + /** + * Returns metadata popup. + * + * @param entity + * entity for which metadata data is displayed + * @param metaData + * metadata to be selected + * @return @link{CommonDialogWindow} + */ + public CommonDialogWindow getWindow(final E entity, final M metaData) { + selectedEntity = entity; + String nameVersion = HawkbitCommonUtil.getFormattedNameVersion(entity.getName(), entity.getVersion()); + metadataWindow = SPUIComponentProvider.getWindow(getMetadataCaption(nameVersion), null, + SPUIDefinitions.CREATE_UPDATE_WINDOW, this, event -> onSave(), event -> onDiscard(), null); + metadataWindow.setSaveButtonEnabled(false); + metadataWindow.setCancelButtonEnabled(false); + metadataWindow.setCancelButtonCaption(i18n.get("button.discard")); + metadataWindow.setCancelButtonIcon(FontAwesome.UNDO); + metadataWindow.setId(SPUIComponentIdProvider.METADATA_POPUP_ID); + metadataWindow.setHeight(550, Unit.PIXELS); + metadataWindow.setWidth(800, Unit.PIXELS); + metadataWindow.getMainLayout().setSizeFull(); + metadataWindow.setResizable(true); + metadataWindow.addWindowModeChangeListener(event -> onResize(event)); + setUpDetails(entity.getId(),metaData); + return metadataWindow; + } + + public void setUpDetails(final Long swId, final M metaData) { + keyTextField.clear(); + valueTextArea.clear(); + metadataWindow.setSaveButtonEnabled(false); + metadataWindow.setCancelButtonEnabled(false); + addIcon.setEnabled(true); + if (swId != null) { + metaDataGrid.getContainerDataSource().removeAllItems(); + populateGrid(); + metaDataGrid.getSelectionModel().reset(); + if (!metaDataGrid.getContainerDataSource().getItemIds().isEmpty()) { + if (metaData == null) { + metaDataGrid.select(metaDataGrid.getContainerDataSource().getIdByIndex(0)); + } else { + metaDataGrid.select(metaData.getKey()); + } + } + } + } + + public E getSelectedEntity() { + return selectedEntity; + } + + public void setSelectedEntity(E selectedEntity) { + this.selectedEntity = selectedEntity; + } + + protected abstract void checkForDuplicate(E entity, String value); + + protected abstract M createMetadata(E entity, String key, String value); + + protected abstract M updateMetadata(E entity, String key, String value); + + protected abstract List getMetadataList(); + + protected abstract void deleteMetadata(E entity, String key, String value); + + private void createComponents() { + keyTextField = createKeyTextField(); + valueTextArea = createValueTextField(); + metaDataGrid = createMetadataGrid(); + addIcon = createAddIcon(); + headerCaption = createHeaderCaption(); + } + + private void buildLayout() { + final HorizontalLayout headerLayout = new HorizontalLayout(); + headerLayout.addStyleName(SPUIStyleDefinitions.WIDGET_TITLE); + headerLayout.setSpacing(false); + headerLayout.setMargin(false); + headerLayout.setSizeFull(); + headerLayout.addComponent(headerCaption); + headerLayout.addComponents(addIcon); + headerLayout.setComponentAlignment(addIcon, Alignment.MIDDLE_RIGHT); + headerLayout.setExpandRatio(headerCaption, 1.0F); + + final HorizontalLayout headerWrapperLayout = new HorizontalLayout(); + headerWrapperLayout.addStyleName("bordered-layout" + " " + "no-border-bottom"); + headerWrapperLayout.addComponent(headerLayout); + headerWrapperLayout.setWidth("100%"); + headerLayout.setHeight("30px"); + + final VerticalLayout tableLayout = new VerticalLayout(); + tableLayout.setSizeFull(); + tableLayout.setHeight("100%"); + tableLayout.addComponent(headerWrapperLayout); + tableLayout.addComponent(metaDataGrid); + tableLayout.addStyleName("table-layout"); + tableLayout.setExpandRatio(metaDataGrid, 1.0F); + + VerticalLayout metadataFieldsLayout = new VerticalLayout(); + metadataFieldsLayout.setSizeFull(); + metadataFieldsLayout.setHeight("100%"); + metadataFieldsLayout.addComponent(keyTextField); + metadataFieldsLayout.addComponent(valueTextArea); + metadataFieldsLayout.setSpacing(true); + metadataFieldsLayout.setExpandRatio(valueTextArea, 1F); + + HorizontalLayout mainLayout = new HorizontalLayout(); + mainLayout.addComponent(tableLayout); + mainLayout.addComponent(metadataFieldsLayout); + mainLayout.setExpandRatio(tableLayout, 0.5F); + mainLayout.setExpandRatio(metadataFieldsLayout, 0.5F); + mainLayout.setSizeFull(); + mainLayout.setSpacing(true); + setCompositionRoot(mainLayout); + setSizeFull(); + } + + private TextField createKeyTextField() { + TextField keyField = SPUIComponentProvider.getTextField(i18n.get("textfield.key"), "", + ValoTheme.TEXTFIELD_TINY, true, "", i18n.get("textfield.key"), true, 128); + keyField.setId(SPUIComponentIdProvider.METADATA_KEY_FIELD_ID); + keyField.addTextChangeListener(event -> onKeyChange(event)); + keyField.setTextChangeEventMode(TextChangeEventMode.EAGER); + keyField.setWidth("100%"); + return keyField; + } + + private TextArea createValueTextField() { + valueTextArea = SPUIComponentProvider.getTextArea(i18n.get("textfield.value"), null, ValoTheme.TEXTAREA_TINY, + true, null, i18n.get("textfield.value"), 4000); + valueTextArea.setId(SPUIComponentIdProvider.METADATA_VALUE_ID); + valueTextArea.setNullRepresentation(""); + valueTextArea.setSizeFull(); + valueTextArea.setHeight(100, Unit.PERCENTAGE); + valueTextArea.addTextChangeListener(event -> onValueChange(event)); + valueTextArea.setTextChangeEventMode(TextChangeEventMode.EAGER); + return valueTextArea; + } + + private Grid createMetadataGrid() { + final Grid metadataGrid = new Grid(); + metadataGrid.addStyleName(SPUIStyleDefinitions.METADATA_GRID); + metadataGrid.setImmediate(true); + metadataGrid.setHeight("100%"); + metadataGrid.setWidth("100%"); + metadataGrid.setId(SPUIComponentIdProvider.METDATA_TABLE_ID); + metadataGrid.setSelectionMode(SelectionMode.SINGLE); + metadataGrid.setColumnReorderingAllowed(true); + metadataGrid.setContainerDataSource(getMetadataContainer()); + metadataGrid.getColumn(KEY).setHeaderCaption(i18n.get("header.key")); + metadataGrid.getColumn(VALUE).setHeaderCaption(i18n.get("header.value")); + metadataGrid.getColumn(VALUE).setHidden(true); + metadataGrid.addSelectionListener(event -> onRowClick(event)); + metadataGrid.getColumn(DELETE_BUTTON).setHeaderCaption(""); + metadataGrid.getColumn(DELETE_BUTTON).setRenderer(new HtmlButtonRenderer(event -> onDelete(event))); + metadataGrid.getColumn(DELETE_BUTTON).setWidth(50); + metadataGrid.getColumn(KEY).setExpandRatio(1); + return metadataGrid; + } + + private void onDelete(RendererClickEvent event) { + Item item = metaDataGrid.getContainerDataSource().getItem(event.getItemId()); + String key = (String) item.getItemProperty(KEY).getValue(); + String value = (String) item.getItemProperty(VALUE).getValue(); + + final ConfirmationDialog confirmDialog = new ConfirmationDialog( + i18n.get("caption.metadata.delete.action.confirmbox"), + i18n.get("message.confirm.delete.metadata", key), i18n.get("button.ok"), i18n.get("button.cancel"), + ok -> { + if (ok) { + deleteMetadata(getSelectedEntity(), key, value); + uiNotification.displaySuccess(i18n.get("message.metadata.deleted.successfully", key)); + Object selectedRow = metaDataGrid.getSelectedRow(); + metaDataGrid.getContainerDataSource().removeItem(event.getItemId()); + // force grid to refresh + metaDataGrid.clearSortOrder(); + if (!metaDataGrid.getContainerDataSource().getItemIds().isEmpty()) { + if (selectedRow != null) { + if (selectedRow.equals(event.getItemId())) { + metaDataGrid.select(metaDataGrid.getContainerDataSource().getIdByIndex(0)); + } else { + metaDataGrid.select(selectedRow); + } + } + } else { + keyTextField.clear(); + keyTextField.setEnabled(true); + valueTextArea.clear(); + metaDataGrid.select(null); + } + } + }); + UI.getCurrent().addWindow(confirmDialog.getWindow()); + confirmDialog.getWindow().bringToFront(); + } + + private Button createAddIcon() { + addIcon = SPUIComponentProvider.getButton(SPUIComponentIdProvider.METADTA_ADD_ICON_ID, i18n.get("button.save"), + null, null, false, FontAwesome.PLUS, SPUIButtonStyleSmallNoBorder.class); + addIcon.addClickListener(event -> onAdd(event)); + return addIcon; + } + + private Label createHeaderCaption() { + final Label captionLabel = SPUIComponentProvider.getLabel(i18n.get("caption.metadata"), + SPUILabelDefinitions.SP_WIDGET_CAPTION); + return captionLabel; + } + + private IndexedContainer getMetadataContainer() { + final IndexedContainer swcontactContainer = new IndexedContainer(); + swcontactContainer.addContainerProperty(KEY, String.class, ""); + swcontactContainer.addContainerProperty(VALUE, String.class, ""); + swcontactContainer.addContainerProperty(DELETE_BUTTON, String.class, FontAwesome.TRASH_O.getHtml()); + return swcontactContainer; + } + + private void popualateKeyValue(final Object metadataCompositeKey) { + if (metadataCompositeKey != null) { + Item item = metaDataGrid.getContainerDataSource().getItem(metadataCompositeKey); + keyTextField.setValue((String) item.getItemProperty(KEY).getValue()); + // TODO value to be stored in table??? + valueTextArea.setValue((String) item.getItemProperty(VALUE).getValue()); + keyTextField.setEnabled(false); + } + } + + private void populateGrid() { + List metadataList = getMetadataList(); + for (final M metaData : metadataList) { + addItemToGrid(metaData.getKey(), metaData.getValue()); + } + } + + private void addItemToGrid(final String key, final String value) { + final IndexedContainer metadataContainer = (IndexedContainer) metaDataGrid.getContainerDataSource(); + final Item item = metadataContainer.addItem(key); + item.getItemProperty(VALUE).setValue(value); + item.getItemProperty(KEY).setValue(key); + } + + private void updateItemInGrid(final String key) { + final IndexedContainer metadataContainer = (IndexedContainer) metaDataGrid.getContainerDataSource(); + final Item item = metadataContainer.getItem(key); + item.getItemProperty(VALUE).setValue(valueTextArea.getValue()); + } + + private void onAdd(ClickEvent event) { + valueTextArea.clear(); + keyTextField.clear(); + addIcon.setEnabled(true); + metaDataGrid.deselect(metaDataGrid.getSelectedRow()); + } + + private void onSave() { + String key = keyTextField.getValue(); + String value = valueTextArea.getValue(); + if (mandatoryCheck()) { + E entity = selectedEntity; + if (metaDataGrid.getSelectedRow() == null) { + if (!duplicateCheck(entity)) { + M metadata = createMetadata(entity, key, value); + uiNotification.displaySuccess(i18n.get("message.metadata.saved", metadata.getKey())); + addItemToGrid(metadata.getKey(), metadata.getValue()); + metaDataGrid.scrollToEnd(); + metaDataGrid.select(metadata.getKey()); + addIcon.setEnabled(true); + metadataWindow.setSaveButtonEnabled(false); + metadataWindow.setCancelButtonEnabled(false); + } + } else { + M metadata = updateMetadata(entity, key, value); + uiNotification.displaySuccess(i18n.get("message.metadata.updated", metadata.getKey())); + updateItemInGrid(metadata.getKey()); + metaDataGrid.select(metadata.getKey()); + addIcon.setEnabled(true); + metadataWindow.setSaveButtonEnabled(false); + metadataWindow.setCancelButtonEnabled(false); + } + } + } + + private boolean mandatoryCheck() { + if (keyTextField.getValue().isEmpty()) { + uiNotification.displayValidationError(i18n.get("message.key.missing")); + return false; + } + if (valueTextArea.getValue().isEmpty()) { + uiNotification.displayValidationError(i18n.get("message.value.missing")); + return false; + } + return true; + } + + private boolean duplicateCheck(E entity) { + try { + checkForDuplicate(entity, keyTextField.getValue()); + } catch (final EntityNotFoundException exception) { + return false; + } + uiNotification.displayValidationError(i18n.get("message.metadata.duplicate.check", keyTextField.getValue())); + return true; + } + + private String getMetadataCaption(String nameVersionStr) { + final StringBuilder caption = new StringBuilder(); + caption.append(HawkbitCommonUtil.DIV_DESCRIPTION + i18n.get("caption.metadata.popup") + " " + + HawkbitCommonUtil.getBoldHTMLText(nameVersionStr)); + caption.append(HawkbitCommonUtil.DIV_CLOSE); + return caption.toString(); + } + + private void onDiscard() { + if (metaDataGrid.getSelectedRow() == null) { + keyTextField.clear(); + valueTextArea.clear(); + } else { + Object itemSelected = metaDataGrid.getSelectedRow(); + popualateKeyValue(itemSelected); + } + metadataWindow.setSaveButtonEnabled(false); + metadataWindow.setCancelButtonEnabled(false); + } + + private void onKeyChange(TextChangeEvent event) { + if (!valueTextArea.getValue().isEmpty() && !event.getText().isEmpty()) { + metadataWindow.setSaveButtonEnabled(true); + metadataWindow.setCancelButtonEnabled(true); + } else { + metadataWindow.setSaveButtonEnabled(false); + metadataWindow.setCancelButtonEnabled(false); + } + + } + + private void onRowClick(SelectionEvent event) { + Set itemsSelected = event.getSelected(); + if (!itemsSelected.isEmpty()) { + Object itemSelected = itemsSelected.stream().findFirst().isPresent() ? itemsSelected.stream().findFirst() + .get() : null; + popualateKeyValue(itemSelected); + addIcon.setEnabled(true); + } else { + keyTextField.clear(); + valueTextArea.clear(); + keyTextField.setEnabled(true); + addIcon.setEnabled(false); + } + metadataWindow.setSaveButtonEnabled(false); + metadataWindow.setCancelButtonEnabled(false); + } + + private void onValueChange(TextChangeEvent event) { + if (!keyTextField.getValue().isEmpty() && !event.getText().isEmpty()) { + metadataWindow.setSaveButtonEnabled(true); + metadataWindow.setCancelButtonEnabled(true); + } else { + metadataWindow.setSaveButtonEnabled(false); + metadataWindow.setCancelButtonEnabled(false); + } + } + + private void onResize(WindowModeChangeEvent event) { + if (event.getWindowMode() == WindowMode.MAXIMIZED) { + metaDataGrid.getColumn(DELETE_BUTTON).setWidth(70); + } else { + metaDataGrid.getColumn(DELETE_BUTTON).setWidth(50); + } + //Repopulating the grid (forcing for repaint)- workaround as grid size is not getting adjusted + Map keyValueDetails = new LinkedHashMap<>(); + for (Object key : metaDataGrid.getContainerDataSource().getItemIds()) { + Item item = metaDataGrid.getContainerDataSource().getItem(key); + String value = (String) item.getItemProperty(VALUE).getValue(); + keyValueDetails.put((String) key, value); + } + metaDataGrid.getContainerDataSource().removeAllItems(); + for (Entry entry : keyValueDetails.entrySet()) { + addItemToGrid(entry.getKey(), entry.getValue()); + } + } + +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetMetadatadetailslayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetMetadatadetailslayout.java new file mode 100644 index 000000000..1a66ee0a2 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/DistributionSetMetadatadetailslayout.java @@ -0,0 +1,190 @@ +/** + * 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.detailslayout; + +import java.util.List; + +import org.eclipse.hawkbit.repository.DistributionSetManagement; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.SpPermissionChecker; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; +import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; +import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder; +import org.eclipse.hawkbit.ui.distributions.dstable.DsMetadataPopupLayout; +import org.eclipse.hawkbit.ui.utils.I18N; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; + +import com.vaadin.data.Item; +import com.vaadin.data.util.IndexedContainer; +import com.vaadin.spring.annotation.SpringComponent; +import com.vaadin.spring.annotation.VaadinSessionScope; +import com.vaadin.ui.Button; +import com.vaadin.ui.Label; +import com.vaadin.ui.Table; +import com.vaadin.ui.UI; +import com.vaadin.ui.themes.ValoTheme; + +/** + * + * DistributionSet Metadata details layout. + * + */ + +@SpringComponent +@VaadinSessionScope +public class DistributionSetMetadatadetailslayout extends Table{ + + private static final long serialVersionUID = 2913758299611837718L; + + + private DistributionSetManagement distributionSetManagement; + + private DsMetadataPopupLayout dsMetadataPopupLayout; + + private static final String METADATA_KEY = "Key"; + + private static final String VIEW ="view"; + + private SpPermissionChecker permissionChecker; + + private transient EntityFactory entityFactory; + + private I18N i18n; + + private Long selectedDistSetId; + + /** + * + * @param i18n + * @param permissionChecker + * @param distributionSetManagement + * @param dsMetadataPopupLayout + */ + public void init(final I18N i18n, final SpPermissionChecker permissionChecker, + final DistributionSetManagement distributionSetManagement, + final DsMetadataPopupLayout dsMetadataPopupLayout, + final EntityFactory entityFactory) { + this.i18n = i18n; + this.permissionChecker = permissionChecker; + this.distributionSetManagement = distributionSetManagement; + this.dsMetadataPopupLayout = dsMetadataPopupLayout; + this.entityFactory = entityFactory; + createDSMetadataTable(); + addCustomGeneratedColumns(); + } + + + /** + * Populate software module metadata. + * + * @param distributionSet + */ + public void populateDSMetadata(final DistributionSet distributionSet) { + removeAllItems(); + if (null != distributionSet) { + selectedDistSetId = distributionSet.getId(); + final List dsMetadataList = distributionSet.getMetadata(); + if (null != dsMetadataList && !dsMetadataList.isEmpty()) { + dsMetadataList.forEach(dsMetadata -> setDSMetadataProperties(dsMetadata)); + } + } + } + + /** + * Create metadata . + * + * @param metadataKeyName + */ + public void createMetadata(final String metadataKeyName){ + final IndexedContainer metadataContainer = (IndexedContainer) getContainerDataSource(); + final Item item = metadataContainer.addItem(metadataKeyName); + item.getItemProperty(METADATA_KEY).setValue(metadataKeyName); + } + + /** + * Delete metadata. + * + * @param metadataKeyName + */ + public void deleteMetadata(final String metadataKeyName){ + final IndexedContainer metadataContainer = (IndexedContainer) getContainerDataSource(); + metadataContainer.removeItem(metadataKeyName); + } + + private void createDSMetadataTable() { + addStyleName(ValoTheme.TABLE_NO_HORIZONTAL_LINES); + addStyleName(ValoTheme.TABLE_NO_STRIPES); + addStyleName(SPUIStyleDefinitions.SW_MODULE_TABLE); + addStyleName("details-layout"); + setSelectable(false); + setImmediate(true); + setContainerDataSource(getDistSetContainer()); + setColumnHeaderMode(ColumnHeaderMode.EXPLICIT); + addDSMetadataTableHeader(); + setSizeFull(); + //same as height of other tabs in details tabsheet + setHeight(116,Unit.PIXELS); + } + + private IndexedContainer getDistSetContainer() { + final IndexedContainer container = new IndexedContainer(); + container.addContainerProperty(METADATA_KEY, String.class, ""); + setColumnExpandRatio(METADATA_KEY, 0.7f); + setColumnAlignment(METADATA_KEY, Align.LEFT); + + if (permissionChecker.hasUpdateDistributionPermission()) { + container.addContainerProperty(VIEW, Label.class, ""); + setColumnExpandRatio(VIEW, 0.2F); + setColumnAlignment(VIEW, Align.RIGHT); + } + return container; + } + + private void addDSMetadataTableHeader() { + setColumnHeader(METADATA_KEY, i18n.get("header.key")); + } + + + private void setDSMetadataProperties(final DistributionSetMetadata dsMetadata){ + final Item item = getContainerDataSource().addItem(dsMetadata.getKey()); + item.getItemProperty(METADATA_KEY).setValue(dsMetadata.getKey()); + + } + + private void addCustomGeneratedColumns() { + addGeneratedColumn(METADATA_KEY, + (source, itemId, columnId) -> customMetadataDetailButton((String) itemId)); + } + + private Button customMetadataDetailButton(final String metadataKey) { + final Button viewIcon = SPUIComponentProvider.getButton(getDetailLinkId(metadataKey), metadataKey, "View " + + metadataKey + " Metadata details", null, false, null, SPUIButtonStyleSmallNoBorder.class); + viewIcon.setData(metadataKey); + viewIcon.addStyleName(ValoTheme.BUTTON_TINY + " " + ValoTheme.BUTTON_LINK + " " + "on-focus-no-border link" + + " " + "text-style"); + viewIcon.addClickListener(event -> showMetadataDetails(selectedDistSetId, metadataKey)); + return viewIcon; + } + + private static String getDetailLinkId(final String name) { + return new StringBuilder(SPUIComponentIdProvider.DS_METADATA_DETAIL_LINK).append('.').append(name) + .toString(); + } + + private void showMetadataDetails(final Long selectedDistSetId , final String metadataKey) { + DistributionSet distSet = distributionSetManagement.findDistributionSetById(selectedDistSetId); + + /* display the window */ + UI.getCurrent().addWindow(dsMetadataPopupLayout.getWindow(distSet, + entityFactory.generateDistributionSetMetadata(distSet, metadataKey, "") )); + } + +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleMetadatadetailslayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleMetadatadetailslayout.java new file mode 100644 index 000000000..b8fda1b99 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/detailslayout/SoftwareModuleMetadatadetailslayout.java @@ -0,0 +1,169 @@ +/** + * 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.detailslayout; + +import java.util.List; + +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.SoftwareManagement; +import org.eclipse.hawkbit.repository.SpPermissionChecker; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; +import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder; +import org.eclipse.hawkbit.ui.distributions.smtable.SwMetadataPopupLayout; +import org.eclipse.hawkbit.ui.utils.I18N; +import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; +import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; + +import com.vaadin.data.Item; +import com.vaadin.data.util.IndexedContainer; +import com.vaadin.spring.annotation.SpringComponent; +import com.vaadin.spring.annotation.ViewScope; +import com.vaadin.ui.Button; +import com.vaadin.ui.Table; +import com.vaadin.ui.UI; +import com.vaadin.ui.themes.ValoTheme; + +/** + * + * SoftwareModule Metadata details layout. + * + */ + +@SpringComponent +@ViewScope +public class SoftwareModuleMetadatadetailslayout extends Table { + + private static final long serialVersionUID = 2913758299611838818L; + + private static final String METADATA_KEY = "Key"; + + private SpPermissionChecker permissionChecker; + + private SoftwareManagement softwareManagement; + + private SwMetadataPopupLayout swMetadataPopupLayout; + + private I18N i18n; + + private Long selectedSWModuleId; + + private transient EntityFactory entityFactory; + + public void init(final I18N i18n, final SpPermissionChecker permissionChecker, + final SoftwareManagement softwareManagement, final SwMetadataPopupLayout swMetadataPopupLayout, + final EntityFactory entityFactory) { + this.i18n = i18n; + this.permissionChecker = permissionChecker; + this.softwareManagement = softwareManagement; + this.swMetadataPopupLayout = swMetadataPopupLayout; + this.entityFactory = entityFactory; + createSWMMetadataTable(); + addCustomGeneratedColumns(); + } + + /** + * Populate software module metadata table. + * + * @param swModule + */ + public void populateSMMetadata(final SoftwareModule swModule) { + removeAllItems(); + if (null != swModule) { + selectedSWModuleId = swModule.getId(); + final List swMetadataList = swModule.getMetadata(); + if (null != swMetadataList && !swMetadataList.isEmpty()) { + swMetadataList.forEach(swMetadata -> setSWMetadataProperties(swMetadata)); + } + } + } + + /** + * Create metadata. + * + * @param metadataKeyName + */ + public void createMetadata(final String metadataKeyName) { + final IndexedContainer metadataContainer = (IndexedContainer) getContainerDataSource(); + final Item item = metadataContainer.addItem(metadataKeyName); + item.getItemProperty(METADATA_KEY).setValue(metadataKeyName); + + } + + /** + * Delete metadata. + * + * @param metadataKeyName + */ + public void deleteMetadata(final String metadataKeyName) { + final IndexedContainer metadataContainer = (IndexedContainer) getContainerDataSource(); + metadataContainer.removeItem(metadataKeyName); + } + + private void createSWMMetadataTable() { + addStyleName(ValoTheme.TABLE_NO_HORIZONTAL_LINES); + addStyleName(ValoTheme.TABLE_NO_STRIPES); + addStyleName(SPUIStyleDefinitions.SW_MODULE_TABLE); + setSelectable(false); + setImmediate(true); + setContainerDataSource(getSwModuleMetadataContainer()); + setColumnHeaderMode(ColumnHeaderMode.EXPLICIT); + addSMMetadataTableHeader(); + setSizeFull(); + //same as height of other tabs in details tabsheet + setHeight(116,Unit.PIXELS); + } + + private IndexedContainer getSwModuleMetadataContainer() { + final IndexedContainer container = new IndexedContainer(); + container.addContainerProperty(METADATA_KEY, String.class, ""); + setColumnAlignment(METADATA_KEY, Align.LEFT); + return container; + } + + private void addSMMetadataTableHeader() { + setColumnHeader(METADATA_KEY, i18n.get("header.key")); + } + + + private void setSWMetadataProperties(final SoftwareModuleMetadata swMetadata) { + final Item item = getContainerDataSource().addItem(swMetadata.getKey()); + item.getItemProperty(METADATA_KEY).setValue(swMetadata.getKey()); + } + + private void addCustomGeneratedColumns() { + addGeneratedColumn(METADATA_KEY, (source, itemId, columnId) -> customMetadataDetailButton((String) itemId)); + } + + private Button customMetadataDetailButton(final String metadataKey) { + final Button viewLink = SPUIComponentProvider.getButton(getDetailLinkId(metadataKey), metadataKey, "View" + + metadataKey + " Metadata details", null, false, null, SPUIButtonStyleSmallNoBorder.class); + viewLink.setData(metadataKey); + if (permissionChecker.hasUpdateDistributionPermission()) { + viewLink.addStyleName(ValoTheme.BUTTON_TINY + " " + ValoTheme.BUTTON_LINK + " " + "on-focus-no-border link" + + " " + "text-style"); + viewLink.addClickListener(event -> showMetadataDetails(selectedSWModuleId, metadataKey)); + } + return viewLink; + } + + private static String getDetailLinkId(final String name) { + return new StringBuilder(SPUIComponentIdProvider.SW_METADATA_DETAIL_LINK).append('.').append(name).toString(); + } + + private void showMetadataDetails(final Long selectedSWModuleId, final String metadataKey) { + SoftwareModule swmodule = softwareManagement.findSoftwareModuleById(selectedSWModuleId); + /* display the window */ + UI.getCurrent().addWindow( + swMetadataPopupLayout.getWindow(swmodule, + entityFactory.generateSoftwareModuleMetadata(swmodule, metadataKey, ""))); + } + + } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java index 09a4f0a08..66ce57197 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DistributionSetTable.java @@ -525,5 +525,50 @@ public class DistributionSetTable extends AbstractNamedVersionTable showMetadataDetails(((DistributionSetIdName) itemId).getId())); + return manageMetaDataBtn; + } + }); + } + + @Override + protected List getTableVisibleColumns() { + final List columnList = super.getTableVisibleColumns(); + if (!isMaximized()) { + columnList.add(new TableColumn(SPUILabelDefinitions.METADATA_ICON, "", 0.1F)); + } + return columnList; + } + + private Button createManageMetadataButton(String nameVersionStr) { + final Button manageMetadataBtn = SPUIComponentProvider.getButton( + SPUIComponentIdProvider.DS_TABLE_MANAGE_METADATA_ID + "." + nameVersionStr, "", "", null, false, + FontAwesome.LIST_ALT, SPUIButtonStyleSmallNoBorder.class); + manageMetadataBtn.addStyleName(SPUIStyleDefinitions.ARTIFACT_DTLS_ICON); + manageMetadataBtn.setDescription(i18n.get("tooltip.metadata.icon")); + return manageMetadataBtn; + } + + private void showMetadataDetails(Long itemId) { + DistributionSet ds = distributionSetManagement.findDistributionSetByIdWithDetails(itemId); + UI.getCurrent().addWindow(dsMetadataPopupLayout.getWindow(ds,null)); + } + + private String getNameAndVerion(final Object itemId) { + final Item item = getItem(itemId); + final String name = (String) item.getItemProperty(SPUILabelDefinitions.VAR_NAME).getValue(); + final String version = (String) item.getItemProperty(SPUILabelDefinitions.VAR_VERSION).getValue(); + return name + "." + version; + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetadataPopupLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetadataPopupLayout.java new file mode 100644 index 000000000..1c3fbc407 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/dstable/DsMetadataPopupLayout.java @@ -0,0 +1,83 @@ +/** + * 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.distributions.dstable; + +import java.util.List; + +import org.eclipse.hawkbit.repository.DistributionSetManagement; +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.model.DistributionSet; +import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; +import org.eclipse.hawkbit.ui.common.AbstractMetadataPopupLayout; +import org.eclipse.hawkbit.ui.distributions.event.MetadataEvent; +import org.eclipse.hawkbit.ui.distributions.event.MetadataEvent.MetadataUIEvent; +import org.springframework.beans.factory.annotation.Autowired; + +import com.vaadin.spring.annotation.SpringComponent; +import com.vaadin.spring.annotation.ViewScope; + +/** + * Pop up layout to display distribution metadata. + */ +@SpringComponent +@ViewScope +public class DsMetadataPopupLayout extends AbstractMetadataPopupLayout { + + private static final long serialVersionUID = -7778944849012048106L; + + @Autowired + private transient DistributionSetManagement distributionSetManagement; + + @Autowired + private EntityFactory entityFactory; + + @Override + protected void checkForDuplicate(DistributionSet entity, String value) { + distributionSetManagement.findOne(entity, value); + } + /** + * Create metadata for DistributionSet. + */ + + @Override + protected DistributionSetMetadata createMetadata(DistributionSet entity, String key, String value) { + DistributionSetMetadata dsMetaData = distributionSetManagement.createDistributionSetMetadata(entityFactory + .generateDistributionSetMetadata(entity, key, value)); + setSelectedEntity(dsMetaData.getDistributionSet()); + eventBus.publish(this, new MetadataEvent(MetadataUIEvent.CREATE_DISTRIBUTION_SET_METADATA, dsMetaData)); + return dsMetaData; + } + + /** + * Update metadata for DistributionSet. + */ + @Override + protected DistributionSetMetadata updateMetadata(DistributionSet entity, String key, String value) { + DistributionSetMetadata dsMetaData = distributionSetManagement.updateDistributionSetMetadata(entityFactory + .generateDistributionSetMetadata(entity, key, value)); + setSelectedEntity(dsMetaData.getDistributionSet()); + return dsMetaData; + } + + @Override + protected List getMetadataList() { + return getSelectedEntity().getMetadata(); + } + + /** + * Update metadata for DistributionSet. + */ + + @Override + protected void deleteMetadata(DistributionSet entity, String key, String value) { + DistributionSetMetadata dsMetaData = entityFactory.generateDistributionSetMetadata(entity, key, value); + distributionSetManagement.deleteDistributionSetMetadata(entity, key); + eventBus.publish(this, new MetadataEvent(MetadataUIEvent.DELETE_DISTRIBUTION_SET_METADATA, dsMetaData)); + } +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/event/MetadataEvent.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/event/MetadataEvent.java new file mode 100644 index 000000000..f82bc5c01 --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/event/MetadataEvent.java @@ -0,0 +1,52 @@ +/** + * 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.distributions.event; + +import org.eclipse.hawkbit.repository.model.DistributionSetMetadata; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +/** + * + * Metadata Events. + * + */ +public class MetadataEvent { + + public enum MetadataUIEvent { + CREATE_DISTRIBUTION_SET_METADATA, DELETE_DISTRIBUTION_SET_METADATA, DELETE_SOFTWARE_MODULE_METADATA, CREATE_SOFTWARE_MODULE_METADATA; + } + + private MetadataUIEvent metadataUIEvent; + + private DistributionSetMetadata distributionSetMetadata; + + private SoftwareModuleMetadata softwareModuleMetadata; + + public MetadataEvent(MetadataUIEvent metadataUIEvent, final DistributionSetMetadata distributionSetMetadata) { + this.metadataUIEvent = metadataUIEvent; + this.distributionSetMetadata = distributionSetMetadata; + } + + public MetadataEvent(MetadataUIEvent metadataUIEvent, final SoftwareModuleMetadata softwareModuleMetadata) { + this.metadataUIEvent = metadataUIEvent; + this.softwareModuleMetadata = softwareModuleMetadata; + } + + public MetadataUIEvent getMetadataUIEvent() { + return metadataUIEvent; + } + + public DistributionSetMetadata getDistributionSetMetadata() { + return distributionSetMetadata; + } + + public SoftwareModuleMetadata getSoftwareModuleMetadata() { + return softwareModuleMetadata; + } + +} diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwMetadataPopupLayout.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwMetadataPopupLayout.java new file mode 100644 index 000000000..74be849de --- /dev/null +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/distributions/smtable/SwMetadataPopupLayout.java @@ -0,0 +1,90 @@ +/** + * 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.distributions.smtable; + +import java.util.List; + +import org.eclipse.hawkbit.repository.EntityFactory; +import org.eclipse.hawkbit.repository.SoftwareManagement; +import org.eclipse.hawkbit.repository.model.SoftwareModule; +import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata; +import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState; +import org.eclipse.hawkbit.ui.common.AbstractMetadataPopupLayout; +import org.eclipse.hawkbit.ui.distributions.event.MetadataEvent; +import org.eclipse.hawkbit.ui.distributions.event.MetadataEvent.MetadataUIEvent; +import org.eclipse.hawkbit.ui.distributions.state.ManageDistUIState; +import org.springframework.beans.factory.annotation.Autowired; + +import com.vaadin.spring.annotation.SpringComponent; +import com.vaadin.spring.annotation.ViewScope; + +/** + * Pop up layout to display software module metadata. + * + */ +@SpringComponent +@ViewScope +public class SwMetadataPopupLayout extends AbstractMetadataPopupLayout { + + private static final long serialVersionUID = -1252090014161012563L; + + @Autowired + private transient SoftwareManagement softwareManagement; + + @Autowired + private ArtifactUploadState artifactUploadState; + + @Autowired + private EntityFactory entityFactory; + + @Autowired + private ManageDistUIState manageDistUIState; + + @Override + protected void checkForDuplicate(SoftwareModule entity, String value) { + softwareManagement.findSoftwareModuleMetadata(entity, value); + } + /** + * Create metadata for SWModule. + */ + @Override + protected SoftwareModuleMetadata createMetadata(SoftwareModule entity, String key, String value) { + SoftwareModuleMetadata swMetadata = softwareManagement.createSoftwareModuleMetadata(entityFactory + .generateSoftwareModuleMetadata(entity, key, value)); + setSelectedEntity(swMetadata.getSoftwareModule()); + eventBus.publish(this, new MetadataEvent(MetadataUIEvent.CREATE_SOFTWARE_MODULE_METADATA, swMetadata)); + return swMetadata; + } + /** + * Update metadata for SWModule. + */ + @Override + protected SoftwareModuleMetadata updateMetadata(SoftwareModule entity, String key, String value) { + SoftwareModuleMetadata swMetadata = softwareManagement.updateSoftwareModuleMetadata(entityFactory + .generateSoftwareModuleMetadata(entity, key, value)); + setSelectedEntity(swMetadata.getSoftwareModule()); + return swMetadata; + } + + @Override + protected List getMetadataList() { + return getSelectedEntity().getMetadata(); + } + + /** + * delete metadata for SWModule. + */ + @Override + protected void deleteMetadata(SoftwareModule entity, String key, String value) { + SoftwareModuleMetadata swMetadata = entityFactory.generateSoftwareModuleMetadata(entity, key, value); + softwareManagement.deleteSoftwareModuleMetadata(entity, key); + eventBus.publish(this, new MetadataEvent(MetadataUIEvent.DELETE_SOFTWARE_MODULE_METADATA, swMetadata)); + } + +}