Updated UI to handle all requirements
* added DurationConfigField (Field which contains a DurationConfigField and a Checkbox) * added labels to messages.properties * added new Interface ConfigurationElement, with functionallity which is important for saving the data Signed-off-by: Nonnenmacher Fabian <fabian.nonnenmacher@bosch-si.com>
This commit is contained in:
committed by
Nonnenmacher Fabian
parent
1eedd3a531
commit
cb3e6863c1
@@ -110,7 +110,7 @@ public class TargetInfo implements Persistable<Long>, Serializable {
|
|||||||
@CollectionTable(name = "sp_target_attributes", joinColumns = {
|
@CollectionTable(name = "sp_target_attributes", joinColumns = {
|
||||||
@JoinColumn(name = "target_id") }, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_attrib_target") )
|
@JoinColumn(name = "target_id") }, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_attrib_target") )
|
||||||
// use deprecated annotation until HHH-8862 is fixed
|
// use deprecated annotation until HHH-8862 is fixed
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
// @org.hibernate.annotations.ForeignKey( name = "fk_targ_attrib_target" )
|
// @org.hibernate.annotations.ForeignKey( name = "fk_targ_attrib_target" )
|
||||||
private final Map<String, String> controllerAttributes = Collections.synchronizedMap(new HashMap<String, String>());
|
private final Map<String, String> controllerAttributes = Collections.synchronizedMap(new HashMap<String, String>());
|
||||||
|
|
||||||
@@ -181,7 +181,7 @@ public class TargetInfo implements Persistable<Long>, Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ipAddress
|
* @param address
|
||||||
* the ipAddress to set
|
* the ipAddress to set
|
||||||
*
|
*
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
@@ -382,6 +382,9 @@ public class TargetInfo implements Persistable<Long>, Serializable {
|
|||||||
return overdueDate;
|
return overdueDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current date
|
||||||
|
*/
|
||||||
public LocalDateTime getCurrentDate() {
|
public LocalDateTime getCurrentDate() {
|
||||||
return currentDate;
|
return currentDate;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package org.eclipse.hawkbit.ui.tenantconfiguration;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public interface ConfigurationElement {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called to verify that the Input done by the user is valid
|
||||||
|
*
|
||||||
|
* @return true when the data is valid, false otherwise
|
||||||
|
*/
|
||||||
|
boolean isUserInputValid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a configuration change listener to notify about configuration
|
||||||
|
* changes.
|
||||||
|
*
|
||||||
|
* @param listener
|
||||||
|
* the listener to be notified in case the item changes some
|
||||||
|
* configuration
|
||||||
|
*/
|
||||||
|
void addChangeListener(ConfigurationGroupChangeListener listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration Change Listener to be notified about configuration changes
|
||||||
|
* in configuration group.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
interface ConfigurationGroupChangeListener extends Serializable {
|
||||||
|
/**
|
||||||
|
* called to notify about configuration has been changed.
|
||||||
|
*/
|
||||||
|
void configurationChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,8 +8,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.ui.tenantconfiguration;
|
package org.eclipse.hawkbit.ui.tenantconfiguration;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
import com.vaadin.ui.Component;
|
import com.vaadin.ui.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,7 +15,7 @@ import com.vaadin.ui.Component;
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public interface ConfigurationGroup extends Component {
|
public interface ConfigurationGroup extends Component, ConfigurationElement {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called to store any configuration changes.
|
* called to store any configuration changes.
|
||||||
@@ -28,34 +26,4 @@ public interface ConfigurationGroup extends Component {
|
|||||||
* called to rollback any configuration changes.
|
* called to rollback any configuration changes.
|
||||||
*/
|
*/
|
||||||
void undo();
|
void undo();
|
||||||
|
|
||||||
/**
|
|
||||||
* called to verify that the Input done by the user is valid
|
|
||||||
*
|
|
||||||
* @return true when the data is valid, false otherwise
|
|
||||||
*/
|
|
||||||
boolean isUserInputValid();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a configuration change listener to notify about configuration
|
|
||||||
* changes.
|
|
||||||
*
|
|
||||||
* @param listener
|
|
||||||
* the listener to be notified in case the item changes some
|
|
||||||
* configuration
|
|
||||||
*/
|
|
||||||
void addChangeListener(ConfigurationGroupChangeListener listener);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configuration Change Listener to be notified about configuration changes
|
|
||||||
* in configuration group.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
interface ConfigurationGroupChangeListener extends Serializable {
|
|
||||||
/**
|
|
||||||
* called to notify about configuration has been changed.
|
|
||||||
*/
|
|
||||||
void configurationChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,18 @@
|
|||||||
package org.eclipse.hawkbit.ui.tenantconfiguration;
|
package org.eclipse.hawkbit.ui.tenantconfiguration;
|
||||||
|
|
||||||
import static org.eclipse.hawkbit.repository.model.helper.PollConfigurationHelper.EXPECTED_POLLING_TIME_FORMAT;
|
import java.time.Duration;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
|
||||||
import org.eclipse.hawkbit.repository.model.helper.PollConfigurationHelper;
|
import org.eclipse.hawkbit.repository.model.helper.PollConfigurationHelper;
|
||||||
import org.eclipse.hawkbit.ui.tenantconfiguration.polling.DurationField;
|
import org.eclipse.hawkbit.ui.tenantconfiguration.polling.DurationConfigField;
|
||||||
import org.eclipse.hawkbit.ui.utils.I18N;
|
import org.eclipse.hawkbit.ui.utils.I18N;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import com.vaadin.data.Property.ValueChangeEvent;
|
|
||||||
import com.vaadin.data.Validator;
|
|
||||||
import com.vaadin.spring.annotation.SpringComponent;
|
import com.vaadin.spring.annotation.SpringComponent;
|
||||||
import com.vaadin.spring.annotation.ViewScope;
|
import com.vaadin.spring.annotation.ViewScope;
|
||||||
import com.vaadin.ui.Field;
|
|
||||||
import com.vaadin.ui.Label;
|
import com.vaadin.ui.Label;
|
||||||
import com.vaadin.ui.Panel;
|
import com.vaadin.ui.Panel;
|
||||||
import com.vaadin.ui.TextField;
|
|
||||||
import com.vaadin.ui.VerticalLayout;
|
import com.vaadin.ui.VerticalLayout;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,21 +24,24 @@ import com.vaadin.ui.VerticalLayout;
|
|||||||
@SpringComponent
|
@SpringComponent
|
||||||
@ViewScope
|
@ViewScope
|
||||||
public class PollingConfigurationView extends BaseConfigurationView
|
public class PollingConfigurationView extends BaseConfigurationView
|
||||||
implements ConfigurationGroup, Field.ValueChangeListener {
|
implements ConfigurationGroup, ConfigurationElement.ConfigurationGroupChangeListener {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private transient SystemManagement systemManagement;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private I18N i18n;
|
private I18N i18n;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
PollConfigurationHelper pollConfigurationHelper;
|
PollConfigurationHelper pollConfigurationHelper;
|
||||||
|
|
||||||
final private DurationField fieldPollingTime = new DurationField();
|
@Autowired
|
||||||
final private DurationField fieldPollingOverdueTime = new DurationField();
|
private DurationConfigField fieldPollingTime;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DurationConfigField fieldPollingOverdueTime;
|
||||||
|
|
||||||
|
private Duration tenantPollingTime;
|
||||||
|
private Duration tenantPollingOverdueTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize Authentication Configuration layout.
|
* Initialize Authentication Configuration layout.
|
||||||
@@ -51,38 +49,34 @@ public class PollingConfigurationView extends BaseConfigurationView
|
|||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init() {
|
public void init() {
|
||||||
|
|
||||||
Validator correctFormatValidator = new Validator() {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void validate(Object value) throws InvalidValueException {
|
|
||||||
if (!(value instanceof String) || !((String) value).matches(EXPECTED_POLLING_TIME_FORMAT)) {
|
|
||||||
throw new InvalidValueException("Not in HH:MM:SS Format.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
final Panel rootPanel = new Panel();
|
final Panel rootPanel = new Panel();
|
||||||
rootPanel.setSizeFull();
|
rootPanel.setSizeFull();
|
||||||
|
|
||||||
rootPanel.addStyleName("config-panel");
|
rootPanel.addStyleName("config-panel");
|
||||||
|
|
||||||
// TODO Better Layout than Vertical Layout - maybe a table layout?
|
|
||||||
final VerticalLayout vLayout = new VerticalLayout();
|
final VerticalLayout vLayout = new VerticalLayout();
|
||||||
vLayout.setMargin(true);
|
vLayout.setMargin(true);
|
||||||
vLayout.setSizeFull();
|
// vLayout.setSizeFull();
|
||||||
|
|
||||||
final Label headerDisSetType = new Label(i18n.get("configuration.polling.title"));
|
final Label headerDisSetType = new Label(i18n.get("configuration.polling.title"));
|
||||||
headerDisSetType.addStyleName("config-panel-header");
|
headerDisSetType.addStyleName("config-panel-header");
|
||||||
vLayout.addComponent(headerDisSetType);
|
vLayout.addComponent(headerDisSetType);
|
||||||
|
|
||||||
final Label labelPollingTime = new Label(i18n.get("configuration.polling.time"));
|
tenantPollingTime = pollConfigurationHelper.getTenantPollTimeIntervall();
|
||||||
vLayout.addComponent(labelPollingTime);
|
fieldPollingTime.setInitValues(i18n.get("configuration.polling.time"), tenantPollingTime,
|
||||||
|
pollConfigurationHelper.getGlobalPollTimeInterval());
|
||||||
|
fieldPollingTime.setAllowedRange(pollConfigurationHelper.getMinimumPollingInterval(),
|
||||||
|
pollConfigurationHelper.getMaximumPollingInterval());
|
||||||
|
fieldPollingTime.addChangeListener(this);
|
||||||
|
|
||||||
vLayout.addComponent(fieldPollingTime);
|
vLayout.addComponent(fieldPollingTime);
|
||||||
|
|
||||||
final Label labelPollingOverdueTime = new Label(i18n.get("configuration.polling.overduetime"));
|
tenantPollingOverdueTime = pollConfigurationHelper.getTenantOverduePollTimeIntervall();
|
||||||
vLayout.addComponent(labelPollingOverdueTime);
|
|
||||||
|
fieldPollingOverdueTime.setInitValues(i18n.get("configuration.polling.overduetime"), tenantPollingOverdueTime,
|
||||||
|
pollConfigurationHelper.getGlobalOverduePollTimeInterval());
|
||||||
|
fieldPollingOverdueTime.setAllowedRange(pollConfigurationHelper.getMinimumPollingInterval(),
|
||||||
|
pollConfigurationHelper.getMaximumPollingInterval());
|
||||||
|
fieldPollingOverdueTime.addChangeListener(this);
|
||||||
|
|
||||||
vLayout.addComponent(fieldPollingOverdueTime);
|
vLayout.addComponent(fieldPollingOverdueTime);
|
||||||
|
|
||||||
@@ -90,55 +84,47 @@ public class PollingConfigurationView extends BaseConfigurationView
|
|||||||
setCompositionRoot(rootPanel);
|
setCompositionRoot(rootPanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
*
|
|
||||||
* @see
|
|
||||||
* com.vaadin.data.Property.ValueChangeListener#valueChange(com.vaadin.data.
|
|
||||||
* Property.ValueChangeEvent)
|
|
||||||
*
|
|
||||||
* This method is called when a value of a textField changes. When the value
|
|
||||||
* is not in the correct format, but has valid data, this method will change
|
|
||||||
* the value to the correct format
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void valueChange(ValueChangeEvent event) {
|
public void save() {
|
||||||
|
// make sure values are only saved, when the value has been changed
|
||||||
|
|
||||||
notifyConfigurationChanged();
|
if (!compareDurations(tenantPollingTime, fieldPollingTime.getValue())) {
|
||||||
|
tenantPollingTime = fieldPollingTime.getValue();
|
||||||
|
pollConfigurationHelper.setTenantPollTimeIntervall(fieldPollingTime.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
if (event.getProperty() instanceof TextField) {
|
if (!compareDurations(tenantPollingOverdueTime, fieldPollingOverdueTime.getValue())) {
|
||||||
TextField textfield = (TextField) event.getProperty();
|
tenantPollingOverdueTime = fieldPollingOverdueTime.getValue();
|
||||||
|
pollConfigurationHelper.setTenantOverduePollTimeIntervall(fieldPollingOverdueTime.getValue());
|
||||||
String value = textfield.getValue();
|
|
||||||
|
|
||||||
if (value.matches("[0-9]{1,6}")) {
|
|
||||||
value = "000000".substring(value.length()) + value;
|
|
||||||
value = value.substring(0, 2) + ":" + value.substring(2, 4) + ":" + value.substring(4, 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value.matches("([0-5]?[0-9]?(:[0-5][0-9]){1,2})")) {
|
|
||||||
value = "00:00:00".substring(0, 8 - value.length()) + value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value.matches(EXPECTED_POLLING_TIME_FORMAT)) {
|
|
||||||
textfield.setValue(value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save() {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void undo() {
|
public void undo() {
|
||||||
|
fieldPollingTime.setValue(tenantPollingTime);
|
||||||
|
fieldPollingOverdueTime.setValue(tenantPollingOverdueTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isUserInputValid() {
|
public boolean isUserInputValid() {
|
||||||
return fieldPollingTime.isValid() && fieldPollingOverdueTime.isValid();
|
return fieldPollingTime.isUserInputValid() && fieldPollingOverdueTime.isUserInputValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configurationChanged() {
|
||||||
|
notifyConfigurationChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean compareDurations(Duration d1, Duration d2) {
|
||||||
|
if (d1 == null && d2 == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d1 != null) {
|
||||||
|
return d1.equals(d2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// d1 == null, d2 != null
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import org.eclipse.hawkbit.ui.HawkbitUI;
|
|||||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||||
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder;
|
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder;
|
||||||
import org.eclipse.hawkbit.ui.documentation.DocumentationPageLink;
|
import org.eclipse.hawkbit.ui.documentation.DocumentationPageLink;
|
||||||
import org.eclipse.hawkbit.ui.tenantconfiguration.ConfigurationGroup.ConfigurationGroupChangeListener;
|
import org.eclipse.hawkbit.ui.tenantconfiguration.ConfigurationElement.ConfigurationGroupChangeListener;
|
||||||
import org.eclipse.hawkbit.ui.utils.I18N;
|
import org.eclipse.hawkbit.ui.utils.I18N;
|
||||||
import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider;
|
import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider;
|
||||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
package org.eclipse.hawkbit.ui.tenantconfiguration.polling;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||||
|
import org.eclipse.hawkbit.ui.tenantconfiguration.ConfigurationElement;
|
||||||
|
import org.eclipse.hawkbit.ui.utils.I18N;
|
||||||
|
import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
|
||||||
|
import com.vaadin.data.Property.ValueChangeEvent;
|
||||||
|
import com.vaadin.data.Property.ValueChangeListener;
|
||||||
|
import com.vaadin.spring.annotation.SpringComponent;
|
||||||
|
import com.vaadin.spring.annotation.ViewScope;
|
||||||
|
import com.vaadin.ui.Alignment;
|
||||||
|
import com.vaadin.ui.CheckBox;
|
||||||
|
import com.vaadin.ui.GridLayout;
|
||||||
|
import com.vaadin.ui.Label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DurationConfigField consists of three vaadin fields. A {@link #Label}
|
||||||
|
* {@link #DurationField} and a {@link #CheckBox}. The user can then enter a
|
||||||
|
* duration in the DurationField or he can configure using the global duration
|
||||||
|
* by changing the CheckBox.
|
||||||
|
*/
|
||||||
|
@SpringComponent
|
||||||
|
@ViewScope
|
||||||
|
@Scope("prototype")
|
||||||
|
public class DurationConfigField extends GridLayout implements ValueChangeListener, ConfigurationElement {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private final List<ConfigurationGroupChangeListener> configurationChangeListeners = new ArrayList<>();
|
||||||
|
|
||||||
|
private CheckBox checkBox;
|
||||||
|
private DurationField durationField;
|
||||||
|
|
||||||
|
private Duration globalDuration;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private I18N i18n;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets i18n
|
||||||
|
*
|
||||||
|
* @param i18n
|
||||||
|
*/
|
||||||
|
public void setI18n(I18N i18n) {
|
||||||
|
this.i18n = i18n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DurationConfigField() {
|
||||||
|
super(3, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize Authentication Configuration layout.
|
||||||
|
*/
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
|
||||||
|
this.addStyleName("duration-config-field");
|
||||||
|
this.setSpacing(true);
|
||||||
|
this.setImmediate(true);
|
||||||
|
this.setColumnExpandRatio(1, 1.0F);
|
||||||
|
// gridLayout.setSizeFull();
|
||||||
|
|
||||||
|
checkBox = new CheckBox();
|
||||||
|
|
||||||
|
this.addComponent(checkBox, 0, 0);
|
||||||
|
this.setComponentAlignment(checkBox, Alignment.MIDDLE_LEFT);
|
||||||
|
|
||||||
|
Label customValue = SPUIComponentProvider.getLabel(i18n.get("configuration.polling.custom.value"),
|
||||||
|
SPUILabelDefinitions.SP_LABEL_SIMPLE);
|
||||||
|
this.addComponent(customValue, 1, 0);
|
||||||
|
this.setComponentAlignment(customValue, Alignment.MIDDLE_LEFT);
|
||||||
|
|
||||||
|
durationField = new DurationField();
|
||||||
|
|
||||||
|
this.addComponent(durationField, 2, 0);
|
||||||
|
this.setComponentAlignment(durationField, Alignment.MIDDLE_LEFT);
|
||||||
|
|
||||||
|
checkBox.addValueChangeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void valueChange(ValueChangeEvent event) {
|
||||||
|
if (event.getProperty() == checkBox) {
|
||||||
|
if (checkBox.getValue()) {
|
||||||
|
durationField.setEnabled(true);
|
||||||
|
} else {
|
||||||
|
durationField.setDuration(globalDuration);
|
||||||
|
durationField.setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notifyConfigurationChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets all mandatitory attributes for correct user interaction
|
||||||
|
*
|
||||||
|
* @param caption
|
||||||
|
* the caption of the field
|
||||||
|
*
|
||||||
|
* @param tenantDuration
|
||||||
|
* tenant specific duration value
|
||||||
|
* @param globalDuration
|
||||||
|
* duration value which is stored in the global configuration
|
||||||
|
*/
|
||||||
|
public void setInitValues(String caption, @NotNull Duration tenantDuration, @NotNull Duration globalDuration) {
|
||||||
|
this.setCaption(caption);
|
||||||
|
this.globalDuration = globalDuration;
|
||||||
|
|
||||||
|
this.setValue(tenantDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the allowed range of the duration values
|
||||||
|
*
|
||||||
|
* @param minimumDuration
|
||||||
|
* minimum allowed duration value
|
||||||
|
* @param maximumDuration
|
||||||
|
* maximum allowed duration value
|
||||||
|
*/
|
||||||
|
public void setAllowedRange(Duration minimumDuration, Duration maximumDuration) {
|
||||||
|
durationField.setMinimumDuration(minimumDuration);
|
||||||
|
durationField.setMaximumDuration(maximumDuration);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the value of the duration field
|
||||||
|
*
|
||||||
|
* @param tenantDuration
|
||||||
|
* duration which will be set in to the duration field, when
|
||||||
|
* {@code null} the global configuration will be used.
|
||||||
|
*/
|
||||||
|
public void setValue(Duration tenantDuration) {
|
||||||
|
if (tenantDuration == null) {
|
||||||
|
// no tenant specific configuration
|
||||||
|
checkBox.setValue(false);
|
||||||
|
durationField.setDuration(globalDuration);
|
||||||
|
durationField.setEnabled(false);
|
||||||
|
} else {
|
||||||
|
checkBox.setValue(true);
|
||||||
|
durationField.setDuration(tenantDuration);
|
||||||
|
durationField.setEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the duration of the duration field or null, when the user has
|
||||||
|
* configured to use the global value.
|
||||||
|
*/
|
||||||
|
public Duration getValue() {
|
||||||
|
if (checkBox.getValue()) {
|
||||||
|
return durationField.getDuration();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUserInputValid() {
|
||||||
|
return !checkBox.getValue() || (durationField.isValid() && durationField.getValue() != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyConfigurationChanged() {
|
||||||
|
configurationChangeListeners.forEach(listener -> listener.configurationChanged());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addChangeListener(final ConfigurationGroupChangeListener listener) {
|
||||||
|
configurationChangeListeners.add(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,17 +2,27 @@ package org.eclipse.hawkbit.ui.tenantconfiguration.polling;
|
|||||||
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
import com.vaadin.data.Property;
|
import com.vaadin.data.Property;
|
||||||
|
import com.vaadin.data.Validator.InvalidValueException;
|
||||||
import com.vaadin.data.util.converter.Converter.ConversionException;
|
import com.vaadin.data.util.converter.Converter.ConversionException;
|
||||||
import com.vaadin.shared.ui.datefield.Resolution;
|
import com.vaadin.shared.ui.datefield.Resolution;
|
||||||
import com.vaadin.ui.DateField;
|
import com.vaadin.ui.DateField;
|
||||||
|
import com.vaadin.ui.themes.ValoTheme;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents a Field which is optimized to enter a time duration in
|
* This class represents a Field which is optimized to enter a time duration in
|
||||||
* form HH:mm:ss (see {@link #DEFAULT_DURATION_FORMAT}). It uses the vaadin
|
* form HH:mm:ss (see {@link #DURATION_FORMAT_STIRNG}). It uses the vaadin
|
||||||
* DateField as a basic element, but the format is optimized for the duration
|
* DateField as a basic element, but the format is optimized for the duration
|
||||||
* input. For a correct view of the popup it is recommended not to display the
|
* input. For a correct view of the popup it is recommended not to display the
|
||||||
* css-class "v-datefield-calendarpanel-header" and
|
* css-class "v-datefield-calendarpanel-header" and
|
||||||
@@ -22,42 +32,61 @@ public class DurationField extends DateField {
|
|||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private static String CSS_STYLE_NAME = "durationfield";
|
private static final String CSS_STYLE_NAME = "durationfield";
|
||||||
|
|
||||||
private static String DEFAULT_DURATION_FORMAT = "HH:mm:ss";
|
private static final String ADDITIONAL_DURATION_STRING = "HHmmss";
|
||||||
private static String ADDITIONAL_DURATION_FORMAT = "HHmmss";
|
private static final String DURATION_FORMAT_STIRNG = "HH:mm:ss";
|
||||||
|
|
||||||
private SimpleDateFormat default_format = new SimpleDateFormat(DEFAULT_DURATION_FORMAT);
|
private static final ZoneId ZONEID_UTC = ZoneId.of("+0");
|
||||||
private SimpleDateFormat additional_format = new SimpleDateFormat(ADDITIONAL_DURATION_FORMAT);
|
|
||||||
|
private static final Duration MAXIMUM_DURATION = Duration.ofHours(23).plusMinutes(59).plusSeconds(59);
|
||||||
|
|
||||||
|
private final SimpleDateFormat durationFormat = new SimpleDateFormat(DURATION_FORMAT_STIRNG);
|
||||||
|
private final SimpleDateFormat additionalFormat = new SimpleDateFormat(ADDITIONAL_DURATION_STRING);
|
||||||
|
|
||||||
|
private Date minimumDuration;
|
||||||
|
private Date maximumDuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a DurationField
|
* Creates a DurationField
|
||||||
*/
|
*/
|
||||||
public DurationField() {
|
protected DurationField() {
|
||||||
|
super();
|
||||||
|
|
||||||
default_format.setLenient(false);
|
this.setTimeZone(TimeZone.getTimeZone(ZONEID_UTC));
|
||||||
additional_format.setLenient(false);
|
durationFormat.setTimeZone(TimeZone.getTimeZone(ZONEID_UTC));
|
||||||
|
additionalFormat.setTimeZone(TimeZone.getTimeZone(ZONEID_UTC));
|
||||||
|
durationFormat.setLenient(false);
|
||||||
|
additionalFormat.setLenient(false);
|
||||||
|
|
||||||
this.setResolution(Resolution.SECOND);
|
this.setResolution(Resolution.SECOND);
|
||||||
this.setDateFormat(DEFAULT_DURATION_FORMAT);
|
this.setDateFormat(DURATION_FORMAT_STIRNG);
|
||||||
this.addStyleName(CSS_STYLE_NAME);
|
this.addStyleName(CSS_STYLE_NAME);
|
||||||
|
this.addStyleName(ValoTheme.TEXTFIELD_TINY);
|
||||||
|
this.setWidth("100px");
|
||||||
|
|
||||||
// needed that popup shows a 24h clock
|
// needed that popup shows a 24h clock
|
||||||
this.setLocale(Locale.GERMANY);
|
this.setLocale(Locale.GERMANY);
|
||||||
// adds empty change Listener, but is needed that field reacts on
|
|
||||||
// pressed enter
|
|
||||||
this.addValueChangeListener(this);
|
this.addValueChangeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called to handle a non-empty date string from the client
|
||||||
|
* if the client could not parse it as a Date. In the current case two
|
||||||
|
* different parsing schemas are tried. If parsing is not possible a
|
||||||
|
* ConversionException is thrown which marks the DurationField as invalid.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Date handleUnparsableDateString(String value) throws ConversionException {
|
protected Date handleUnparsableDateString(String value) throws ConversionException {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return default_format.parse(value);
|
return durationFormat.parse(value);
|
||||||
|
|
||||||
} catch (ParseException e1) {
|
} catch (ParseException e1) {
|
||||||
try {
|
try {
|
||||||
return additional_format.parse(value);
|
|
||||||
|
return additionalFormat.parse("000000".substring(value.length() <= 6 ? value.length() : 6) + value);
|
||||||
} catch (ParseException e2) {
|
} catch (ParseException e2) {
|
||||||
// if Parsing is not possible ConversionException is thrown
|
// if Parsing is not possible ConversionException is thrown
|
||||||
}
|
}
|
||||||
@@ -65,32 +94,128 @@ public class DurationField extends DateField {
|
|||||||
throw new ConversionException("input is not in HH:MM:SS format.");
|
throw new ConversionException("input is not in HH:MM:SS format.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Sets the duration value as a String
|
public void valueChange(Property.ValueChangeEvent event) {
|
||||||
*
|
// do not delete this method, even when removing the code inside this
|
||||||
* @param duration
|
// method. This method overwrites the super method, which is
|
||||||
* duration as String in format HH:mm:ss, only values <= 23:59:59
|
// necessary, that parsing works correctly on pressing enter key
|
||||||
* are excepted
|
|
||||||
* @throws ParseException
|
|
||||||
* Exception is thrown, when String parameter is in wrong
|
|
||||||
* format.
|
|
||||||
*/
|
|
||||||
public void setValueAsString(String duration) throws ParseException {
|
|
||||||
super.setValue(default_format.parse(duration));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if (event.getProperty() instanceof DurationField) {
|
||||||
* Gets the duration value as a formated String
|
Date value = (Date) event.getProperty().getValue();
|
||||||
*
|
|
||||||
* @return duration as String in format HH:mm:ss
|
// setValue() calls valueChanged again, when the minimum is greater
|
||||||
*/
|
// than the maximum this can lead to an endless loop
|
||||||
public String getValueAsString() {
|
if (value != null && minimumDuration != null && maximumDuration != null
|
||||||
return default_format.format(super.getValue());
|
&& minimumDuration.before(maximumDuration)) {
|
||||||
|
|
||||||
|
if (compareTimeOfDates(value, maximumDuration) > 0) {
|
||||||
|
((DateField) event.getProperty()).setValue(maximumDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compareTimeOfDates(minimumDuration, value) > 0) {
|
||||||
|
((DateField) event.getProperty()).setValue(minimumDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void valueChange(Property.ValueChangeEvent event) {
|
public void validate(Date value) throws InvalidValueException {
|
||||||
// does nothing, but method overrides super methods and is needed that
|
super.validate(value);
|
||||||
// parsing works correctly on pressed enter key
|
|
||||||
|
if (value != null && maximumDuration != null && compareTimeOfDates(value, maximumDuration) > 0) {
|
||||||
|
throw new InvalidValueException("value is greater than the allowed maximum value");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value != null && minimumDuration != null && compareTimeOfDates(minimumDuration, value) > 0) {
|
||||||
|
throw new InvalidValueException("value is smaller than the allowed minimum value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the duration value
|
||||||
|
*
|
||||||
|
* @param duration
|
||||||
|
* duration, only values <= 23:59:59 are excepted
|
||||||
|
*/
|
||||||
|
public void setDuration(@NotNull Duration duration) {
|
||||||
|
if (duration.compareTo(MAXIMUM_DURATION) > 0) {
|
||||||
|
throw new IllegalArgumentException("The duaration has to be smaller than 23:59:59.");
|
||||||
|
}
|
||||||
|
super.setValue(durationToDate(duration));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the duration value of the TextField
|
||||||
|
*
|
||||||
|
* @return duration which is written in the vaadin Field
|
||||||
|
*/
|
||||||
|
public Duration getDuration() {
|
||||||
|
if (this.getValue() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return dateToDuration(this.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the minimal allowed duration value as a String
|
||||||
|
*
|
||||||
|
* @param minimumDuration
|
||||||
|
* minimum Duration, only values smaller 23:59:59 are excepted
|
||||||
|
*/
|
||||||
|
public void setMinimumDuration(@NotNull Duration minimumDuration) {
|
||||||
|
if (minimumDuration.compareTo(MAXIMUM_DURATION) > 0) {
|
||||||
|
throw new IllegalArgumentException("The minimum duaration has to be smaller than 23:59:59.");
|
||||||
|
}
|
||||||
|
this.minimumDuration = durationToDate(minimumDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the maximum allowed duration value as a String
|
||||||
|
*
|
||||||
|
* @param maximumDuration
|
||||||
|
* maximumDuration, only values smaller 23:59:59 are excepted
|
||||||
|
*/
|
||||||
|
public void setMaximumDuration(@NotNull Duration maximumDuration) {
|
||||||
|
if (maximumDuration.compareTo(MAXIMUM_DURATION) > 0) {
|
||||||
|
throw new IllegalArgumentException("The maximum duaration has to be smaller than 23:59:59.");
|
||||||
|
}
|
||||||
|
this.maximumDuration = durationToDate(maximumDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Date durationToDate(final Duration duration) {
|
||||||
|
if (duration.compareTo(MAXIMUM_DURATION) > 0) {
|
||||||
|
throw new IllegalArgumentException("The duaration has to be smaller than 23:59:59.");
|
||||||
|
}
|
||||||
|
|
||||||
|
final LocalTime lt = LocalTime.ofNanoOfDay(duration.toNanos());
|
||||||
|
return Date.from(lt.atDate(LocalDate.now(ZONEID_UTC)).atZone(ZONEID_UTC).toInstant());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Duration dateToDuration(final Date date) {
|
||||||
|
final LocalTime endExclusive = LocalDateTime.ofInstant(date.toInstant(), ZONEID_UTC).toLocalTime();
|
||||||
|
return Duration.between(LocalTime.MIDNIGHT, LocalTime.from(endExclusive));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Because parsing done by base class returns a different date than parsing
|
||||||
|
* done by the user or converting duration to a date. But for the
|
||||||
|
* DurationField comparison only the time is important. This function helps
|
||||||
|
* comparing the time and ignores the values for day, month and year.
|
||||||
|
*
|
||||||
|
* @param d1
|
||||||
|
* date, which time will compared with the time of d2
|
||||||
|
* @param d2
|
||||||
|
* date, which time will compared with the time of d1
|
||||||
|
* @return the value 0 if the time represented d1 is equal to the time
|
||||||
|
* represented by d2; a value less than 0 if the time of d1 is
|
||||||
|
* before the time of d2; and a value greater than 0 if the time of
|
||||||
|
* d1 is after the time represented by d2.
|
||||||
|
*/
|
||||||
|
private int compareTimeOfDates(Date d1, Date d2) {
|
||||||
|
LocalTime lt1 = LocalDateTime.ofInstant(d1.toInstant(), ZONEID_UTC).toLocalTime();
|
||||||
|
LocalTime lt2 = LocalDateTime.ofInstant(d2.toInstant(), ZONEID_UTC).toLocalTime();
|
||||||
|
|
||||||
|
return lt1.compareTo(lt2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -400,6 +400,7 @@ configuration.authentication.title=Authentication Configuration
|
|||||||
configuration.polling.title=Polling Configuration
|
configuration.polling.title=Polling Configuration
|
||||||
configuration.polling.time=Polling Time
|
configuration.polling.time=Polling Time
|
||||||
configuration.polling.overduetime=Polling Overdue Time
|
configuration.polling.overduetime=Polling Overdue Time
|
||||||
|
configuration.polling.custom.value=use a custom value
|
||||||
|
|
||||||
#Calendar
|
#Calendar
|
||||||
calendar.year=year
|
calendar.year=year
|
||||||
|
|||||||
Reference in New Issue
Block a user