From db74c793d4c7b211d24b098e52ee7246462d3108 Mon Sep 17 00:00:00 2001 From: Javier Godoy <11554739+javier-godoy@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:38:58 -0300 Subject: [PATCH] feat: initial implementation --- README.md | 26 +-- pom.xml | 32 ++- .../vaadin/addons/uploadhelper/FileInfo.java | 212 ++++++++++++++++++ .../META-INF/VAADIN/package.properties | 19 ++ .../addons/AppShellConfiguratorImpl.java} | 25 +-- .../flowingcode/vaadin/addons/DemoLayout.java | 8 +- .../vaadin/addons/template/TemplateDemo.java | 17 -- .../vaadin/addons/template/it/ViewIT.java | 64 ------ .../template/test/SerializationTest.java | 52 ----- .../{template => uploadhelper}/DemoView.java | 12 +- .../addons/uploadhelper/FileInfoDemo.java | 101 +++++++++ .../addons/uploadhelper/NullUpload.java | 53 +++++ .../addons/uploadhelper/PlaygroundDemo.java | 104 +++++++++ .../UploadHelperDemoView.java} | 17 +- .../it/AbstractViewTest.java | 10 +- .../uploadhelper/it/IntegrationCallables.java | 34 +++ .../uploadhelper/it/IntegrationView.java | 73 ++++++ .../vaadin/addons/uploadhelper/it/ViewIT.java | 81 +++++++ .../frontend/styles/shared-styles.css | 21 +- 19 files changed, 767 insertions(+), 194 deletions(-) create mode 100644 src/main/java/com/flowingcode/vaadin/addons/uploadhelper/FileInfo.java rename src/{main/java/com/flowingcode/vaadin/addons/template/TemplateAddon.java => test/java/com/flowingcode/vaadin/addons/AppShellConfiguratorImpl.java} (56%) delete mode 100644 src/test/java/com/flowingcode/vaadin/addons/template/TemplateDemo.java delete mode 100644 src/test/java/com/flowingcode/vaadin/addons/template/it/ViewIT.java delete mode 100644 src/test/java/com/flowingcode/vaadin/addons/template/test/SerializationTest.java rename src/test/java/com/flowingcode/vaadin/addons/{template => uploadhelper}/DemoView.java (84%) create mode 100644 src/test/java/com/flowingcode/vaadin/addons/uploadhelper/FileInfoDemo.java create mode 100644 src/test/java/com/flowingcode/vaadin/addons/uploadhelper/NullUpload.java create mode 100644 src/test/java/com/flowingcode/vaadin/addons/uploadhelper/PlaygroundDemo.java rename src/test/java/com/flowingcode/vaadin/addons/{template/TemplateDemoView.java => uploadhelper/UploadHelperDemoView.java} (71%) rename src/test/java/com/flowingcode/vaadin/addons/{template => uploadhelper}/it/AbstractViewTest.java (96%) create mode 100644 src/test/java/com/flowingcode/vaadin/addons/uploadhelper/it/IntegrationCallables.java create mode 100644 src/test/java/com/flowingcode/vaadin/addons/uploadhelper/it/IntegrationView.java create mode 100644 src/test/java/com/flowingcode/vaadin/addons/uploadhelper/it/ViewIT.java diff --git a/README.md b/README.md index e600a7e..db54cc3 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,24 @@ -[![Published on Vaadin Directory](https://img.shields.io/badge/Vaadin%20Directory-published-00b4f0.svg)](https://vaadin.com/directory/component/template-addon) -[![Stars on vaadin.com/directory](https://img.shields.io/vaadin-directory/star/template-addon.svg)](https://vaadin.com/directory/component/template-addon) -[![Build Status](https://jenkins.flowingcode.com/job/template-addon/badge/icon)](https://jenkins.flowingcode.com/job/template-addon) -[![Maven Central](https://img.shields.io/maven-central/v/com.flowingcode.vaadin.addons/template-addon)](https://mvnrepository.com/artifact/com.flowingcode.vaadin.addons/template-addon) -[![Javadoc](https://img.shields.io/badge/javadoc-00b4f0)](https://javadoc.flowingcode.com/artifact/com.flowingcode.vaadin.addons/template-addon) +[![Published on Vaadin Directory](https://img.shields.io/badge/Vaadin%20Directory-published-00b4f0.svg)](https://vaadin.com/directory/component/upload-helper-add-on) +[![Stars on vaadin.com/directory](https://img.shields.io/vaadin-directory/star/upload-helper-addon.svg)](https://vaadin.com/directory/component/upload-helper-add-on) +[![Build Status](https://jenkins.flowingcode.com/job/upload-helper-addon/badge/icon)](https://jenkins.flowingcode.com/job/upload-helper-addon) +[![Maven Central](https://img.shields.io/maven-central/v/com.flowingcode.vaadin.addons/upload-helper-addon)](https://mvnrepository.com/artifact/com.flowingcode.vaadin.addons/upload-helper-addon) +[![Javadoc](https://img.shields.io/badge/javadoc-00b4f0)](https://javadoc.flowingcode.com/artifact/com.flowingcode.vaadin.addons/upload-helper-addon) -# Template Add-on +# Upload helper Add-on -This is a template project for building new Vaadin 24 add-ons +Flow API for `vaadin-upload-file` ## Features -* List the features of your add-on in here +* Provide an API for manipulating the [vaadin-upload-file](https://cdn.vaadin.com/vaadin-web-components/24.5.0/#/elements/vaadin-upload-file) element. ## Online demo -[Online demo here](http://addonsv24.flowingcode.com/template) +[Online demo here](http://addonsv24.flowingcode.com/upload-helper) ## Download release -[Available in Vaadin Directory](https://vaadin.com/directory/component/template-addon) +[Available in Vaadin Directory](https://vaadin.com/directory/component/upload-helper-add-on) ### Maven install @@ -27,7 +27,7 @@ Add the following dependencies in your pom.xml file: ```xml com.flowingcode.vaadin.addons - template-addon + upload-helper-addon X.Y.Z ``` @@ -44,7 +44,7 @@ To see the demo, navigate to http://localhost:8080/ ## Release notes -See [here](https://github.com/FlowingCode/TemplateAddon/releases) +See [here](https://github.com/FlowingCode/UploadHelper/releases) ## Issue tracking @@ -69,7 +69,7 @@ Then, follow these steps for creating a contribution: This add-on is distributed under Apache License 2.0. For license terms, see LICENSE.txt. -TEMPLATE_ADDON is written by Flowing Code S.A. +Upload Helper Add-On is written by Flowing Code S.A. # Developer Guide diff --git a/pom.xml b/pom.xml index 7ceac95..432318a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,14 +5,14 @@ 4.0.0 com.flowingcode.vaadin.addons - template-addon + upload-helper-addon 1.0.0-SNAPSHOT - Template Add-on - Template Add-on for Vaadin Flow + Upload Helper Add-on + Upload Helper Add-on for Vaadin Flow https://www.flowingcode.com/en/open-source/ - 24.4.6 + 24.5.0 4.10.0 17 17 @@ -29,7 +29,7 @@ https://www.flowingcode.com - 2024 + 2022 Apache 2 @@ -39,9 +39,9 @@ - https://github.com/FlowingCode/AddonStarter24 - scm:git:git://github.com/FlowingCode/AddonStarter24.git - scm:git:ssh://git@github.com:/FlowingCode/AddonStarter24.git + https://github.com/FlowingCode/UploadHelper + scm:git:git://github.com/FlowingCode/UploadHelper.git + scm:git:ssh://git@github.com:/FlowingCode/UploadHelper.git master @@ -122,6 +122,17 @@ vaadin-core true + + org.projectlombok + lombok + 1.18.34 + provided + + + com.flowingcode.vaadin.test + testbench-rpc + 1.3.0 + com.flowingcode.vaadin.addons.demo commons-demo @@ -313,9 +324,9 @@ true none - true + true - https://javadoc.io/doc/com.vaadin/vaadin-platform-javadoc/${vaadin.version} + https://javadoc.io/doc/com.vaadin/vaadin-platform-javadoc/${vaadin.version} @@ -496,6 +507,7 @@ **/it/* **/DemoView.class **/DemoLayout.class + **/AppShellConfiguratorImpl.class diff --git a/src/main/java/com/flowingcode/vaadin/addons/uploadhelper/FileInfo.java b/src/main/java/com/flowingcode/vaadin/addons/uploadhelper/FileInfo.java new file mode 100644 index 0000000..4557e91 --- /dev/null +++ b/src/main/java/com/flowingcode/vaadin/addons/uploadhelper/FileInfo.java @@ -0,0 +1,212 @@ +/*- + * #%L + * Upload Helper Add-on + * %% + * Copyright (C) 2022 - 2024 Flowing Code + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package com.flowingcode.vaadin.addons.uploadhelper; + +import com.vaadin.flow.component.upload.FinishedEvent; +import com.vaadin.flow.component.upload.Upload; +import elemental.json.Json; +import elemental.json.JsonObject; +import java.io.Serializable; +import lombok.AccessLevel; +import lombok.Getter; + +/** Represents a file in the file list of an {@link Upload} component. */ +@SuppressWarnings("serial") +public final class FileInfo implements Serializable { + + private final String name; + + @Getter(AccessLevel.PACKAGE) + private Upload upload; + + private Boolean complete; + private Boolean indeterminate; + private String errorMessage; + private Integer progress; + private String status; + + /** + * Constructs a {@code FileInfo} object with the specified upload and file name. + * + * @param upload the {@code Upload} instance representing the file upload source + * @param name the name of the file being uploaded + */ + public FileInfo(Upload upload, String name) { + this.upload = upload; + this.name = name; + } + + /** + * Constructs a {@code FileInfo} object from the specified finished upload event. + * + * @param ev the {@code FinishedEvent} representing the succeeded or failed event + */ + public FileInfo(FinishedEvent ev) { + upload = ev.getSource(); + name = ev.getFileName(); + } + + /** Updates this file in the upload component. */ + public void update() { + update(false); + } + + /** Adds a new file to the upload component. */ + public void create() { + update(true); + } + + private void update(boolean createIfNotExists) { + upload.getElement().executeJs( + """ + var d = this; + var i = d.files.findIndex(f=>f.name==$0.name); + if (i<0) { + if ($1) d.files = [... d.files, $0]; else return; + } else { + if (d.files.some((e,j)=>e.name==$0.name && j>i)) d.files=d.files.filter((e,j)=>e.name!=$0.name || j<=i); + d.files[i] = Object.assign(d.files[i], $0); + } + d.files = Array.from(d.files); + """, + toJson(), createIfNotExists); + } + + private JsonObject toJson() { + JsonObject json = Json.createObject(); + json.put("name", name); + if (complete != null) { + json.put("complete", complete); + } + if (indeterminate != null) { + json.put("indeterminate", indeterminate); + } + if (errorMessage != null) { + json.put("error", errorMessage); + } + if (progress != null) { + json.put("progress", progress); + } + if (status != null) { + json.put("status", status); + } + return json; + } + + /** + * True if uploading is completed, false otherwise. + * + * @return This instance for method chaining + */ + public FileInfo complete(Boolean complete) { + this.complete = complete; + return this; + } + + /** + * Configure the upload in complete state (i.e. uploading is completed) + * + * @return This instance for method chaining + */ + public FileInfo complete() { + complete = true; + return this; + } + + /** + * Configure the upload in indeterminate state (i.e. the remaining time is unknown) + * + * @return This instance for method chaining + */ + public FileInfo indeterminate() { + return indeterminate(true); + } + + /** + * True if the remaining time is unknown, false otherwise. + * + * @return This instance for method chaining + */ + public FileInfo indeterminate(Boolean indeterminate) { + this.indeterminate = indeterminate; + return this; + } + + /** + * Error message returned by the server, if any. + * + * @return This instance for method chaining + */ + public FileInfo errorMessage(String errorMessage) { + this.errorMessage = errorMessage; + return this; + } + + /** + * Number representing the uploading progress. + * + * @return This instance for method chaining + */ + public FileInfo progress(Integer progress) { + this.progress = progress; + return this; + } + + /** + * Uploading status message. + * + * @return This instance for method chaining + */ + public FileInfo status(String status) { + this.status = status; + return this; + } + + /** Returns the name of the uploaded file. */ + public String getName() { + return name; + } + + /** Returns {@code true} if uploading is completed, false otherwise. */ + public Boolean getComplete() { + return complete; + } + + /** Returns {@code true} if the remaining progress is unknown, false otherwise. */ + public Boolean getIndeterminate() { + return indeterminate; + } + + /** Returns the error message returned by the server. */ + public String getErrorMessage() { + return errorMessage; + } + + /** Returns a number between 0 and 100, representing the uploading progress. */ + public Integer getProgress() { + return progress; + } + + /** Returns the uploading status. */ + public String getStatus() { + return status; + } + +} diff --git a/src/main/resources/META-INF/VAADIN/package.properties b/src/main/resources/META-INF/VAADIN/package.properties index c66616f..b96d56a 100644 --- a/src/main/resources/META-INF/VAADIN/package.properties +++ b/src/main/resources/META-INF/VAADIN/package.properties @@ -1 +1,20 @@ +### +# #%L +# Upload Helper Add-on +# %% +# Copyright (C) 2022 - 2024 Flowing Code +# %% +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# #L% +### vaadin.allowed-packages=com.flowingcode diff --git a/src/main/java/com/flowingcode/vaadin/addons/template/TemplateAddon.java b/src/test/java/com/flowingcode/vaadin/addons/AppShellConfiguratorImpl.java similarity index 56% rename from src/main/java/com/flowingcode/vaadin/addons/template/TemplateAddon.java rename to src/test/java/com/flowingcode/vaadin/addons/AppShellConfiguratorImpl.java index c9ec694..e7a6481 100644 --- a/src/main/java/com/flowingcode/vaadin/addons/template/TemplateAddon.java +++ b/src/test/java/com/flowingcode/vaadin/addons/AppShellConfiguratorImpl.java @@ -1,15 +1,15 @@ /*- * #%L - * Template Add-on + * Upload Helper Add-on * %% - * Copyright (C) 2024 Flowing Code + * Copyright (C) 2022 - 2024 Flowing Code * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,16 +17,13 @@ * limitations under the License. * #L% */ +package com.flowingcode.vaadin.addons; -package com.flowingcode.vaadin.addons.template; - -import com.vaadin.flow.component.Tag; -import com.vaadin.flow.component.dependency.JsModule; -import com.vaadin.flow.component.dependency.NpmPackage; -import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.page.AppShellConfigurator; +import com.vaadin.flow.component.page.Push; @SuppressWarnings("serial") -@NpmPackage(value = "@polymer/paper-input", version = "3.2.1") -@JsModule("@polymer/paper-input/paper-input.js") -@Tag("paper-input") -public class TemplateAddon extends Div {} +@Push +public class AppShellConfiguratorImpl implements AppShellConfigurator { + +} diff --git a/src/test/java/com/flowingcode/vaadin/addons/DemoLayout.java b/src/test/java/com/flowingcode/vaadin/addons/DemoLayout.java index b84172e..988e949 100644 --- a/src/test/java/com/flowingcode/vaadin/addons/DemoLayout.java +++ b/src/test/java/com/flowingcode/vaadin/addons/DemoLayout.java @@ -1,15 +1,15 @@ /*- * #%L - * Template Add-on + * Upload Helper Add-on * %% - * Copyright (C) 2024 Flowing Code + * Copyright (C) 2022 - 2024 Flowing Code * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/src/test/java/com/flowingcode/vaadin/addons/template/TemplateDemo.java b/src/test/java/com/flowingcode/vaadin/addons/template/TemplateDemo.java deleted file mode 100644 index 5f6e6ee..0000000 --- a/src/test/java/com/flowingcode/vaadin/addons/template/TemplateDemo.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.flowingcode.vaadin.addons.template; - -import com.flowingcode.vaadin.addons.demo.DemoSource; -import com.vaadin.flow.component.html.Div; -import com.vaadin.flow.router.PageTitle; -import com.vaadin.flow.router.Route; - -@DemoSource -@PageTitle("Template Add-on Demo") -@SuppressWarnings("serial") -@Route(value = "demo", layout = TemplateDemoView.class) -public class TemplateDemo extends Div { - - public TemplateDemo() { - add(new TemplateAddon()); - } -} diff --git a/src/test/java/com/flowingcode/vaadin/addons/template/it/ViewIT.java b/src/test/java/com/flowingcode/vaadin/addons/template/it/ViewIT.java deleted file mode 100644 index 0e5f164..0000000 --- a/src/test/java/com/flowingcode/vaadin/addons/template/it/ViewIT.java +++ /dev/null @@ -1,64 +0,0 @@ -/*- - * #%L - * Template Add-on - * %% - * Copyright (C) 2024 Flowing Code - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -package com.flowingcode.vaadin.addons.template.it; - -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertThat; - -import com.vaadin.testbench.TestBenchElement; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeDiagnosingMatcher; -import org.junit.Test; - -public class ViewIT extends AbstractViewTest { - - private Matcher hasBeenUpgradedToCustomElement = - new TypeSafeDiagnosingMatcher() { - - @Override - public void describeTo(Description description) { - description.appendText("a custom element"); - } - - @Override - protected boolean matchesSafely(TestBenchElement item, Description mismatchDescription) { - String script = "let s=arguments[0].shadowRoot; return !!(s&&s.childElementCount)"; - if (!item.getTagName().contains("-")) { - return true; - } - if ((Boolean) item.getCommandExecutor().executeScript(script, item)) { - return true; - } else { - mismatchDescription.appendText(item.getTagName() + " "); - mismatchDescription.appendDescriptionOf(is(not(this))); - return false; - } - } - }; - - @Test - public void componentWorks() { - TestBenchElement element = $("paper-input").first(); - assertThat(element, hasBeenUpgradedToCustomElement); - } -} diff --git a/src/test/java/com/flowingcode/vaadin/addons/template/test/SerializationTest.java b/src/test/java/com/flowingcode/vaadin/addons/template/test/SerializationTest.java deleted file mode 100644 index 1ee78c3..0000000 --- a/src/test/java/com/flowingcode/vaadin/addons/template/test/SerializationTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/*- - * #%L - * Template Add-on - * %% - * Copyright (C) 2024 Flowing Code - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ -package com.flowingcode.vaadin.addons.template.test; - -import com.flowingcode.vaadin.addons.template.TemplateAddon; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import org.junit.Assert; -import org.junit.Test; - -public class SerializationTest { - - private void testSerializationOf(Object obj) throws IOException, ClassNotFoundException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { - oos.writeObject(obj); - } - try (ObjectInputStream in = - new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { - obj.getClass().cast(in.readObject()); - } - } - - @Test - public void testSerialization() throws ClassNotFoundException, IOException { - try { - testSerializationOf(new TemplateAddon()); - } catch (Exception e) { - Assert.fail("Problem while testing serialization: " + e.getMessage()); - } - } -} diff --git a/src/test/java/com/flowingcode/vaadin/addons/template/DemoView.java b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/DemoView.java similarity index 84% rename from src/test/java/com/flowingcode/vaadin/addons/template/DemoView.java rename to src/test/java/com/flowingcode/vaadin/addons/uploadhelper/DemoView.java index a600c9d..1d9e1b5 100644 --- a/src/test/java/com/flowingcode/vaadin/addons/template/DemoView.java +++ b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/DemoView.java @@ -1,15 +1,15 @@ /*- * #%L - * Template Add-on + * Upload Helper Add-on * %% - * Copyright (C) 2024 Flowing Code + * Copyright (C) 2022 - 2024 Flowing Code * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,7 +18,7 @@ * #L% */ -package com.flowingcode.vaadin.addons.template; +package com.flowingcode.vaadin.addons.uploadhelper; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.router.BeforeEnterEvent; @@ -31,6 +31,6 @@ public class DemoView extends VerticalLayout implements BeforeEnterObserver { @Override public void beforeEnter(BeforeEnterEvent event) { - event.forwardTo(TemplateDemoView.class); + event.forwardTo(UploadHelperDemoView.class); } } diff --git a/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/FileInfoDemo.java b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/FileInfoDemo.java new file mode 100644 index 0000000..efdf0c6 --- /dev/null +++ b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/FileInfoDemo.java @@ -0,0 +1,101 @@ +/*- + * #%L + * Upload Helper Add-on + * %% + * Copyright (C) 2022 - 2024 Flowing Code + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package com.flowingcode.vaadin.addons.uploadhelper; + +import com.flowingcode.vaadin.addons.demo.DemoSource; +import com.vaadin.flow.component.UI; +import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.upload.Upload; +import com.vaadin.flow.component.upload.receivers.MultiFileMemoryBuffer; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; +import java.io.OutputStream; // hide-source +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.commons.io.output.NullOutputStream; // hide-source + +@DemoSource +@PageTitle("FileInfo Demo") +@SuppressWarnings("serial") +@Route(value = "upload-helper/demo2", layout = UploadHelperDemoView.class) +public class FileInfoDemo extends Div { + + public FileInfoDemo() { + // show-source Upload upload = new Upload(new MultiFileMemoryBuffer()); + + // #if vaadin eq 0 + add(new Div( + """ + Simulates progress updates, incrementing from 0% to 100% and updating the UI in real-time. + After reaching 100%, the file is set to "Please wait..." with an indeterminate progress state to represent some final processing. + After a 2-second delay, the system randomly determines if the processing succeeded or failed, updating the UI accordingly.""")); + + Upload upload = new Upload(new MultiFileMemoryBuffer() { + @Override + public OutputStream receiveUpload(String fileName, String MIMEType) { + super.receiveUpload(fileName, MIMEType); + return NullOutputStream.INSTANCE; + } + }); + add(upload); + // #endif + + Map processing = new ConcurrentHashMap<>(); + + upload.addSucceededListener(ev -> { + if (processing.put(ev.getFileName(), true) == null) { + UI ui = ev.getSource().getUI().get(); + new Thread(() -> { + AtomicInteger progress = new AtomicInteger(); + while (progress.get() <= 100) { + int p = progress.getAndIncrement(); + ui.access(() -> new FileInfo(ev).status(String.format("Processing (%s%%)", p)) + .progress(p).update()); + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + ui.access(() -> new FileInfo(ev).indeterminate().status("Please wait...").update()); + + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + if (Math.random() < 0.5) { + ui.access(() -> new FileInfo(ev).complete().update()); + } else { + ui.access(() -> new FileInfo(ev).errorMessage("Random failure").update()); + } + + processing.remove(ev.getFileName()); + }).start(); + } + }); + + } + + +} diff --git a/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/NullUpload.java b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/NullUpload.java new file mode 100644 index 0000000..dba136a --- /dev/null +++ b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/NullUpload.java @@ -0,0 +1,53 @@ +/*- + * #%L + * Upload Helper Add-on + * %% + * Copyright (C) 2022 - 2024 Flowing Code + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package com.flowingcode.vaadin.addons.uploadhelper; + +import com.vaadin.flow.component.upload.MultiFileReceiver; +import com.vaadin.flow.component.upload.Upload; +import com.vaadin.flow.component.upload.receivers.MemoryBuffer; +import com.vaadin.flow.component.upload.receivers.MultiFileMemoryBuffer; +import java.io.OutputStream; +import org.apache.commons.io.output.NullOutputStream; + +// this is just a helper class that discards the uploaded file +@SuppressWarnings("serial") +class NullUpload extends Upload { + + public NullUpload(MultiFileReceiver receiver) { + super(new MultiFileMemoryBuffer() { + @Override + public OutputStream receiveUpload(String fileName, String MIMEType) { + super.receiveUpload(fileName, MIMEType); + return NullOutputStream.INSTANCE; + } + }); + } + + public NullUpload() { + super(new MemoryBuffer() { + @Override + public OutputStream receiveUpload(String fileName, String MIMEType) { + super.receiveUpload(fileName, MIMEType); + return NullOutputStream.INSTANCE; + } + }); + } + +} diff --git a/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/PlaygroundDemo.java b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/PlaygroundDemo.java new file mode 100644 index 0000000..a7f3af3 --- /dev/null +++ b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/PlaygroundDemo.java @@ -0,0 +1,104 @@ +/*- + * #%L + * Upload Helper Add-on + * %% + * Copyright (C) 2022 - 2024 Flowing Code + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package com.flowingcode.vaadin.addons.uploadhelper; + +import com.vaadin.flow.component.checkbox.Checkbox; +import com.vaadin.flow.component.formlayout.FormLayout; +import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.textfield.IntegerField; +import com.vaadin.flow.component.textfield.TextField; +import com.vaadin.flow.component.upload.Upload; +import com.vaadin.flow.data.binder.Binder; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; +import lombok.Data; +import lombok.experimental.Accessors; + +@PageTitle("Playground") +@SuppressWarnings("serial") +@Route(value = "upload-helper/demo", layout = UploadHelperDemoView.class) +public class PlaygroundDemo extends Div { + + private String fileName; + private Upload upload; + + @Data + @Accessors(fluent = true) + private static class Bean { + boolean complete; + boolean indeterminate; + int progress; + String status; + String errorMessage; + } + + public PlaygroundDemo() { + add(upload = new NullUpload()); + new FileInfo(upload, fileName = "test").create(); + + upload.addSucceededListener(ev -> { + fileName = ev.getFileName(); + new FileInfo(ev).indeterminate().status("Processing...").update(); + }); + + Binder binder = new Binder<>(); + + FormLayout formLayout = new FormLayout(); + formLayout.setResponsiveSteps(new FormLayout.ResponsiveStep("0", 1)); + add(formLayout); + + Checkbox indeterminate = new Checkbox(); + Checkbox complete = new Checkbox(); + TextField status = new TextField(); + TextField errorMessage = new TextField(); + + IntegerField progress = new IntegerField(); + progress.setStepButtonsVisible(true); + + formLayout.addFormItem(indeterminate, "Indeterminate"); + formLayout.addFormItem(complete, "Complete"); + formLayout.addFormItem(status, "Status"); + formLayout.addFormItem(errorMessage, "Error Message"); + formLayout.addFormItem(progress, "Progress"); + + binder.forField(indeterminate).bind(Bean::indeterminate, Bean::indeterminate); + binder.forField(complete).bind(Bean::complete, Bean::complete); + binder.forField(status).bind(Bean::status, Bean::status); + binder.forField(errorMessage).bind(Bean::errorMessage, Bean::errorMessage); + binder.forField(progress).bind(Bean::progress, Bean::progress); + + binder.setBean(new Bean()); + + binder.addValueChangeListener(ev -> { + Bean bean = binder.getBean(); + var file = new FileInfo(upload, fileName); + file.indeterminate(bean.indeterminate); + file.complete(bean.complete); + file.status(bean.status); + file.errorMessage(bean.errorMessage); + file.progress(bean.progress); + file.update(); + }); + + indeterminate.setValue(true); + } + + +} diff --git a/src/test/java/com/flowingcode/vaadin/addons/template/TemplateDemoView.java b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/UploadHelperDemoView.java similarity index 71% rename from src/test/java/com/flowingcode/vaadin/addons/template/TemplateDemoView.java rename to src/test/java/com/flowingcode/vaadin/addons/uploadhelper/UploadHelperDemoView.java index 1954535..2f839b3 100644 --- a/src/test/java/com/flowingcode/vaadin/addons/template/TemplateDemoView.java +++ b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/UploadHelperDemoView.java @@ -1,8 +1,8 @@ /*- * #%L - * Template Add-on + * Upload Helper Add-on * %% - * Copyright (C) 2024 Flowing Code + * Copyright (C) 2022 - 2024 Flowing Code * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ * limitations under the License. * #L% */ -package com.flowingcode.vaadin.addons.template; +package com.flowingcode.vaadin.addons.uploadhelper; import com.flowingcode.vaadin.addons.DemoLayout; import com.flowingcode.vaadin.addons.GithubLink; @@ -27,12 +27,13 @@ @SuppressWarnings("serial") @ParentLayout(DemoLayout.class) -@Route("template") -@GithubLink("https://github.com/FlowingCode/AddonStarter24") -public class TemplateDemoView extends TabbedDemo { +@Route("upload-helper") +@GithubLink("https://github.com/FlowingCode/UploadHelper") +public class UploadHelperDemoView extends TabbedDemo { - public TemplateDemoView() { - addDemo(TemplateDemo.class); + public UploadHelperDemoView() { + addDemo(PlaygroundDemo.class); + addDemo(FileInfoDemo.class); setSizeFull(); } } diff --git a/src/test/java/com/flowingcode/vaadin/addons/template/it/AbstractViewTest.java b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/it/AbstractViewTest.java similarity index 96% rename from src/test/java/com/flowingcode/vaadin/addons/template/it/AbstractViewTest.java rename to src/test/java/com/flowingcode/vaadin/addons/uploadhelper/it/AbstractViewTest.java index 1f7749b..eda431a 100644 --- a/src/test/java/com/flowingcode/vaadin/addons/template/it/AbstractViewTest.java +++ b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/it/AbstractViewTest.java @@ -1,15 +1,15 @@ /*- * #%L - * Template Add-on + * Upload Helper Add-on * %% - * Copyright (C) 2024 Flowing Code + * Copyright (C) 2022 - 2024 Flowing Code * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,7 +18,7 @@ * #L% */ -package com.flowingcode.vaadin.addons.template.it; +package com.flowingcode.vaadin.addons.uploadhelper.it; import com.vaadin.testbench.ScreenshotOnFailureRule; import com.vaadin.testbench.TestBench; diff --git a/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/it/IntegrationCallables.java b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/it/IntegrationCallables.java new file mode 100644 index 0000000..0095e8e --- /dev/null +++ b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/it/IntegrationCallables.java @@ -0,0 +1,34 @@ +/*- + * #%L + * Upload Helper Add-on + * %% + * Copyright (C) 2022 - 2024 Flowing Code + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package com.flowingcode.vaadin.addons.uploadhelper.it; + +public interface IntegrationCallables { + + void complete(); + + void indeterminate(); + + void progress(int progress); + + void status(String status); + + void errorMessage(String errorMessage); + +} diff --git a/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/it/IntegrationView.java b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/it/IntegrationView.java new file mode 100644 index 0000000..414c4f6 --- /dev/null +++ b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/it/IntegrationView.java @@ -0,0 +1,73 @@ +/*- + * #%L + * Upload Helper Add-on + * %% + * Copyright (C) 2022 - 2024 Flowing Code + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package com.flowingcode.vaadin.addons.uploadhelper.it; + +import com.flowingcode.vaadin.addons.uploadhelper.FileInfo; +import com.vaadin.flow.component.ClientCallable; +import com.vaadin.flow.component.html.Div; +import com.vaadin.flow.component.upload.Upload; +import com.vaadin.flow.component.upload.receivers.MemoryBuffer; +import com.vaadin.flow.router.Route; + +@Route("it") +public class IntegrationView extends Div implements IntegrationCallables { + + private Upload upload; + + public IntegrationView() { + add(upload = new Upload(new MemoryBuffer())); + file().create(); + } + + private FileInfo file() { + return new FileInfo(upload, "test"); + } + + @Override + @ClientCallable + public void indeterminate() { + file().indeterminate().update(); + } + + @Override + @ClientCallable + public void complete() { + file().complete().update(); + } + + @Override + @ClientCallable + public void progress(int progress) { + file().progress(progress).update(); + } + + @Override + @ClientCallable + public void status(String status) { + file().status(status).update(); + } + + @Override + @ClientCallable + public void errorMessage(String errorMessage) { + file().errorMessage(errorMessage).update(); + } + +} diff --git a/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/it/ViewIT.java b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/it/ViewIT.java new file mode 100644 index 0000000..660b7d0 --- /dev/null +++ b/src/test/java/com/flowingcode/vaadin/addons/uploadhelper/it/ViewIT.java @@ -0,0 +1,81 @@ +/*- + * #%L + * Upload Helper Add-on + * %% + * Copyright (C) 2022 - 2024 Flowing Code + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +package com.flowingcode.vaadin.addons.uploadhelper.it; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import com.flowingcode.vaadin.testbench.rpc.HasRpcSupport; +import com.vaadin.flow.component.progressbar.testbench.ProgressBarElement; +import com.vaadin.testbench.TestBenchElement; +import org.junit.Before; +import org.junit.Test; + +public class ViewIT extends AbstractViewTest implements HasRpcSupport { + + IntegrationCallables $server = createCallableProxy(IntegrationCallables.class); + + public ViewIT() { + super("it"); + } + + private TestBenchElement file() { + return $("vaadin-upload-file").waitForFirst(); + } + + @Before + public void before() { + file(); + } + + @Test + public void indeterminate() { + $server.indeterminate(); + assertTrue("has attribute indeterminate", file().hasAttribute("indeterminate")); + } + + @Test + public void complete() { + $server.complete(); + assertTrue("has attribute complete", file().hasAttribute("complete")); + } + + @Test + public void errorMessage() { + $server.errorMessage("msg1"); + assertTrue("has attribute error", file().hasAttribute("error")); + assertEquals("msg1", + file().$("div").withAttribute("part", "error").first().getText()); + } + + @Test + public void status() { + $server.status("msg2"); + assertEquals("msg2", + file().$("div").withAttribute("part", "status").first().getText()); + } + + @Test + public void progress() { + $server.progress(42); + assertEquals(0.42, file().$(ProgressBarElement.class).first().getValue(), 0.001); + } + +} diff --git a/src/test/resources/META-INF/frontend/styles/shared-styles.css b/src/test/resources/META-INF/frontend/styles/shared-styles.css index 6680e2d..591fc71 100644 --- a/src/test/resources/META-INF/frontend/styles/shared-styles.css +++ b/src/test/resources/META-INF/frontend/styles/shared-styles.css @@ -1 +1,20 @@ -/*Demo styles*/ \ No newline at end of file +/*- + * #%L + * Upload Helper Add-on + * %% + * Copyright (C) 2022 - 2024 Flowing Code + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +/*Demo styles*/