Merge pull request #178 from bsinno/feature_minimize_status_popup

Minimize status popup
This commit is contained in:
Kai Zimmermann
2016-06-03 11:53:33 +02:00
19 changed files with 1126 additions and 294 deletions

View File

@@ -15,6 +15,5 @@ package org.eclipse.hawkbit.ui.artifacts.event;
* *
*/ */
public enum UploadArtifactUIEvent { public enum UploadArtifactUIEvent {
SHOW_DROP_HINTS, HIDE_DROP_HINTS, SOFTWARE_DRAG_START, SOFTWARE_TYPE_DRAG_START, UPDATE_UPLOAD_COUNT, HIDE_FILTER_BY_TYPE, SHOW_FILTER_BY_TYPE, DISCARD_DELETE_SOFTWARE, DISCARD_ALL_DELETE_SOFTWARE, DELETED_ALL_SOFWARE, DISCARD_DELETE_SOFTWARE_TYPE, DISCARD_ALL_DELETE_SOFTWARE_TYPE, DELETED_ALL_SOFWARE_TYPE, MINIMIZED_STATUS_POPUP, MAXIMIZED_STATUS_POPUP, UPLOAD_IN_PROGESS, ARTIFACT_RESULT_POPUP_CLOSED
SHOW_DROP_HINTS, HIDE_DROP_HINTS, SOFTWARE_DRAG_START, SOFTWARE_TYPE_DRAG_START, UPDATE_UPLOAD_COUNT, ENABLE_PROCESS_BUTTON, HIDE_FILTER_BY_TYPE, SHOW_FILTER_BY_TYPE, DISCARD_DELETE_SOFTWARE, DISCARD_ALL_DELETE_SOFTWARE, DELETED_ALL_SOFWARE, DISABLE_PROCESS_BUTTON, DISCARD_DELETE_SOFTWARE_TYPE, DISCARD_ALL_DELETE_SOFTWARE_TYPE, DELETED_ALL_SOFWARE_TYPE
} }

View File

@@ -0,0 +1,70 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.artifacts.event;
import java.io.Serializable;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
/**
*
* Holds file and upload status details.Meta data sent with upload events.
*
*/
public class UploadFileStatus implements Serializable {
private static final long serialVersionUID = -3599629192216760811L;
private String fileName;
private long contentLength;
private long bytesRead;
private String failureReason;
private SoftwareModule softwareModule;
public UploadFileStatus(String fileName) {
this.fileName = fileName;
}
public UploadFileStatus(String fileName, long bytesRead, long contentLength,SoftwareModule softwareModule) {
this.fileName = fileName;
this.contentLength = contentLength;
this.bytesRead = bytesRead;
this.softwareModule = softwareModule;
}
public UploadFileStatus(String fileName, String failureReason,SoftwareModule selectedSw) {
this.failureReason = failureReason;
this.fileName = fileName;
this.softwareModule = selectedSw;
}
public String getFileName() {
return fileName;
}
public long getContentLength() {
return contentLength;
}
public long getBytesRead() {
return bytesRead;
}
public String getFailureReason() {
return failureReason;
}
public SoftwareModule getSoftwareModule() {
return softwareModule;
}
}

View File

@@ -0,0 +1,42 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.artifacts.event;
/**
*
* Holds the upload file status.
*
*/
public class UploadStatusEvent {
public enum UploadStatusEventType {
UPLOAD_FAILED, UPLOAD_IN_PROGRESS, UPLOAD_STARTED, UPLOAD_FINISHED, UPLOAD_SUCCESSFUL, UPLOAD_STREAMING_FAILED, UPLOAD_STREAMING_FINISHED, ABORT_UPLOAD
}
private UploadStatusEventType uploadProgressEventType;
private UploadFileStatus uploadStatus;
public UploadStatusEvent(UploadStatusEventType eventType, UploadFileStatus entity) {
this.uploadProgressEventType = eventType;
this.uploadStatus = entity;
}
public UploadFileStatus getUploadStatus() {
return uploadStatus;
}
public void setUploadStatus(UploadFileStatus uploadStatus) {
this.uploadStatus = uploadStatus;
}
public UploadStatusEventType getUploadProgressEventType() {
return uploadProgressEventType;
}
}

View File

@@ -9,14 +9,18 @@
package org.eclipse.hawkbit.ui.artifacts.state; package org.eclipse.hawkbit.ui.artifacts.state;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.artifacts.upload.UploadStatusObject;
import org.eclipse.hawkbit.ui.common.ManagmentEntityState; import org.eclipse.hawkbit.ui.common.ManagmentEntityState;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -58,8 +62,61 @@ public class ArtifactUploadState implements ManagmentEntityState<Long>, Serializ
private final Set<String> selectedDeleteSWModuleTypes = new HashSet<>(); private final Set<String> selectedDeleteSWModuleTypes = new HashSet<>();
private boolean noDataAvilableSoftwareModule = Boolean.FALSE; private boolean noDataAvilableSoftwareModule = Boolean.FALSE;
private boolean isStatusPopupMinimized = Boolean.FALSE;
private boolean isUploadCompleted = Boolean.FALSE;
private List<UploadStatusObject> uploadedFileStatusList = new ArrayList<>();
private final AtomicInteger numberOfFileUploadsExpected = new AtomicInteger();
/** private final AtomicInteger numberOfFilesActuallyUpload = new AtomicInteger();
private final AtomicInteger numberOfFileUploadsFailed = new AtomicInteger();
public AtomicInteger getNumberOfFileUploadsFailed() {
return numberOfFileUploadsFailed;
}
public AtomicInteger getNumberOfFilesActuallyUpload() {
return numberOfFilesActuallyUpload;
}
public AtomicInteger getNumberOfFileUploadsExpected() {
return numberOfFileUploadsExpected;
}
public List<UploadStatusObject> getUploadedFileStatusList() {
return uploadedFileStatusList;
}
public void setUploadedFileStatusList(List<UploadStatusObject> uploadedFileStatusList) {
this.uploadedFileStatusList = uploadedFileStatusList;
}
public boolean isUploadCompleted() {
return isUploadCompleted;
}
public void setUploadCompleted(boolean isUploadCompleted) {
this.isUploadCompleted = isUploadCompleted;
}
public void setStatusPopupMinimized(boolean isStatusPopupMinimized) {
this.isStatusPopupMinimized = isStatusPopupMinimized;
}
public boolean isStatusPopupMinimized() {
return isStatusPopupMinimized;
}
/**
* Set software. * Set software.
* *
* @return * @return

View File

@@ -544,7 +544,7 @@ public class UploadConfirmationwindow implements Button.ClickListener {
if (event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_ARTIFACT_DETAILS_CLOSE)) { if (event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_ARTIFACT_DETAILS_CLOSE)) {
uploadConfrimationWindow.close(); uploadConfrimationWindow.close();
} else if (event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_DISCARD_DETAILS_BUTTON)) { } else if (event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_DISCARD_DETAILS_BUTTON)) {
uploadLayout.clearFileList(); uploadLayout.clearUploadedFileDetails();
uploadConfrimationWindow.close(); uploadConfrimationWindow.close();
} else if (event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_BUTTON)) { } else if (event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_BUTTON)) {
processArtifactUpload(); processArtifactUpload();
@@ -568,10 +568,10 @@ public class UploadConfirmationwindow implements Button.ClickListener {
uploadDetailsTable.removeItem(((Button) event.getComponent()).getData()); uploadDetailsTable.removeItem(((Button) event.getComponent()).getData());
uploadLayout.getFileSelected().remove(customFile); uploadLayout.getFileSelected().remove(customFile);
uploadLayout.updateActionCount(); uploadLayout.updateUploadCounts();
if (uploadDetailsTable.getItemIds().isEmpty()) { if (uploadDetailsTable.getItemIds().isEmpty()) {
uploadLayout.clearFileList();
uploadConfrimationWindow.close(); uploadConfrimationWindow.close();
uploadLayout.clearUploadedFileDetails();
} }
} }

View File

@@ -11,13 +11,21 @@ package org.eclipse.hawkbit.ui.artifacts.upload;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import javax.annotation.PreDestroy;
import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException; import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException;
import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.artifacts.state.CustomFile; import org.eclipse.hawkbit.ui.artifacts.event.UploadFileStatus;
import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent;
import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent.UploadStatusEventType;
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
import org.eclipse.hawkbit.ui.utils.I18N; import org.eclipse.hawkbit.ui.utils.I18N;
import org.eclipse.hawkbit.ui.utils.SpringContextHelper; import org.eclipse.hawkbit.ui.utils.SpringContextHelper;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.vaadin.spring.events.EventBus;
import org.vaadin.spring.events.EventScope;
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
import com.vaadin.server.StreamVariable; import com.vaadin.server.StreamVariable;
import com.vaadin.ui.Upload; import com.vaadin.ui.Upload;
@@ -49,28 +57,53 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
private final long fileSize; private final long fileSize;
private final UploadLayout view; private final UploadLayout view;
private final UploadStatusInfoWindow infoWindow;
private final long maxSize; private final long maxSize;
private final Upload upload; private final Upload upload;
private volatile String fileName = null; private volatile String fileName = null;
private volatile String mimeType = null; private volatile String mimeType = null;
private volatile boolean interrupted = false; private volatile boolean streamingInterrupted = false;
private volatile boolean uploadInterrupted = false;
private volatile boolean aborted = false;
private String failureReason; private String failureReason;
private final I18N i18n; private final I18N i18n;
private transient EventBus.SessionEventBus eventBus;
private final SoftwareModule selectedSw;
private SoftwareModule selectedSwForUpload;
private ArtifactUploadState artifactUploadState;
UploadHandler(final String fileName, final long fileSize, final UploadLayout view, UploadHandler(final String fileName, final long fileSize, final UploadLayout view, final long maxSize,
final UploadStatusInfoWindow infoWindow, final long maxSize, final Upload upload, final String mimeType) { final Upload upload, final String mimeType, SoftwareModule selectedSw) {
super(); super();
this.aborted = false;
this.fileName = fileName; this.fileName = fileName;
this.fileSize = fileSize; this.fileSize = fileSize;
this.view = view; this.view = view;
this.infoWindow = infoWindow;
this.maxSize = maxSize; this.maxSize = maxSize;
this.upload = upload; this.upload = upload;
this.mimeType = mimeType; this.mimeType = mimeType;
this.selectedSw = selectedSw;
this.i18n = SpringContextHelper.getBean(I18N.class); this.i18n = SpringContextHelper.getBean(I18N.class);
this.eventBus = SpringContextHelper.getBean(EventBus.SessionEventBus.class);
this.artifactUploadState = SpringContextHelper.getBean(ArtifactUploadState.class);
eventBus.subscribe(this);
}
@PreDestroy
void destroy() {
/*
* It's good manners to do this, even though vaadin-spring will
* automatically unsubscribe when this UI is garbage collected.
*/
eventBus.unsubscribe(this);
}
@EventBusListenerMethod(scope = EventScope.SESSION)
void onEvent(final UploadStatusEventType event) {
if (event == UploadStatusEventType.ABORT_UPLOAD) {
aborted = true;
}
} }
/** /**
@@ -81,11 +114,13 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
@Override @Override
public final OutputStream getOutputStream() { public final OutputStream getOutputStream() {
try { try {
return view.saveUploadedFileDetails(fileName, fileSize, mimeType); streamingInterrupted = false;
failureReason = null;
return view.saveUploadedFileDetails(fileName, fileSize, mimeType, selectedSw);
} catch (final ArtifactUploadFailedException e) { } catch (final ArtifactUploadFailedException e) {
LOG.error("Atifact upload failed {} ", e); LOG.error("Atifact upload failed {} ", e);
failureReason = e.getMessage(); failureReason = e.getMessage();
interrupted = true; streamingInterrupted = true;
return new NullOutputStream(); return new NullOutputStream();
} }
} }
@@ -98,23 +133,22 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
*/ */
@Override @Override
public OutputStream receiveUpload(final String fileName, final String mimeType) { public OutputStream receiveUpload(final String fileName, final String mimeType) {
aborted = false;
failureReason = null;
this.fileName = fileName; this.fileName = fileName;
this.mimeType = mimeType; this.mimeType = mimeType;
// reset has directory flag before upload // reset has directory flag before upload
view.setHasDirectory(false); view.setHasDirectory(false);
try { try {
if (view.checkIfSoftwareModuleIsSelected()) { if (view.checkIfSoftwareModuleIsSelected() && !view.checkForDuplicate(fileName, selectedSwForUpload)) {
if (view.checkForDuplicate(fileName)) { view.increaseNumberOfFileUploadsExpected();
view.showDuplicateMessage(); return view.saveUploadedFileDetails(fileName, 0, mimeType, selectedSwForUpload);
} else {
view.increaseNumberOfFileUploadsExpected();
return view.saveUploadedFileDetails(fileName, 0, mimeType);
}
} }
} catch (final ArtifactUploadFailedException e) { } catch (final ArtifactUploadFailedException e) {
LOG.error("Atifact upload failed {} ", e); LOG.error("Atifact upload failed {} ", e);
failureReason = e.getMessage(); failureReason = e.getMessage();
upload.interruptUpload(); upload.interruptUpload();
uploadInterrupted = true;
} }
// if final validation fails ,final no upload ,return NullOutputStream // if final validation fails ,final no upload ,return NullOutputStream
return new NullOutputStream(); return new NullOutputStream();
@@ -129,13 +163,8 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
@Override @Override
public void uploadSucceeded(final SucceededEvent event) { public void uploadSucceeded(final SucceededEvent event) {
LOG.debug("Streaming finished for file :{}", event.getFilename()); LOG.debug("Streaming finished for file :{}", event.getFilename());
view.updateFileSize(event.getFilename(), event.getLength()); eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_SUCCESSFUL, new UploadFileStatus(
event.getFilename(), 0, event.getLength(), selectedSwForUpload)));
// recorded that we now one more uploaded
view.increaseNumberOfFilesActuallyUpload();
// inform upload status window
infoWindow.uploadSucceeded(event.getFilename());
} }
/** /**
@@ -148,20 +177,8 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
@Override @Override
public void streamingFinished(final StreamingEndEvent event) { public void streamingFinished(final StreamingEndEvent event) {
LOG.debug("Streaming finished for file :{}", event.getFileName()); LOG.debug("Streaming finished for file :{}", event.getFileName());
// record that we now one more uploaded eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_STREAMING_FINISHED,
view.increaseNumberOfFilesActuallyUpload(); new UploadFileStatus(event.getFileName(), 0, event.getContentLength(), selectedSw)));
// inform upload status window
infoWindow.uploadSucceeded(event.getFileName());
// check if we are finished
if (view.enableProcessBtn()) {
infoWindow.uploadSessionFinished();
}
view.updateActionCount();
// display the duplicate message after streaming all files
view.displayDuplicateValidationMessage();
} }
/** /**
@@ -173,12 +190,8 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
@Override @Override
public void uploadFinished(final FinishedEvent event) { public void uploadFinished(final FinishedEvent event) {
LOG.debug("Upload finished for file :{}", event.getFilename()); LOG.debug("Upload finished for file :{}", event.getFilename());
// check if we are finished eventBus.publish(this,
if (view.enableProcessBtn()) { new UploadStatusEvent(UploadStatusEventType.UPLOAD_FINISHED, new UploadFileStatus(event.getFilename())));
infoWindow.uploadSessionFinished();
}
view.updateActionCount();
} }
/** /**
@@ -189,7 +202,8 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
@Override @Override
public void streamingStarted(final StreamingStartEvent event) { public void streamingStarted(final StreamingStartEvent event) {
LOG.debug("Streaming started for file :{}", fileName); LOG.debug("Streaming started for file :{}", fileName);
infoWindow.uploadStarted(fileName); eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_STARTED, new UploadFileStatus(
fileName, 0, 0, selectedSw)));
} }
/** /**
@@ -199,14 +213,24 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
*/ */
@Override @Override
public void uploadStarted(final StartedEvent event) { public void uploadStarted(final StartedEvent event) {
// single file session uploadInterrupted = false;
if (view.isSoftwareModuleSelected() && !view.checkIfFileIsDuplicate(event.getFilename())) { selectedSwForUpload = artifactUploadState.getSelectedBaseSoftwareModule().isPresent() ? artifactUploadState
infoWindow.uploadSessionStarted(); .getSelectedBaseSoftwareModule().get() : null;
LOG.debug("Upload started for file :{}", event.getFilename());
infoWindow.uploadStarted(event.getFilename()); if (view.isSoftwareModuleSelected()) {
} else { // single file session
if (!view.checkIfFileIsDuplicate(event.getFilename(), selectedSwForUpload)) {
LOG.debug("Upload started for file :{}", event.getFilename());
eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_STARTED,
new UploadFileStatus(event.getFilename(), 0, 0, selectedSwForUpload)));
}
}
else {
failureReason = i18n.get("message.upload.failed"); failureReason = i18n.get("message.upload.failed");
upload.interruptUpload(); upload.interruptUpload();
// actual interrupt will happen a bit late so setting the below
// flag
uploadInterrupted = true;
} }
} }
@@ -227,21 +251,25 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
*/ */
@Override @Override
public void updateProgress(final long readBytes, final long contentLength) { public void updateProgress(final long readBytes, final long contentLength) {
if (readBytes > maxSize || contentLength > maxSize) { // Update progress is called event after upload interrupted in
LOG.error("User tried to upload more than was allowed ({}).", maxSize); // uploadStarted method
view.decreaseNumberOfFileUploadsExpected(); if (!uploadInterrupted) {
final SoftwareModule sw = view.getSoftwareModuleSelected(); if (aborted) {
view.getFileSelected().remove(new CustomFile(fileName, sw.getName(), sw.getVersion())); LOG.info("User aborted file upload for file : {}", fileName);
view.updateActionCount(); failureReason = i18n.get("message.uploadedfile.aborted");
failureReason = i18n.get("message.uploadedfile.size.exceeded", maxSize); interruptFileUpload();
infoWindow.uploadFailed(fileName, failureReason); return;
upload.interruptUpload(); }
interrupted = true; if (readBytes > maxSize || contentLength > maxSize) {
return; LOG.error("User tried to upload more than was allowed ({}).", maxSize);
failureReason = i18n.get("message.uploadedfile.size.exceeded", maxSize);
interruptFileUpload();
return;
}
eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_IN_PROGRESS,
new UploadFileStatus(fileName, readBytes, contentLength, selectedSwForUpload)));
LOG.info("Update progress - {} : {}", fileName, (double) readBytes / (double) contentLength);
} }
infoWindow.updateProgress(fileName, readBytes, contentLength);
LOG.info("Update progress - {} : {}", fileName, (double) readBytes / (double) contentLength);
} }
/** /**
@@ -251,19 +279,20 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
*/ */
@Override @Override
public void onProgress(final StreamingProgressEvent event) { public void onProgress(final StreamingProgressEvent event) {
if (event.getBytesReceived() > maxSize || event.getContentLength() > maxSize) { if (aborted) {
LOG.error("User tried to upload more than was allowed ({}).", maxSize); LOG.info("User aborted the upload for file : {}", event.getFileName());
view.decreaseNumberOfFileUploadsExpected(); failureReason = i18n.get("message.uploadedfile.aborted");
final SoftwareModule sw = view.getSoftwareModuleSelected(); interruptFileStreaming();
view.getFileSelected().remove(new CustomFile(fileName, sw.getName(), sw.getVersion()));
view.updateActionCount();
failureReason = i18n.get("message.uploadedfile.size.exceeded", maxSize);
infoWindow.uploadFailed(event.getFileName(), failureReason);
interrupted = true;
return; return;
} }
if (event.getBytesReceived() > maxSize || event.getContentLength() > maxSize) {
infoWindow.updateProgress(event.getFileName(), event.getBytesReceived(), event.getContentLength()); LOG.error("User tried to upload more than was allowed ({}).", maxSize);
failureReason = i18n.get("message.uploadedfile.size.exceeded", maxSize);
interruptFileStreaming();
return;
}
eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_IN_PROGRESS, new UploadFileStatus(
fileName, event.getBytesReceived(), event.getContentLength(), selectedSw)));
// Logging to solve sonar issue // Logging to solve sonar issue
LOG.trace("Streaming in progress for file :{}", event.getFileName()); LOG.trace("Streaming in progress for file :{}", event.getFileName());
} }
@@ -276,19 +305,16 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
*/ */
@Override @Override
public void streamingFailed(final StreamingErrorEvent event) { public void streamingFailed(final StreamingErrorEvent event) {
LOG.info("Streaming failed for file :{}", event.getFileName()); if (failureReason == null) {
view.decreaseNumberOfFileUploadsExpected(); failureReason = event.getException().getMessage();
final SoftwareModule sw = view.getSoftwareModuleSelected();
view.getFileSelected().remove(new CustomFile(fileName, sw.getName(), sw.getVersion()));
view.updateActionCount();
infoWindow.uploadFailed(event.getFileName(), failureReason);
// check if we are finished
if (view.enableProcessBtn()) {
infoWindow.uploadSessionFinished();
} }
view.displayDuplicateValidationMessage(); eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_STREAMING_FAILED,
new UploadFileStatus(fileName, failureReason, selectedSw)));
LOG.info("Streaming failed due to :{}", event.getException()); if (!aborted) {
LOG.info("Streaming failed for file :{}", event.getFileName());
LOG.info("Streaming failed due to :{}", event.getException());
}
} }
/** /**
@@ -298,20 +324,21 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
*/ */
@Override @Override
public void uploadFailed(final FailedEvent event) { public void uploadFailed(final FailedEvent event) {
LOG.info("Upload failed for file :{}", event.getFilename());
view.decreaseNumberOfFileUploadsExpected();
/** /**
* If upload interrupted because of duplicate file,do not remove the * If upload failed due to no selected software UPLOAD_FAILED event need
* file already in upload list * not be published.
**/ */
if (!view.getDuplicateFileNamesList().isEmpty()) { if (selectedSwForUpload != null) {
final SoftwareModule sw = view.getSoftwareModuleSelected(); if (failureReason == null) {
view.getFileSelected().remove(new CustomFile(fileName, sw.getName(), sw.getVersion())); failureReason = event.getReason().getMessage();
}
eventBus.publish(this, new UploadStatusEvent(UploadStatusEventType.UPLOAD_FAILED, new UploadFileStatus(
fileName, failureReason, selectedSwForUpload)));
if (!aborted) {
LOG.info("Upload failed for file :{}", event.getFilename());
LOG.info("Upload failed for file :{}", event.getReason());
}
} }
view.updateActionCount();
infoWindow.uploadFailed(event.getFilename(), failureReason);
LOG.info("Upload failed for file :{}", event.getReason());
} }
/** /**
@@ -319,7 +346,7 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
*/ */
@Override @Override
public boolean isInterrupted() { public boolean isInterrupted() {
return interrupted; return streamingInterrupted;
} }
private static class NullOutputStream extends OutputStream { private static class NullOutputStream extends OutputStream {
@@ -365,4 +392,13 @@ public class UploadHandler implements StreamVariable, Receiver, SucceededListene
return true; return true;
} }
private void interruptFileStreaming() {
streamingInterrupted = true;
}
private void interruptFileUpload() {
upload.interruptUpload();
uploadInterrupted = true;
}
} }

View File

@@ -16,7 +16,6 @@ import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
@@ -26,6 +25,8 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent; import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent;
import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent.SoftwareModuleEventType; import org.eclipse.hawkbit.ui.artifacts.event.SoftwareModuleEvent.SoftwareModuleEventType;
import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent; import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent;
import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent;
import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent.UploadStatusEventType;
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState; import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
import org.eclipse.hawkbit.ui.artifacts.state.CustomFile; import org.eclipse.hawkbit.ui.artifacts.state.CustomFile;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
@@ -97,10 +98,6 @@ public class UploadLayout extends VerticalLayout {
@Autowired @Autowired
private transient SPInfo spInfo; private transient SPInfo spInfo;
private final AtomicInteger numberOfFileUploadsExpected = new AtomicInteger();
private final AtomicInteger numberOfFilesActuallyUpload = new AtomicInteger();
private final List<String> duplicateFileNamesList = new ArrayList<>(); private final List<String> duplicateFileNamesList = new ArrayList<>();
private Button processBtn; private Button processBtn;
@@ -119,6 +116,8 @@ public class UploadLayout extends VerticalLayout {
private Boolean hasDirectory = Boolean.FALSE; private Boolean hasDirectory = Boolean.FALSE;
private Button uploadStatusButton;
/** /**
* Initialize the upload layout. * Initialize the upload layout.
*/ */
@@ -126,13 +125,52 @@ public class UploadLayout extends VerticalLayout {
void init() { void init() {
createComponents(); createComponents();
buildLayout(); buildLayout();
updateActionCount(); restoreState();
eventBus.subscribe(this); eventBus.subscribe(this);
ui = UI.getCurrent(); ui = UI.getCurrent();
} }
private void createComponents() { @EventBusListenerMethod(scope = EventScope.SESSION)
void onEvent(final UploadArtifactUIEvent event) {
if (event == UploadArtifactUIEvent.DELETED_ALL_SOFWARE) {
ui.access(() -> updateActionCount());
} else if (event == UploadArtifactUIEvent.MINIMIZED_STATUS_POPUP) {
ui.access(() -> showUploadStatusButton());
} else if (event == UploadArtifactUIEvent.MAXIMIZED_STATUS_POPUP) {
ui.access(() -> maximizeStatusPopup());
} else if (event == UploadArtifactUIEvent.ARTIFACT_RESULT_POPUP_CLOSED) {
ui.access(() -> closeUploadStatusPopup());
}
}
@EventBusListenerMethod(scope = EventScope.SESSION)
void onEvent(final UploadStatusEvent event) {
if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STARTED) {
ui.access(() -> onStartOfUpload());
} else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_FAILED) {
ui.access(() -> onUploadFailure(event));
} else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_FINISHED) {
ui.access(() -> onUploadCompletion());
} else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_SUCCESSFUL) {
ui.access(() -> onUploadSuccess(event));
} else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STREAMING_FAILED) {
ui.access(() -> onUploadStreamingFailure(event));
} else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STREAMING_FINISHED) {
ui.access(() -> onUploadStreamingSuccess());
}
}
@PreDestroy
void destroy() {
/*
* It's good manners to do this, even though vaadin-spring will
* automatically unsubscribe when this UI is garbage collected.
*/
eventBus.unsubscribe(this);
}
private void createComponents() {
createUploadStatusButton();
createProcessButton(); createProcessButton();
createDiscardBtn(); createDiscardBtn();
} }
@@ -140,8 +178,8 @@ public class UploadLayout extends VerticalLayout {
private void buildLayout() { private void buildLayout() {
final Upload upload = new Upload(); final Upload upload = new Upload();
final UploadHandler uploadHandler = new UploadHandler(null, 0, this, uploadInfoWindow, final UploadHandler uploadHandler = new UploadHandler(null, 0, this, spInfo.getMaxArtifactFileSize(), upload,
spInfo.getMaxArtifactFileSize(), upload, null); null, null);
upload.setButtonCaption(i18n.get("upload.file")); upload.setButtonCaption(i18n.get("upload.file"));
upload.setImmediate(true); upload.setImmediate(true);
upload.setReceiver(uploadHandler); upload.setReceiver(uploadHandler);
@@ -154,12 +192,15 @@ public class UploadLayout extends VerticalLayout {
fileUploadLayout = new HorizontalLayout(); fileUploadLayout = new HorizontalLayout();
fileUploadLayout.setSpacing(true); fileUploadLayout.setSpacing(true);
fileUploadLayout.addStyleName(SPUIStyleDefinitions.FOOTER_LAYOUT);
fileUploadLayout.addComponent(upload); fileUploadLayout.addComponent(upload);
fileUploadLayout.setComponentAlignment(upload, Alignment.MIDDLE_LEFT); fileUploadLayout.setComponentAlignment(upload, Alignment.MIDDLE_LEFT);
fileUploadLayout.addComponent(processBtn); fileUploadLayout.addComponent(processBtn);
fileUploadLayout.setComponentAlignment(processBtn, Alignment.MIDDLE_RIGHT); fileUploadLayout.setComponentAlignment(processBtn, Alignment.MIDDLE_RIGHT);
fileUploadLayout.addComponent(discardBtn); fileUploadLayout.addComponent(discardBtn);
fileUploadLayout.setComponentAlignment(discardBtn, Alignment.MIDDLE_RIGHT); fileUploadLayout.setComponentAlignment(discardBtn, Alignment.MIDDLE_RIGHT);
fileUploadLayout.addComponent(uploadStatusButton);
fileUploadLayout.setComponentAlignment(uploadStatusButton, Alignment.MIDDLE_RIGHT);
setMargin(false); setMargin(false);
/* create drag-drop wrapper for drop area */ /* create drag-drop wrapper for drop area */
@@ -167,7 +208,25 @@ public class UploadLayout extends VerticalLayout {
dropAreaWrapper.setDropHandler(new DropAreahandler()); dropAreaWrapper.setDropHandler(new DropAreahandler());
setSizeFull(); setSizeFull();
setSpacing(true); setSpacing(true);
}
private void restoreState() {
updateActionCount();
if (!artifactUploadState.getFileSelected().isEmpty() && artifactUploadState.isUploadCompleted()) {
processBtn.setEnabled(true);
}
if (artifactUploadState.isStatusPopupMinimized()) {
showUploadStatusButton();
if (artifactUploadState.isUploadCompleted()) {
setUploadStatusButtonIconToFinished();
}
}
if (artifactUploadState.isUploadCompleted()) {
artifactUploadState.getNumberOfFilesActuallyUpload().set(0);
artifactUploadState.getNumberOfFileUploadsExpected().set(0);
artifactUploadState.getNumberOfFileUploadsFailed().set(0);
}
} }
public DragAndDropWrapper getDropAreaWrapper() { public DragAndDropWrapper getDropAreaWrapper() {
@@ -187,15 +246,16 @@ public class UploadLayout extends VerticalLayout {
public void drop(final DragAndDropEvent event) { public void drop(final DragAndDropEvent event) {
if (validate(event)) { if (validate(event)) {
final Html5File[] files = ((WrapperTransferable) event.getTransferable()).getFiles(); final Html5File[] files = ((WrapperTransferable) event.getTransferable()).getFiles();
// selected software module at the time of file drop is
// considered for upload
SoftwareModule selectedSw = artifactUploadState.getSelectedBaseSoftwareModule().get();
// reset the flag // reset the flag
hasDirectory = Boolean.FALSE; hasDirectory = Boolean.FALSE;
for (final Html5File file : files) { for (final Html5File file : files) {
processFile(file); processFile(file, selectedSw);
} }
if (numberOfFileUploadsExpected.get() > 0) { if (artifactUploadState.getNumberOfFileUploadsExpected().get() > 0) {
processBtn.setEnabled(false); processBtn.setEnabled(false);
// reset before we start
uploadInfoWindow.uploadSessionStarted();
} else { } else {
// If the upload is not started, it signifies all // If the upload is not started, it signifies all
// dropped files as either duplicate or directory.So // dropped files as either duplicate or directory.So
@@ -205,20 +265,20 @@ public class UploadLayout extends VerticalLayout {
} }
} }
private void processFile(final Html5File file) { private void processFile(final Html5File file, SoftwareModule selectedSw) {
if (!isDirectory(file)) { if (!isDirectory(file)) {
if (!checkForDuplicate(file.getFileName())) { if (!checkForDuplicate(file.getFileName(), selectedSw)) {
numberOfFileUploadsExpected.incrementAndGet(); artifactUploadState.getNumberOfFileUploadsExpected().incrementAndGet();
file.setStreamVariable(createStreamVariable(file)); file.setStreamVariable(createStreamVariable(file, selectedSw));
} }
} else { } else {
hasDirectory = Boolean.TRUE; hasDirectory = Boolean.TRUE;
} }
} }
private StreamVariable createStreamVariable(final Html5File file) { private StreamVariable createStreamVariable(final Html5File file, SoftwareModule selectedSw) {
return new UploadHandler(file.getFileName(), file.getFileSize(), UploadLayout.this, uploadInfoWindow, return new UploadHandler(file.getFileName(), file.getFileSize(), UploadLayout.this,
spInfo.getMaxArtifactFileSize(), null, file.getType()); spInfo.getMaxArtifactFileSize(), null, file.getType(), selectedSw);
} }
private boolean isDirectory(final Html5File file) { private boolean isDirectory(final Html5File file) {
@@ -270,9 +330,7 @@ public class UploadLayout extends VerticalLayout {
processBtn.addStyleName(SPUIStyleDefinitions.ACTION_BUTTON); processBtn.addStyleName(SPUIStyleDefinitions.ACTION_BUTTON);
processBtn.addClickListener(event -> displayConfirmWindow(event)); processBtn.addClickListener(event -> displayConfirmWindow(event));
processBtn.setHtmlContentAllowed(true); processBtn.setHtmlContentAllowed(true);
if (artifactUploadState.getFileSelected().isEmpty()) { processBtn.setEnabled(false);
processBtn.setEnabled(false);
}
} }
private void createDiscardBtn() { private void createDiscardBtn() {
@@ -284,23 +342,14 @@ public class UploadLayout extends VerticalLayout {
discardBtn.addClickListener(event -> discardUploadData(event)); discardBtn.addClickListener(event -> discardUploadData(event));
} }
boolean checkForDuplicate(final String filename) { boolean checkForDuplicate(final String filename, final SoftwareModule selectedSw) {
final Boolean isDuplicate = checkIfFileIsDuplicate(filename); final Boolean isDuplicate = checkIfFileIsDuplicate(filename, selectedSw);
if (isDuplicate) { if (isDuplicate) {
getDuplicateFileNamesList().add(filename); getDuplicateFileNamesList().add(filename);
} }
return isDuplicate; return isDuplicate;
} }
@EventBusListenerMethod(scope = EventScope.SESSION)
void toggleProcessButton(final UploadArtifactUIEvent event) {
if (event == UploadArtifactUIEvent.ENABLE_PROCESS_BUTTON) {
processBtn.setEnabled(true);
} else if (event == UploadArtifactUIEvent.DISABLE_PROCESS_BUTTON) {
processBtn.setEnabled(false);
}
}
/** /**
* Save uploaded file details. * Save uploaded file details.
* *
@@ -312,29 +361,29 @@ public class UploadLayout extends VerticalLayout {
* file size * file size
* @param mimeType * @param mimeType
* the mimeType of the file * the mimeType of the file
* @param selectedSw
* @throws IOException * @throws IOException
* in case of upload errors * in case of upload errors
*/ */
OutputStream saveUploadedFileDetails(final String name, final long size, final String mimeType) { OutputStream saveUploadedFileDetails(final String name, final long size, final String mimeType,
SoftwareModule selectedSw) {
File tempFile = null; File tempFile = null;
try { try {
tempFile = File.createTempFile("spUiArtifactUpload", null); tempFile = File.createTempFile("spUiArtifactUpload", null);
final OutputStream out = new FileOutputStream(tempFile); final OutputStream out = new FileOutputStream(tempFile);
final SoftwareModule selectedSoftwareModule = artifactUploadState.getSelectedBaseSoftwareModule().get(); final String currentBaseSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion(selectedSw.getName(),
selectedSw.getVersion());
final String currentBaseSoftwareModuleKey = HawkbitCommonUtil final CustomFile customFile = new CustomFile(name, size, tempFile.getAbsolutePath(), selectedSw.getName(),
.getFormattedNameVersion(selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion()); selectedSw.getVersion(), mimeType);
final CustomFile customFile = new CustomFile(name, size, tempFile.getAbsolutePath(),
selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion(), mimeType);
artifactUploadState.getFileSelected().add(customFile); artifactUploadState.getFileSelected().add(customFile);
processBtn.setEnabled(false); processBtn.setEnabled(false);
if (!artifactUploadState.getBaseSwModuleList().keySet().contains(currentBaseSoftwareModuleKey)) { if (!artifactUploadState.getBaseSwModuleList().keySet().contains(currentBaseSoftwareModuleKey)) {
artifactUploadState.getBaseSwModuleList().put(currentBaseSoftwareModuleKey, selectedSoftwareModule); artifactUploadState.getBaseSwModuleList().put(currentBaseSoftwareModuleKey, selectedSw);
} }
return out; return out;
} catch (final FileNotFoundException e) { } catch (final FileNotFoundException e) {
@@ -344,6 +393,7 @@ public class UploadLayout extends VerticalLayout {
LOG.error("Upload failed {}", e); LOG.error("Upload failed {}", e);
throw new ArtifactUploadFailedException(i18n.get("message.upload.failed")); throw new ArtifactUploadFailedException(i18n.get("message.upload.failed"));
} }
} }
Boolean validate(final DragAndDropEvent event) { Boolean validate(final DragAndDropEvent event) {
@@ -378,13 +428,6 @@ public class UploadLayout extends VerticalLayout {
return true; return true;
} }
SoftwareModule getSoftwareModuleSelected() {
if (artifactUploadState.getSelectedBaseSoftwareModule().isPresent()) {
return artifactUploadState.getSelectedBaseSoftwareModule().get();
}
return null;
}
Boolean isSoftwareModuleSelected() { Boolean isSoftwareModuleSelected() {
if (!artifactUploadState.getSelectedBaseSwModuleId().isPresent()) { if (!artifactUploadState.getSelectedBaseSwModuleId().isPresent()) {
return false; return false;
@@ -400,11 +443,10 @@ public class UploadLayout extends VerticalLayout {
* file name * file name
* @return Boolean * @return Boolean
*/ */
public Boolean checkIfFileIsDuplicate(final String name) { public Boolean checkIfFileIsDuplicate(final String name, final SoftwareModule selectedSoftwareModule) {
Boolean isDuplicate = false; Boolean isDuplicate = false;
final SoftwareModule selectedSoftwareModule = artifactUploadState.getSelectedBaseSoftwareModule().get(); final String currentBaseSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion(
final String currentBaseSoftwareModuleKey = HawkbitCommonUtil selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion());
.getFormattedNameVersion(selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion());
for (final CustomFile customFile : artifactUploadState.getFileSelected()) { for (final CustomFile customFile : artifactUploadState.getFileSelected()) {
final String fileSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion( final String fileSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion(
@@ -418,7 +460,7 @@ public class UploadLayout extends VerticalLayout {
} }
void decreaseNumberOfFileUploadsExpected() { void decreaseNumberOfFileUploadsExpected() {
numberOfFileUploadsExpected.decrementAndGet(); artifactUploadState.getNumberOfFileUploadsExpected().decrementAndGet();
} }
List<String> getDuplicateFileNamesList() { List<String> getDuplicateFileNamesList() {
@@ -439,8 +481,10 @@ public class UploadLayout extends VerticalLayout {
void displayDuplicateValidationMessage() { void displayDuplicateValidationMessage() {
// check if streaming of all dropped files are completed // check if streaming of all dropped files are completed
if (numberOfFilesActuallyUpload.intValue() == numberOfFileUploadsExpected.intValue()) { if (artifactUploadState.getNumberOfFilesActuallyUpload().intValue() == artifactUploadState
.getNumberOfFileUploadsExpected().intValue()) {
displayCompositeMessage(); displayCompositeMessage();
duplicateFileNamesList.clear();
} }
} }
@@ -454,7 +498,6 @@ public class UploadLayout extends VerticalLayout {
} else if (duplicateFileNamesList.size() > 1) { } else if (duplicateFileNamesList.size() > 1) {
message.append(i18n.get("message.no.duplicateFiles")); message.append(i18n.get("message.no.duplicateFiles"));
} }
duplicateFileNamesList.clear();
} }
return message.toString(); return message.toString();
} }
@@ -464,13 +507,12 @@ public class UploadLayout extends VerticalLayout {
} }
void increaseNumberOfFileUploadsExpected() { void increaseNumberOfFileUploadsExpected() {
numberOfFileUploadsExpected.incrementAndGet(); artifactUploadState.getNumberOfFileUploadsExpected().incrementAndGet();
} }
void updateFileSize(final String name, final long size) { void updateFileSize(final String name, final long size, SoftwareModule selectedSoftwareModule) {
final SoftwareModule selectedSoftwareModule = artifactUploadState.getSelectedBaseSoftwareModule().get(); final String currentBaseSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion(
final String currentBaseSoftwareModuleKey = HawkbitCommonUtil selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion());
.getFormattedNameVersion(selectedSoftwareModule.getName(), selectedSoftwareModule.getVersion());
for (final CustomFile customFile : artifactUploadState.getFileSelected()) { for (final CustomFile customFile : artifactUploadState.getFileSelected()) {
final String fileSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion( final String fileSoftwareModuleKey = HawkbitCommonUtil.getFormattedNameVersion(
@@ -483,17 +525,22 @@ public class UploadLayout extends VerticalLayout {
} }
void increaseNumberOfFilesActuallyUpload() { void increaseNumberOfFilesActuallyUpload() {
numberOfFilesActuallyUpload.incrementAndGet(); artifactUploadState.getNumberOfFilesActuallyUpload().incrementAndGet();
}
void increaseNumberOfFileUploadsFailed() {
artifactUploadState.getNumberOfFileUploadsFailed().incrementAndGet();
} }
/** /**
* Enable process button once upload is completed. * Enable process button once upload is completed.
*/ */
boolean enableProcessBtn() { boolean enableProcessBtn() {
if (numberOfFilesActuallyUpload.intValue() >= numberOfFileUploadsExpected.intValue()) { if (artifactUploadState.getNumberOfFilesActuallyUpload().intValue() >= artifactUploadState
.getNumberOfFileUploadsExpected().intValue() && !getFileSelected().isEmpty()) {
processBtn.setEnabled(true); processBtn.setEnabled(true);
numberOfFileUploadsExpected.set(0); artifactUploadState.getNumberOfFilesActuallyUpload().set(0);
numberOfFilesActuallyUpload.set(0); artifactUploadState.getNumberOfFileUploadsExpected().set(0);
return true; return true;
} }
return false; return false;
@@ -507,13 +554,23 @@ public class UploadLayout extends VerticalLayout {
if (event.getButton().equals(discardBtn)) { if (event.getButton().equals(discardBtn)) {
if (artifactUploadState.getFileSelected().isEmpty()) { if (artifactUploadState.getFileSelected().isEmpty()) {
uiNotification.displayValidationError(i18n.get("message.error.noFileSelected")); uiNotification.displayValidationError(i18n.get("message.error.noFileSelected"));
} else { } else {
clearFileList(); clearUploadedFileDetails();
} }
} }
} }
protected void clearUploadedFileDetails() {
clearFileList();
closeUploadStatusPopup();
}
private void closeUploadStatusPopup() {
uploadInfoWindow.clearWindow();
hideUploadStatusButton();
artifactUploadState.setStatusPopupMinimized(false);
}
/** /**
* Clear details. * Clear details.
*/ */
@@ -529,19 +586,20 @@ public class UploadLayout extends VerticalLayout {
processBtn.setCaption(SPUILabelDefinitions.PROCESS); processBtn.setCaption(SPUILabelDefinitions.PROCESS);
/* disable when there is no files to upload. */ /* disable when there is no files to upload. */
processBtn.setEnabled(false); processBtn.setEnabled(false);
numberOfFileUploadsExpected.set(0); artifactUploadState.getNumberOfFilesActuallyUpload().set(0);
numberOfFilesActuallyUpload.set(0); artifactUploadState.getNumberOfFileUploadsExpected().set(0);
artifactUploadState.getNumberOfFileUploadsFailed().set(0);
duplicateFileNamesList.clear(); duplicateFileNamesList.clear();
} }
private void setConfirmationPopupHeightWidth(final float newWidth, final float newHeight) { private void setConfirmationPopupHeightWidth(final float newWidth, final float newHeight) {
if (currentUploadConfirmationwindow != null) { if (currentUploadConfirmationwindow != null) {
currentUploadConfirmationwindow.getUploadArtifactDetails().setWidth(HawkbitCommonUtil currentUploadConfirmationwindow.getUploadArtifactDetails().setWidth(
.getArtifactUploadPopupWidth(newWidth, SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_WIDTH), HawkbitCommonUtil.getArtifactUploadPopupWidth(newWidth,
Unit.PIXELS); SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_WIDTH), Unit.PIXELS);
currentUploadConfirmationwindow.getUploadDetailsTable().setHeight(HawkbitCommonUtil currentUploadConfirmationwindow.getUploadDetailsTable().setHeight(
.getArtifactUploadPopupHeight(newHeight, SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_HEIGHT), HawkbitCommonUtil.getArtifactUploadPopupHeight(newHeight,
Unit.PIXELS); SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_HEIGHT), Unit.PIXELS);
} }
} }
@@ -558,10 +616,12 @@ public class UploadLayout extends VerticalLayout {
&& currentUploadConfirmationwindow.getCurrentUploadResultWindow() != null) { && currentUploadConfirmationwindow.getCurrentUploadResultWindow() != null) {
final UploadResultWindow uploadResultWindow = currentUploadConfirmationwindow final UploadResultWindow uploadResultWindow = currentUploadConfirmationwindow
.getCurrentUploadResultWindow(); .getCurrentUploadResultWindow();
uploadResultWindow.getUploadResultsWindow().setWidth(HawkbitCommonUtil.getArtifactUploadPopupWidth(newWidth, uploadResultWindow.getUploadResultsWindow().setWidth(
SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_WIDTH), Unit.PIXELS); HawkbitCommonUtil.getArtifactUploadPopupWidth(newWidth,
uploadResultWindow.getUploadResultTable().setHeight(HawkbitCommonUtil.getArtifactUploadPopupHeight( SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_WIDTH), Unit.PIXELS);
newHeight, SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_HEIGHT), Unit.PIXELS); uploadResultWindow.getUploadResultTable().setHeight(
HawkbitCommonUtil.getArtifactUploadPopupHeight(newHeight,
SPUIDefinitions.MIN_UPLOAD_CONFIRMATION_POPUP_HEIGHT), Unit.PIXELS);
} }
} }
@@ -572,8 +632,8 @@ public class UploadLayout extends VerticalLayout {
} else { } else {
currentUploadConfirmationwindow = new UploadConfirmationwindow(this, artifactUploadState); currentUploadConfirmationwindow = new UploadConfirmationwindow(this, artifactUploadState);
UI.getCurrent().addWindow(currentUploadConfirmationwindow.getUploadConfrimationWindow()); UI.getCurrent().addWindow(currentUploadConfirmationwindow.getUploadConfrimationWindow());
setConfirmationPopupHeightWidth(Page.getCurrent().getBrowserWindowWidth(), setConfirmationPopupHeightWidth(Page.getCurrent().getBrowserWindowWidth(), Page.getCurrent()
Page.getCurrent().getBrowserWindowHeight()); .getBrowserWindowHeight());
} }
} }
} }
@@ -599,25 +659,101 @@ public class UploadLayout extends VerticalLayout {
/** /**
* @return * @return
*/ */
VerticalLayout getDropAreaLayout() { VerticalLayout getDropAreaLayout() {
return dropAreaLayout; return dropAreaLayout;
} }
@EventBusListenerMethod(scope = EventScope.SESSION) private void onStartOfUpload() {
void onEvent(final UploadArtifactUIEvent event) { setUploadStatusButtonIconToInProgress();
if (event == UploadArtifactUIEvent.DELETED_ALL_SOFWARE) { if (artifactUploadState.isStatusPopupMinimized()) {
ui.access(() -> updateActionCount()); updateStatusButtonCount();
} }
} }
@PreDestroy private void onUploadStreamingSuccess() {
void destroy() { increaseNumberOfFilesActuallyUpload();
/* updateUploadCounts();
* It's good manners to do this, even though vaadin-spring will enableProcessBtn();
* automatically unsubscribe when this UI is garbage collected. if (isUploadComplete()) {
*/ uploadInfoWindow.uploadSessionFinished();
eventBus.unsubscribe(this); setUploadStatusButtonIconToFinished();
}
// display the duplicate message after streaming all files
displayDuplicateValidationMessage();
}
private void onUploadStreamingFailure(UploadStatusEvent event) {
/**
* If upload interrupted because of duplicate file,do not remove the
* file already in upload list
**/
if (getDuplicateFileNamesList().isEmpty()
|| !getDuplicateFileNamesList().contains(event.getUploadStatus().getFileName())) {
final SoftwareModule sw = event.getUploadStatus().getSoftwareModule();
if (sw != null) {
getFileSelected().remove(
new CustomFile(event.getUploadStatus().getFileName(), sw.getName(), sw.getVersion()));
}
// failed reason to be updated only if there is error other than
// duplicate file error
uploadInfoWindow.uploadFailed(event.getUploadStatus().getFileName(), event.getUploadStatus()
.getFailureReason(), event.getUploadStatus().getSoftwareModule());
increaseNumberOfFileUploadsFailed();
}
decreaseNumberOfFileUploadsExpected();
updateUploadCounts();
enableProcessBtn();
// check if we are finished
if (isUploadComplete()) {
uploadInfoWindow.uploadSessionFinished();
setUploadStatusButtonIconToFinished();
}
displayDuplicateValidationMessage();
}
private void onUploadSuccess(UploadStatusEvent event) {
updateFileSize(event.getUploadStatus().getFileName(), event.getUploadStatus().getContentLength(), event
.getUploadStatus().getSoftwareModule());
// recorded that we now one more uploaded
increaseNumberOfFilesActuallyUpload();
}
private void onUploadCompletion() {
// check if we are finished
if (isUploadComplete()) {
uploadInfoWindow.uploadSessionFinished();
setUploadStatusButtonIconToFinished();
displayDuplicateValidationMessage();
}
updateUploadCounts();
enableProcessBtn();
}
private boolean isUploadComplete() {
int uploadedCount = artifactUploadState.getNumberOfFilesActuallyUpload().intValue();
int expectedUploadsCount = artifactUploadState.getNumberOfFileUploadsExpected().intValue();
return uploadedCount == expectedUploadsCount;
}
private void onUploadFailure(final UploadStatusEvent event) {
/**
* If upload interrupted because of duplicate file,do not remove the
* file already in upload list
**/
if (getDuplicateFileNamesList().isEmpty()
|| !getDuplicateFileNamesList().contains(event.getUploadStatus().getFileName())) {
final SoftwareModule sw = event.getUploadStatus().getSoftwareModule();
if (sw != null) {
getFileSelected().remove(
new CustomFile(event.getUploadStatus().getFileName(), sw.getName(), sw.getVersion()));
}
// failed reason to be updated only if there is error other than
// duplicate file error
uploadInfoWindow.uploadFailed(event.getUploadStatus().getFileName(), event.getUploadStatus()
.getFailureReason(), event.getUploadStatus().getSoftwareModule());
increaseNumberOfFileUploadsFailed();
decreaseNumberOfFileUploadsExpected();
}
} }
/** /**
@@ -637,8 +773,8 @@ public class UploadLayout extends VerticalLayout {
* @param selectedBaseSoftwareModule * @param selectedBaseSoftwareModule
*/ */
public void refreshArtifactDetailsLayout(final SoftwareModule selectedBaseSoftwareModule) { public void refreshArtifactDetailsLayout(final SoftwareModule selectedBaseSoftwareModule) {
eventBus.publish(this, eventBus.publish(this, new SoftwareModuleEvent(SoftwareModuleEventType.ARTIFACTS_CHANGED,
new SoftwareModuleEvent(SoftwareModuleEventType.ARTIFACTS_CHANGED, selectedBaseSoftwareModule)); selectedBaseSoftwareModule));
} }
/** /**
@@ -655,4 +791,79 @@ public class UploadLayout extends VerticalLayout {
public void setHasDirectory(final Boolean hasDirectory) { public void setHasDirectory(final Boolean hasDirectory) {
this.hasDirectory = hasDirectory; this.hasDirectory = hasDirectory;
} }
private void createUploadStatusButton() {
uploadStatusButton = SPUIComponentProvider.getButton(SPUIComponentIdProvider.UPLOAD_STATUS_BUTTON, "", "", "",
false, null, SPUIButtonStyleSmall.class);
uploadStatusButton.setStyleName(SPUIStyleDefinitions.ACTION_BUTTON);
uploadStatusButton.addStyleName(SPUIStyleDefinitions.UPLOAD_PROGRESS_INDICATOR_STYLE);
uploadStatusButton.setWidth("100px");
uploadStatusButton.setHtmlContentAllowed(true);
uploadStatusButton.addClickListener(event -> onClickOfUploadStatusButton());
uploadStatusButton.setVisible(false);
}
void updateStatusButtonCount() {
int uploadsPending = artifactUploadState.getNumberOfFileUploadsExpected().get()
- artifactUploadState.getNumberOfFilesActuallyUpload().get();
int uploadsFailed = artifactUploadState.getNumberOfFileUploadsFailed().get();
StringBuilder builder = new StringBuilder("");
if (uploadsFailed != 0) {
if (uploadsPending != 0) {
builder.append("<div class='error-count error-count-color'>" + uploadsFailed + "</div>");
} else {
builder.append("<div class='unread error-count-color'>" + uploadsFailed + "</div>");
}
}
if (uploadsPending != 0) {
builder.append("<div class='unread'>" + uploadsPending + "</div>");
}
uploadStatusButton.setCaption(builder.toString());
}
private void onClickOfUploadStatusButton() {
artifactUploadState.setStatusPopupMinimized(false);
eventBus.publish(this, UploadArtifactUIEvent.MAXIMIZED_STATUS_POPUP);
}
private void showUploadStatusButton() {
if (uploadStatusButton == null) {
return;
}
uploadStatusButton.setVisible(true);
updateStatusButtonCount();
}
protected void hideUploadStatusButton() {
if (uploadStatusButton == null) {
return;
}
uploadStatusButton.setVisible(false);
}
private void maximizeStatusPopup() {
hideUploadStatusButton();
uploadInfoWindow.maximizeStatusPopup();
}
private void setUploadStatusButtonIconToFinished() {
if (uploadStatusButton == null) {
return;
}
uploadStatusButton.removeStyleName(SPUIStyleDefinitions.UPLOAD_PROGRESS_INDICATOR_STYLE);
uploadStatusButton.setIcon(FontAwesome.UPLOAD);
}
private void setUploadStatusButtonIconToInProgress() {
if (uploadStatusButton == null) {
return;
}
uploadStatusButton.addStyleName(SPUIStyleDefinitions.UPLOAD_PROGRESS_INDICATOR_STYLE);
uploadStatusButton.setIcon(null);
}
protected void updateUploadCounts() {
updateActionCount();
updateStatusButtonCount();
}
} }

View File

@@ -11,6 +11,7 @@ package org.eclipse.hawkbit.ui.artifacts.upload;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleTiny; import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleTiny;
import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil; import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
@@ -19,6 +20,8 @@ import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.SPUIDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions; import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.eclipse.hawkbit.ui.utils.SpringContextHelper;
import org.vaadin.spring.events.EventBus;
import com.vaadin.data.Item; import com.vaadin.data.Item;
import com.vaadin.data.util.IndexedContainer; import com.vaadin.data.util.IndexedContainer;
@@ -63,6 +66,9 @@ public class UploadResultWindow implements Button.ClickListener {
private static final String UPLOAD_RESULT = "uploadResult"; private static final String UPLOAD_RESULT = "uploadResult";
private static final String REASON = "reason"; private static final String REASON = "reason";
private transient EventBus.SessionEventBus eventBus;
/** /**
* Initialize upload status popup. * Initialize upload status popup.
@@ -75,6 +81,7 @@ public class UploadResultWindow implements Button.ClickListener {
public UploadResultWindow(final List<UploadStatus> uploadResultList, final I18N i18n) { public UploadResultWindow(final List<UploadStatus> uploadResultList, final I18N i18n) {
this.uploadResultList = uploadResultList; this.uploadResultList = uploadResultList;
this.i18n = i18n; this.i18n = i18n;
eventBus = SpringContextHelper.getBean( EventBus.SessionEventBus.class);
createComponents(); createComponents();
createLayout(); createLayout();
} }
@@ -183,6 +190,8 @@ public class UploadResultWindow implements Button.ClickListener {
if (event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_ARTIFACT_RESULT_CLOSE) if (event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_ARTIFACT_RESULT_CLOSE)
|| event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_ARTIFACT_RESULT_POPUP_CLOSE)) { || event.getComponent().getId().equals(SPUIComponentIdProvider.UPLOAD_ARTIFACT_RESULT_POPUP_CLOSE)) {
uploadResultsWindow.close(); uploadResultsWindow.close();
//close upload status popup if open
eventBus.publish(this, UploadArtifactUIEvent.ARTIFACT_RESULT_POPUP_CLOSED);
} }
} }

View File

@@ -8,20 +8,49 @@
*/ */
package org.eclipse.hawkbit.ui.artifacts.upload; package org.eclipse.hawkbit.ui.artifacts.upload;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions; import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.ui.artifacts.event.UploadArtifactUIEvent;
import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent;
import org.eclipse.hawkbit.ui.artifacts.event.UploadStatusEvent.UploadStatusEventType;
import org.eclipse.hawkbit.ui.artifacts.state.ArtifactUploadState;
import org.eclipse.hawkbit.ui.common.ConfirmationDialog;
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
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.SPUILabelDefinitions;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.springframework.beans.factory.annotation.Autowired;
import org.vaadin.spring.events.EventBus;
import org.vaadin.spring.events.EventScope;
import org.vaadin.spring.events.annotation.EventBusListenerMethod;
import com.vaadin.data.Container.Indexed;
import com.vaadin.data.Item; import com.vaadin.data.Item;
import com.vaadin.data.util.IndexedContainer; import com.vaadin.data.util.IndexedContainer;
import com.vaadin.server.FontAwesome; import com.vaadin.server.FontAwesome;
import com.vaadin.shared.ui.window.WindowMode; import com.vaadin.shared.ui.window.WindowMode;
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.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Grid; import com.vaadin.ui.Grid;
import com.vaadin.ui.Grid.SelectionMode; import com.vaadin.ui.Grid.SelectionMode;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI; import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window; import com.vaadin.ui.Window;
import com.vaadin.ui.renderers.HtmlRenderer; import com.vaadin.ui.renderers.HtmlRenderer;
import com.vaadin.ui.renderers.ProgressBarRenderer; import com.vaadin.ui.renderers.ProgressBarRenderer;
import com.vaadin.ui.themes.ValoTheme;
import elemental.json.JsonValue; import elemental.json.JsonValue;
@@ -34,7 +63,16 @@ import elemental.json.JsonValue;
@ViewScope @ViewScope
@SpringComponent @SpringComponent
public class UploadStatusInfoWindow extends Window implements Window.CloseListener, Window.WindowModeChangeListener { public class UploadStatusInfoWindow extends Window {
@Autowired
private transient EventBus.SessionEventBus eventBus;
@Autowired
private ArtifactUploadState artifactUploadState;
@Autowired
private I18N i18n;
private static final String PROGRESS = "Progress"; private static final String PROGRESS = "Progress";
@@ -46,52 +84,173 @@ public class UploadStatusInfoWindow extends Window implements Window.CloseListen
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final Grid grid; private Grid grid;
private final IndexedContainer uploads; private IndexedContainer uploads;
private volatile boolean errorOccured = false; private volatile boolean errorOccured = false;
private volatile boolean uploadAborted = false;
private Button minimizeButton;
private VerticalLayout mainLayout;
private Label windowCaption;
private Button closeButton;
private Button resizeButton;
private UI ui;
private ConfirmationDialog confirmDialog;
/** /**
* Default Constructor. * Default Constructor.
*/ */
UploadStatusInfoWindow() { @PostConstruct
super("Upload Status"); void init() {
addStyleName(SPUIStyleDefinitions.UPLOAD_INFO); setPopupProperties();
center(); createStatusPopupHeaderComponents();
setImmediate(true);
setResizable(true);
setDraggable(true);
setClosable(true);
uploads = new IndexedContainer();
uploads.addContainerProperty(STATUS, String.class, "Active");
uploads.addContainerProperty(FILE_NAME, String.class, null);
uploads.addContainerProperty(PROGRESS, Double.class, 0D);
uploads.addContainerProperty(REASON, String.class, "");
grid = new Grid(uploads); mainLayout = new VerticalLayout();
grid.addStyleName(SPUIStyleDefinitions.UPLOAD_STATUS_GRID); mainLayout.setSpacing(Boolean.TRUE);
grid.setSelectionMode(SelectionMode.NONE); mainLayout.setSizeUndefined();
grid.getColumn(STATUS).setRenderer(new StatusRenderer());
grid.getColumn(PROGRESS).setRenderer(new ProgressBarRenderer());
setColumnWidth();
grid.setFrozenColumnCount(4);
grid.setColumnOrder(STATUS, PROGRESS, FILE_NAME, REASON);
grid.setHeaderVisible(true);
grid.setImmediate(true);
setPopupSizeInMinMode(); setPopupSizeInMinMode();
setContent(grid); uploads = getGridContainer();
addCloseListener(this); grid = createGrid();
addWindowModeChangeListener(this); setGridColumnProperties();
mainLayout.addComponents(getCaptionLayout(), grid);
mainLayout.setExpandRatio(grid, 1.0F);
setContent(mainLayout);
eventBus.subscribe(this);
ui = UI.getCurrent();
createConfirmDialog();
}
@EventBusListenerMethod(scope = EventScope.SESSION)
void onEvent(final UploadStatusEvent event) {
if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_IN_PROGRESS) {
UI.getCurrent().access(
() -> updateProgress(event.getUploadStatus().getFileName(), event.getUploadStatus().getBytesRead(),
event.getUploadStatus().getContentLength(), event.getUploadStatus().getSoftwareModule()));
} else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STARTED) {
UI.getCurrent().access(() -> onStartOfUpload(event));
} else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STREAMING_FAILED) {
ui.access(() -> uploadFailed(event.getUploadStatus().getFileName(), event.getUploadStatus()
.getFailureReason(), event.getUploadStatus().getSoftwareModule()));
} else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_SUCCESSFUL) {
UI.getCurrent().access(
() -> uploadSucceeded(event.getUploadStatus().getFileName(), event.getUploadStatus()
.getSoftwareModule()));
} else if (event.getUploadProgressEventType() == UploadStatusEventType.UPLOAD_STREAMING_FINISHED) {
ui.access(() -> uploadSucceeded(event.getUploadStatus().getFileName(), event.getUploadStatus()
.getSoftwareModule()));
}
}
private void onStartOfUpload(UploadStatusEvent event) {
uploadSessionStarted();
uploadStarted(event.getUploadStatus().getFileName(), event.getUploadStatus().getSoftwareModule());
}
@PreDestroy
void destroy() {
/*
* It's good manners to do this, even though vaadin-spring will
* automatically unsubscribe when this UI is garbage collected.
*/
eventBus.unsubscribe(this);
}
private void restoreState() {
Indexed container = grid.getContainerDataSource();
if (container.getItemIds().isEmpty()) {
container.removeAllItems();
for (UploadStatusObject statusObject : artifactUploadState.getUploadedFileStatusList()) {
Item item = container.addItem(getItemid(statusObject.getFilename(),
statusObject.getSelectedSoftwareModule()));
item.getItemProperty(REASON).setValue(statusObject.getReason() != null ? statusObject.getReason() : "");
item.getItemProperty(STATUS).setValue(statusObject.getStatus());
item.getItemProperty(PROGRESS).setValue(statusObject.getProgress());
item.getItemProperty(FILE_NAME).setValue(statusObject.getFilename());
SoftwareModule sw = statusObject.getSelectedSoftwareModule();
item.getItemProperty(SPUILabelDefinitions.NAME_VERSION).setValue(
HawkbitCommonUtil.getFormattedNameVersion(sw.getName(), sw.getVersion()));
}
if (artifactUploadState.isUploadCompleted()) {
minimizeButton.setEnabled(false);
}
}
}
private void setPopupProperties() {
setId(SPUIComponentIdProvider.UPLOAD_STATUS_POPUP_ID);
addStyleName(SPUIStyleDefinitions.UPLOAD_INFO);
setImmediate(true);
setResizable(false);
setDraggable(true);
setClosable(false);
setModal(true);
}
private void setGridColumnProperties() {
grid.getColumn(STATUS).setRenderer(new StatusRenderer());
grid.getColumn(PROGRESS).setRenderer(new ProgressBarRenderer());
grid.setColumnOrder(STATUS, PROGRESS, FILE_NAME, SPUILabelDefinitions.NAME_VERSION, REASON);
setColumnWidth();
grid.getColumn(SPUILabelDefinitions.NAME_VERSION).setHeaderCaption(i18n.get("upload.swModuleTable.header"));
grid.setFrozenColumnCount(5);
}
private Grid createGrid() {
Grid statusGrid = new Grid(uploads);
statusGrid.addStyleName(SPUIStyleDefinitions.UPLOAD_STATUS_GRID);
statusGrid.setSelectionMode(SelectionMode.NONE);
statusGrid.setHeaderVisible(true);
statusGrid.setImmediate(true);
statusGrid.setSizeFull();
return statusGrid;
}
private IndexedContainer getGridContainer() {
IndexedContainer uploadContainer = new IndexedContainer();
uploadContainer.addContainerProperty(STATUS, String.class, "Active");
uploadContainer.addContainerProperty(FILE_NAME, String.class, null);
uploadContainer.addContainerProperty(PROGRESS, Double.class, 0D);
uploadContainer.addContainerProperty(REASON, String.class, "");
uploadContainer.addContainerProperty(SPUILabelDefinitions.NAME_VERSION, String.class, "");
return uploadContainer;
}
private HorizontalLayout getCaptionLayout() {
final HorizontalLayout captionLayout = new HorizontalLayout();
captionLayout.setSizeFull();
captionLayout.setHeight("36px");
captionLayout.addComponents(windowCaption, minimizeButton, resizeButton, closeButton);
captionLayout.setExpandRatio(windowCaption, 1.0F);
captionLayout.addStyleName("v-window-header");
return captionLayout;
}
private void createStatusPopupHeaderComponents() {
minimizeButton = getMinimizeButton();
windowCaption = new Label("Upload status");
closeButton = getCloseButton();
resizeButton = getResizeButton();
} }
private void setColumnWidth() { private void setColumnWidth() {
grid.getColumn(STATUS).setWidth(70); grid.getColumn(STATUS).setWidth(60);
grid.getColumn(PROGRESS).setWidth(150); grid.getColumn(PROGRESS).setWidth(150);
grid.getColumn(FILE_NAME).setWidth(280); grid.getColumn(FILE_NAME).setWidth(200);
grid.getColumn(REASON).setWidth(300); grid.getColumn(REASON).setWidth(290);
grid.getColumn(SPUILabelDefinitions.NAME_VERSION).setWidth(200);
} }
private void resetColumnWidth() { private void resetColumnWidth() {
@@ -99,15 +258,16 @@ public class UploadStatusInfoWindow extends Window implements Window.CloseListen
grid.getColumn(PROGRESS).setWidthUndefined(); grid.getColumn(PROGRESS).setWidthUndefined();
grid.getColumn(FILE_NAME).setWidthUndefined(); grid.getColumn(FILE_NAME).setWidthUndefined();
grid.getColumn(REASON).setWidthUndefined(); grid.getColumn(REASON).setWidthUndefined();
grid.getColumn(SPUILabelDefinitions.NAME_VERSION).setWidthUndefined();
} }
private static class StatusRenderer extends HtmlRenderer { private static class StatusRenderer extends HtmlRenderer {
private static final long serialVersionUID = -5365795450234970943L;
@Override @Override
public JsonValue encode(final String value) { public JsonValue encode(final String value) {
String result;
String result = "";
switch (value) { switch (value) {
case "Finished": case "Finished":
result = "<div class=\"statusIconGreen\">" + FontAwesome.CHECK_CIRCLE.getHtml() + "</div>"; result = "<div class=\"statusIconGreen\">" + FontAwesome.CHECK_CIRCLE.getHtml() + "</div>";
@@ -127,30 +287,66 @@ public class UploadStatusInfoWindow extends Window implements Window.CloseListen
* Automatically close if not error has occured. * Automatically close if not error has occured.
*/ */
void uploadSessionFinished() { void uploadSessionFinished() {
if (!errorOccured) { uploadAborted = false;
close(); if (!errorOccured && !artifactUploadState.isStatusPopupMinimized()) {
clearWindow();
} }
artifactUploadState.setUploadCompleted(true);
minimizeButton.setEnabled(false);
closeButton.setEnabled(true);
confirmDialog.getWindow().close();
UI.getCurrent().removeWindow(confirmDialog.getWindow());
} }
void uploadSessionStarted() { void uploadSessionStarted() {
close(); if (artifactUploadState.getNumberOfFilesActuallyUpload().intValue() == 0
&& artifactUploadState.getNumberOfFileUploadsFailed().intValue() == 0
&& !artifactUploadState.isStatusPopupMinimized()) {
openWindow();
}
if (!uploadAborted) {
minimizeButton.setEnabled(true);
closeButton.setEnabled(true);
artifactUploadState.setUploadCompleted(false);
}
}
void openWindow() {
UI.getCurrent().addWindow(this); UI.getCurrent().addWindow(this);
center(); center();
} }
void uploadStarted(final String filename) { void maximizeStatusPopup() {
final Item item = uploads.addItem(filename); openWindow();
item.getItemProperty(FILE_NAME).setValue(filename); restoreState();
grid.scrollToEnd();
} }
void updateProgress(final String filename, final long readBytes, final long contentLength) { void uploadStarted(final String filename, final SoftwareModule softwareModule) {
final Item item = uploads.getItem(filename); final Item item = uploads.addItem(getItemid(filename, softwareModule));
if (item != null) { if (item != null) {
item.getItemProperty(PROGRESS).setValue((double) readBytes / (double) contentLength); item.getItemProperty(FILE_NAME).setValue(filename);
item.getItemProperty(SPUILabelDefinitions.NAME_VERSION).setValue(
HawkbitCommonUtil.getFormattedNameVersion(softwareModule.getName(), softwareModule.getVersion()));
}
grid.scrollToEnd();
UploadStatusObject uploadStatus = new UploadStatusObject(filename, softwareModule);
uploadStatus.setStatus("Active");
artifactUploadState.getUploadedFileStatusList().add(uploadStatus);
}
void updateProgress(final String filename, final long readBytes, final long contentLength,
final SoftwareModule softwareModule) {
final Item item = uploads.getItem(getItemid(filename, softwareModule));
double progress = (double) readBytes / (double) contentLength;
if (item != null) {
item.getItemProperty(PROGRESS).setValue(progress);
}
List<UploadStatusObject> uploadStatusObjectList = (List<UploadStatusObject>) artifactUploadState
.getUploadedFileStatusList().stream().filter(e -> e.getFilename().equals(filename))
.collect(Collectors.toList());
if (!uploadStatusObjectList.isEmpty()) {
UploadStatusObject uploadStatusObject = uploadStatusObjectList.get(0);
uploadStatusObject.setProgress(progress);
} }
} }
@@ -159,67 +355,142 @@ public class UploadStatusInfoWindow extends Window implements Window.CloseListen
* *
* @param filename * @param filename
* of the uploaded file. * of the uploaded file.
* @param softwareModule
* selected software module
*/ */
public void uploadSucceeded(final String filename) { public void uploadSucceeded(final String filename, SoftwareModule softwareModule) {
final Item item = uploads.getItem(filename); final Item item = uploads.getItem(getItemid(filename, softwareModule));
String status = "Finished";
if (item != null) { if (item != null) {
item.getItemProperty(STATUS).setValue("Finished"); item.getItemProperty(STATUS).setValue(status);
}
List<UploadStatusObject> uploadStatusObjectList = (List<UploadStatusObject>) artifactUploadState
.getUploadedFileStatusList().stream().filter(e -> e.getFilename().equals(filename))
.collect(Collectors.toList());
if (!uploadStatusObjectList.isEmpty()) {
UploadStatusObject uploadStatusObject = uploadStatusObjectList.get(0);
uploadStatusObject.setStatus(status);
uploadStatusObject.setProgress(1d);
} }
} }
void uploadFailed(final String filename, final String errorReason) { void uploadFailed(final String filename, final String errorReason, SoftwareModule softwareModule) {
final Item item = uploads.getItem(filename); errorOccured = true;
String status = "Failed";
final Item item = uploads.getItem(getItemid(filename, softwareModule));
if (item != null) { if (item != null) {
if (!errorOccured) {
errorOccured = true;
}
item.getItemProperty(REASON).setValue(errorReason); item.getItemProperty(REASON).setValue(errorReason);
item.getItemProperty(STATUS).setValue("Failed"); item.getItemProperty(STATUS).setValue(status);
}
List<UploadStatusObject> uploadStatusObjectList = (List<UploadStatusObject>) artifactUploadState
.getUploadedFileStatusList().stream().filter(e -> e.getFilename().equals(filename))
.collect(Collectors.toList());
if (!uploadStatusObjectList.isEmpty()) {
UploadStatusObject uploadStatusObject = uploadStatusObjectList.get(0);
uploadStatusObject.setStatus(status);
uploadStatusObject.setReason(errorReason);
} }
} }
/* protected void clearWindow() {
* (non-Javadoc)
*
* @see com.vaadin.ui.Window.CloseListener#windowClose(com.vaadin.ui.Window.
* CloseEvent)
*/
@Override
public void windowClose(final CloseEvent e) {
clearWindow();
}
private void clearWindow() {
errorOccured = false; errorOccured = false;
uploads.removeAllItems(); uploads.removeAllItems();
setWindowMode(WindowMode.NORMAL); setWindowMode(WindowMode.NORMAL);
setColumnWidth();
setPopupSizeInMinMode();
resizeButton.setIcon(FontAwesome.EXPAND);
this.close();
artifactUploadState.getUploadedFileStatusList().clear();
artifactUploadState.getNumberOfFileUploadsFailed().set(0);
} }
/* private void setPopupSizeInMinMode() {
* (non-Javadoc) mainLayout.setWidth(900, Unit.PIXELS);
* mainLayout.setHeight(510, Unit.PIXELS);
* @see com.vaadin.ui.Window.WindowModeChangeListener#windowModeChanged(com. }
* vaadin.ui.Window. WindowModeChangeEvent)
*/ private Button getMinimizeButton() {
@Override final Button minimizeBtn = SPUIComponentProvider.getButton(
public void windowModeChanged(final WindowModeChangeEvent event) { SPUIComponentIdProvider.UPLOAD_STATUS_POPUP_MINIMIZE_BUTTON_ID, "", "", "", true, FontAwesome.MINUS,
if (event.getWindow().getWindowMode() == WindowMode.MAXIMIZED) { SPUIButtonStyleSmallNoBorder.class);
minimizeBtn.addStyleName(ValoTheme.BUTTON_BORDERLESS);
minimizeBtn.addClickListener(event -> minimizeWindow());
minimizeBtn.setEnabled(true);
return minimizeBtn;
}
private Button getResizeButton() {
final Button resizeBtn = SPUIComponentProvider.getButton(
SPUIComponentIdProvider.UPLOAD_STATUS_POPUP_RESIZE_BUTTON_ID, "", "", "", true, FontAwesome.EXPAND,
SPUIButtonStyleSmallNoBorder.class);
resizeBtn.addStyleName(ValoTheme.BUTTON_BORDERLESS);
resizeBtn.addClickListener(event -> resizeWindow(event));
return resizeBtn;
}
private void resizeWindow(ClickEvent event) {
if (event.getButton().getIcon() == FontAwesome.EXPAND) {
event.getButton().setIcon(FontAwesome.COMPRESS);
setWindowMode(WindowMode.MAXIMIZED);
resetColumnWidth(); resetColumnWidth();
grid.getColumn(STATUS).setExpandRatio(0); grid.getColumn(STATUS).setExpandRatio(0);
grid.getColumn(PROGRESS).setExpandRatio(1); grid.getColumn(PROGRESS).setExpandRatio(1);
grid.getColumn(FILE_NAME).setExpandRatio(2); grid.getColumn(FILE_NAME).setExpandRatio(2);
grid.getColumn(REASON).setExpandRatio(3); grid.getColumn(REASON).setExpandRatio(3);
grid.setSizeFull(); grid.getColumn(SPUILabelDefinitions.NAME_VERSION).setExpandRatio(4);
mainLayout.setSizeFull();
} else { } else {
event.getButton().setIcon(FontAwesome.EXPAND);
setWindowMode(WindowMode.NORMAL);
setColumnWidth(); setColumnWidth();
setPopupSizeInMinMode(); setPopupSizeInMinMode();
} }
} }
private void setPopupSizeInMinMode() { private void minimizeWindow() {
grid.setWidth(800, Unit.PIXELS); this.close();
grid.setHeight(510, Unit.PIXELS); artifactUploadState.setStatusPopupMinimized(true);
eventBus.publish(this, UploadArtifactUIEvent.MINIMIZED_STATUS_POPUP);
}
private Button getCloseButton() {
final Button closeBtn = SPUIComponentProvider.getButton(
SPUIComponentIdProvider.UPLOAD_STATUS_POPUP_CLOSE_BUTTON_ID, "", "", "", true, FontAwesome.TIMES,
SPUIButtonStyleSmallNoBorder.class);
closeBtn.addStyleName(ValoTheme.BUTTON_BORDERLESS);
closeBtn.addClickListener(event -> onClose());
return closeBtn;
}
private void onClose() {
if (!artifactUploadState.isUploadCompleted()) {
confirmAbortAction();
} else {
clearWindow();
}
}
private void confirmAbortAction() {
UI.getCurrent().addWindow(confirmDialog.getWindow());
confirmDialog.getWindow().bringToFront();
}
private void createConfirmDialog() {
confirmDialog = new ConfirmationDialog(i18n.get("caption.confirm.abort.action"),
i18n.get("message.abort.upload"), i18n.get("button.ok"), i18n.get("button.cancel"), ok -> {
if (ok) {
eventBus.publish(this, UploadStatusEventType.ABORT_UPLOAD);
uploadAborted = true;
errorOccured = true;
minimizeButton.setEnabled(false);
closeButton.setEnabled(false);
}
});
}
private String getItemid(final String filename, final SoftwareModule softwareModule) {
return new StringBuilder(filename).append(
HawkbitCommonUtil.getFormattedNameVersion(softwareModule.getName(), softwareModule.getVersion()))
.toString();
} }
} }

View File

@@ -0,0 +1,86 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.ui.artifacts.upload;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
/**
*
* Holds uploaded file status.Used to display the details in upload status
* popup.
*
*/
public class UploadStatusObject {
private String status;
private Double progress;
private String filename;
private String reason;
private SoftwareModule selectedSoftwareModule;
public UploadStatusObject(final String status, final Double progress, final String fileName, final String reason,
final SoftwareModule selectedSoftwareModule) {
this(fileName,selectedSoftwareModule);
this.status = status;
this.progress = progress;
this.reason = reason;
}
public UploadStatusObject(String fileName, SoftwareModule selectedSoftwareModule) {
this.filename = fileName;
this.selectedSoftwareModule = selectedSoftwareModule;
}
public SoftwareModule getSelectedSoftwareModule() {
return selectedSoftwareModule;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Double getProgress() {
return progress;
}
public void setProgress(Double progress) {
this.progress = progress;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
@Override
public boolean equals(Object obj) {
if (this == null || obj == null) {
return false;
}
if (obj instanceof UploadStatusObject && this.getFilename() == ((UploadStatusObject) obj).getFilename()) {
return true;
}
return false;
}
}

View File

@@ -130,7 +130,7 @@ public abstract class AbstractDeleteActionsLayout extends VerticalLayout impleme
addComponent(hLayout); addComponent(hLayout);
setComponentAlignment(hLayout, Alignment.BOTTOM_CENTER); setComponentAlignment(hLayout, Alignment.BOTTOM_CENTER);
} }
setStyleName("footer-layout"); setStyleName(SPUIStyleDefinitions.FOOTER_LAYOUT);
setWidth("100%"); setWidth("100%");
} }
@@ -168,7 +168,7 @@ public abstract class AbstractDeleteActionsLayout extends VerticalLayout impleme
final Button button = SPUIComponentProvider.getButton(SPUIComponentIdProvider.BULK_UPLOAD_STATUS_BUTTON, "", "", final Button button = SPUIComponentProvider.getButton(SPUIComponentIdProvider.BULK_UPLOAD_STATUS_BUTTON, "", "",
"", false, null, SPUIButtonStyleSmall.class); "", false, null, SPUIButtonStyleSmall.class);
button.setStyleName(SPUIStyleDefinitions.ACTION_BUTTON); button.setStyleName(SPUIStyleDefinitions.ACTION_BUTTON);
button.addStyleName(SPUIStyleDefinitions.BULK_UPLOAD_PROGRESS_INDICATOR_STYLE); button.addStyleName(SPUIStyleDefinitions.UPLOAD_PROGRESS_INDICATOR_STYLE);
button.setWidth("100px"); button.setWidth("100px");
button.setHtmlContentAllowed(true); button.setHtmlContentAllowed(true);
button.addClickListener(event -> onClickBulkUploadNotificationButton()); button.addClickListener(event -> onClickBulkUploadNotificationButton());
@@ -199,7 +199,7 @@ public abstract class AbstractDeleteActionsLayout extends VerticalLayout impleme
if (bulkUploadStatusButton == null) { if (bulkUploadStatusButton == null) {
return; return;
} }
bulkUploadStatusButton.removeStyleName(SPUIStyleDefinitions.BULK_UPLOAD_PROGRESS_INDICATOR_STYLE); bulkUploadStatusButton.removeStyleName(SPUIStyleDefinitions.UPLOAD_PROGRESS_INDICATOR_STYLE);
bulkUploadStatusButton.setIcon(FontAwesome.UPLOAD); bulkUploadStatusButton.setIcon(FontAwesome.UPLOAD);
} }
@@ -207,7 +207,7 @@ public abstract class AbstractDeleteActionsLayout extends VerticalLayout impleme
if (bulkUploadStatusButton == null) { if (bulkUploadStatusButton == null) {
return; return;
} }
bulkUploadStatusButton.addStyleName(SPUIStyleDefinitions.BULK_UPLOAD_PROGRESS_INDICATOR_STYLE); bulkUploadStatusButton.addStyleName(SPUIStyleDefinitions.UPLOAD_PROGRESS_INDICATOR_STYLE);
bulkUploadStatusButton.setIcon(null); bulkUploadStatusButton.setIcon(null);
} }

View File

@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.ui.common.grid; package org.eclipse.hawkbit.ui.common.grid;
import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider; import org.eclipse.hawkbit.ui.utils.SPUIComponentIdProvider;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import com.vaadin.ui.Alignment; import com.vaadin.ui.Alignment;
import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.HorizontalLayout;
@@ -72,7 +73,7 @@ public abstract class AbstractGridLayout extends VerticalLayout {
final Label countMessageLabel = getCountMessageLabel(); final Label countMessageLabel = getCountMessageLabel();
countMessageLabel.setId(SPUIComponentIdProvider.ROLLOUT_GROUP_TARGET_LABEL); countMessageLabel.setId(SPUIComponentIdProvider.ROLLOUT_GROUP_TARGET_LABEL);
rolloutGroupTargetsCountLayout.addComponent(getCountMessageLabel()); rolloutGroupTargetsCountLayout.addComponent(getCountMessageLabel());
rolloutGroupTargetsCountLayout.setStyleName("footer-layout"); rolloutGroupTargetsCountLayout.setStyleName(SPUIStyleDefinitions.FOOTER_LAYOUT);
rolloutGroupTargetsCountLayout.setWidth("100%"); rolloutGroupTargetsCountLayout.setWidth("100%");
return rolloutGroupTargetsCountLayout; return rolloutGroupTargetsCountLayout;

View File

@@ -14,6 +14,7 @@ import org.eclipse.hawkbit.ui.HawkbitUI;
import org.eclipse.hawkbit.ui.filtermanagement.event.CustomFilterUIEvent; import org.eclipse.hawkbit.ui.filtermanagement.event.CustomFilterUIEvent;
import org.eclipse.hawkbit.ui.filtermanagement.footer.TargetFilterCountMessageLabel; import org.eclipse.hawkbit.ui.filtermanagement.footer.TargetFilterCountMessageLabel;
import org.eclipse.hawkbit.ui.filtermanagement.state.FilterManagementUIState; import org.eclipse.hawkbit.ui.filtermanagement.state.FilterManagementUIState;
import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.vaadin.spring.events.EventBus; import org.vaadin.spring.events.EventBus;
import org.vaadin.spring.events.EventScope; import org.vaadin.spring.events.EventScope;
@@ -152,7 +153,7 @@ public class FilterManagementView extends VerticalLayout implements View {
private HorizontalLayout addTargetFilterMessageLabel() { private HorizontalLayout addTargetFilterMessageLabel() {
final HorizontalLayout messageLabelLayout = new HorizontalLayout(); final HorizontalLayout messageLabelLayout = new HorizontalLayout();
messageLabelLayout.addComponent(targetFilterCountMessageLabel); messageLabelLayout.addComponent(targetFilterCountMessageLabel);
messageLabelLayout.addStyleName("footer-layout"); messageLabelLayout.addStyleName(SPUIStyleDefinitions.FOOTER_LAYOUT);
return messageLabelLayout; return messageLabelLayout;
} }

View File

@@ -888,6 +888,30 @@ public final class SPUIComponentIdProvider {
*/ */
public static final String VALIDATION_STATUS_ICON_ID = "validation.status.icon"; public static final String VALIDATION_STATUS_ICON_ID = "validation.status.icon";
/**
* Artifact upload status popup - minimize button id.
*/
public static final String UPLOAD_STATUS_POPUP_MINIMIZE_BUTTON_ID = "artifact.upload.minimize.button.id";
/**
* Artifact upload status popup - close button id.
*/
public static final String UPLOAD_STATUS_POPUP_CLOSE_BUTTON_ID = "artifact.upload.close.button.id";
/**
* Artifact upload status popup - resize button id.
*/
public static final String UPLOAD_STATUS_POPUP_RESIZE_BUTTON_ID = "artifact.upload.resize.button.id";
/**
* Artifact upload view - upload status button id.
*/
public static final String UPLOAD_STATUS_BUTTON = "artficat.upload.status.button.id";
/**
* Artifact uplaod view - uplod status popup id.
*/
public static final String UPLOAD_STATUS_POPUP_ID = "artifact.upload.status.popup.id";
/** /**
* /* Private Constructor. * /* Private Constructor.
*/ */

View File

@@ -240,9 +240,9 @@ public final class SPUIStyleDefinitions {
public static final String DISABLE_ACTION_TYPE_LAYOUT = "disable-action-type-layout"; public static final String DISABLE_ACTION_TYPE_LAYOUT = "disable-action-type-layout";
/** /**
* Bulk upload progress indicator style. * Upload progress indicator style.
*/ */
public static final String BULK_UPLOAD_PROGRESS_INDICATOR_STYLE = "app-loading"; public static final String UPLOAD_PROGRESS_INDICATOR_STYLE = "app-loading";
/** /**
* Target filter search progress indicator style. * Target filter search progress indicator style.
@@ -293,6 +293,11 @@ public final class SPUIStyleDefinitions {
* Status pending icon. * Status pending icon.
*/ */
public static final String STATUS_ICON_PENDING = "statusIconPending"; public static final String STATUS_ICON_PENDING = "statusIconPending";
/**
* Footer layout style.
*/
public static final String FOOTER_LAYOUT = "footer-layout";
/** /**
* Constructor. * Constructor.

View File

@@ -10,7 +10,7 @@
@mixin others { @mixin others {
//Style to display the pending action count //Style to display the pending action count
.unread { .unread, .error-count {
@include valo-badge-style; @include valo-badge-style;
position: absolute; position: absolute;
pointer-events: none; pointer-events: none;
@@ -21,6 +21,15 @@
border-radius: $v-border-radius; border-radius: $v-border-radius;
color: $widget-bg; color: $widget-bg;
} }
.error-count {
top: round($v-unit-size / -5);
right: round($v-unit-size / 1.9);
}
.error-count-color{
@include valo-gradient($color: $red-color);
}
//Deployment view - Style of count message //Deployment view - Style of count message
.v-caption-count-msg-box { .v-caption-count-msg-box {

View File

@@ -86,6 +86,7 @@ caption.cancel.action.confirmbox = Confirm action cancel
caption.forcequit.action.confirmbox = Confirm force quit action caption.forcequit.action.confirmbox = Confirm force quit action
caption.forced.datefield = Force update at time caption.forced.datefield = Force update at time
caption.force.action.confirmbox = Confirm Force Active Action caption.force.action.confirmbox = Confirm Force Active Action
caption.confirm.abort.action = Confirm abort action
caption.filter.delete.confirmbox = Confirm Filter Delete Action caption.filter.delete.confirmbox = Confirm Filter Delete Action
@@ -321,8 +322,11 @@ message.duplicate.filename = Duplicate file name
message.swModule.deleted = {0} Software module(s) deleted message.swModule.deleted = {0} Software module(s) deleted
message.upload.failed = Streaming Failed message.upload.failed = Streaming Failed
message.uploadedfile.size.exceeded = File size exceeded .Allowed size {0} bytes message.uploadedfile.size.exceeded = File size exceeded .Allowed size {0} bytes
message.uploadedfile.aborted = File upload aborted
message.file.not.found = File not found message.file.not.found = File not found
message.artifact.deleted =Artifact with file {0} deleted successfully message.artifact.deleted =Artifact with file {0} deleted successfully
message.abort.upload = Are you sure that you want to abort the upload?
upload.swModuleTable.header = Software module upload.swModuleTable.header = Software module

View File

@@ -85,8 +85,9 @@ caption.forced.datefield = Force update at time
caption.force.action.confirmbox = Confirm Force Active Action caption.force.action.confirmbox = Confirm Force Active Action
caption.filter.simple = Simple Filter caption.filter.simple = Simple Filter
caption.filter.custom = Custom Filter caption.filter.custom = Custom Filter
caption.filter.delete.confirmbox = Confirm Filter Delete Action caption.filter.delete.confirmbox = Confirm Filter Delete Action
caption.confirm.abort.action = Confirm abort action
# Labels prefix with - label # Labels prefix with - label
label.dist.details.type = Type : label.dist.details.type = Type :
@@ -319,8 +320,11 @@ message.swModule.deleted = {0} Software module(s) deleted
message.error.missing.tagname = Please select tag name message.error.missing.tagname = Please select tag name
message.upload.failed = Streaming Failed message.upload.failed = Streaming Failed
message.uploadedfile.size.exceeded = File size exceeded .Allowed size {0} bytes message.uploadedfile.size.exceeded = File size exceeded .Allowed size {0} bytes
message.uploadedfile.aborted = File upload aborted
message.file.not.found = File not found message.file.not.found = File not found
message.artifact.deleted =Artifact with file {0} deleted successfully message.artifact.deleted =Artifact with file {0} deleted successfully
message.abort.upload = Are you sure that you want to abort the upload?
upload.swModuleTable.header = Software module upload.swModuleTable.header = Software module

View File

@@ -85,8 +85,8 @@ caption.soft.delete.confirmbox = Confirm Software Module Delete Action
caption.cancel.action.confirmbox = Confirm action cancellation caption.cancel.action.confirmbox = Confirm action cancellation
caption.forced.datefield = Force update at time caption.forced.datefield = Force update at time
caption.force.action.confirmbox = Confirm Force Active Action caption.force.action.confirmbox = Confirm Force Active Action
caption.filter.delete.confirmbox = Confirm Filter Delete Action caption.filter.delete.confirmbox = Confirm Filter Delete Action
caption.confirm.abort.action = Confirm abort action
# Labels prefix with - label # Labels prefix with - label
label.dist.details.type = Type : label.dist.details.type = Type :
@@ -313,7 +313,10 @@ message.duplicate.filename = Duplicate file name
message.swModule.deleted = {0} Software module(s) deleted message.swModule.deleted = {0} Software module(s) deleted
message.upload.failed = Streaming Failed message.upload.failed = Streaming Failed
message.uploadedfile.size.exceeded = File size exceeded .Allowed size {0} bytes message.uploadedfile.size.exceeded = File size exceeded .Allowed size {0} bytes
message.uploadedfile.aborted = File upload aborted
message.file.not.found = File not found message.file.not.found = File not found
message.abort.upload = Are you sure that you want to abort the upload?
upload.swModuleTable.header = Software module upload.swModuleTable.header = Software module
upload.selectedfile.name = file selected for upload upload.selectedfile.name = file selected for upload