diff --git a/.github/workflows/codequality.yml b/.github/workflows/codequality.yml new file mode 100644 index 00000000..6091ad33 --- /dev/null +++ b/.github/workflows/codequality.yml @@ -0,0 +1,26 @@ +name: Code Quality + +on: + pull_request: + branches: [master, development] + push: + branches: [master, development, java-8] + +jobs: + code_scan: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Set up JDK 10 + uses: actions/setup-java@v1 + with: + java-version: 10 + - name: Scan on SonarCloud.io + run: mvn verify sonar:sonar -Psonar --file superfields/pom.xml + env: + SONAR_TOKEN: ${{ secrets.SONARCLOUD_IO_LOGIN_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/makerelease.yml b/.github/workflows/makerelease.yml new file mode 100644 index 00000000..a6beb2a8 --- /dev/null +++ b/.github/workflows/makerelease.yml @@ -0,0 +1,34 @@ +name: Make Release + +on: + push: + branches: [master] + +jobs: + create-release: + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - uses: actions/checkout@v2 + - id: variables + run: | + echo "::set-output name=version::`head -1 superfields/release-notes.md | cut -d' ' -f2`" + echo "::set-output name=title::`head -1 superfields/release-notes.md | sed -n -e 's/^.* - //p'`" + export NOTES=`cat superfields/release-notes.md | sed -e '0,/^# /d;/^# /,$d'` + export NOTES="${NOTES//'%'/'%25'}" + export NOTES="${NOTES//$'\n'/'%0A'}" + export NOTES="${NOTES//$'\r'/'%0D'}" + echo "::set-output name=notes::$NOTES" + - name: Create Release + uses: fleskesvor/create-release@feature/support-target-commitish + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: "v${{ steps.variables.outputs.version }}" + commitish: "master" + release_name: "${{ steps.variables.outputs.version }} - ${{ steps.variables.outputs.title }}" + body: | + ${{ steps.variables.outputs.notes }} + draft: false + prerelease: false \ No newline at end of file diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 08afac21..e0a87645 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -1,18 +1,19 @@ # This workflow will build a Java project with Maven # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven -name: Java CI with Maven +name: Build (Java 10) on: push: - branches: [ master ] + branches: [ master, development ] pull_request: - branches: [ master ] + branches: [ master, development ] jobs: - build: + package: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/mavenpublish.yml b/.github/workflows/mavenpublish.yml index 2aadfd45..0f4b2017 100644 --- a/.github/workflows/mavenpublish.yml +++ b/.github/workflows/mavenpublish.yml @@ -8,9 +8,10 @@ on: types: [created] jobs: - build: + publish: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/releasebranch.yml b/.github/workflows/releasebranch.yml new file mode 100644 index 00000000..fc67f869 --- /dev/null +++ b/.github/workflows/releasebranch.yml @@ -0,0 +1,22 @@ +name: Release branch on milestone close + +on: + milestone: + types: [closed] + +jobs: + make-branch: + runs-on: ubuntu-latest + if: ${{ startsWith(github.event.milestone.title, '0.') || startsWith(github.event.milestone.title, '1.') || startsWith(github.event.milestone.title, '2.') || startsWith(github.event.milestone.title, '3.') || startsWith(github.event.milestone.title, '4.') || startsWith(github.event.milestone.title, '5.') || startsWith(github.event.milestone.title, '6.') || startsWith(github.event.milestone.title, '7.') || startsWith(github.event.milestone.title, '8.') || startsWith(github.event.milestone.title, '9.') }} + steps: + - id: version + run: | + set -x + echo "::set-output name=version::`echo '${{ github.event.milestone.title }}' | cut -d' ' -f1`" + - name: Push release branch + uses: UnforgivenPL/push-branch@v2 + with: + repository: ${{ github.repository }} + token: ${{ secrets.ACTIONS_PAT }} + source: development + target: release-${{ steps.version.outputs.version }} diff --git a/.github/workflows/setversion.yml b/.github/workflows/setversion.yml new file mode 100644 index 00000000..74525957 --- /dev/null +++ b/.github/workflows/setversion.yml @@ -0,0 +1,63 @@ +name: Version and Release Notes + +on: create + +jobs: + set-version: + if: ${{ (github.event.ref_type == 'branch') && startsWith(github.event.ref, 'release-') }} + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 10 + uses: actions/setup-java@v1 + with: + java-version: 10 + server-id: github # Value of the distributionManagement/repository/id field of the pom.xml + settings-path: ${{ github.workspace }} # location for the settings.xml file + - id: what-version + name: Determine version + run: | + set -x + export VERSION="`echo ${{ github.event.ref }} | sed -e s/release-//g`" + echo "::set-output name=version::$VERSION" + - name: Set version and update readme + run: | + set -x + export VERSION="${{ steps.what-version.outputs.version }}" + mvn versions:set -DnewVersion=$VERSION --file pom.xml + mvn versions:set -DnewVersion=$VERSION --file superfields/pom.xml + sed -i -e s/{VERSION}/$VERSION/g ./README.md + - name: Create milestone notes + uses: UnforgivenPL/milestone-notes@v1 + with: + match-milestone: "^${{ steps.what-version.outputs.version }} " + repository: ${{ github.repository }} + labels: "enhancement, api, bug" + - name: Format milestone notes + run: | + sed -i -e "s/## enhancement/## New features and enhancements/g" milestone-notes.md + sed -i -e "s/## api/## Changes to API/g" milestone-notes.md + sed -i -e "s/## bug/## Bug fixes/g" milestone-notes.md + sed -i -e "s/^$/(nothing reported)/g" milestone-notes.md + - name: Update release notes + run: | + echo -e "\n" | cat milestone-notes.md - superfields/release-notes.md > superfields/release-notes.md.new + mv superfields/release-notes.md.new superfields/release-notes.md + - name: Remove milestone notes + run: rm milestone-notes.md + - name: Push changes + uses: stefanzweifel/git-auto-commit-action@v4.1.6 + with: + commit_message: "(bot) version and release notes updated to ${{ steps.what-version.outputs.version }}" + branch: ${{ github.event.ref }} + - name: Create PR + uses: UnforgivenPL/pull-request@v1 + with: + source: ${{ github.event.ref }} + target: master + repository: ${{ github.repository }} + token: ${{ secrets.ACTIONS_PAT }} + pr-title: Release ${{ steps.what-version.outputs.version }} ready + pr-body: Automatically created release ${{ steps.what-version.outputs.version }}. + pr-assignees: ${{ github.actor }} diff --git a/README.md b/README.md index b0b97532..c425aafc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Welcome to SuperFields! ## Overview + This is a collection of hopefully useful Vaadin 14 components, grouped into several sub-projects: * `superfields` are various input components; * `demo-v14` contains an app for Vaadin 14 that shows all components - [see the demo online](https://superfields.herokuapp.com/) on Heroku @@ -18,7 +19,7 @@ This is the relevant dependency: org.vaadin.miki superfields - 0.6.0 + 0.6.1 ``` @@ -38,11 +39,13 @@ All releases are available: ### Java 8 -Some versions compatible with Java 8 may be released only to the Vaadin Directory. The repository has a branch `java-8`. The most recent version that supports Java 8 is `0.6.0.java8`. +Some versions compatible with Java 8 are available in the Vaadin Directory. They are marked with `.java8` suffix in the version, e.g. `0.6.0.java8`. Their functionality is identical to the official release. + +This repository has a branch `java-8` which contains the most recent release compatible with Java 8. ## Contribution guidelines -You are more than welcome to contribute. Feel free to make PRs, submit issues, etc. +You are more than welcome to contribute. Feel free to make PRs, submit issues, ideas etc. ## Small print diff --git a/demo-v14/pom.xml b/demo-v14/pom.xml index e0d44b68..fc1877fa 100644 --- a/demo-v14/pom.xml +++ b/demo-v14/pom.xml @@ -4,11 +4,11 @@ superfields-parent org.vaadin.miki - 0.6.0 + 0.6.1 superfields-demo-v14 - 0.6.0 + 0.6.1 V14 demo app for SuperFields Showcase application for V14 and SuperFields. war @@ -23,7 +23,7 @@ org.vaadin.miki superfields - 0.6.0 + 0.6.1 javax.servlet diff --git a/pom.xml b/pom.xml index 914f8f10..d011eabb 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.vaadin.miki superfields-parent - 0.6.0 + 0.6.1 superfields demo-v14 diff --git a/settings.xml b/settings.xml new file mode 100644 index 00000000..ea5758a7 --- /dev/null +++ b/settings.xml @@ -0,0 +1,11 @@ + + + + + github + ${env.GITHUB_ACTOR} + ${env.GITHUB_TOKEN} + + + + \ No newline at end of file diff --git a/superfields/pom.xml b/superfields/pom.xml index 620fea3c..adaba0c4 100644 --- a/superfields/pom.xml +++ b/superfields/pom.xml @@ -8,7 +8,7 @@ superfields SuperFields Code for various V14+ fields and other components. - 0.6.0 + 0.6.1 10 @@ -204,6 +204,27 @@ + + + sonar + + vaadin-miki_super-fields + vaadin-miki + https://sonarcloud.io + + + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 3.7.0.1746 + + + + + + directory diff --git a/superfields/release-notes.md b/superfields/release-notes.md new file mode 100644 index 00000000..55a763d9 --- /dev/null +++ b/superfields/release-notes.md @@ -0,0 +1,73 @@ +# 0.6.1 - Release process improvement +## New features and enhancements +* \#107 - [Generate release notes from a milestone](https://api.github.com/repos/vaadin-miki/super-fields/issues/107) +## Changes to API +(nothing reported) +## Bug fixes +* \#105 - [Removing date (time) picker and adding it back in the dom resets the display pattern](https://api.github.com/repos/vaadin-miki/super-fields/issues/105) + +# 0.6 - ComponentObserver and UnloadObserver +## New features and enhancements +* \#66 - [A field that changes value on becoming shown and hidden](https://api.github.com/repos/vaadin-miki/super-fields/issues/66) +* \#69 - [ComponentObserver - reusing client-side IntersectionObserver as a server-side component](https://api.github.com/repos/vaadin-miki/super-fields/issues/69) +* \#75 - [Component for encapsulating beforeunload events](https://api.github.com/repos/vaadin-miki/super-fields/issues/75) +* \#80 - [Expand SuperTabs to work also with removing tab contents](https://api.github.com/repos/vaadin-miki/super-fields/issues/80) +* \#82 - [Allow overriding default container in SuperTabs](https://api.github.com/repos/vaadin-miki/super-fields/issues/82) +## Changes to API +* \#76 - [Make Vaadin dependencies not transitive](https://api.github.com/repos/vaadin-miki/super-fields/issues/76) +* \#85 - [Add WithItems also to ItemGrid](https://api.github.com/repos/vaadin-miki/super-fields/issues/85) +* \#86 - [Create WithValue to allow chaining setValue calls](https://api.github.com/repos/vaadin-miki/super-fields/issues/86) +* \#89 - [Expose DatePicker and TimePicker in SuperDateTimePicker](https://api.github.com/repos/vaadin-miki/super-fields/issues/89) +* \#92 - [Add WithIdMixin to all components](https://api.github.com/repos/vaadin-miki/super-fields/issues/92) +## Bug fixes +* \#81 - [Setting date display pattern does not work out-of-the-box](https://api.github.com/repos/vaadin-miki/super-fields/issues/81) +* \#83 - [SuperTabs should implement HasItems](https://api.github.com/repos/vaadin-miki/super-fields/issues/83) +* \#90 - [SuperTabs should be using removing handler by default](https://api.github.com/repos/vaadin-miki/super-fields/issues/90) +* \#93 - ["this.observer is undefined" after ObservedField is removed from dom and added again](https://api.github.com/repos/vaadin-miki/super-fields/issues/93) +* \#98 - [Vaadin production mode not included](https://api.github.com/repos/vaadin-miki/super-fields/issues/98) +# 0.5.1 - Fix maven dependencies +## New features and enhancements +(nothing reported) +## Changes to API +(nothing reported) +## Bug fixes +* \#70 - [Parent pom unavailable for Directory downloads](https://api.github.com/repos/vaadin-miki/super-fields/issues/70) +# 0.5 - LazyLoad +## New features and enhancements +* \#50 - [Investigate lazy loading for ItemGrid](https://api.github.com/repos/vaadin-miki/super-fields/issues/50) +* \#51 - [Custom date formatting for date components](https://api.github.com/repos/vaadin-miki/super-fields/issues/51) +## Changes to API +(nothing reported) +## Bug fixes +* \#56 - [Set width to full in number fields](https://api.github.com/repos/vaadin-miki/super-fields/issues/56) +# 0.4 - ItemGrid +## New features and enhancements +* \#34 - [Basic version of `ItemGrid`](https://api.github.com/repos/vaadin-miki/super-fields/issues/34) +## Changes to API +(nothing reported) +## Bug fixes +(nothing reported) +# 0.3 - SuperTabs +## New features and enhancements +* \#26 - [SuperTabs](https://api.github.com/repos/vaadin-miki/super-fields/issues/26) +## Changes to API +* \#30 - [Add .withXYZ methods to all fields](https://api.github.com/repos/vaadin-miki/super-fields/issues/30) +## Bug fixes +(nothing reported) +# 0.2 - Date components +## New features and enhancements +* \#12 - [SuperDatePicker](https://api.github.com/repos/vaadin-miki/super-fields/issues/12) +* \#20 - [SuperDateTimePicker](https://api.github.com/repos/vaadin-miki/super-fields/issues/20) +## Changes to API +(nothing reported) +## Bug fixes +(nothing reported) +# 0.1 - Number fields +## New features and enhancements +* \#2 - [SuperDoubleField](https://api.github.com/repos/vaadin-miki/super-fields/issues/2) +* \#4 - [SuperIntegerField and SuperLongField](https://api.github.com/repos/vaadin-miki/super-fields/issues/4) +* \#5 - [SuperBigDecimalField](https://api.github.com/repos/vaadin-miki/super-fields/issues/5) +## Changes to API +(nothing reported) +## Bug fixes +* \#10 - [Max integer length does not work if it is a multiplication of grouping size](https://api.github.com/repos/vaadin-miki/super-fields/issues/10) \ No newline at end of file diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternHelper.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternHelper.java index 82431830..556cd364 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternHelper.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternHelper.java @@ -1,5 +1,6 @@ package org.vaadin.miki.superfields.dates; +import com.vaadin.flow.component.AttachEvent; import com.vaadin.flow.component.Component; /** @@ -9,7 +10,7 @@ * @author miki * @since 2020-05-02 */ -final class DatePatternHelper { +final class DatePatternHelper { /** * Returns the pattern descriptor string expected by the client-side code. @@ -52,20 +53,48 @@ private static String convertDatePatternToClientPattern(DatePattern pattern) { } } + private final C source; + /** - * Does magic and sets the display pattern on the client side. - * Requires the client-side connector to have a {@code setDisplayPattern} method. - * @param source Source component. - * @param pattern Pattern to set. + * Creates a helper for a given source object. + * The client-side representation should have mixed in methods from {@code date-pattern-mixin.js}. + * @param source Source to use. + */ + DatePatternHelper(C source) { + this.source = source; + this.source.addAttachListener(this::onAttached); + } + + /** + * Class client-side method {@code initPatternSetting()} that, well, inits pattern setting. + * In general, client-side code overrides a few methods to make sure pattern displaying and parsing works properly with custom patterns. */ - static void setClientSidePattern(Component source, DatePattern pattern) { - source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(source, context -> - source.getElement().callJsFunction("setDisplayPattern", source.getElement(), convertDatePatternToClientPattern(pattern)) + protected void initPatternSetting() { + this.source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> + this.source.getElement().callJsFunction("initPatternSetting", this.source) )); } - private DatePatternHelper() { - // instances not allowed + /** + * Callback when onAttach() is called. + * @param event An {@link AttachEvent}. + */ + protected void onAttached(AttachEvent event) { + this.initPatternSetting(); + this.updateClientSidePattern(); + } + + /** + * Does magic and sets the display pattern on the client side. + * Requires the client-side connector to have a {@code setDisplayPattern} method. + */ + protected void updateClientSidePattern() { + this.source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> + this.source.getElement().callJsFunction( + "setDisplayPattern", + this.source.getElement(), convertDatePatternToClientPattern(this.source.getDatePattern()) + ) + )); } } diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java index 346b6b57..f8a8f264 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java @@ -30,6 +30,8 @@ public class SuperDatePicker extends DatePicker WithValueMixin, LocalDate, SuperDatePicker>, WithIdMixin { + private final DatePatternHelper delegate = new DatePatternHelper<>(this); + private DatePattern datePattern; public SuperDatePicker() { @@ -77,22 +79,25 @@ public SuperDatePicker(String label, LocalDate initialDate, ValueChangeListener< } public SuperDatePicker(LocalDate initialDate, Locale locale) { - super(initialDate, locale); + super(initialDate); + this.setLocale(locale); } @Override public final void setLocale(Locale locale) { - this.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this, context -> - this.getElement().callJsFunction("initPatternSetting", this.getElement()) - )); - SuperDatePickerI18nHelper.updateI18N(locale, this::getI18n, this::setI18n); + // there is a call for setting locale from the superclass' constructor + // and when that happens, the field is not yet initialised + if(this.delegate != null) { + this.delegate.initPatternSetting(); + SuperDatePickerI18nHelper.updateI18N(locale, this::getI18n, this::setI18n); + } super.setLocale(locale); } @Override public void setDatePattern(DatePattern datePattern) { this.datePattern = datePattern; - DatePatternHelper.setClientSidePattern(this, datePattern); + this.delegate.updateClientSidePattern(); } @Override diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java index b724ba4c..dce504f9 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java @@ -36,6 +36,8 @@ public class SuperDateTimePicker extends DateTimePicker private static final String INTERNAL_DATE_PICKER_FIELD_NAME = "datePicker"; private static final String INTERNAL_TIME_PICKER_FIELD_NAME = "timePicker"; + private final DatePatternHelper delegate = new DatePatternHelper<>(this); + private DatePattern datePattern; public SuperDateTimePicker() { @@ -89,11 +91,12 @@ public SuperDateTimePicker(LocalDateTime initialDateTime, Locale locale) { @Override public void setLocale(Locale locale) { - this.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this, context -> - this.getElement().callJsFunction("initPatternSetting", this) - )) - ; - SuperDatePickerI18nHelper.updateI18N(locale, this::getDatePickerI18n, this::setDatePickerI18n); + // this method is called from the constructor of the superclass + // which means that first time it gets called, the delegate is not yet initialised + if(this.delegate != null) { + this.delegate.initPatternSetting(); + SuperDatePickerI18nHelper.updateI18N(locale, this::getDatePickerI18n, this::setDatePickerI18n); + } super.setLocale(locale); } @@ -101,7 +104,7 @@ public void setLocale(Locale locale) { * Exposes an internal {@link DatePicker}, if it was successfully obtained through reflection. * @return A {@link DatePicker} used by this component, if possible. */ - public Optional getDatePicker() { + public Optional getInternalDatePicker() { return ReflectTools.getValueOfField(this, DatePicker.class, INTERNAL_DATE_PICKER_FIELD_NAME); } @@ -116,7 +119,7 @@ public Optional getInternalTimePicker() { @Override public void setDatePattern(DatePattern pattern) { this.datePattern = pattern; - DatePatternHelper.setClientSidePattern(this, pattern); + this.delegate.updateClientSidePattern(); } @Override