diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9bb88d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/.DS_Store diff --git a/bugrap/.gitignore b/bugrap/.gitignore index 3415bc6..c6f0364 100644 --- a/bugrap/.gitignore +++ b/bugrap/.gitignore @@ -4,3 +4,4 @@ /.settings/ /**/.DS_Store /**/rebel.xml +/.vaadin-designer2/ diff --git a/bugrap/.vaadin-designer2/designer-theme.css b/bugrap/.vaadin-designer2/designer-theme.css index 80bcfdf..fe650de 100644 --- a/bugrap/.vaadin-designer2/designer-theme.css +++ b/bugrap/.vaadin-designer2/designer-theme.css @@ -12500,4 +12500,36 @@ div.v-layout.v-horizontal.v-widget { display: inline-block; width: 19px; overflow: hidden; +} + +.mytheme div.bar { + background-color: gray; + height: 20px; + width: 10px; + vertical-align: center; +} + +.mytheme div.v-slot-removed-upload { + display: none; +} + +.mytheme div.completed-upload div.v-button { + display: none; +} + +.mytheme div.completed-upload:hover div.v-button { + display: inline-block; +} + +.mytheme div.v-slot-completed-upload:hover { + color: #474747; + border-radius: 4px; + border: 1px solid #d5d5d5; + -webkit-box-shadow: 0 2px 3px rgba(0, 0, 0, 0.05); + box-shadow: 0 2px 3px rgba(0, 0, 0, 0.05); +} + +.mytheme div.v-slot-completed-upload div { + margin-bottom: 5px; + margin-left: 5px; } \ No newline at end of file diff --git a/bugrap/pom.xml b/bugrap/pom.xml index 4f63df3..ae2d8b5 100644 --- a/bugrap/pom.xml +++ b/bugrap/pom.xml @@ -105,8 +105,8 @@ update-widgetset compile + compile-theme diff --git a/bugrap/src/main/java/org/vaadin/bugrap/ui/ReportDetailView.java b/bugrap/src/main/java/org/vaadin/bugrap/ui/ReportDetailView.java index ba8c0ec..f9bc4a8 100644 --- a/bugrap/src/main/java/org/vaadin/bugrap/ui/ReportDetailView.java +++ b/bugrap/src/main/java/org/vaadin/bugrap/ui/ReportDetailView.java @@ -1,39 +1,33 @@ package org.vaadin.bugrap.ui; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.OutputStream; import java.util.List; import org.vaadin.bugrap.domain.entities.Comment; import org.vaadin.bugrap.domain.entities.Report; +import org.vaadin.bugrap.ui.beans.FileUploadEvent; import org.vaadin.bugrap.ui.generated.ReportDetailViewBase; +import org.vaadin.bugrap.util.IUploadedFileListener; import com.vaadin.data.Binder; -import com.vaadin.server.FileDownloader; -import com.vaadin.server.FileResource; +import com.vaadin.ui.Component; import com.vaadin.ui.HorizontalLayout; -import com.vaadin.ui.Link; import com.vaadin.ui.Notification; import com.vaadin.ui.Notification.Type; -import com.vaadin.ui.ProgressBar; -import com.vaadin.ui.Upload.ProgressListener; -import com.vaadin.ui.Upload.Receiver; +import com.vaadin.ui.Upload; +import com.vaadin.ui.Upload.FinishedEvent; +import com.vaadin.ui.Upload.FinishedListener; import com.vaadin.ui.Upload.StartedEvent; import com.vaadin.ui.Upload.StartedListener; -import com.vaadin.ui.Upload.SucceededEvent; -import com.vaadin.ui.Upload.SucceededListener; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; public class ReportDetailView extends ReportDetailViewBase - implements Receiver, SucceededListener, StartedListener, ProgressListener { + implements StartedListener, Component.Listener, IUploadedFileListener, FinishedListener { private ReportsModel model; private Binder binder = new Binder(); - private ProgressBar uploadInProgress; + private int numOfOngoingUploads = 0; public ReportDetailView(ReportsModel reportModel) { model = reportModel; @@ -55,11 +49,10 @@ private void initializeUIComponents() { btnRevertReport.addClickListener(evt -> revertChanges()); btnDone.addClickListener(evt -> saveComment()); btnCancel.addClickListener(evt -> closeWindow()); - btnUpload.setReceiver(this); btnUpload.addStartedListener(this); - btnUpload.addSucceededListener(this); - btnUpload.addProgressListener(this); - txtComment.addValueChangeListener(evt -> commentsUpdated()); + btnUpload.addFinishedListener(this); + txtComment.addValueChangeListener(evt -> setDoneButtonEnablement()); + pnlAttachments.getContent().addListener(this); } private void init() { @@ -73,7 +66,6 @@ private void init() { private void cleanAttachments() { ((HorizontalLayout) pnlAttachments.getContent()).removeAllComponents(); - pnlAttachments.setVisible(false); } private void initializeComboContents() { @@ -95,8 +87,13 @@ private void fillComments() { btnDone.setEnabled(false); } - private void commentsUpdated() { - btnDone.setEnabled(true); + private void setDoneButtonEnablement() { + boolean isEnabled = false; + if (numOfOngoingUploads > 0) + isEnabled = false; + else + isEnabled = !txtComment.isEmpty() || model.hasFilesToSave(); + btnDone.setEnabled(isEnabled); } private void saveReport() { @@ -119,55 +116,61 @@ private void saveComment() { @Override public void uploadStarted(StartedEvent event) { - pnlAttachments.setVisible(true); + initiateUploadTracker(event); + addNewUpload(); + numOfOngoingUploads++; + } + + private void addNewUpload() { + HorizontalLayout layout = (HorizontalLayout) btnUpload.getParent(); + Upload newUpload = new Upload(); + newUpload.setButtonCaption("Attachments..."); + newUpload.addStartedListener(this); + newUpload.addFinishedListener(this); + layout.addComponent(newUpload, layout.getComponentIndex(btnUpload)); + btnUpload.setStyleName("removed-upload", true); + btnUpload = newUpload; + } + + private void initiateUploadTracker(StartedEvent event) { + UploadTracker uploadTracker = new UploadTracker((Upload) event.getSource(), event.getFilename()); + uploadTracker.setUploadedFileListener(this); HorizontalLayout layout = (HorizontalLayout) pnlAttachments.getContent(); - ProgressBar progress = new ProgressBar(); - progress.setCaption(event.getFilename()); - uploadInProgress = progress; - layout.addComponent(progress); - btnDone.setEnabled(false);//disable done button until upload completes + layout.addComponent(uploadTracker); + } + + private void closeWindow() { + Window window = (Window) getParent(); + window.close(); } @Override - public void uploadSucceeded(SucceededEvent event) { - HorizontalLayout layout = (HorizontalLayout) pnlAttachments.getContent(); - layout.removeComponent(uploadInProgress); - uploadInProgress = null; - FileResource file = new FileResource(new File(ReportsModel.FILEUPLOAD_PATH + event.getFilename())); - try { - model.attachFile(event.getFilename(), event.getMIMEType(), file.getStream()); - } catch (IOException e) { - Notification.show("Error occurred while uploading the file", e.getMessage(), Type.ERROR_MESSAGE); - } - FileDownloader downloader = new FileDownloader(file); - Link link = new Link(); - link.setCaption(event.getFilename()); - link.setStyleName("tiny"); - downloader.extend(link); - layout.addComponent(link); - commentsUpdated(); + public void componentEvent(Event event) { + HorizontalLayout layout = (HorizontalLayout) event.getSource(); + pnlAttachments.setVisible(layout.getComponentCount() > 0); } @Override - public OutputStream receiveUpload(String filename, String mimeType) { - FileOutputStream fos = null; + public void uploadedFileReceived(FileUploadEvent event) { try { - fos = new FileOutputStream(ReportsModel.FILEUPLOAD_PATH + filename); - } catch (FileNotFoundException e) { - Notification.show("Error occurred while uploading the file", e.getMessage(), Type.ERROR_MESSAGE); - } finally { - return fos; + model.attachFile(event.getSource(), event.getFilename(), event.getFilename(), event.getStream()); + setDoneButtonEnablement(); + } catch (IOException e) { + Notification.show("Error uploading file : " + event.getFilename(), + "There was an error while uploading the file :" + e.getMessage(), + com.vaadin.ui.Notification.Type.ERROR_MESSAGE); } } @Override - public void updateProgress(long readBytes, long contentLength) { - if (uploadInProgress != null) - uploadInProgress.setValue(((float) readBytes) / contentLength); + public void uploadFinished(FinishedEvent event) { + numOfOngoingUploads--; + setDoneButtonEnablement(); } - private void closeWindow() { - Window window = (Window) getParent(); - window.close(); + @Override + public void uploadedFileDeleted(Object source) { + model.removeAttachedFile(source); + setDoneButtonEnablement(); } } diff --git a/bugrap/src/main/java/org/vaadin/bugrap/ui/ReportsModel.java b/bugrap/src/main/java/org/vaadin/bugrap/ui/ReportsModel.java index 20ccd34..412dd0b 100644 --- a/bugrap/src/main/java/org/vaadin/bugrap/ui/ReportsModel.java +++ b/bugrap/src/main/java/org/vaadin/bugrap/ui/ReportsModel.java @@ -1,13 +1,16 @@ package org.vaadin.bugrap.ui; import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.vaadin.bugrap.BaseModel; @@ -25,7 +28,6 @@ import com.vaadin.data.ValidationException; import com.vaadin.navigator.Navigator; -import com.vaadin.server.DownloadStream; public class ReportsModel extends BaseModel { @@ -35,13 +37,11 @@ public class ReportsModel extends BaseModel { public static final int ASSIGNEE_ME = 0; public static final int ASSIGNEE_ALL = 1; - - public static final int VERSIONID_ALL = 0; - public static final String FILEUPLOAD_PATH = "/Users/onuridrisoglu/Downloads/temp/"; + public static final int VERSIONID_ALL = 0; private List selectedReports = new ArrayList(); - private List uploadedFilesToSave = new ArrayList(); + private Map uploadedFilesToSave = new HashMap(); protected Report reportForEdit; private int assigneeFilterMode = ASSIGNEE_ALL; @@ -70,14 +70,6 @@ else if (selectedReports.size() == 1) return SELECTIONMODE_MULTI; } - public List getUploadedFilesToSave() { - return uploadedFilesToSave; - } - - public void setUploadedFilesToSave(List uploadedFilesToSave) { - this.uploadedFilesToSave = uploadedFilesToSave; - } - public List findProjects() { List projects = new ArrayList(); projects.addAll(getRepository().findProjects()); @@ -104,15 +96,15 @@ public Collection findReporters() { public List findProjectVersions() { return findProjectVersions(reportForEdit.getProject()); } - + public List findProjectVersionsWithAllOption(Project project) { List projectVersions = findProjectVersions(project); - + ProjectVersion allVersion = new ProjectVersion(); allVersion.setId(VERSIONID_ALL); allVersion.setVersion("All Versions"); allVersion.setProject(project); - + projectVersions.add(0, allVersion); return projectVersions; } @@ -131,7 +123,7 @@ public Collection findReports(Project project, ProjectVersion version) { query.projectVersion = version; } if (assigneeFilterMode == ASSIGNEE_ME) { - query.reportAssignee = getLoginUser(); + query.reportAssignee = getLoginUser(); } query.reportStatuses = statusFilters; return getRepository().findReports(query); @@ -192,10 +184,10 @@ public void saveComment(String commentTxt) { getRepository().save(comment); } - public Comment createComment(String filename, String mimeType, DownloadStream stream) throws IOException { + public Comment createComment(String filename, String mimeType, InputStream stream) throws IOException { Comment comment = new Comment(); comment.setReport(reportForEdit); - comment.setAttachment(stream.getStream().readAllBytes()); + comment.setAttachment(stream.readAllBytes()); comment.setAttachmentName(filename); comment.setAuthor(getLoginUser()); comment.setTimestamp(new Date()); @@ -203,24 +195,35 @@ public Comment createComment(String filename, String mimeType, DownloadStream st return comment; } - public void attachFile(String filename, String mimeType, DownloadStream stream) throws IOException { + public void attachFile(Object source, String filename, String mimeType, InputStream stream) throws IOException { Comment attachmentComment = createComment(filename, mimeType, stream); - uploadedFilesToSave.add(attachmentComment); + uploadedFilesToSave.put(source, attachmentComment); + } + + public void removeAttachedFile(Object source) { + uploadedFilesToSave.remove(source); } public void saveAttachments() { - for (Comment attachment : uploadedFilesToSave) { + for (Comment attachment : uploadedFilesToSave.values()) { getRepository().save(attachment); } uploadedFilesToSave.clear(); } + public boolean hasFilesToSave() { + return uploadedFilesToSave.size() > 0; + } + public ReportDistribution getReportDistribution(ProjectVersion version) { ReportDistribution distribution = new ReportDistribution(); boolean isAllVersions = version.getId() == VERSIONID_ALL; - distribution.setClosedReports(isAllVersions ? getRepository().countClosedReports(version.getProject()) : getRepository().countClosedReports(version)); - distribution.setAssignedReports(isAllVersions ? getRepository().countOpenedReports(version.getProject()) : getRepository().countOpenedReports(version)); - distribution.setUnassignedReports(isAllVersions ? getRepository().countUnassignedReports(version.getProject()) : getRepository().countUnassignedReports(version)); + distribution.setClosedReports(isAllVersions ? getRepository().countClosedReports(version.getProject()) + : getRepository().countClosedReports(version)); + distribution.setAssignedReports(isAllVersions ? getRepository().countOpenedReports(version.getProject()) + : getRepository().countOpenedReports(version)); + distribution.setUnassignedReports(isAllVersions ? getRepository().countUnassignedReports(version.getProject()) + : getRepository().countUnassignedReports(version)); return distribution; } @@ -247,4 +250,5 @@ public void changeStatusFilters(boolean isChecked, Status... status) { else statusFilters.removeAll(Arrays.asList(status)); } + } diff --git a/bugrap/src/main/java/org/vaadin/bugrap/ui/UploadTracker.java b/bugrap/src/main/java/org/vaadin/bugrap/ui/UploadTracker.java new file mode 100644 index 0000000..9f2b210 --- /dev/null +++ b/bugrap/src/main/java/org/vaadin/bugrap/ui/UploadTracker.java @@ -0,0 +1,98 @@ +package org.vaadin.bugrap.ui; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; + +import org.vaadin.bugrap.ui.beans.FileUploadEvent; +import org.vaadin.bugrap.ui.generated.UploadTrackerBase; +import org.vaadin.bugrap.util.IUploadedFileListener; + +import com.vaadin.server.FileDownloader; +import com.vaadin.server.FileResource; +import com.vaadin.server.Resource; +import com.vaadin.server.StreamResource; +import com.vaadin.server.StreamResource.StreamSource; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Notification; +import com.vaadin.ui.Notification.Type; +import com.vaadin.ui.Upload; +import com.vaadin.ui.Upload.ProgressListener; +import com.vaadin.ui.Upload.Receiver; +import com.vaadin.ui.Upload.SucceededEvent; +import com.vaadin.ui.Upload.SucceededListener; + +public class UploadTracker extends UploadTrackerBase implements Receiver, ProgressListener, SucceededListener { + + private Upload btnUpload; + private IUploadedFileListener uploadedFileListener; + private UploadTrackerModel model = new UploadTrackerModel(); + private ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + public UploadTracker(Upload upload, String filename) { + btnUpload = upload; + btnUpload.setReceiver(this); + btnUpload.addProgressListener(this); + btnUpload.addSucceededListener(this); + uploadProgress.setIndeterminate(false); + lnkFilename.setCaption(filename); + btnCancel.addClickListener(evt -> cancel()); + arrangeComponents(); + } + + private void arrangeComponents() { + uploadProgress.setVisible(!model.isUploadCompleted()); + if (model.isUploadCompleted()) { + setStyleName("completed-upload", true); + btnUpload.setVisible(false); + } + } + + private void cancel() { + if (!model.isUploadCompleted()) { + btnUpload.interruptUpload(); + } + uploadedFileListener.uploadedFileDeleted(btnUpload); + HorizontalLayout layout = (HorizontalLayout) getParent(); + layout.removeComponent(this); + } + + @Override + public void uploadSucceeded(SucceededEvent event) { + InputStream is = new ByteArrayInputStream(baos.toByteArray()); + StreamResource resource = new StreamResource(new StreamSource() { + @Override + public InputStream getStream() { + return is; + } + }, event.getFilename()); + FileDownloader downloader = new FileDownloader(resource); + downloader.extend(lnkFilename); + model.setUploadCompleted(true); + arrangeComponents(); + uploadedFileListener.uploadedFileReceived( + new FileUploadEvent(event.getSource(), event.getFilename(), event.getMIMEType(), is)); + } + + @Override + public void updateProgress(long readBytes, long contentLength) { + uploadProgress.setValue(((float) readBytes) / (float) contentLength); + } + + @Override + public OutputStream receiveUpload(String filename, String mimeType) { + return baos; + } + + public IUploadedFileListener getUploadedFileListener() { + return uploadedFileListener; + } + + public void setUploadedFileListener(IUploadedFileListener uploadedFileListener) { + this.uploadedFileListener = uploadedFileListener; + } +} diff --git a/bugrap/src/main/java/org/vaadin/bugrap/ui/UploadTrackerModel.java b/bugrap/src/main/java/org/vaadin/bugrap/ui/UploadTrackerModel.java new file mode 100644 index 0000000..ed56dcf --- /dev/null +++ b/bugrap/src/main/java/org/vaadin/bugrap/ui/UploadTrackerModel.java @@ -0,0 +1,13 @@ +package org.vaadin.bugrap.ui; + +public class UploadTrackerModel { + + private boolean isUploadCompleted = false; + + public boolean isUploadCompleted() { + return isUploadCompleted; + } + public void setUploadCompleted(boolean isUploadCompleted) { + this.isUploadCompleted = isUploadCompleted; + } +} diff --git a/bugrap/src/main/java/org/vaadin/bugrap/ui/beans/FileUploadEvent.java b/bugrap/src/main/java/org/vaadin/bugrap/ui/beans/FileUploadEvent.java new file mode 100644 index 0000000..06bd56c --- /dev/null +++ b/bugrap/src/main/java/org/vaadin/bugrap/ui/beans/FileUploadEvent.java @@ -0,0 +1,50 @@ +package org.vaadin.bugrap.ui.beans; + +import java.io.InputStream; + +public class FileUploadEvent { + + private String filename; + private String mimeType; + private Object source; + private InputStream stream; + + public FileUploadEvent(Object source, String filename, String mimeType, InputStream stream) { + this.filename = filename; + this.mimeType = mimeType; + this.source = source; + this.stream = stream; + } + + public String getFilename() { + return filename; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + public String getMimeType() { + return mimeType; + } + + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + public Object getSource() { + return source; + } + + public void setSource(Object source) { + this.source = source; + } + + public InputStream getStream() { + return stream; + } + + public void setStream(InputStream stream) { + this.stream = stream; + } +} diff --git a/bugrap/src/main/java/org/vaadin/bugrap/ui/generated/UploadTrackerBase.java b/bugrap/src/main/java/org/vaadin/bugrap/ui/generated/UploadTrackerBase.java new file mode 100644 index 0000000..e14fff2 --- /dev/null +++ b/bugrap/src/main/java/org/vaadin/bugrap/ui/generated/UploadTrackerBase.java @@ -0,0 +1,30 @@ +package org.vaadin.bugrap.ui.generated; + +import com.vaadin.annotations.AutoGenerated; +import com.vaadin.annotations.DesignRoot; +import com.vaadin.ui.Button; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Link; +import com.vaadin.ui.ProgressBar; +import com.vaadin.ui.declarative.Design; + +/** + * !! DO NOT EDIT THIS FILE !! + * + * This class is generated by Vaadin Designer and will be overwritten. + * + * Please make a subclass with logic and additional interfaces as needed, + * e.g class LoginView extends LoginDesign implements View { } + */ +@DesignRoot +@AutoGenerated +@SuppressWarnings("serial") +public class UploadTrackerBase extends HorizontalLayout { + protected Link lnkFilename; + protected ProgressBar uploadProgress; + protected Button btnCancel; + + public UploadTrackerBase() { + Design.read(this); + } +} diff --git a/bugrap/src/main/java/org/vaadin/bugrap/util/IUploadedFileListener.java b/bugrap/src/main/java/org/vaadin/bugrap/util/IUploadedFileListener.java new file mode 100644 index 0000000..aa41ccc --- /dev/null +++ b/bugrap/src/main/java/org/vaadin/bugrap/util/IUploadedFileListener.java @@ -0,0 +1,10 @@ +package org.vaadin.bugrap.util; + +import org.vaadin.bugrap.ui.beans.FileUploadEvent; + +public interface IUploadedFileListener { + + public void uploadedFileReceived(FileUploadEvent event); + + public void uploadedFileDeleted(Object source); +} diff --git a/bugrap/src/main/resources/org/vaadin/bugrap/ui/generated/ReportDetailViewBase.html b/bugrap/src/main/resources/org/vaadin/bugrap/ui/generated/ReportDetailViewBase.html index 0639b60..4da7484 100644 --- a/bugrap/src/main/resources/org/vaadin/bugrap/ui/generated/ReportDetailViewBase.html +++ b/bugrap/src/main/resources/org/vaadin/bugrap/ui/generated/ReportDetailViewBase.html @@ -36,7 +36,7 @@ - + diff --git a/bugrap/src/main/resources/org/vaadin/bugrap/ui/generated/UploadTrackerBase.html b/bugrap/src/main/resources/org/vaadin/bugrap/ui/generated/UploadTrackerBase.html new file mode 100644 index 0000000..49e4c93 --- /dev/null +++ b/bugrap/src/main/resources/org/vaadin/bugrap/ui/generated/UploadTrackerBase.html @@ -0,0 +1,17 @@ + + + + + + + + + + + + + Button + + + + \ No newline at end of file diff --git a/bugrap/src/main/webapp/VAADIN/themes/mytheme/mytheme.scss b/bugrap/src/main/webapp/VAADIN/themes/mytheme/mytheme.scss index 963fcea..f9fea18 100644 --- a/bugrap/src/main/webapp/VAADIN/themes/mytheme/mytheme.scss +++ b/bugrap/src/main/webapp/VAADIN/themes/mytheme/mytheme.scss @@ -39,5 +39,30 @@ height: 20px; width: 10px; vertical-align: center; + margin-right: 2px; + } + + div.v-slot-removed-upload{ + display: none; + } + + div.completed-upload div.v-button{ + display: none; + } + + div.completed-upload:hover div.v-button{ + display: inline-block; + } + + div.v-slot-completed-upload:hover{ + color: #474747; + border-radius: 4px; + border: 1px solid #d5d5d5; + -webkit-box-shadow: 0 2px 3px rgba(0, 0, 0, 0.05); + box-shadow: 0 2px 3px rgba(0, 0, 0, 0.05); + } + div.v-slot-completed-upload div{ + margin-bottom: 5px; + margin-left: 5px; } } diff --git a/bugrap/src/main/webapp/VAADIN/themes/mytheme/styles.css b/bugrap/src/main/webapp/VAADIN/themes/mytheme/styles.css index 9a73de5..3d47e48 100644 --- a/bugrap/src/main/webapp/VAADIN/themes/mytheme/styles.css +++ b/bugrap/src/main/webapp/VAADIN/themes/mytheme/styles.css @@ -14784,6 +14784,31 @@ div.v-layout.v-horizontal.v-widget { background-color: gray; height: 20px; width: 10px; - vertical-align: middle; - margin-left: 1px; + vertical-align: center; + margin-right: 2px; +} + +.mytheme div.v-slot-removed-upload { + display: none; +} + +.mytheme div.completed-upload div.v-button { + display: none; +} + +.mytheme div.completed-upload:hover div.v-button { + display: inline-block; +} + +.mytheme div.v-slot-completed-upload:hover { + color: #474747; + border-radius: 4px; + border: 1px solid #d5d5d5; + -webkit-box-shadow: 0 2px 3px rgba(0, 0, 0, 0.05); + box-shadow: 0 2px 3px rgba(0, 0, 0, 0.05); +} + +.mytheme div.v-slot-completed-upload div { + margin-bottom: 5px; + margin-left: 5px; } \ No newline at end of file