diff --git a/.github/actions/archive-test-results/action.yaml b/.github/actions/archive-test-results/action.yaml new file mode 100644 index 000000000..e3ec9f8a0 --- /dev/null +++ b/.github/actions/archive-test-results/action.yaml @@ -0,0 +1,40 @@ +name: Archive Test Results +description: Archive runtime logs, screenshots, and artifacts from test runs +inputs: + platform: + description: Platform (android or ios) + required: true + test-type: + description: Test type (widget name or js-actions) + required: true + workspace-path: + description: Workspace path for artifacts + required: false + default: ${{ github.workspace }} + +runs: + using: composite + steps: + - name: Archive runtime logs + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 + if: always() + with: + name: ${{ inputs.platform }}-runtime-logs-${{ inputs.test-type }} + path: log/*.log + if-no-files-found: ignore + + - name: Archive test screenshots + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 + if: always() + with: + name: ${{ inputs.platform }}-screenshots-${{ inputs.test-type }} + path: ${{ inputs.workspace-path }}/maestro/images/actual/${{ inputs.platform }}/**/*.png + if-no-files-found: ignore + + - name: Archive artifacts + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 + if: always() + with: + name: ${{ inputs.platform }}-artifacts-${{ inputs.test-type }} + path: packages/pluggableWidgets/**/artifacts/ + if-no-files-found: ignore \ No newline at end of file diff --git a/.github/actions/create-native-bundle/action.yml b/.github/actions/create-native-bundle/action.yml index 91dd7f185..4ae5ea850 100644 --- a/.github/actions/create-native-bundle/action.yml +++ b/.github/actions/create-native-bundle/action.yml @@ -16,20 +16,23 @@ runs: apt install curl -y shell: bash - name: "Download test project" - run: curl -L -o project.zip https://github.com/mendix/Native-Mobile-Resources/archive/refs/heads/main.zip + run: curl -L -o project.zip https://github.com/mendix/Native-Mobile-Resources/archive/refs/heads/mx-version/10.zip shell: bash - name: "Extract test project" uses: montudor/action-zip@v1.0.0 with: args: unzip -qq project.zip + - name: "Rename extracted directory" + run: mv Native-Mobile-Resources-mx-version-10 Native-Mobile-Resources-mx10 + shell: bash - name: "Extract deployment package" uses: montudor/action-zip@v1.0.0 with: - args: unzip -qq ${{ inputs.mda-file }} -d Native-Mobile-Resources-main/deployment + args: unzip -qq ${{ inputs.mda-file }} -d Native-Mobile-Resources-mx10/deployment - name: "Create bundle for ${{ inputs.platform }}" run: | mkdir -p ${{ inputs.platform }}/assets - cd Native-Mobile-Resources-main/deployment/native && \ + cd Native-Mobile-Resources-mx10/deployment/native && \ /tmp/mxbuild/modeler/tools/node/linux-x64/node \ /tmp/mxbuild/modeler/tools/node/node_modules/react-native/cli.js \ bundle --verbose --platform ${{ inputs.platform }} --dev false \ diff --git a/.github/actions/setup-maestro/action.yaml b/.github/actions/setup-maestro/action.yaml new file mode 100644 index 000000000..ca316aee2 --- /dev/null +++ b/.github/actions/setup-maestro/action.yaml @@ -0,0 +1,21 @@ +name: "Setup Maestro" +description: "Install and cache Maestro" +runs: + using: "composite" + steps: + - name: "Cache Maestro" + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 + with: + path: $HOME/.local/bin/maestro + key: maestro-${{ runner.os }}-v1 + + - name: "Install Maestro" + shell: bash + run: | + if [ ! -f "$HOME/.local/bin/maestro/bin/maestro" ]; then + mkdir -p $HOME/.local/bin + curl -L "https://github.com/mobile-dev-inc/maestro/releases/latest/download/maestro.zip" -o maestro.zip + unzip maestro.zip -d $HOME/.local/bin + chmod +x $HOME/.local/bin/maestro/bin/maestro + fi + echo "$HOME/.local/bin" >> $GITHUB_PATH \ No newline at end of file diff --git a/.github/actions/setup-node-with-cache/action.yaml b/.github/actions/setup-node-with-cache/action.yaml new file mode 100644 index 000000000..719b600dd --- /dev/null +++ b/.github/actions/setup-node-with-cache/action.yaml @@ -0,0 +1,30 @@ +name: 'Setup Node with Cached Dependencies' +description: 'Set up Node.js and install dependencies with caching' +runs: + using: 'composite' + steps: + - name: "Set up node" + uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4 + with: + node-version-file: .nvmrc + + - name: "Cache yarn dependencies" + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4 + with: + path: | + .yarn/cache + .yarn/unplugged + .yarn/install-state.gz + node_modules + key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock', '.yarnrc.yml') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: "Install dependencies" + shell: bash + run: | + if [ ! -d "node_modules" ]; then + yarn install --immutable + else + echo "Dependencies already installed from cache" + fi \ No newline at end of file diff --git a/.github/actions/setup-python/action.yaml b/.github/actions/setup-python/action.yaml new file mode 100644 index 000000000..4f63b3a6a --- /dev/null +++ b/.github/actions/setup-python/action.yaml @@ -0,0 +1,10 @@ +name: "Setup Python Common" +description: "Setup Python and install dependencies" +runs: + using: "composite" + steps: + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: '3.12' + - run: pip install PyYAML httplib2 + shell: bash \ No newline at end of file diff --git a/.github/actions/setup-tools/action.yaml b/.github/actions/setup-tools/action.yaml new file mode 100644 index 000000000..ef6661bf5 --- /dev/null +++ b/.github/actions/setup-tools/action.yaml @@ -0,0 +1,42 @@ +name: "Setup Tools" +description: "Common setup for widget and js test jobs" +inputs: + mendix_version: + description: "Mendix version" + required: true +outputs: + java-path: + description: "Path to the installed Java" + value: ${{ steps.setup-java.outputs.path }} +runs: + using: "composite" + steps: + - name: "Setup Python and dependencies" + uses: ./.github/actions/setup-python + + - name: "Setup Node and dependencies" + uses: ./.github/actions/setup-node-with-cache + + - name: "Setup Java 21" + id: setup-java + uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 #v4 + with: + distribution: "temurin" + java-version: "21" + + - name: "Cache Mendix runtime" + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 #v4 + with: + path: tmp/runtime.tar.gz + key: mendix-runtime-${{ inputs.mendix_version }} + + - name: "Cache m2ee-tools" + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 #v4 + with: + path: tmp/m2ee + key: m2ee-tools-v1 + + - name: "Install Maestro" + uses: ./.github/actions/setup-maestro + + diff --git a/.github/actions/setup-xcode-cli-tools/action.yaml b/.github/actions/setup-xcode-cli-tools/action.yaml new file mode 100644 index 000000000..4062c9e05 --- /dev/null +++ b/.github/actions/setup-xcode-cli-tools/action.yaml @@ -0,0 +1,14 @@ +name: "Setup Xcode CLI Tools" +description: "Ensure Xcode CLI tools are configured" +runs: + using: "composite" + steps: + - name: "Verify and set Xcode CLI tools" + shell: bash + run: | + if ! xcode-select --print-path; then + echo "Xcode CLI tools not set. Setting them now." + sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer + else + echo "Xcode CLI tools are already configured." + fi \ No newline at end of file diff --git a/.github/actions/start-runtime/action.yml b/.github/actions/start-runtime/action.yml deleted file mode 100644 index 908276941..000000000 --- a/.github/actions/start-runtime/action.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: "Start the runtime" -description: "Start the runtime in preparation of the native e2e tests" -inputs: - mda-file: - description: "Path to the deployment package" - required: true - mendix-version: - description: "Mendix version to use for the runtime" - required: true -runs: - using: composite - steps: - - name: "Setup Python" - uses: actions/setup-python@v4.5.0 - with: - python-version: "3.x" - - - name: "Install Python dependencies" - run: pip install pyaml httplib2 - shell: bash - - - name: "Setup Java 21" - id: setup-java - uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 #v4 - with: - distribution: "temurin" - java-version: "21" - - - name: "Make setup-runtime.sh executable" - run: chmod +x .github/scripts/setup-runtime.sh - shell: bash - - - name: "Initial setup" - run: | - .github/scripts/setup-runtime.sh "${{ inputs.mda-file }}" "${{ inputs.mendix-version }}" "${{ steps.setup-java.outputs.path }}" "${{ github.workspace }}" - shell: bash - - - name: "Start mxruntime with retries" - run: | - MAX_RETRIES=3 - RETRY=0 - until bin/m2ee -c ${{ github.workspace }}/project/m2ee-native.yml --verbose --yolo start; do - RETRY=$((RETRY+1)) - if [ $RETRY -ge $MAX_RETRIES ]; then - echo "mxruntime failed after $MAX_RETRIES attempts." - exit 1 - fi - echo "mxruntime failed, retrying ($RETRY/$MAX_RETRIES)..." - .github/scripts/setup-runtime.sh "${{ inputs.mda-file }}" "${{ inputs.mendix-version }}" "${{ steps.setup-java.outputs.path }}" "${{ github.workspace }}" - done - shell: bash \ No newline at end of file diff --git a/.github/actions/use-arficats-from-specific-run/action.yaml b/.github/actions/use-arficats-from-specific-run/action.yaml new file mode 100644 index 000000000..694d61649 --- /dev/null +++ b/.github/actions/use-arficats-from-specific-run/action.yaml @@ -0,0 +1,76 @@ +name: "Download Artifact from Specific Run" +description: "Download an artifact from a specific workflow run using GitHub CLI" +inputs: + artifact_name: + description: "Name of the artifact to download" + required: true + run_id: + description: "Workflow run ID" + required: true + output_dir: + description: "Directory to extract the artifact" + required: true + platform: + description: "Platform (android or ios)" + required: true + github_token: + description: "GitHub token for authentication" + required: true +runs: + using: "composite" + steps: + - name: "Install GitHub CLI" + shell: bash + run: | + if ! command -v gh &> /dev/null; then + if [[ "$RUNNER_OS" == "Linux" ]]; then + sudo apt update + sudo apt install -y gh + elif [[ "$RUNNER_OS" == "macOS" ]]; then + brew install gh + fi + fi + - name: "Authenticate GitHub CLI" + shell: bash + run: | + unset GITHUB_TOKEN + echo "${{ inputs.github_token }}" | gh auth login --with-token + - name: "Fetch artifact URL" + id: fetch-artifacts + shell: bash + run: | + echo "Fetching artifacts for run ID: ${{ inputs.run_id }}" + echo "Looking for artifact: ${{ inputs.artifact_name }}" + echo "Note: Use the full run ID from the URL (e.g., 17402124525), not the run number from the UI (e.g., #1269)" + + # Check if the run exists + if ! gh api "repos/${{ github.repository }}/actions/runs/${{ inputs.run_id }}" > /dev/null 2>&1; then + echo "Error: Run ID ${{ inputs.run_id }} not found or not accessible" + echo "Make sure you're using the full run ID from the URL, not the run number displayed in the UI" + exit 1 + fi + + # Get the artifact URL + url=$(gh api "repos/${{ github.repository }}/actions/runs/${{ inputs.run_id }}/artifacts" --jq '.artifacts[] | select(.name == "${{ inputs.artifact_name }}") | .archive_download_url' 2>/dev/null || echo "") + + if [ -z "$url" ]; then + echo "Error: Artifact '${{ inputs.artifact_name }}' not found in run ${{ inputs.run_id }}" + echo "Available artifacts in this run:" + gh api "repos/${{ github.repository }}/actions/runs/${{ inputs.run_id }}/artifacts" --jq '.artifacts[].name' 2>/dev/null || echo "No artifacts found or run not accessible" + exit 1 + fi + + echo "Found artifact URL: $url" + echo "artifacts_url=$url" >> $GITHUB_ENV + - name: "Download and extract artifact" + if: env.artifacts_url != '' + shell: bash + run: | + echo "Downloading artifact from: $artifacts_url" + curl -L -H "Authorization: token ${{ inputs.github_token }}" -o ${{ inputs.platform }}-app.zip "$artifacts_url" + + echo "Extracting artifact to: ${{ inputs.output_dir }}" + unzip ${{ inputs.platform }}-app.zip -d ${{ inputs.output_dir }} + + echo "Contents of ${{ inputs.output_dir }}:" + ls -la ${{ inputs.output_dir }}/ \ No newline at end of file diff --git a/.github/scripts/determine-widget-scope.sh b/.github/scripts/determine-widget-scope.sh index 333ca4e56..e3e886db7 100644 --- a/.github/scripts/determine-widget-scope.sh +++ b/.github/scripts/determine-widget-scope.sh @@ -10,6 +10,9 @@ current_commit="$4" # List of all native widgets all_widgets='["accordion-native","activity-indicator-native","animation-native","app-events-native","background-gradient-native","background-image-native","badge-native","bar-chart-native","barcode-scanner-native","bottom-sheet-native","carousel-native","color-picker-native","column-chart-native","feedback-native","floating-action-button-native","gallery-native","gallery-text-filter-native","image-native","intro-screen-native","line-chart-native","listview-swipe-native","maps-native","pie-doughnut-chart-native","popup-menu-native","progress-bar-native","progress-circle-native","qr-code-native","radio-buttons-native","range-slider-native","rating-native","repeater-native","safe-area-view-native","signature-native","slider-native","switch-native","toggle-buttons-native","video-player-native","web-view-native"]' +# Combined widgets and JS actions for default cases +all_widgets_and_js='["accordion-native","activity-indicator-native","animation-native","app-events-native","background-gradient-native","background-image-native","badge-native","bar-chart-native","barcode-scanner-native","bottom-sheet-native","carousel-native","color-picker-native","column-chart-native","feedback-native","floating-action-button-native","gallery-native","gallery-text-filter-native","image-native","intro-screen-native","line-chart-native","listview-swipe-native","maps-native","pie-doughnut-chart-native","popup-menu-native","progress-bar-native","progress-circle-native","qr-code-native","radio-buttons-native","range-slider-native","rating-native","repeater-native","safe-area-view-native","signature-native","slider-native","switch-native","toggle-buttons-native","video-player-native","web-view-native","mobile-resources-native","nanoflow-actions-native"]' + if [ "$event_name" == "pull_request" ]; then if git cat-file -e "$before_commit" 2>/dev/null; then changed_files=$(git diff --name-only "$before_commit" "$current_commit") @@ -19,24 +22,42 @@ if [ "$event_name" == "pull_request" ]; then fi selected_workspaces="" + js_actions_changed=false + for file in $changed_files; do if [[ $file == packages/pluggableWidgets/* ]]; then widget=$(echo $file | cut -d'/' -f3) if [[ ! $selected_workspaces =~ $widget ]]; then selected_workspaces="$selected_workspaces $widget" fi + elif [[ $file == packages/jsActions/mobile-resources-native/* ]] || [[ $file == packages/jsActions/nanoflow-actions-native/* ]]; then + js_actions_changed=true fi done # Trim leading and trailing spaces from selected_workspaces selected_workspaces=$(echo $selected_workspaces | xargs) - if [[ -n "$selected_workspaces" ]]; then + # Build the final scope and widgets output + if [[ -n "$selected_workspaces" ]] && [[ "$js_actions_changed" == "true" ]]; then + # Both widgets and JS actions changed + # Convert space-separated widget names to JSON array format + widget_array=$(echo "$selected_workspaces" | sed 's/ /","/g') + echo "scope=--all --include '$selected_workspaces mobile-resources-native nanoflow-actions-native'" >> $GITHUB_OUTPUT + echo "widgets=[\"$widget_array\",\"mobile-resources-native\",\"nanoflow-actions-native\"]" >> $GITHUB_OUTPUT + elif [[ -n "$selected_workspaces" ]] && [[ "$js_actions_changed" == "false" ]]; then + # Only widgets changed + widget_array=$(echo "$selected_workspaces" | sed 's/ /","/g') echo "scope=--all --include '$selected_workspaces'" >> $GITHUB_OUTPUT - echo "widgets=[\"$selected_workspaces\"]" >> $GITHUB_OUTPUT + echo "widgets=[\"$widget_array\"]" >> $GITHUB_OUTPUT + elif [[ -z "$selected_workspaces" ]] && [[ "$js_actions_changed" == "true" ]]; then + # Only JS actions changed + echo "scope=--all --include 'mobile-resources-native nanoflow-actions-native'" >> $GITHUB_OUTPUT + echo "widgets=[\"mobile-resources-native\",\"nanoflow-actions-native\"]" >> $GITHUB_OUTPUT else - echo "scope=--all --include '*-native'" >> $GITHUB_OUTPUT - echo "widgets=${all_widgets}" >> $GITHUB_OUTPUT + # No specific changes detected in widgets or JS actions, run everything + echo "scope=--all --include '*-native mobile-resources-native nanoflow-actions-native'" >> $GITHUB_OUTPUT + echo "widgets=${all_widgets_and_js}" >> $GITHUB_OUTPUT fi else if [ -n "$input_workspace" ] && [ "$input_workspace" != "*-native" ] && [ "$input_workspace" != "js-actions" ]; then @@ -47,8 +68,8 @@ else echo "scope=--all --include 'mobile-resources-native nanoflow-actions-native'" >> $GITHUB_OUTPUT echo "widgets=[\"mobile-resources-native\",\"nanoflow-actions-native\"]" >> $GITHUB_OUTPUT else - echo "scope=--all --include '*-native'" >> $GITHUB_OUTPUT - echo "widgets=${all_widgets}" >> $GITHUB_OUTPUT + echo "scope=--all --include '*-native mobile-resources-native nanoflow-actions-native'" >> $GITHUB_OUTPUT + echo "widgets=${all_widgets_and_js}" >> $GITHUB_OUTPUT fi fi diff --git a/.github/scripts/setup-runtime.sh b/.github/scripts/setup-runtime.sh index 1d4f7c2f3..72b26aa76 100644 --- a/.github/scripts/setup-runtime.sh +++ b/.github/scripts/setup-runtime.sh @@ -15,14 +15,19 @@ sed -i -- "s=\$ROOT_PATH=$WORKSPACE=g" project/m2ee-native.yml sed -i -- "s=\$JAVA_HOME=$JAVA_PATH=g" project/m2ee-native.yml mkdir -p var/log var/opt/m2ee var/run bin tmp -git clone https://github.com/KevinVlaanderen/m2ee-tools.git tmp/m2ee +# Clone m2ee-tools only if not cached +if [ ! -d tmp/m2ee ]; then + git clone https://github.com/KevinVlaanderen/m2ee-tools.git tmp/m2ee +fi mv tmp/m2ee/src/* var/opt/m2ee chmod a=rwx var/log/ var/run/ echo "#!/bin/bash -x" > bin/m2ee echo "python3 var/opt/m2ee/m2ee.py \$@" >>bin/m2ee chmod +x bin/m2ee +# Download only if not cached mkdir -p "$WORKSPACE/project/runtimes" "$WORKSPACE/project/data/model-upload" "$WORKSPACE/project/data/database" "$WORKSPACE/project/data/files" "$WORKSPACE/project/data/tmp" -wget -q "https://cdn.mendix.com/runtime/mendix-$MENDIX_VERSION.tar.gz" -O tmp/runtime.tar.gz -tar xfz tmp/runtime.tar.gz --directory "$WORKSPACE/project/runtimes" -rm tmp/runtime.tar.gz \ No newline at end of file +if [ ! -f tmp/runtime.tar.gz ]; then + wget -q "https://cdn.mendix.com/runtime/mendix-$MENDIX_VERSION.tar.gz" -O tmp/runtime.tar.gz +fi +tar xfz tmp/runtime.tar.gz --directory "$WORKSPACE/project/runtimes" \ No newline at end of file diff --git a/.github/scripts/start-runtime-with-verification.sh b/.github/scripts/start-runtime-with-verification.sh new file mode 100644 index 000000000..cb6f181e3 --- /dev/null +++ b/.github/scripts/start-runtime-with-verification.sh @@ -0,0 +1,33 @@ +#!/bin/bash +set -e + +# Arguments +MDA_FILE="$1" +MENDIX_VERSION="$2" +JAVA_PATH="$3" +WORKSPACE="$4" + +# Ensure setup script is executable +chmod +x .github/scripts/setup-runtime.sh + +# Run setup +.github/scripts/setup-runtime.sh "$MDA_FILE" "$MENDIX_VERSION" "$JAVA_PATH" "$WORKSPACE" + +# Stop any running Mendix runtime before starting a new one +if bin/m2ee -c "$WORKSPACE/project/m2ee-native.yml" status | grep -q "running"; then + echo "Stopping previous Mendix runtime..." + bin/m2ee -c "$WORKSPACE/project/m2ee-native.yml" stop + sleep 10 +fi + +# Start runtime +START_OUTPUT=$(bin/m2ee -c "$WORKSPACE/project/m2ee-native.yml" --verbose --yolo start 2>&1) +echo "Full output from start command:" +echo "$START_OUTPUT" +if [ $? -eq 0 ]; then + echo "Runtime started successfully (exit code)." + exit 0 +fi + +echo "Runtime did not start successfully." +exit 1 \ No newline at end of file diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 7b418cf16..3dc9af2c7 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -3,11 +3,11 @@ name: Run build on: push: branches: - - main + - mx-version/10 - 'mx/release/**' pull_request: branches: - - main + - mx-version/10 - 'mx/release/**' jobs: test: @@ -23,7 +23,7 @@ jobs: uses: softprops/diffset@db8c4e13f5cc3f8ab666ba2cb6998b688058a41c # v1 if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository with: - base: main + base: mx-version/10 global_files: | !{packages/**/*,configs/e2e/*.json,scripts/**/*,data/**/*} env: diff --git a/.github/workflows/NativePipeline.yml b/.github/workflows/NativePipeline.yml index 3acf5ead4..60f852e8f 100644 --- a/.github/workflows/NativePipeline.yml +++ b/.github/workflows/NativePipeline.yml @@ -2,6 +2,10 @@ name: Run Native Pipeline on: workflow_dispatch: inputs: + run_name: + description: "Provide a name for the run" + required: false + default: "" mendix_version: description: "Provide the SP version to be used (e.g., 10.14.0.43709) - has to be a released version (Default: latest from Mendix versions.json)" required: false @@ -11,6 +15,10 @@ on: default: "" required: false type: string + LOCAL_TEST_ARTIFACT_RUN_ID: + description: "Workflow run ID for local artifact download (leave empty for normal CI). Use the full run ID from the URL, not the run number displayed in UI." + required: false + default: "" workspace: description: "Select a widget to test (Default will run all)" required: true @@ -57,12 +65,14 @@ on: - toggle-buttons-native - video-player-native - web-view-native - - # Run at 0:00 UTC (2:00 AM CET time during summer, 1:00 AM during winter) - schedule: - - cron: '0 0 * * *' + # Trigger on PR - # pull_request: + pull_request: + +# Use default name in case no input +run-name: ${{ github.event.inputs.run_name || 'Run Native Pipeline' }} +env: + LOCAL_TEST_ARTIFACT_RUN_ID: ${{ github.event.inputs.LOCAL_TEST_ARTIFACT_RUN_ID || '' }} permissions: packages: write jobs: @@ -86,7 +96,7 @@ jobs: echo "Scope is: ${{ steps.scope.outputs.scope }}" echo "Widgets or js actions are: ${{ steps.scope.outputs.widgets }}" mendix-version: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 outputs: mendix_version: ${{ steps.set-mendix-version.outputs.MENDIX_VERSION }} steps: @@ -152,7 +162,7 @@ jobs: echo "Final nt_branch value: ${{ steps.set-output.outputs.nt_branch }}" docker-images: needs: [mendix-version] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: "Login to GitHub Container Registry" uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 @@ -179,7 +189,7 @@ jobs: tags: ghcr.io/mendix/native-widgets/mxbuild:${{ needs.mendix-version.outputs.mendix_version }} resources: needs: [scope, mendix-version] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 permissions: packages: read contents: read @@ -235,7 +245,7 @@ jobs: packages/jsActions/nanoflow-actions-native/dist/**/* project: needs: [resources, mendix-version] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 container: image: ghcr.io/mendix/native-widgets/mxbuild:${{ needs.mendix-version.outputs.mendix_version }} credentials: @@ -247,11 +257,13 @@ jobs: apt update && apt upgrade -y apt install curl -y - name: "Download test project" - run: curl -L -o project.zip https://github.com/mendix/Native-Mobile-Resources/archive/refs/heads/main.zip + run: curl -L -o project.zip https://github.com/mendix/Native-Mobile-Resources/archive/refs/heads/mx-version/10.zip - name: "Extract test project" uses: montudor/action-zip@0852c26906e00f8a315c704958823928d8018b28 # v1.0.0 with: args: unzip -qq project.zip -d . + - name: "Rename extracted directory" # Doing this since mxbuild fails with - path too long + run: mv Native-Mobile-Resources-mx-version-10 Native-Mobile-Resources-mx10 - name: "Download resources artifact" uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: @@ -265,26 +277,26 @@ jobs: run: | if compgen -G 'resources/pluggableWidgets/**/dist/*/*.mpk' > /dev/null; then for oldPath in resources/pluggableWidgets/**/dist/*/*.mpk; do - newPath=Native-Mobile-Resources-main/widgets/$(basename $oldPath) + newPath=Native-Mobile-Resources-mx10/widgets/$(basename $oldPath) mv -f $oldPath $newPath done - mx update-widgets --loose-version-check Native-Mobile-Resources-main/NativeComponentsTestProject.mpr + mx update-widgets --loose-version-check Native-Mobile-Resources-mx10/NativeComponentsTestProject.mpr fi - name: "Move mobile-resources" shell: bash run: | if compgen -G 'resources/jsActions/mobile-resources-native/*' > /dev/null; then - mv -f resources/jsActions/mobile-resources-native/* Native-Mobile-Resources-main/javascriptsource/nativemobileresources/actions/ + mv -f resources/jsActions/mobile-resources-native/* Native-Mobile-Resources-mx10/javascriptsource/nativemobileresources/actions/ fi - name: "Move nanoflow-actions" shell: bash run: | if compgen -G 'resources/jsActions/mobile-resources-native/*' > /dev/null; then - mv -f resources/jsActions/nanoflow-actions-native/* Native-Mobile-Resources-main/javascriptsource/nanoflowcommons/actions/ + mv -f resources/jsActions/nanoflow-actions-native/* Native-Mobile-Resources-mx10/javascriptsource/nanoflowcommons/actions/ fi - name: "Force rebuild test project" run: | - mxbuild -o automation.mda --loose-version-check Native-Mobile-Resources-main/NativeComponentsTestProject.mpr + mxbuild -o automation.mda --loose-version-check Native-Mobile-Resources-mx10/NativeComponentsTestProject.mpr - name: "Upload MDA" uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 with: @@ -292,7 +304,9 @@ jobs: path: automation.mda android-bundle: needs: [project, mendix-version] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 + # Skip this job if we're using artifacts from a specific run + if: ${{ github.event.inputs.LOCAL_TEST_ARTIFACT_RUN_ID == '' }} container: image: ghcr.io/mendix/native-widgets/mxbuild:${{ needs.mendix-version.outputs.mendix_version }} credentials: @@ -312,7 +326,9 @@ jobs: mda-file: automation.mda ios-bundle: needs: [project, mendix-version] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 + # Skip this job if we're using artifacts from a specific run + if: ${{ github.event.inputs.LOCAL_TEST_ARTIFACT_RUN_ID == '' }} container: image: ghcr.io/mendix/native-widgets/mxbuild:${{ needs.mendix-version.outputs.mendix_version }} credentials: @@ -332,7 +348,9 @@ jobs: mda-file: automation.mda android-app: needs: [android-bundle, determine-nt-version] - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 + # Skip this job if we're using artifacts from a specific run, but allow it to run if android-bundle was skipped + if: ${{ github.event.inputs.LOCAL_TEST_ARTIFACT_RUN_ID == '' && always() && (needs.android-bundle.result == 'success') }} steps: - name: Debug branch value run: echo "Using branch ${{ needs.determine-nt-version.outputs.nt_branch }}" @@ -400,7 +418,9 @@ jobs: path: native-template/android/app/build/outputs/apk/**/*.apk ios-app: needs: [ios-bundle, determine-nt-version] - runs-on: macos-13 + runs-on: macos-15 + # Skip this job if we're using artifacts from a specific run, but allow it to run if ios-bundle was skipped + if: ${{ github.event.inputs.LOCAL_TEST_ARTIFACT_RUN_ID == '' && always() && (needs.ios-bundle.result == 'success') }} steps: - name: "Check out Native Template for Native Components Test Project" uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 @@ -461,11 +481,12 @@ jobs: android-widget-tests: needs: [scope, mendix-version, project, android-app] - if: ${{ github.event.inputs.workspace != 'js-actions' || github.event_name == 'schedule' }} - runs-on: ubuntu-22.04 + # Run if project succeeds and either android-app succeeds OR we're using custom artifacts (android-app was skipped) + if: ${{ (github.event.inputs.workspace != 'js-actions' || github.event_name == 'schedule') && always() && needs.project.result == 'success' && (needs.android-app.result == 'success' || needs.android-app.result == 'skipped') }} + runs-on: ubuntu-24.04 timeout-minutes: 60 strategy: - max-parallel: 10 + max-parallel: 5 matrix: widget: ${{ fromJson(needs.scope.outputs.widgets) }} fail-fast: false @@ -474,70 +495,40 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: fetch-depth: 0 - - name: "Set up node" - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4 - with: - node-version-file: .nvmrc - cache: yarn - - name: "Install dependencies" - run: yarn install --immutable - name: "Download project MDA file" uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: mda - - # USED ONLY FOR TESTING PURPOSE - TO SKIP APP BUILD PART AND DOWNLOAD FROM SPECIFIC RUN - # - name: "Install GitHub CLI" - # run: | - # curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg - # sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg - # echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null - # sudo apt update - # sudo apt install gh - # - name: "Authenticate GitHub CLI" - # run: | - # unset GITHUB_TOKEN - # echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token - # - name: "Fetch artifacts from run 676" - # id: fetch-artifacts - # run: | - # artifacts_url=$(gh api "repos/${{ github.repository }}/actions/runs/13453887084/artifacts" --jq '.artifacts[] | select(.name == "android-app") | .archive_download_url') - # echo "Artifacts URL: $artifacts_url" - # echo "artifacts_url=$artifacts_url" >> $GITHUB_ENV - # - name: "Download Android app" - # if: env.artifacts_url != '' - # run: | - # if [ -z "$artifacts_url" ]; then - # echo "No artifacts URL found." - # exit 1 - # fi - # curl -L -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -o android-app.zip "$artifacts_url" - # unzip android-app.zip -d android-app - + # Used only when specific run id is provided when triggering the jbo + - name: "Download Android app from specific run" + if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID != '' }} + uses: ./.github/actions/use-arficats-from-specific-run + with: + artifact_name: android-app + run_id: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID }} + output_dir: android-app + platform: android + github_token: ${{ secrets.GITHUB_TOKEN }} - name: "Download Android app" + if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID == '' }} uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: android-app path: android-app - - - name: "Start runtime" - uses: ./.github/actions/start-runtime + - name: "Setup needed tools" + id: setup-needed-tools + uses: ./.github/actions/setup-tools with: - mda-file: automation.mda - mendix-version: ${{ needs.mendix-version.outputs.mendix_version }} - - - name: "Install Maestro" - run: | - mkdir -p $HOME/.local/bin - curl -L "https://github.com/mobile-dev-inc/maestro/releases/latest/download/maestro.zip" -o maestro.zip - unzip maestro.zip -d $HOME/.local/bin - chmod +x $HOME/.local/bin/maestro/bin/maestro - echo "$HOME/.local/bin" >> $GITHUB_PATH - - name: Verify maestro - run: $HOME/.local/bin/maestro/bin/maestro --version - - name: Set up Android SDK - run: echo "ANDROID_HOME=$ANDROID_SDK_ROOT" >> $GITHUB_ENV - + mendix_version: ${{ needs.mendix-version.outputs.mendix_version }} + + - name: "Start runtime with retry" + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 #v3.0.2 + with: + timeout_minutes: 20 + max_attempts: 3 + command: | + chmod +x .github/scripts/start-runtime-with-verification.sh + .github/scripts/start-runtime-with-verification.sh automation.mda ${{ needs.mendix-version.outputs.mendix_version }} "${{ steps.setup-needed-tools.outputs.java-path }}" "${{ github.workspace }}" - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules @@ -546,7 +537,7 @@ jobs: - name: "Run android tests" uses: reactivecircus/android-emulator-runner@62dbb605bba737720e10b196cb4220d374026a6d # v2.0.0 with: - api-level: 30 + api-level: 35 target: google_apis arch: x86_64 profile: pixel @@ -558,117 +549,95 @@ jobs: bash maestro/helpers/prepare_android.sh bash maestro/run_maestro_widget_tests.sh android "${{ matrix.widget }}" - - name: "Archive runtime logs" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() + - name: Archive test results + uses: ./.github/actions/archive-test-results with: - name: android-runtime-logs-${{ matrix.widget }} - path: log/*.log - if-no-files-found: ignore - - name: "Archive test screenshots" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: android-screenshots-${{ matrix.widget }} - path: ${{ github.workspace }}/maestro/images/actual/android/**/*.png - if-no-files-found: ignore - - name: "Archive artifacts" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: android-artifacts-${{ matrix.widget }} - path: packages/pluggableWidgets/**/artifacts/ - if-no-files-found: ignore + platform: android + test-type: ${{ matrix.widget }} ios-widget-tests: needs: [scope, mendix-version, project, ios-app] - if: ${{ github.event.inputs.workspace != 'js-actions' || github.event_name == 'schedule' }} + # Run if project succeeds and either ios-app succeeds OR we're using custom artifacts (ios-app was skipped) + if: ${{ (github.event.inputs.workspace != 'js-actions' || github.event_name == 'schedule') && always() && needs.project.result == 'success' && (needs.ios-app.result == 'success' || needs.ios-app.result == 'skipped') }} runs-on: macos-15 timeout-minutes: 60 strategy: - max-parallel: 10 + max-parallel: 5 matrix: widget: ${{ fromJson(needs.scope.outputs.widgets) }} fail-fast: false steps: + - name: "Force cleanup workspace" + run: | + # Kill all Git and Xcode processes aggressively + sudo pkill -9 -f git || true + sudo pkill -9 -f xcodebuild || true + sudo pkill -9 -f node || true + + # Wait for processes to be killed + sleep 5 + + # Clean the workspace contents while preserving directory structure + cd /Users/runner/work/native-widgets + if [ -d "native-widgets" ]; then + cd native-widgets + + # Force remove all git state and locks with extreme prejudice + sudo rm -rf .git || true + find . -name "*.lock" -type f -exec sudo rm -f {} \; 2>/dev/null || true + find . -name ".git*" -exec sudo rm -rf {} \; 2>/dev/null || true + + # Remove all other contents + sudo find . -mindepth 1 -not -path "./.git*" -delete 2>/dev/null || true + fi + + # Final wait and process cleanup + sudo pkill -9 -f git || true + sleep 3 + continue-on-error: true - name: "Check out code" uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: - fetch-depth: 0 - - name: "Set up node" - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4 - with: - node-version-file: .nvmrc - cache: yarn - - name: "Install dependencies" - run: | - yarn cache clean - yarn install --immutable + fetch-depth: 1 + fetch-tags: false + clean: true + ref: ${{ github.sha }} - name: "Download project MDA file" uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: mda - - - # USED ONLY FOR TESTING PURPOSE - TO SKIP APP BUILD PART AND DOWNLOAD APP FROM SPECIFIC RUN - # - name: "Install GitHub CLI" - # run: | - # brew install gh - # - name: "Authenticate GitHub CLI" - # run: | - # unset GITHUB_TOKEN - # echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token - # - name: "Fetch artifacts from run 676" - # id: fetch-artifacts - # run: | - # artifacts_url=$(gh api "repos/${{ github.repository }}/actions/runs/13453887084/artifacts" --jq '.artifacts[] | select(.name == "ios-app") | .archive_download_url') - # echo "Artifacts URL: $artifacts_url" - # echo "artifacts_url=$artifacts_url" >> $GITHUB_ENV - # - name: "Download iOS app" - # if: env.artifacts_url != '' - # run: | - # if [ -z "$artifacts_url" ]; then - # echo "No artifacts URL found." - # exit 1 - # fi - # curl -L -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -o ios-app.zip "$artifacts_url" - # unzip ios-app.zip -d ios-app - - - name: "Start runtime" - uses: ./.github/actions/start-runtime - with: - mda-file: automation.mda - mendix-version: ${{ needs.mendix-version.outputs.mendix_version }} - + # Used only for local testing, will be empty on GitHub + - name: "Download iOS app from specific run" + if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID != '' }} + uses: ./.github/actions/use-arficats-from-specific-run + with: + artifact_name: ios-app + run_id: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID }} + output_dir: ios-app + platform: ios + github_token: ${{ secrets.GITHUB_TOKEN }} - name: "Download iOS app" + if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID == '' }} uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: ios-app path: ios-app - - name: Check iOS App Path - run: ls ios-app - - - name: "Verify Xcode CLI Tools" - run: | - if ! xcode-select --print-path; then - echo "Xcode CLI tools not set. Setting them now." - sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer - else - echo "Xcode CLI tools are already configured." - fi - - - name: "Install Maestro" - run: | - mkdir -p $HOME/.local/bin - curl -L "https://github.com/mobile-dev-inc/maestro/releases/latest/download/maestro.zip" -o maestro.zip - unzip maestro.zip -d $HOME/.local/bin - chmod +x $HOME/.local/bin/maestro/bin/maestro - echo "$HOME/.local/bin" >> $GITHUB_PATH - - name: "Verify maestro" - run: $HOME/.local/bin/maestro/bin/maestro --version - - name: "List Available Simulators" - run: xcrun simctl list devices - + - name: "Setup needed tools" + id: setup-needed-tools + uses: ./.github/actions/setup-tools + with: + mendix_version: ${{ needs.mendix-version.outputs.mendix_version }} + - name: "Start runtime with retry" + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 #v3.0.2 + with: + timeout_minutes: 10 + max_attempts: 3 + command: | + chmod +x .github/scripts/start-runtime-with-verification.sh + .github/scripts/start-runtime-with-verification.sh automation.mda ${{ needs.mendix-version.outputs.mendix_version }} "${{ steps.setup-needed-tools.outputs.java-path }}" "${{ github.workspace }}" + + - name: "Setup Xcode CLI Tools" + uses: ./.github/actions/setup-xcode-cli-tools - name: "Run iOS tests" run: | chmod +x maestro/helpers/prepare_ios.sh @@ -676,70 +645,56 @@ jobs: bash maestro/helpers/prepare_ios.sh bash maestro/run_maestro_widget_tests.sh ios "${{ matrix.widget }}" - - name: "Archive runtime logs" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: ios-runtime-logs-${{ matrix.widget }} - path: log/*.log - if-no-files-found: ignore - - name: "Archive test screenshots" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: ios-screenshots-${{ matrix.widget }} - path: ${{ github.workspace }}/maestro/images/actual/ios/**/*.png - if-no-files-found: ignore - - name: "Archive artifacts" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() + - name: Archive test results + uses: ./.github/actions/archive-test-results with: - name: ios-artifacts-${{ matrix.widget }} - path: packages/pluggableWidgets/**/artifacts/ - if-no-files-found: ignore + platform: ios + test-type: ${{ matrix.widget }} android-js-tests: - if: ${{ github.event.inputs.workspace == '*-native' || github.event_name == 'schedule' || github.event.inputs.workspace == 'js-actions'}} - needs: [mendix-version, project, android-app] - runs-on: ubuntu-22.04 + needs: [scope, mendix-version, project, android-app] + # Run if project succeeds and either android-app succeeds OR we're using custom artifacts (android-app was skipped) + if: ${{ (github.event.inputs.workspace == '*-native' || github.event_name == 'schedule' || github.event.inputs.workspace == 'js-actions' || contains(needs.scope.outputs.widgets, 'mobile-resources-native') || contains(needs.scope.outputs.widgets, 'nanoflow-actions-native')) && always() && needs.project.result == 'success' && (needs.android-app.result == 'success' || needs.android-app.result == 'skipped') }} + runs-on: ubuntu-24.04 timeout-minutes: 90 steps: - name: "Check out code" uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: fetch-depth: 0 - - name: "Set up node" - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4 - with: - node-version-file: .nvmrc - cache: yarn - - name: "Install dependencies" - run: yarn install --immutable - name: "Download project MDA file" uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: mda + # Used only for local testing, will be empty on GitHub + - name: "Download Android app from specific run" + if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID != '' }} + uses: ./.github/actions/use-arficats-from-specific-run + with: + artifact_name: android-app + run_id: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID }} + output_dir: android-app + platform: android + github_token: ${{ secrets.GITHUB_TOKEN }} - name: "Download Android app" + if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID == '' }} uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: android-app path: android-app - - name: "Start runtime" - uses: ./.github/actions/start-runtime - with: - mda-file: automation.mda - mendix-version: ${{ needs.mendix-version.outputs.mendix_version }} - - name: "Install Maestro" - run: | - mkdir -p $HOME/.local/bin - curl -L "https://github.com/mobile-dev-inc/maestro/releases/latest/download/maestro.zip" -o maestro.zip - unzip maestro.zip -d $HOME/.local/bin - chmod +x $HOME/.local/bin/maestro/bin/maestro - echo "$HOME/.local/bin" >> $GITHUB_PATH - - name: Verify maestro - run: $HOME/.local/bin/maestro/bin/maestro --version - - name: Set up Android SDK - run: echo "ANDROID_HOME=$ANDROID_SDK_ROOT" >> $GITHUB_ENV + - name: "Setup needed tools" + id: setup-needed-tools + uses: ./.github/actions/setup-tools + with: + mendix_version: ${{ needs.mendix-version.outputs.mendix_version }} + - name: "Start runtime with retry" + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 #v3.0.2 + with: + timeout_minutes: 10 + max_attempts: 3 + command: | + chmod +x .github/scripts/start-runtime-with-verification.sh + .github/scripts/start-runtime-with-verification.sh automation.mda ${{ needs.mendix-version.outputs.mendix_version }} "${{ steps.setup-needed-tools.outputs.java-path }}" "${{ github.workspace }}" - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules @@ -748,7 +703,7 @@ jobs: - name: "Run android tests" uses: reactivecircus/android-emulator-runner@62dbb605bba737720e10b196cb4220d374026a6d # v2.0.0 with: - api-level: 30 + api-level: 35 target: google_apis arch: x86_64 profile: pixel @@ -760,84 +715,88 @@ jobs: bash maestro/helpers/prepare_android.sh bash maestro/run_maestro_jsactions_tests.sh android - - name: "Archive runtime logs" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: android-runtime-logs-js-actions - path: log/*.log - if-no-files-found: ignore - - name: "Archive test screenshots" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() + - name: Archive test results + uses: ./.github/actions/archive-test-results with: - name: android-screenshots-js-actions - path: ${{ github.workspace }}/maestro/images/actual/android/**/*.png - if-no-files-found: ignore - - name: "Archive artifacts" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: android-artifacts-js-actions - path: packages/pluggableWidgets/**/artifacts/ - if-no-files-found: ignore + platform: android + test-type: js-actions ios-js-tests: - if: ${{ github.event.inputs.workspace == '*-native' || github.event_name == 'schedule' || github.event.inputs.workspace == 'js-actions'}} - needs: [mendix-version, project, ios-app] + needs: [scope, mendix-version, project, ios-app] + # Run if project succeeds and either ios-app succeeds OR we're using custom artifacts (ios-app was skipped) + if: ${{ (github.event.inputs.workspace == '*-native' || github.event_name == 'schedule' || github.event.inputs.workspace == 'js-actions' || contains(needs.scope.outputs.widgets, 'mobile-resources-native') || contains(needs.scope.outputs.widgets, 'nanoflow-actions-native')) && always() && needs.project.result == 'success' && (needs.ios-app.result == 'success' || needs.ios-app.result == 'skipped') }} runs-on: macos-15 timeout-minutes: 90 steps: + - name: "Clean up any Git locks" + run: | + # Kill all git and related processes aggressively + sudo pkill -9 -f git || true + sudo pkill -9 -f node || true + + # Wait for processes to be killed + sleep 5 + + # Clean the workspace contents while preserving directory structure + cd /Users/runner/work/native-widgets + if [ -d "native-widgets" ]; then + cd native-widgets + + # Force remove git state and locks + sudo rm -rf .git || true + find . -name "*.lock" -type f -exec sudo rm -f {} \; 2>/dev/null || true + find . -name ".git*" -exec sudo rm -rf {} \; 2>/dev/null || true + + # Remove all other contents + sudo find . -mindepth 1 -not -path "./.git*" -delete 2>/dev/null || true + fi + + # Final cleanup + sudo pkill -9 -f git || true + sleep $((RANDOM % 5 + 3)) + continue-on-error: true - name: "Check out code" uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: - fetch-depth: 0 - - name: "Set up node" - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4 - with: - node-version-file: .nvmrc - cache: yarn - - name: "Install dependencies" - run: | - yarn cache clean - yarn install --immutable + fetch-depth: 1 + fetch-tags: false + clean: true - name: "Download project MDA file" uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: mda - - name: "Start runtime" - uses: ./.github/actions/start-runtime - with: - mda-file: automation.mda - mendix-version: ${{ needs.mendix-version.outputs.mendix_version }} - + # Used only for local testing, will be empty on GitHub + - name: "Download iOS app from specific run" + if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID != '' }} + uses: ./.github/actions/use-arficats-from-specific-run + with: + artifact_name: ios-app + run_id: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID }} + output_dir: ios-app + platform: ios + github_token: ${{ secrets.GITHUB_TOKEN }} - name: "Download iOS app" + if: ${{ env.LOCAL_TEST_ARTIFACT_RUN_ID == '' }} uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: ios-app path: ios-app - - name: Check iOS App Path - run: ls ios-app - - - name: "Verify Xcode CLI Tools" - run: | - if ! xcode-select --print-path; then - echo "Xcode CLI tools not set. Setting them now." - sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer - else - echo "Xcode CLI tools are already configured." - fi - - name: "Install Maestro" - run: | - mkdir -p $HOME/.local/bin - curl -L "https://github.com/mobile-dev-inc/maestro/releases/latest/download/maestro.zip" -o maestro.zip - unzip maestro.zip -d $HOME/.local/bin - chmod +x $HOME/.local/bin/maestro/bin/maestro - echo "$HOME/.local/bin" >> $GITHUB_PATH - - name: "Verify maestro" - run: $HOME/.local/bin/maestro/bin/maestro --version - - name: "List Available Simulators" - run: xcrun simctl list devices + - name: "Setup needed tools" + id: setup-needed-tools + uses: ./.github/actions/setup-tools + with: + mendix_version: ${{ needs.mendix-version.outputs.mendix_version }} + - name: "Start runtime with retry" + uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 #v3.0.2 + with: + timeout_minutes: 10 + max_attempts: 3 + command: | + chmod +x .github/scripts/start-runtime-with-verification.sh + .github/scripts/start-runtime-with-verification.sh automation.mda ${{ needs.mendix-version.outputs.mendix_version }} "${{ steps.setup-needed-tools.outputs.java-path }}" "${{ github.workspace }}" + + - name: "Setup Xcode CLI Tools" + uses: ./.github/actions/setup-xcode-cli-tools - name: "Run iOS tests" run: | chmod +x maestro/helpers/prepare_ios.sh @@ -845,27 +804,11 @@ jobs: bash maestro/helpers/prepare_ios.sh bash maestro/run_maestro_jsactions_tests.sh ios - - name: "Archive runtime logs" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() + - name: Archive test results + uses: ./.github/actions/archive-test-results with: - name: ios-runtime-logs-js-actions - path: log/*.log - if-no-files-found: ignore - - name: "Archive test screenshots" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: ios-screenshots-js-actions - path: ${{ github.workspace }}/maestro/images/actual/ios/**/*.png - if-no-files-found: ignore - - name: "Archive artifacts" - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4 - if: always() - with: - name: ios-artifacts-js-actions - path: packages/pluggableWidgets/**/artifacts/ - if-no-files-found: ignore + platform: ios + test-type: js-actions compare-screenshots: needs: [scope, android-widget-tests, ios-widget-tests, android-js-tests, ios-js-tests] runs-on: ubuntu-latest @@ -904,15 +847,9 @@ jobs: gh run download ${{ github.run_id }} --name ios-screenshots-js-actions --dir images/actual/ios/ || true ls -l images/actual/ios/ - - name: "Set up node" - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4 - with: - node-version-file: .nvmrc - cache: yarn + - name: "Setup Node and dependencies" + uses: ./.github/actions/setup-node-with-cache - - name: "Install dependencies" - run: yarn install - - name: "Compare Android screenshots" continue-on-error: true run: node ${{ github.workspace }}/maestro/helpers/compare_screenshots.js android diff --git a/.github/workflows/PublishDockerImage.yml b/.github/workflows/PublishDockerImage.yml index 0c6624bc5..87c079a0c 100644 --- a/.github/workflows/PublishDockerImage.yml +++ b/.github/workflows/PublishDockerImage.yml @@ -2,7 +2,7 @@ name: Publishing docker images for mxbuild on: push: - branches: [main] + branches: [mx-version/10] paths: - "configs/e2e/mendix-versions.json" diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index 0b5226f2f..fba51882a 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -2,9 +2,9 @@ name: Run release on: push: - branches: [main] + branches: [mx-version/10] pull_request: - branches: [main] + branches: [mx-version/10] jobs: test: @@ -20,7 +20,7 @@ jobs: uses: softprops/diffset@db8c4e13f5cc3f8ab666ba2cb6998b688058a41c # v1 if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository with: - base: main + base: mx-version/10 global_files: | !{packages/**/*,configs/e2e/*.json,scripts/**/*,data/**/*} env: diff --git a/.github/workflows/ShaCheck.yml b/.github/workflows/ShaCheck.yml index e69a08fb4..4d684e28b 100644 --- a/.github/workflows/ShaCheck.yml +++ b/.github/workflows/ShaCheck.yml @@ -2,11 +2,11 @@ name: Ensure SHA pinned actions on: push: - branches: [main] + branches: [mx-version/10] paths: - ".github/workflows/*.yml" pull_request: - branches: [main] + branches: [mx-version/10] paths: - ".github/workflows/*.yml" diff --git a/.github/workflows/UnitTests.yml b/.github/workflows/UnitTests.yml index 554ee1b75..aaf7f21c6 100644 --- a/.github/workflows/UnitTests.yml +++ b/.github/workflows/UnitTests.yml @@ -2,9 +2,9 @@ name: Run unit tests on: push: - branches: [main] + branches: [mx-version/10] pull_request: - branches: [main] + branches: [mx-version/10] jobs: test: @@ -17,7 +17,7 @@ jobs: uses: softprops/diffset@d5947696689a571f7a984a52505e2649eead5c22 # v1 if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository with: - base: main + base: mx-version/10 global_files: | !{packages/**/*,configs/e2e/*.json,scripts/**/*,data/**/*} env: diff --git a/.yarnrc.yml b/.yarnrc.yml index a5fe79487..8a6d9718f 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -1,9 +1,9 @@ changesetBaseRefs: - - main - - origin/main - - upstream/main - - refs/remotes/origin/main - - +refs/heads/main + - mx-version/10 + - origin/mx-version/10 + - upstream/mx-version/10 + - refs/remotes/origin/mx-version/10 + - +refs/heads/mx-version/10 compressionLevel: mixed diff --git a/configs/e2e/mendix-versions.json b/configs/e2e/mendix-versions.json index 5b003248f..1bb0404c1 100644 --- a/configs/e2e/mendix-versions.json +++ b/configs/e2e/mendix-versions.json @@ -1,3 +1,3 @@ { - "latest": "11.0.0.73100" + "latest": "10.24.4.77222" } diff --git a/configs/e2e/native_dependencies.json b/configs/e2e/native_dependencies.json index fd61c93fc..e2f04ed89 100644 --- a/configs/e2e/native_dependencies.json +++ b/configs/e2e/native_dependencies.json @@ -1,10 +1,10 @@ { "react-native-maps": "1.14.0", "react-native-geocoder": "0.5.0", - "react-native-device-info": "14.0.4", + "react-native-device-info": "13.0.0", "react-native-action-button": "2.8.5", "react-native-material-menu": "1.2.0", - "react-native-linear-gradient": "2.8.3", + "react-native-linear-gradient": "2.5.6", "@react-native-community/netinfo": "11.4.1", "react-native-svg": "15.11.1", "react-native-system-navigation-bar": "2.6.3", diff --git a/maestro/helpers/prepare_ios.sh b/maestro/helpers/prepare_ios.sh index 63af57742..87f639cf5 100644 --- a/maestro/helpers/prepare_ios.sh +++ b/maestro/helpers/prepare_ios.sh @@ -1,25 +1,72 @@ #!/bin/bash +# Configuration - modify these values as needed +DEVICE_TYPE="iPhone 16" +IOS_VERSION="18.5" + start_simulator() { echo "Starting iOS Simulator..." - xcrun simctl boot "iPhone 16" || echo "Simulator already booted" + echo "Looking for: $DEVICE_TYPE with iOS $IOS_VERSION" + + # List available simulators to debug + # echo "Available simulators:" + # xcrun simctl list devices available + + # Try to find the specified device with the specified iOS version + DEVICE_ID=$(xcrun simctl list devices available | grep -A1 "iOS $IOS_VERSION" | grep "$DEVICE_TYPE " | head -1 | grep -o "[A-F0-9-]{36}") + + if [ -z "$DEVICE_ID" ]; then + echo "No $DEVICE_TYPE with iOS $IOS_VERSION found. Trying to create one..." + # Try to create the device with the specified iOS version + IOS_RUNTIME="com.apple.CoreSimulator.SimRuntime.iOS-${IOS_VERSION//./-}" + DEVICE_TYPE_ID="com.apple.CoreSimulator.SimDeviceType.${DEVICE_TYPE// /-}" + DEVICE_ID=$(xcrun simctl create "${DEVICE_TYPE} Test" "$DEVICE_TYPE_ID" "$IOS_RUNTIME" 2>/dev/null) + + if [ -z "$DEVICE_ID" ]; then + echo "Failed to create $DEVICE_TYPE with iOS $IOS_VERSION. Using any available $DEVICE_TYPE." + DEVICE_ID=$(xcrun simctl list devices available | grep "$DEVICE_TYPE " | head -1 | grep -o "[A-F0-9-]{36}") + fi + fi + + if [ -z "$DEVICE_ID" ]; then + echo "Error: Could not find or create any $DEVICE_TYPE device" + exit 1 + fi + + echo "Using device ID: $DEVICE_ID" + export SIMULATOR_DEVICE_ID="$DEVICE_ID" + + # Boot the device + xcrun simctl boot "$DEVICE_ID" || echo "Simulator already booted" sleep 30 - xcrun simctl bootstatus || echo "Simulator booted successfully" + xcrun simctl bootstatus "$DEVICE_ID" || echo "Simulator booted successfully" } set_status_bar() { echo "Setting status bar on iOS Simulator..." - xcrun simctl status_bar "iPhone 16" override --time "11:01" --wifiBars 3 --cellularBars 4 --batteryState charged --batteryLevel 100 + if [ -z "$SIMULATOR_DEVICE_ID" ]; then + echo "Error: SIMULATOR_DEVICE_ID not set" + return 1 + fi + xcrun simctl status_bar "$SIMULATOR_DEVICE_ID" override --time "11:01" --wifiBars 3 --cellularBars 4 --batteryState charged --batteryLevel 100 } install_ios_app() { echo "Installing iOS app on simulator..." - xcrun simctl install booted ios-app/Debug-iphonesimulator/NativeTemplate.app + if [ -z "$SIMULATOR_DEVICE_ID" ]; then + echo "Error: SIMULATOR_DEVICE_ID not set" + return 1 + fi + xcrun simctl install "$SIMULATOR_DEVICE_ID" ios-app/Debug-iphonesimulator/NativeTemplate.app } verify_installed_app() { echo "Verifying installed app..." - xcrun simctl get_app_container booted com.mendix.native.template + if [ -z "$SIMULATOR_DEVICE_ID" ]; then + echo "Error: SIMULATOR_DEVICE_ID not set" + return 1 + fi + xcrun simctl get_app_container "$SIMULATOR_DEVICE_ID" com.mendix.native.template } start_simulator diff --git a/maestro/images/expected/android/accordion_custom.png b/maestro/images/expected/android/accordion_custom.png index 2ecf94d4b..9c2232912 100644 Binary files a/maestro/images/expected/android/accordion_custom.png and b/maestro/images/expected/android/accordion_custom.png differ diff --git a/maestro/images/expected/android/accordion_multiple.png b/maestro/images/expected/android/accordion_multiple.png index 26a19048e..aa75378a6 100644 Binary files a/maestro/images/expected/android/accordion_multiple.png and b/maestro/images/expected/android/accordion_multiple.png differ diff --git a/maestro/images/expected/android/accordion_noncollapsible.png b/maestro/images/expected/android/accordion_noncollapsible.png index 98a570805..3ced2fb4c 100644 Binary files a/maestro/images/expected/android/accordion_noncollapsible.png and b/maestro/images/expected/android/accordion_noncollapsible.png differ diff --git a/maestro/images/expected/android/animation.png b/maestro/images/expected/android/animation.png index abfae0649..69fde3a6c 100644 Binary files a/maestro/images/expected/android/animation.png and b/maestro/images/expected/android/animation.png differ diff --git a/maestro/images/expected/android/authentication.png b/maestro/images/expected/android/authentication.png index 6cbd9375f..da2c54511 100644 Binary files a/maestro/images/expected/android/authentication.png and b/maestro/images/expected/android/authentication.png differ diff --git a/maestro/images/expected/android/background_gradient.png b/maestro/images/expected/android/background_gradient.png index c5bd858ff..f365aefd3 100644 Binary files a/maestro/images/expected/android/background_gradient.png and b/maestro/images/expected/android/background_gradient.png differ diff --git a/maestro/images/expected/android/bg_image_clickable_container.png b/maestro/images/expected/android/bg_image_clickable_container.png index 3f2e600db..3b236773c 100644 Binary files a/maestro/images/expected/android/bg_image_clickable_container.png and b/maestro/images/expected/android/bg_image_clickable_container.png differ diff --git a/maestro/images/expected/android/bg_image_conditional_visibility.png b/maestro/images/expected/android/bg_image_conditional_visibility.png index cf305054d..99455bed3 100644 Binary files a/maestro/images/expected/android/bg_image_conditional_visibility.png and b/maestro/images/expected/android/bg_image_conditional_visibility.png differ diff --git a/maestro/images/expected/android/bg_image_dynamic_image.png b/maestro/images/expected/android/bg_image_dynamic_image.png index ab6aaad57..e60cea4b4 100644 Binary files a/maestro/images/expected/android/bg_image_dynamic_image.png and b/maestro/images/expected/android/bg_image_dynamic_image.png differ diff --git a/maestro/images/expected/android/bg_image_layout_grid.png b/maestro/images/expected/android/bg_image_layout_grid.png index 30ce98909..5affc44f2 100644 Binary files a/maestro/images/expected/android/bg_image_layout_grid.png and b/maestro/images/expected/android/bg_image_layout_grid.png differ diff --git a/maestro/images/expected/android/bg_image_nested.png b/maestro/images/expected/android/bg_image_nested.png index 9c106c9f6..cd70758b1 100644 Binary files a/maestro/images/expected/android/bg_image_nested.png and b/maestro/images/expected/android/bg_image_nested.png differ diff --git a/maestro/images/expected/android/bg_image_static_images.png b/maestro/images/expected/android/bg_image_static_images.png index 7ce112274..376ec8bb9 100644 Binary files a/maestro/images/expected/android/bg_image_static_images.png and b/maestro/images/expected/android/bg_image_static_images.png differ diff --git a/maestro/images/expected/android/bg_image_static_svg.png b/maestro/images/expected/android/bg_image_static_svg.png index 76879ea75..dc9a4b965 100644 Binary files a/maestro/images/expected/android/bg_image_static_svg.png and b/maestro/images/expected/android/bg_image_static_svg.png differ diff --git a/maestro/images/expected/android/bottom_sheet_expanding.png b/maestro/images/expected/android/bottom_sheet_expanding.png index e7805e362..472702c32 100644 Binary files a/maestro/images/expected/android/bottom_sheet_expanding.png and b/maestro/images/expected/android/bottom_sheet_expanding.png differ diff --git a/maestro/images/expected/android/bottom_sheet_expanding_fullscreen.png b/maestro/images/expected/android/bottom_sheet_expanding_fullscreen.png index a1593e748..650086465 100644 Binary files a/maestro/images/expected/android/bottom_sheet_expanding_fullscreen.png and b/maestro/images/expected/android/bottom_sheet_expanding_fullscreen.png differ diff --git a/maestro/images/expected/android/bottom_sheet_modal_basic_non_native.png b/maestro/images/expected/android/bottom_sheet_modal_basic_non_native.png index ed6858015..4e1d3be77 100644 Binary files a/maestro/images/expected/android/bottom_sheet_modal_basic_non_native.png and b/maestro/images/expected/android/bottom_sheet_modal_basic_non_native.png differ diff --git a/maestro/images/expected/android/bottom_sheet_modal_custom.png b/maestro/images/expected/android/bottom_sheet_modal_custom.png index f25e03129..c0b019750 100644 Binary files a/maestro/images/expected/android/bottom_sheet_modal_custom.png and b/maestro/images/expected/android/bottom_sheet_modal_custom.png differ diff --git a/maestro/images/expected/android/clipboard.png b/maestro/images/expected/android/clipboard.png index a11de62ae..9ac82d3f1 100644 Binary files a/maestro/images/expected/android/clipboard.png and b/maestro/images/expected/android/clipboard.png differ diff --git a/maestro/images/expected/android/color_picker_conditional.png b/maestro/images/expected/android/color_picker_conditional.png index c17e36f18..81d0f2783 100644 Binary files a/maestro/images/expected/android/color_picker_conditional.png and b/maestro/images/expected/android/color_picker_conditional.png differ diff --git a/maestro/images/expected/android/color_picker_disabled.png b/maestro/images/expected/android/color_picker_disabled.png index b816f98b3..91b1e4e64 100644 Binary files a/maestro/images/expected/android/color_picker_disabled.png and b/maestro/images/expected/android/color_picker_disabled.png differ diff --git a/maestro/images/expected/android/color_picker_normal.png b/maestro/images/expected/android/color_picker_normal.png index c1820ee44..6f0927d2f 100644 Binary files a/maestro/images/expected/android/color_picker_normal.png and b/maestro/images/expected/android/color_picker_normal.png differ diff --git a/maestro/images/expected/android/color_picker_partial.png b/maestro/images/expected/android/color_picker_partial.png index bba4d66a7..3928a935c 100644 Binary files a/maestro/images/expected/android/color_picker_partial.png and b/maestro/images/expected/android/color_picker_partial.png differ diff --git a/maestro/images/expected/android/device_info.png b/maestro/images/expected/android/device_info.png index 3e9e0914f..2391fbd55 100644 Binary files a/maestro/images/expected/android/device_info.png and b/maestro/images/expected/android/device_info.png differ diff --git a/maestro/images/expected/android/doughnut_chart_custom.png b/maestro/images/expected/android/doughnut_chart_custom.png index e5d291f47..a7c8776bc 100644 Binary files a/maestro/images/expected/android/doughnut_chart_custom.png and b/maestro/images/expected/android/doughnut_chart_custom.png differ diff --git a/maestro/images/expected/android/doughnut_chart_multiple_data_points.png b/maestro/images/expected/android/doughnut_chart_multiple_data_points.png index e62426900..e1d588631 100644 Binary files a/maestro/images/expected/android/doughnut_chart_multiple_data_points.png and b/maestro/images/expected/android/doughnut_chart_multiple_data_points.png differ diff --git a/maestro/images/expected/android/floating_action_button.png b/maestro/images/expected/android/floating_action_button.png index 1d843e4e0..e0b82aa64 100644 Binary files a/maestro/images/expected/android/floating_action_button.png and b/maestro/images/expected/android/floating_action_button.png differ diff --git a/maestro/images/expected/android/image_dynamic.png b/maestro/images/expected/android/image_dynamic.png index 1184ed349..88031dc22 100644 Binary files a/maestro/images/expected/android/image_dynamic.png and b/maestro/images/expected/android/image_dynamic.png differ diff --git a/maestro/images/expected/android/image_icon.png b/maestro/images/expected/android/image_icon.png index e09ba7ef2..7d8fea92f 100644 Binary files a/maestro/images/expected/android/image_icon.png and b/maestro/images/expected/android/image_icon.png differ diff --git a/maestro/images/expected/android/image_static.png b/maestro/images/expected/android/image_static.png index 21f087061..9499064f8 100644 Binary files a/maestro/images/expected/android/image_static.png and b/maestro/images/expected/android/image_static.png differ diff --git a/maestro/images/expected/android/image_url.png b/maestro/images/expected/android/image_url.png index 8423bd7ff..298349b73 100644 Binary files a/maestro/images/expected/android/image_url.png and b/maestro/images/expected/android/image_url.png differ diff --git a/maestro/images/expected/android/line_chart.png b/maestro/images/expected/android/line_chart.png index 59f929f1a..d1078c00a 100644 Binary files a/maestro/images/expected/android/line_chart.png and b/maestro/images/expected/android/line_chart.png differ diff --git a/maestro/images/expected/android/pie_chart_custom.png b/maestro/images/expected/android/pie_chart_custom.png index 0e4ba44b7..ba713a628 100644 Binary files a/maestro/images/expected/android/pie_chart_custom.png and b/maestro/images/expected/android/pie_chart_custom.png differ diff --git a/maestro/images/expected/android/pie_chart_multiple_data_points.png b/maestro/images/expected/android/pie_chart_multiple_data_points.png index da2dcd8b8..196807000 100644 Binary files a/maestro/images/expected/android/pie_chart_multiple_data_points.png and b/maestro/images/expected/android/pie_chart_multiple_data_points.png differ diff --git a/maestro/images/expected/android/popup_menu_alert.png b/maestro/images/expected/android/popup_menu_alert.png index 8ebae2d26..a48f6bed5 100644 Binary files a/maestro/images/expected/android/popup_menu_alert.png and b/maestro/images/expected/android/popup_menu_alert.png differ diff --git a/maestro/images/expected/android/progress_bar.png b/maestro/images/expected/android/progress_bar.png index 4bc545bb4..8bc7985cc 100644 Binary files a/maestro/images/expected/android/progress_bar.png and b/maestro/images/expected/android/progress_bar.png differ diff --git a/maestro/images/expected/android/progress_circle.png b/maestro/images/expected/android/progress_circle.png index f5b0d1277..ec2fd3f89 100644 Binary files a/maestro/images/expected/android/progress_circle.png and b/maestro/images/expected/android/progress_circle.png differ diff --git a/maestro/images/expected/android/qr_code.png b/maestro/images/expected/android/qr_code.png index ff5bf9491..1147e57d2 100644 Binary files a/maestro/images/expected/android/qr_code.png and b/maestro/images/expected/android/qr_code.png differ diff --git a/maestro/images/expected/android/radio_buttons.png b/maestro/images/expected/android/radio_buttons.png index 23599aeec..0dc485000 100644 Binary files a/maestro/images/expected/android/radio_buttons.png and b/maestro/images/expected/android/radio_buttons.png differ diff --git a/maestro/images/expected/android/range_slider.png b/maestro/images/expected/android/range_slider.png index bbcb5787b..2287617c2 100644 Binary files a/maestro/images/expected/android/range_slider.png and b/maestro/images/expected/android/range_slider.png differ diff --git a/maestro/images/expected/android/rating.png b/maestro/images/expected/android/rating.png index 0495c9cee..6f3002d40 100644 Binary files a/maestro/images/expected/android/rating.png and b/maestro/images/expected/android/rating.png differ diff --git a/maestro/images/expected/android/safe_area_view_bottom_bar.png b/maestro/images/expected/android/safe_area_view_bottom_bar.png index 3b99d90a0..c1b9360ed 100644 Binary files a/maestro/images/expected/android/safe_area_view_bottom_bar.png and b/maestro/images/expected/android/safe_area_view_bottom_bar.png differ diff --git a/maestro/images/expected/android/safe_area_view_container.png b/maestro/images/expected/android/safe_area_view_container.png index fcd350883..a0b3a5c8d 100644 Binary files a/maestro/images/expected/android/safe_area_view_container.png and b/maestro/images/expected/android/safe_area_view_container.png differ diff --git a/maestro/images/expected/android/safe_area_view_image.png b/maestro/images/expected/android/safe_area_view_image.png index 06f5b0809..d1be50de8 100644 Binary files a/maestro/images/expected/android/safe_area_view_image.png and b/maestro/images/expected/android/safe_area_view_image.png differ diff --git a/maestro/images/expected/android/safe_area_view_list_view.png b/maestro/images/expected/android/safe_area_view_list_view.png index 269341161..574554adb 100644 Binary files a/maestro/images/expected/android/safe_area_view_list_view.png and b/maestro/images/expected/android/safe_area_view_list_view.png differ diff --git a/maestro/images/expected/android/safe_area_view_text.png b/maestro/images/expected/android/safe_area_view_text.png index 91727de84..661a8b482 100644 Binary files a/maestro/images/expected/android/safe_area_view_text.png and b/maestro/images/expected/android/safe_area_view_text.png differ diff --git a/maestro/images/expected/android/safe_area_view_top_bar.png b/maestro/images/expected/android/safe_area_view_top_bar.png index 691100edd..e6c219432 100644 Binary files a/maestro/images/expected/android/safe_area_view_top_bar.png and b/maestro/images/expected/android/safe_area_view_top_bar.png differ diff --git a/maestro/images/expected/android/slider.png b/maestro/images/expected/android/slider.png index 529dcc361..21d15a1af 100644 Binary files a/maestro/images/expected/android/slider.png and b/maestro/images/expected/android/slider.png differ diff --git a/maestro/images/expected/android/toggle_buttons.png b/maestro/images/expected/android/toggle_buttons.png index 6d8a5b469..b5639ef06 100644 Binary files a/maestro/images/expected/android/toggle_buttons.png and b/maestro/images/expected/android/toggle_buttons.png differ diff --git a/maestro/images/expected/android/toggle_sidebar.png b/maestro/images/expected/android/toggle_sidebar.png index 91af73a1f..6aec5f577 100644 Binary files a/maestro/images/expected/android/toggle_sidebar.png and b/maestro/images/expected/android/toggle_sidebar.png differ diff --git a/packages/jsActions/mobile-resources-native/CHANGELOG.md b/packages/jsActions/mobile-resources-native/CHANGELOG.md index 4a618f1de..29bff8453 100644 --- a/packages/jsActions/mobile-resources-native/CHANGELOG.md +++ b/packages/jsActions/mobile-resources-native/CHANGELOG.md @@ -6,6 +6,29 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +## [10.1.3] Native Mobile Resources - 2025-9-9 + + +## [4.1.0] IntroScreen +### Fixed + +- We have fixed defaultProps deprecation warning. +- Initial slide now correctly positioned on mount. + +## [3.1.1] SafeAreaView +- We fixed the issue where navigation buttons were being overlapped due to improper safe area handling. + +## [2.3.0] Signature +- Updated react-native-webview from version v13.12.5 to latest + +## [6.1.1] VideoPlayer +### Changed + +- We have updated `react-native-video` version to 6.10.0 + +## [4.3.0] WebView +- Updated react-native-webview from version v13.12.5 to latest to support react-native 0.77 + ## [10.0.0] Native Mobile Resources - 2025-3-31 - We migrated from react-native-inappbrowser-reborn to @swan-io/react-native-browser to prevent issues for next rn upgrade. diff --git a/packages/jsActions/mobile-resources-native/e2e/specs/maestro/Clipboard.yaml b/packages/jsActions/mobile-resources-native/e2e/specs/maestro/Clipboard.yaml index 5ca416f79..eb8374bc8 100644 --- a/packages/jsActions/mobile-resources-native/e2e/specs/maestro/Clipboard.yaml +++ b/packages/jsActions/mobile-resources-native/e2e/specs/maestro/Clipboard.yaml @@ -12,5 +12,10 @@ appId: "${APP_ID}" text: "Set clipboard content to 'Hi there'" - tapOn: text: "Get clipboard content" +# Because the image loading can take some time due to resources on emulator, we need to wait for the image to be visible +- extendedWaitUntil: + visible: randText # Any random text that does not exist in the UI + optional: true # This should be true so that the test won't fail + timeout: 5000 # 5 seconds - takeScreenshot: path: "maestro/images/actual/${PLATFORM}/clipboard" diff --git a/packages/jsActions/mobile-resources-native/package.json b/packages/jsActions/mobile-resources-native/package.json index 947f251c3..d7e2e158f 100644 --- a/packages/jsActions/mobile-resources-native/package.json +++ b/packages/jsActions/mobile-resources-native/package.json @@ -1,7 +1,7 @@ { "name": "mobile-resources-native", "moduleName": "Native Mobile Resources", - "version": "10.0.0", + "version": "10.1.4", "license": "Apache-2.0", "copyright": "© Mendix Technology BV 2022. All rights reserved.", "repository": { @@ -9,12 +9,12 @@ "url": "https://github.com/mendix/native-widgets.git" }, "marketplace": { - "minimumMXVersion": "11.0.0.73100", + "minimumMXVersion": "10.24.0.73019", "marketplaceId": 109513 }, "testProject": { "githubUrl": "https://github.com/mendix/native-mobile-resources", - "branchName": "main" + "branchName": "mx/10.24.x" }, "scripts": { "prestart": "rimraf ./dist/tsc", @@ -26,30 +26,32 @@ "release:marketplace": "node ../../../scripts/release/marketplaceRelease.js" }, "dependencies": { - "@notifee/react-native": "9.1.8", "@react-native-camera-roll/camera-roll": "7.4.0", + "@react-native-community/push-notification-ios": "1.10.1", "@react-native-firebase/messaging": "17.3.0", - "@swan-io/react-native-browser": "0.4.1", + "@swan-io/react-native-browser": "^0.4.1", "fbjs": "3.0.4", "mime": "3.0.0", - "react-native-biometrics": "3.0.1", "react-native-blob-util": "0.21.2", - "react-native-device-info": "14.0.4", + "react-native-device-info": "13.0.0", "react-native-file-viewer": "2.1.5", "react-native-image-picker": "7.2.3", "react-native-localize": "3.2.1", "react-native-permissions": "4.1.5", + "react-native-push-notification": "8.1.1", "react-native-schedule-exact-alarm-permission": "^0.1.3", "react-native-sound": "0.11.0", + "react-native-touch-id": "4.4.1", "url-parse": "^1.4.7" }, "devDependencies": { "@mendix/pluggable-widgets-tools": "^10.0.1", "@types/querystringify": "^2.0.0", + "@types/react-native-push-notification": "8.1.1", "@types/url-parse": "^1.4.3", "eslint": "^7.32.0", "mendix": "~10.0.9976", "rimraf": "^4.4.1", "rollup": "^2.79.2" } -} +} \ No newline at end of file diff --git a/packages/jsActions/mobile-resources-native/src/authentication/BiometricAuthentication.ts b/packages/jsActions/mobile-resources-native/src/authentication/BiometricAuthentication.ts index d44e79e70..c9b62e70e 100644 --- a/packages/jsActions/mobile-resources-native/src/authentication/BiometricAuthentication.ts +++ b/packages/jsActions/mobile-resources-native/src/authentication/BiometricAuthentication.ts @@ -5,7 +5,7 @@ // - the code between BEGIN USER CODE and END USER CODE // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. -import ReactNativeBiometrics from "react-native-biometrics"; +import TouchID from "react-native-touch-id"; // BEGIN EXTRA CODE // END EXTRA CODE @@ -16,12 +16,9 @@ import ReactNativeBiometrics from "react-native-biometrics"; */ export async function BiometricAuthentication(reason?: string): Promise { // BEGIN USER CODE - // Documentation https://github.com/smallcase/react-native-simple-biometrics + // Documentation https://github.com/naoufal/react-native-touch-id - const rnBiometrics = new ReactNativeBiometrics(); - - return rnBiometrics - .simplePrompt({ promptMessage: reason ?? "" }) + return TouchID.authenticate(reason) .then(() => true) .catch(() => false); diff --git a/packages/jsActions/mobile-resources-native/src/authentication/IsBiometricAuthenticationSupported.ts b/packages/jsActions/mobile-resources-native/src/authentication/IsBiometricAuthenticationSupported.ts index 99a1b8d48..3387850b4 100644 --- a/packages/jsActions/mobile-resources-native/src/authentication/IsBiometricAuthenticationSupported.ts +++ b/packages/jsActions/mobile-resources-native/src/authentication/IsBiometricAuthenticationSupported.ts @@ -5,7 +5,7 @@ // - the code between BEGIN USER CODE and END USER CODE // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. -import ReactNativeBiometrics from "react-native-biometrics"; +import TouchID from "react-native-touch-id"; // BEGIN EXTRA CODE // END EXTRA CODE @@ -15,13 +15,10 @@ import ReactNativeBiometrics from "react-native-biometrics"; */ export async function IsBiometricAuthenticationSupported(): Promise { // BEGIN USER CODE - // Documentation https://github.com/smallcase/react-native-simple-biometrics + // Documentation https://github.com/naoufal/react-native-touch-id - const rnBiometrics = new ReactNativeBiometrics(); - - return rnBiometrics - .isSensorAvailable() - .then(result => result.available) + return TouchID.isSupported() + .then(() => true) .catch(() => false); // END USER CODE diff --git a/packages/jsActions/mobile-resources-native/src/notifications/CancelAllScheduledNotifications.ts b/packages/jsActions/mobile-resources-native/src/notifications/CancelAllScheduledNotifications.ts index e3e547625..f47fde625 100644 --- a/packages/jsActions/mobile-resources-native/src/notifications/CancelAllScheduledNotifications.ts +++ b/packages/jsActions/mobile-resources-native/src/notifications/CancelAllScheduledNotifications.ts @@ -5,8 +5,8 @@ // - the code between BEGIN USER CODE and END USER CODE // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. -import { NativeModules } from "react-native"; -import notifee from "@notifee/react-native"; +import { NativeModules, Platform } from "react-native"; +import PushNotification from "react-native-push-notification"; // BEGIN EXTRA CODE // END EXTRA CODE @@ -17,12 +17,13 @@ import notifee from "@notifee/react-native"; */ export async function CancelAllScheduledNotifications(): Promise { // BEGIN USER CODE - // Documentation https://github.com/invertase/notifee - if (NativeModules && !NativeModules.NotifeeApiModule) { - return Promise.reject(new Error("Notifee native module is not available in your app")); + // Documentation https://github.com/zo0r/react-native-push-notification + const isIOS = Platform.OS === "ios"; + if (NativeModules && isIOS && !NativeModules.RNCPushNotificationIOS) { + return Promise.reject(new Error("Notifications module is not available in your app")); } - notifee.cancelAllNotifications(); + PushNotification.cancelAllLocalNotifications(); return Promise.resolve(); // END USER CODE diff --git a/packages/jsActions/mobile-resources-native/src/notifications/CancelScheduledNotification.ts b/packages/jsActions/mobile-resources-native/src/notifications/CancelScheduledNotification.ts index d840fc9cd..20b1ab7b8 100644 --- a/packages/jsActions/mobile-resources-native/src/notifications/CancelScheduledNotification.ts +++ b/packages/jsActions/mobile-resources-native/src/notifications/CancelScheduledNotification.ts @@ -5,8 +5,8 @@ // - the code between BEGIN USER CODE and END USER CODE // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. -import { NativeModules } from "react-native"; -import notifee from "@notifee/react-native"; +import { NativeModules, Platform } from "react-native"; +import PushNotification from "react-native-push-notification"; // BEGIN EXTRA CODE // END EXTRA CODE @@ -17,16 +17,17 @@ import notifee from "@notifee/react-native"; */ export async function CancelScheduledNotification(notificationId?: string): Promise { // BEGIN USER CODE - // Documentation Documentation https://github.com/invertase/notifee - if (NativeModules && !NativeModules.NotifeeApiModule) { - return Promise.reject(new Error("Notifee native module is not available in your app")); + // Documentation https://github.com/zo0r/react-native-push-notification + const isIOS = Platform.OS === "ios"; + if (NativeModules && isIOS && !NativeModules.RNCPushNotificationIOS) { + return Promise.reject(new Error("Notifications module is not available in your app")); } if (!notificationId) { return Promise.reject(new Error("Input parameter 'Notification id' is required")); } - notifee.cancelNotification(notificationId); + PushNotification.cancelLocalNotification(notificationId); return Promise.resolve(); // END USER CODE diff --git a/packages/jsActions/mobile-resources-native/src/notifications/ClearAllDeliveredNotifications.ts b/packages/jsActions/mobile-resources-native/src/notifications/ClearAllDeliveredNotifications.ts index cd0debaed..ba197fdfc 100644 --- a/packages/jsActions/mobile-resources-native/src/notifications/ClearAllDeliveredNotifications.ts +++ b/packages/jsActions/mobile-resources-native/src/notifications/ClearAllDeliveredNotifications.ts @@ -5,8 +5,8 @@ // - the code between BEGIN USER CODE and END USER CODE // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. -import { NativeModules } from "react-native"; -import notifee from "@notifee/react-native"; +import { NativeModules, Platform } from "react-native"; +import PushNotification from "react-native-push-notification"; // BEGIN EXTRA CODE // END EXTRA CODE @@ -17,12 +17,13 @@ import notifee from "@notifee/react-native"; */ export async function ClearAllDeliveredNotifications(): Promise { // BEGIN USER CODE - // Documentation Documentation https://github.com/invertase/notifee - if (NativeModules && !NativeModules.NotifeeApiModule) { - return Promise.reject(new Error("Notifee native module is not available in your app")); + // Documentation https://github.com/zo0r/react-native-push-notification + const isIOS = Platform.OS === "ios"; + if (NativeModules && isIOS && !NativeModules.RNCPushNotificationIOS) { + return Promise.reject(new Error("Notifications module is not available in your app")); } - notifee.cancelAllNotifications(); + PushNotification.removeAllDeliveredNotifications(); return Promise.resolve(); // END USER CODE diff --git a/packages/jsActions/mobile-resources-native/src/notifications/DisplayNotification.ts b/packages/jsActions/mobile-resources-native/src/notifications/DisplayNotification.ts index bbfff2e5f..de1077f8e 100644 --- a/packages/jsActions/mobile-resources-native/src/notifications/DisplayNotification.ts +++ b/packages/jsActions/mobile-resources-native/src/notifications/DisplayNotification.ts @@ -6,7 +6,7 @@ // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. import { NativeModules, Platform } from "react-native"; -import notifee, { AndroidChannel, AndroidImportance, Notification } from "@notifee/react-native"; +import PushNotification, { PushNotificationObject } from "react-native-push-notification"; // BEGIN EXTRA CODE // END EXTRA CODE @@ -32,54 +32,59 @@ export async function DisplayNotification( actionGuid?: string ): Promise { // BEGIN USER CODE - if (!body) { - throw new Error("Input parameter 'Body' is required"); + // Documentation https://github.com/zo0r/react-native-push-notification + + const isIOS = Platform.OS === "ios"; + if (NativeModules && isIOS && !NativeModules.RNCPushNotificationIOS) { + return Promise.reject(new Error("Notifications module is not available in your app")); } - // Documentation Documentation https://github.com/invertase/notifee - if (NativeModules && !NativeModules.NotifeeApiModule) { - return Promise.reject(new Error("Notifee native module is not available in your app")); + if (!body) { + return Promise.reject(new Error("Input parameter 'Body' is required")); } - const channelId = playSound ? "mendix-local-notifications-withsound" : "mendix-local-notifications"; - await createNotificationChannelIfNeeded(channelId); + const notification = { message: body } as PushNotificationObject; - const notification: Notification = { - title: title || undefined, - body, - android: { channelId, sound: "default" }, - ios: playSound ? { sound: "default" } : {} - }; + if (!isIOS) { + const channelId = "mendix-local-notifications"; + const channelExists = await new Promise(resolve => + PushNotification.channelExists(channelId, (exists: boolean) => resolve(exists)) + ); + if (!channelExists) { + const channel = await new Promise(resolve => + PushNotification.createChannel( + { + channelId, + channelName: "Local notifications" + }, + created => resolve(created) + ) + ); + if (!channel) { + return Promise.reject(new Error("Could not create the local notifications channel")); + } + } + notification.channelId = channelId; + } - if (subtitle && Platform.OS === "ios") { - notification.subtitle = subtitle; + if (title) { + notification.title = title; } - if (actionName || actionGuid) { - notification.data = { - actionName: actionName ?? "", - guid: actionGuid ?? "" - }; + if (subtitle && !isIOS) { + notification.subText = subtitle; } - await notifee.displayNotification(notification); + notification.playSound = !!playSound; - async function createNotificationChannelIfNeeded(channelId: string): Promise { - if (Platform.OS === "ios") { - return; - } - const existingChannel = await notifee.getChannel(channelId); - const channel: AndroidChannel = { - id: channelId, - name: "Local Notifications", - importance: AndroidImportance.HIGH, - ...(playSound ? { sound: "default" } : {}) + if (actionName || actionGuid) { + notification.userInfo = { + actionName, + guid: actionGuid }; - if (existingChannel === null) { - await notifee.createChannel(channel); - } } + PushNotification.localNotification(notification); return Promise.resolve(); // END USER CODE } diff --git a/packages/jsActions/mobile-resources-native/src/notifications/ScheduleNotification.ts b/packages/jsActions/mobile-resources-native/src/notifications/ScheduleNotification.ts index a0683e593..bf7e445ba 100644 --- a/packages/jsActions/mobile-resources-native/src/notifications/ScheduleNotification.ts +++ b/packages/jsActions/mobile-resources-native/src/notifications/ScheduleNotification.ts @@ -5,15 +5,9 @@ // - the code between BEGIN USER CODE and END USER CODE // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. -import { Platform } from "react-native"; -import notifee, { - TimestampTrigger, - TriggerType, - AndroidChannel, - AndroidImportance, - Notification, - AlarmType -} from "@notifee/react-native"; +import { NativeModules, Platform } from "react-native"; +import PushNotification, { PushNotificationScheduleObject } from "react-native-push-notification"; + // BEGIN EXTRA CODE // END EXTRA CODE @@ -42,59 +36,68 @@ export async function ScheduleNotification( actionGuid?: string ): Promise { // BEGIN USER CODE - const channelId = playSound ? "mendix-local-notifications-withsound" : "mendix-local-notifications"; - await createNotificationChannelIfNeeded(channelId); + // Documentation https://github.com/zo0r/react-native-push-notification - if (!body) { - throw new Error("Input parameter 'Body' is required"); + const isIOS = Platform.OS === "ios"; + if (NativeModules && isIOS && !NativeModules.RNCPushNotificationIOS) { + return Promise.reject(new Error("Notifications module is not available in your app")); } - if (!date || !date.getTime()) { - throw new Error("Input parameter 'Date' is required and must be a valid Date object"); + if (!body) { + return Promise.reject(new Error("Input parameter 'Body' is required")); } - const trigger: TimestampTrigger = { - type: TriggerType.TIMESTAMP, - timestamp: date.getTime(), - alarmManager: { allowWhileIdle: true, type: AlarmType.SET_EXACT_AND_ALLOW_WHILE_IDLE } - }; + const notification = { message: body } as PushNotificationScheduleObject; + const notificationIdNumber = Number(notificationId); - const notification: Notification = { - id: notificationId || undefined, - title: title || undefined, - body, - android: { - channelId + if (!isIOS) { + const channelId = "mendix-local-notifications"; + const channelExists = await new Promise(resolve => + PushNotification.channelExists(channelId, (exists: boolean) => resolve(exists)) + ); + if (!channelExists) { + const channel = await new Promise(resolve => + PushNotification.createChannel( + { + channelId, + channelName: "Local notifications" + }, + created => resolve(created) + ) + ); + if (!channel) { + return Promise.reject(new Error("Could not create the local notifications channel")); + } } - }; + notification.channelId = channelId; + } + + if (notificationIdNumber) { + notification.id = notificationIdNumber; + } - if (subtitle && Platform.OS === "ios") { - notification.subtitle = subtitle; + if (title) { + notification.title = title; } + if (subtitle && !isIOS) { + notification.subText = subtitle; + } + + notification.playSound = !!playSound; + if (actionName || actionGuid) { - notification.data = { - actionName: actionName ?? "", - guid: actionGuid ?? "" + notification.userInfo = { + actionName, + guid: actionGuid }; } - async function createNotificationChannelIfNeeded(channelId: string): Promise { - if (Platform.OS === "ios") { - return; - } - const existingChannel = await notifee.getChannel(channelId); - const channel: AndroidChannel = { - id: channelId, - name: "Local Notifications", - importance: AndroidImportance.HIGH, - ...(playSound ? { sound: "default" } : {}) - }; - if (existingChannel === null) { - await notifee.createChannel(channel); - } + if (date && date.getTime()) { + notification.date = date; } - await notifee.createTriggerNotification(notification, trigger); + PushNotification.localNotificationSchedule(notification); + return Promise.resolve(); // END USER CODE } diff --git a/packages/jsActions/mobile-resources-native/src/notifications/SetBadgeNumber.ts b/packages/jsActions/mobile-resources-native/src/notifications/SetBadgeNumber.ts index e5e80a248..30752a575 100644 --- a/packages/jsActions/mobile-resources-native/src/notifications/SetBadgeNumber.ts +++ b/packages/jsActions/mobile-resources-native/src/notifications/SetBadgeNumber.ts @@ -6,8 +6,8 @@ // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. import { Big } from "big.js"; -import { NativeModules } from "react-native"; -import notifee from "@notifee/react-native"; +import { NativeModules, Platform } from "react-native"; +import PushNotification from "react-native-push-notification"; // BEGIN EXTRA CODE // END EXTRA CODE @@ -18,10 +18,11 @@ import notifee from "@notifee/react-native"; */ export async function SetBadgeNumber(badgeNumber?: Big): Promise { // BEGIN USER CODE - // Documentation Documentation https://github.com/invertase/notifee + // Documentation https://github.com/zo0r/react-native-push-notification - if (NativeModules && !NativeModules.NotifeeApiModule) { - return Promise.reject(new Error("Notifee native module is not available in your app")); + const isIOS = Platform.OS === "ios"; + if (NativeModules && isIOS && !NativeModules.RNCPushNotificationIOS) { + return Promise.reject(new Error("Notifications module is not available in your app")); } if (!badgeNumber) { @@ -32,7 +33,7 @@ export async function SetBadgeNumber(badgeNumber?: Big): Promise { return Promise.reject(new Error("Input parameter 'Badge number' should be zero or greater")); } - return notifee.setBadgeCount(Number(badgeNumber)); + return PushNotification.setApplicationIconBadgeNumber(Number(badgeNumber)); // END USER CODE } diff --git a/packages/jsActions/mobile-resources-native/typings/TouchID.d.ts b/packages/jsActions/mobile-resources-native/typings/TouchID.d.ts new file mode 100644 index 000000000..8aab38c7a --- /dev/null +++ b/packages/jsActions/mobile-resources-native/typings/TouchID.d.ts @@ -0,0 +1,116 @@ +/** + * Source: https://github.com/naoufal/react-native-touch-id/blob/master/index.d.ts + * (Modified) + * + * Copyright (c) 2015, Naoufal Kadhom + * Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +declare module "react-native-touch-id" { + /** + * The supported biometry type + */ + type BiometryType = "FaceID" | "TouchID"; + + /** + * Base config to pass to `TouchID.isSupported` and `TouchID.authenticate` + */ + interface IsSupportedConfig { + /** + * Return unified error messages + */ + unifiedErrors?: boolean; + } + + /** + * Authentication config + */ + export interface AuthenticateConfig extends IsSupportedConfig { + /** + * **Android only** - Title of confirmation dialog + */ + title?: string; + /** + * **Android only** - Color of fingerprint image + */ + imageColor?: string; + /** + * **Android only** - Color of fingerprint image after failed attempt + */ + imageErrorColor?: string; + /** + * **Android only** - Text shown next to the fingerprint image + */ + sensorDescription?: string; + /** + * **Android only** - Text shown next to the fingerprint image after failed attempt + */ + sensorErrorDescription?: string; + /** + * **Android only** - Cancel button text + */ + cancelText?: string; + /** + * **iOS only** - By default specified 'Show Password' label. If set to empty string label is invisible. + */ + fallbackLabel?: string; + /** + * **iOS only** - By default set to false. If set to true, will allow use of keypad passcode. + */ + passcodeFallback?: boolean; + } + /** + * `isSupported` error code + */ + type IsSupportedErrorCode = "NOT_SUPPORTED" | "NOT_AVAILABLE" | "NOT_PRESENT" | "NOT_ENROLLED"; + + /** + * `authenticate` error code + */ + type AuthenticateErrorCode = + | IsSupportedErrorCode + | "AUTHENTICATION_FAILED" + | "USER_CANCELED" + | "SYSTEM_CANCELED" + | "TIMEOUT" + | "LOCKOUT" + | "LOCKOUT_PERMANENT" + | "PROCESSING_ERROR" + | "USER_FALLBACK" + | "UNKNOWN_ERROR"; + + /** + * Error returned from `authenticate` + */ + export interface AuthenticationError { + name: "TouchIDError"; + message: string; + code: AuthenticateErrorCode; + details: string; + } + /** + * Error returned from `isSupported` + */ + export interface IsSupportedError { + name: "TouchIDError"; + message: string; + code: IsSupportedErrorCode; + details: string; + } + + const TouchID: { + /** + * + * @param reason String that provides a clear reason for requesting authentication. + * @param config Configuration object for more detailed dialog setup + */ + authenticate(reason?: string, config?: AuthenticateConfig): Promise; + /** + * + * @param config - Returns a `Promise` that rejects if TouchID is not supported. On iOS resolves with a `biometryType` `String` of `FaceID` or `TouchID` + */ + isSupported(config?: IsSupportedConfig): Promise; + }; + export default TouchID; +} diff --git a/packages/jsActions/nanoflow-actions-native/CHANGELOG.md b/packages/jsActions/nanoflow-actions-native/CHANGELOG.md index ddb24599f..5b3bf3611 100644 --- a/packages/jsActions/nanoflow-actions-native/CHANGELOG.md +++ b/packages/jsActions/nanoflow-actions-native/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Fixed + +- We've fixed location permission issue on iOS. + ### Changed - We've updated the minimum Mendix version to 10.21. diff --git a/packages/jsActions/nanoflow-actions-native/package.json b/packages/jsActions/nanoflow-actions-native/package.json index 00c61c5dd..2108e1938 100644 --- a/packages/jsActions/nanoflow-actions-native/package.json +++ b/packages/jsActions/nanoflow-actions-native/package.json @@ -1,7 +1,7 @@ { "name": "nanoflow-actions-native", "moduleName": "Nanoflow Commons", - "version": "5.1.2", + "version": "5.1.3", "license": "Apache-2.0", "copyright": "© Mendix Technology BV 2022. All rights reserved.", "repository": { @@ -9,12 +9,12 @@ "url": "https://github.com/mendix/native-widgets.git" }, "marketplace": { - "minimumMXVersion": "11.0.0.73100", + "minimumMXVersion": "10.24.0.73019", "marketplaceId": 109515 }, "testProject": { "githubUrl": "https://github.com/mendix/native-mobile-resources", - "branchName": "main" + "branchName": "mx/10.24.x" }, "scripts": { "start": "rollup --config ../../../configs/jsactions/rollup.config.js --watch --configProject nanoflowcommons", diff --git a/packages/jsActions/nanoflow-actions-native/src/geolocation/RequestLocationPermission.ts b/packages/jsActions/nanoflow-actions-native/src/geolocation/RequestLocationPermission.ts index 625cde953..0bdf03337 100644 --- a/packages/jsActions/nanoflow-actions-native/src/geolocation/RequestLocationPermission.ts +++ b/packages/jsActions/nanoflow-actions-native/src/geolocation/RequestLocationPermission.ts @@ -5,7 +5,7 @@ // - the code between BEGIN USER CODE and END USER CODE // - the code between BEGIN EXTRA CODE and END EXTRA CODE // Other code you write will be lost the next time you deploy the project. -import Geolocation, { GeolocationError } from "@react-native-community/geolocation"; +import Geolocation from "@react-native-community/geolocation"; import type { GeolocationServiceStatic, AuthorizationResult } from "../../typings/Geolocation"; @@ -119,14 +119,16 @@ export async function RequestLocationPermission(): Promise { ) ); } else if (geolocationModule) { - geolocationModule.requestAuthorization( - () => { - return Promise.resolve(true); - }, - (err: GeolocationError) => { - return Promise.reject(err); - } - ); + return new Promise(resolve => { + geolocationModule.requestAuthorization( + () => { + resolve(true); + }, + () => { + resolve(false); + } + ); + }); } return false; diff --git a/packages/modules/atlas-content-native/package.json b/packages/modules/atlas-content-native/package.json index 0835cf6fa..3c6115904 100644 --- a/packages/modules/atlas-content-native/package.json +++ b/packages/modules/atlas-content-native/package.json @@ -9,12 +9,12 @@ "url": "https://github.com/mendix/native-widgets.git" }, "marketplace": { - "minimumMXVersion": "9.6.0.27784", + "minimumMXVersion": "10.24.0.73019", "marketplaceId": 117175 }, "testProject": { "githubUrl": "https://github.com/mendix/native-mobile-resources", - "branchName": "main" + "branchName": "mx/10.24.x" }, "scripts": { "release": "ts-node ./scripts/build.ts release", diff --git a/packages/pluggableWidgets/background-gradient-native/CHANGELOG.md b/packages/pluggableWidgets/background-gradient-native/CHANGELOG.md index 1eb9cc7e1..c48f6cee3 100644 --- a/packages/pluggableWidgets/background-gradient-native/CHANGELOG.md +++ b/packages/pluggableWidgets/background-gradient-native/CHANGELOG.md @@ -6,8 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] -- Updated react-native-linear-gradient to latest version. - ## [2.1.0] - 2024-12-3 ### Changed diff --git a/packages/pluggableWidgets/background-gradient-native/package.json b/packages/pluggableWidgets/background-gradient-native/package.json index e2eccc6f8..e235e949d 100644 --- a/packages/pluggableWidgets/background-gradient-native/package.json +++ b/packages/pluggableWidgets/background-gradient-native/package.json @@ -1,7 +1,7 @@ { "name": "background-gradient-native", "widgetName": "BackgroundGradient", - "version": "2.2.0", + "version": "2.1.0", "repository": { "type": "git", "url": "https://github.com/mendix/native-widgets.git" @@ -24,6 +24,6 @@ }, "dependencies": { "@mendix/piw-utils-internal": "*", - "react-native-linear-gradient": "2.8.3" + "react-native-linear-gradient": "2.5.6" } } diff --git a/packages/pluggableWidgets/background-gradient-native/src/package.xml b/packages/pluggableWidgets/background-gradient-native/src/package.xml index 7ae868b45..f8c80fdc7 100644 --- a/packages/pluggableWidgets/background-gradient-native/src/package.xml +++ b/packages/pluggableWidgets/background-gradient-native/src/package.xml @@ -1,6 +1,6 @@ - + diff --git a/packages/pluggableWidgets/bottom-sheet-native/CHANGELOG.md b/packages/pluggableWidgets/bottom-sheet-native/CHANGELOG.md index ab4e97380..8bb1cfe2e 100644 --- a/packages/pluggableWidgets/bottom-sheet-native/CHANGELOG.md +++ b/packages/pluggableWidgets/bottom-sheet-native/CHANGELOG.md @@ -6,8 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] -- Updated react-native-device-info to latest version. - ## [5.0.0] - 2025-3-31 ### Changed diff --git a/packages/pluggableWidgets/bottom-sheet-native/package.json b/packages/pluggableWidgets/bottom-sheet-native/package.json index b741239b7..0483b66c8 100644 --- a/packages/pluggableWidgets/bottom-sheet-native/package.json +++ b/packages/pluggableWidgets/bottom-sheet-native/package.json @@ -1,7 +1,7 @@ { "name": "bottom-sheet-native", "widgetName": "BottomSheet", - "version": "5.0.1", + "version": "5.0.0", "license": "Apache-2.0", "repository": { "type": "git", @@ -23,7 +23,7 @@ "@mendix/piw-native-utils-internal": "*", "@mendix/piw-utils-internal": "*", "@shopify/flash-list": "1.7.3", - "react-native-device-info": "14.0.4", + "react-native-device-info": "13.0.0", "react-native-gesture-handler": "2.24.0", "react-native-reanimated": "3.16.1" }, diff --git a/packages/pluggableWidgets/bottom-sheet-native/src/package.xml b/packages/pluggableWidgets/bottom-sheet-native/src/package.xml index c4f1be9f3..c92801bb3 100644 --- a/packages/pluggableWidgets/bottom-sheet-native/src/package.xml +++ b/packages/pluggableWidgets/bottom-sheet-native/src/package.xml @@ -1,6 +1,6 @@ - + diff --git a/packages/pluggableWidgets/gallery-native/CHANGELOG.md b/packages/pluggableWidgets/gallery-native/CHANGELOG.md index b02304cc2..a43eb8433 100644 --- a/packages/pluggableWidgets/gallery-native/CHANGELOG.md +++ b/packages/pluggableWidgets/gallery-native/CHANGELOG.md @@ -8,8 +8,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [2.0.0] - 2024-12-3 -- Updated react-native-device-info to latest version. - ### Changed - Updated @mendix/pluggable-widgets-tools from version v9.0.0 to v10.15.0. diff --git a/packages/pluggableWidgets/gallery-native/package.json b/packages/pluggableWidgets/gallery-native/package.json index b94b6c8dd..58b906b1d 100644 --- a/packages/pluggableWidgets/gallery-native/package.json +++ b/packages/pluggableWidgets/gallery-native/package.json @@ -1,7 +1,7 @@ { "name": "gallery-native", "widgetName": "Gallery", - "version": "2.0.1", + "version": "2.0.0", "description": "A flexible gallery widget that renders columns, rows and layouts.", "copyright": "© Mendix Technology BV 2022. All rights reserved.", "license": "Apache-2.0", @@ -23,7 +23,7 @@ }, "dependencies": { "@mendix/piw-utils-internal": "*", - "react-native-device-info": "14.0.4" + "react-native-device-info": "13.0.0" }, "devDependencies": { "@mendix/pluggable-widgets-tools": "~10.0.1", diff --git a/packages/pluggableWidgets/gallery-native/src/package.xml b/packages/pluggableWidgets/gallery-native/src/package.xml index 80b03d697..eb13e1580 100644 --- a/packages/pluggableWidgets/gallery-native/src/package.xml +++ b/packages/pluggableWidgets/gallery-native/src/package.xml @@ -1,6 +1,6 @@ - + diff --git a/packages/pluggableWidgets/intro-screen-native/CHANGELOG.md b/packages/pluggableWidgets/intro-screen-native/CHANGELOG.md index ff4a6db94..a240c665f 100644 --- a/packages/pluggableWidgets/intro-screen-native/CHANGELOG.md +++ b/packages/pluggableWidgets/intro-screen-native/CHANGELOG.md @@ -6,22 +6,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] -### Fixes - -- Initial slide now correctly positioned on mount. - -### Changed - -- Updated react-native-device-info to latest version. +## [4.1.0] - 2025-9-9 ### Fixed - We have fixed defaultProps deprecation warning. +- Initial slide now correctly positioned on mount. ## [4.0.0] - 2024-12-3 -- Updated react-native-device-info to latest version. - ### Changed - Updated @mendix/pluggable-widgets-tools from version v9.0.0 to v10.15.0. diff --git a/packages/pluggableWidgets/intro-screen-native/package.json b/packages/pluggableWidgets/intro-screen-native/package.json index cd6e725f2..a6dc423c8 100644 --- a/packages/pluggableWidgets/intro-screen-native/package.json +++ b/packages/pluggableWidgets/intro-screen-native/package.json @@ -1,7 +1,7 @@ { "name": "intro-screen-native", "widgetName": "IntroScreen", - "version": "4.2.0", + "version": "4.1.0", "license": "Apache-2.0", "repository": { "type": "git", @@ -22,7 +22,7 @@ "@mendix/piw-native-utils-internal": "*", "@mendix/piw-utils-internal": "*", "@react-native-async-storage/async-storage": "2.0.0", - "react-native-device-info": "14.0.4" + "react-native-device-info": "13.0.0" }, "devDependencies": { "@mendix/pluggable-widgets-tools": "~10.0.1", diff --git a/packages/pluggableWidgets/intro-screen-native/src/package.xml b/packages/pluggableWidgets/intro-screen-native/src/package.xml index 2b935564d..34d0ef2ea 100644 --- a/packages/pluggableWidgets/intro-screen-native/src/package.xml +++ b/packages/pluggableWidgets/intro-screen-native/src/package.xml @@ -1,6 +1,6 @@ - + diff --git a/packages/pluggableWidgets/notifications-native/CHANGELOG.md b/packages/pluggableWidgets/notifications-native/CHANGELOG.md index 4d6cee63d..eedb8ae3c 100644 --- a/packages/pluggableWidgets/notifications-native/CHANGELOG.md +++ b/packages/pluggableWidgets/notifications-native/CHANGELOG.md @@ -6,8 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] -- The widget has been migrated to notifee. - ## [4.1.0] - 2024-12-3 ### Changed diff --git a/packages/pluggableWidgets/notifications-native/package.json b/packages/pluggableWidgets/notifications-native/package.json index 4c4807592..adc991592 100644 --- a/packages/pluggableWidgets/notifications-native/package.json +++ b/packages/pluggableWidgets/notifications-native/package.json @@ -1,7 +1,7 @@ { "name": "notifications-native", "widgetName": "Notifications", - "version": "5.0.0", + "version": "4.1.0", "license": "Apache-2.0", "repository": { "type": "git", @@ -19,9 +19,9 @@ }, "dependencies": { "@mendix/piw-utils-internal": "*", - "@notifee/react-native": "9.1.8", "@react-native-firebase/app": "17.3.0", - "@react-native-firebase/messaging": "17.3.0" + "@react-native-firebase/messaging": "17.3.0", + "react-native-push-notification": "8.1.1" }, "devDependencies": { "@mendix/pluggable-widgets-tools": "~10.0.1", diff --git a/packages/pluggableWidgets/notifications-native/src/Notifications.tsx b/packages/pluggableWidgets/notifications-native/src/Notifications.tsx index 1d71686f0..9518cfdf9 100644 --- a/packages/pluggableWidgets/notifications-native/src/Notifications.tsx +++ b/packages/pluggableWidgets/notifications-native/src/Notifications.tsx @@ -1,14 +1,19 @@ import messaging, { FirebaseMessagingTypes } from "@react-native-firebase/messaging"; +import PushNotification, { ReceivedNotification } from "react-native-push-notification"; import { executeAction } from "@mendix/piw-utils-internal"; import { useCallback, useEffect, useRef, useState } from "react"; import { Platform } from "react-native"; import { ActionValue, ValueStatus, Option } from "mendix"; import "@react-native-firebase/app"; -import notifee, { EventType } from "@notifee/react-native"; import { ActionsType, NotificationsProps } from "../typings/NotificationsProps"; // re-declare the library's type because: 1) it doesn't match library version 2) the definition file exports two symbols with same name. +interface IPushNotification extends ReceivedNotification { + title: string; + message: string; +} + interface ActionData { actionName?: string; guid?: string; @@ -105,27 +110,22 @@ export function Notifications(props: NotificationsProps): null { // wait for all used DynamicValues are available before configuring, else handleNotification is invoked while // properties in scope are loading. if (loadNotifications) { - // Handle notifications when the app is in the foreground - notifee.onForegroundEvent(({ type, detail }) => { - if (type === EventType.PRESS) { - const notification = detail.notification; - if (notification === undefined || notification.data === undefined) { - console.log("notificaiton is not exist"); - return; - } - const messageId = - notification.data?.[Platform.OS === "ios" ? "gcm.message_id" : "google.message_id"]; + PushNotification.configure({ + // called when user taps local notification + onNotification(notification: IPushNotification) { + const messageId = notification.data[Platform.OS === "ios" ? "gcm.message_id" : "google.message_id"]; handleNotification( { data: notification.data, title: notification.title, - body: notification.body, - subTitle: notification.subtitle + body: notification.message, + subTitle: notification.subText }, action => action.onOpen, - messageId as any + messageId ); - } + }, + requestPermissions: Platform.OS === "ios" }); } }, [loadNotifications, handleNotification]); diff --git a/packages/pluggableWidgets/notifications-native/src/package.xml b/packages/pluggableWidgets/notifications-native/src/package.xml index f9b7fcb99..01942a958 100644 --- a/packages/pluggableWidgets/notifications-native/src/package.xml +++ b/packages/pluggableWidgets/notifications-native/src/package.xml @@ -1,6 +1,6 @@ - + diff --git a/packages/pluggableWidgets/safe-area-view-native/CHANGELOG.md b/packages/pluggableWidgets/safe-area-view-native/CHANGELOG.md index c4eb191bc..cd5889c44 100644 --- a/packages/pluggableWidgets/safe-area-view-native/CHANGELOG.md +++ b/packages/pluggableWidgets/safe-area-view-native/CHANGELOG.md @@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +## [3.1.1] - 2025-9-9 + +- We fixed the issue where navigation buttons were being overlapped due to improper safe area handling. + +## [3.1.0] - 2025-4-25 + - We fixed the issue where the header is going outside of page in some android versions. ## [3.0.1] - 2025-3-18 diff --git a/packages/pluggableWidgets/safe-area-view-native/package.json b/packages/pluggableWidgets/safe-area-view-native/package.json index af5426da0..feb51b958 100644 --- a/packages/pluggableWidgets/safe-area-view-native/package.json +++ b/packages/pluggableWidgets/safe-area-view-native/package.json @@ -1,7 +1,7 @@ { "name": "safe-area-view-native", "widgetName": "SafeAreaView", - "version": "3.1.0", + "version": "3.1.1", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/pluggableWidgets/safe-area-view-native/src/SafeAreaView.tsx b/packages/pluggableWidgets/safe-area-view-native/src/SafeAreaView.tsx index 149cae2ae..8421a932a 100644 --- a/packages/pluggableWidgets/safe-area-view-native/src/SafeAreaView.tsx +++ b/packages/pluggableWidgets/safe-area-view-native/src/SafeAreaView.tsx @@ -3,33 +3,18 @@ import { flattenStyles } from "@mendix/piw-native-utils-internal"; import { SafeAreaViewStyle, defaultSafeAreaViewStyle } from "./ui/Styles"; import { SafeAreaViewProps } from "../typings/SafeAreaViewProps"; import { SafeAreaView as SafeAreaViewComponent } from "react-native-safe-area-context"; -import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs"; import { View } from "react-native"; -export function useSafeBottomTabBarHeight(): number { - try { - const height = useBottomTabBarHeight(); - return height; - } catch (e) { - return 0; - } -} - export const SafeAreaView = (props: SafeAreaViewProps): JSX.Element => { const styles = flattenStyles(defaultSafeAreaViewStyle, props.style); - const tabBarHeight = useSafeBottomTabBarHeight(); - const isBottomBarActive = tabBarHeight > 0; return ( - - - {props.content} - - + + + + {props.content} + + + ); }; diff --git a/packages/pluggableWidgets/safe-area-view-native/src/package.xml b/packages/pluggableWidgets/safe-area-view-native/src/package.xml index db3f8bef5..80b8cdade 100644 --- a/packages/pluggableWidgets/safe-area-view-native/src/package.xml +++ b/packages/pluggableWidgets/safe-area-view-native/src/package.xml @@ -1,6 +1,6 @@ - + diff --git a/packages/pluggableWidgets/signature-native/CHANGELOG.md b/packages/pluggableWidgets/signature-native/CHANGELOG.md index e0764ac72..18284d865 100644 --- a/packages/pluggableWidgets/signature-native/CHANGELOG.md +++ b/packages/pluggableWidgets/signature-native/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +## [2.3.0] - 2025-9-9 + - Updated react-native-webview from version v13.12.5 to latest ## [2.2.0] - 2025-3-31 diff --git a/packages/pluggableWidgets/video-player-native/CHANGELOG.md b/packages/pluggableWidgets/video-player-native/CHANGELOG.md index 6841340ea..326667d5a 100644 --- a/packages/pluggableWidgets/video-player-native/CHANGELOG.md +++ b/packages/pluggableWidgets/video-player-native/CHANGELOG.md @@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +## [6.1.1] - 2025-9-9 + +### Changed + +- We have updated `react-native-video` version to 6.10.0 + ## [6.1.0] - 2024-12-3 ### Changed diff --git a/packages/pluggableWidgets/video-player-native/package.json b/packages/pluggableWidgets/video-player-native/package.json index b14dbc9b8..56731cf6f 100644 --- a/packages/pluggableWidgets/video-player-native/package.json +++ b/packages/pluggableWidgets/video-player-native/package.json @@ -1,7 +1,7 @@ { "name": "video-player-native", "widgetName": "VideoPlayer", - "version": "6.1.0", + "version": "6.1.1", "license": "Apache-2.0", "repository": { "type": "git", @@ -23,12 +23,11 @@ "deprecated-react-native-prop-types": "^4.0.0", "react-native-system-navigation-bar": "2.6.3", "react-native-vector-icons": "10.2.0", - "react-native-video": "6.4.5" + "react-native-video": "6.10.0" }, "devDependencies": { "@mendix/piw-utils-internal": "1.0.0", "@mendix/pluggable-widgets-tools": "~10.0.1", - "@types/react-native-video": "^5.0.4", "eslint": "^7.32.0" } } diff --git a/packages/pluggableWidgets/video-player-native/src/package.xml b/packages/pluggableWidgets/video-player-native/src/package.xml index f5ed039c6..935a2fdf6 100644 --- a/packages/pluggableWidgets/video-player-native/src/package.xml +++ b/packages/pluggableWidgets/video-player-native/src/package.xml @@ -1,6 +1,6 @@ - + diff --git a/packages/pluggableWidgets/web-view-native/CHANGELOG.md b/packages/pluggableWidgets/web-view-native/CHANGELOG.md index ec14537e0..884ed2716 100644 --- a/packages/pluggableWidgets/web-view-native/CHANGELOG.md +++ b/packages/pluggableWidgets/web-view-native/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +## [4.3.0] - 2025-9-9 + - Updated react-native-webview from version v13.12.5 to latest to support react-native 0.77 ## [4.2.0] - 2025-3-31 diff --git a/scripts/release/createNativeModules.js b/scripts/release/createNativeModules.js index 1c464bfe1..b8342f5a0 100644 --- a/scripts/release/createNativeModules.js +++ b/scripts/release/createNativeModules.js @@ -129,7 +129,7 @@ async function updateNativeComponentsTestProject(moduleInfo, tmpFolder, nativeWi const tmpFolderActions = join(tmpFolder, `javascriptsource/${moduleInfo.moduleFolderNameInModeler}/actions`); console.log("Updating NativeComponentsTestProject..."); - await cloneRepo(moduleInfo.testProjectUrl, tmpFolder); + await cloneRepo(moduleInfo.testProjectUrl, tmpFolder, moduleInfo.testProjectBranchName); console.log("Deleting existing JS Actions from test project..."); await rm(tmpFolderActions, { force: true, recursive: true }); // this is useful to avoid retaining stale dependencies in the test project. @@ -199,7 +199,7 @@ async function updateNativeComponentsTestProjectWithAtlas(moduleInfo, tmpFolder) const tmpFolderNativeStyles = join(tmpFolder, `themesource/${moduleInfo.moduleFolderNameInModeler}`); console.log("Updating NativeComponentsTestProject.."); - await cloneRepo(moduleInfo.testProjectUrl, tmpFolder); + await cloneRepo(moduleInfo.testProjectUrl, tmpFolder, moduleInfo.testProjectBranchName); console.log("Copying Native styling files.."); await Promise.all([ diff --git a/scripts/release/module-automation/commons.js b/scripts/release/module-automation/commons.js index e51de0002..c362c414e 100644 --- a/scripts/release/module-automation/commons.js +++ b/scripts/release/module-automation/commons.js @@ -207,12 +207,12 @@ async function githubAuthentication(moduleInfo) { await execShellCommand(`echo "${process.env.GH_PAT}" | gh auth login --with-token`); } -async function cloneRepo(githubUrl, localFolder) { +async function cloneRepo(githubUrl, localFolder, branchName = "main") { const githubUrlDomain = githubUrl.replace("https://", ""); const githubUrlAuthenticated = `https://${process.env.GH_USERNAME}:${process.env.GH_PAT}@${githubUrlDomain}`; await rm(localFolder, { recursive: true, force: true }); await mkdir(localFolder, { recursive: true }); - await execShellCommand(`git clone ${githubUrlAuthenticated} ${localFolder}`); + await execShellCommand(`git clone -b ${branchName} ${githubUrlAuthenticated} ${localFolder}`); await setLocalGitCredentials(localFolder); } diff --git a/scripts/test/e2e-native.js b/scripts/test/e2e-native.js deleted file mode 100644 index 281aa08b3..000000000 --- a/scripts/test/e2e-native.js +++ /dev/null @@ -1,253 +0,0 @@ -const { execSync } = require("child_process"); -const fetch = require("node-fetch"); -const { join } = require("path"); -const { cat, mkdir, rm, mv } = require("shelljs"); -const { pipeline } = require("stream"); -const { promisify } = require("util"); -const { createWriteStream } = require("fs"); -const { tmpdir } = require("os"); -const nodeIp = require("ip"); - -main().catch(e => { - console.error(e); - process.exit(-1); -}); - -// todo: add all docker run inside a try finally, cleanup. -// not sure of docker container lifecycles in github actions environment -async function main() { - const mendixVersion = await getMendixVersion(); - const ip = nodeIp.address(); - const ghcr = process.env.CI && process.env.FORKED !== "true" ? "ghcr.io/mendix/native-widgets/" : ""; - - const testArchivePath = await getTestProject("https://github.com/mendix/Native-Mobile-Resources", "main"); - const root = process.cwd(); - const projectsRoot = join(root, "tests"); - const projectDir = join(root, "tests/testProject"); - try { - mkdir("-p", projectsRoot); - execSync(`unzip -o ${testArchivePath} -d ${projectsRoot}`); - mv(`${projectsRoot}/Native-Mobile-Resources-main`, projectDir); - rm("-f", testArchivePath); - } catch (e) { - throw new Error("Failed to unzip the test project into testProject", e.message); - } - - const output = execSync("yarn workspaces list --json --since origin/master"); - const packages = JSON.parse(output); - - execSync("yarn workspaces foreach run release --since origin/master"); - - packages.forEach(({ name, location }) => { - if (["mobile-resources-native", "nanoflow-actions-native"].includes(name)) { - // for js actions - const path = name === "mobile-resources-native" ? "nativemobileresources" : "nanoflowcommons"; - const jsActionsPath = `${projectDir}/javascriptsource/${path}/actions`; - rm("-rf", jsActionsPath); - cp("-r", `${location}/dist`, jsActionsPath); - } else { - // for widgets - // this is acceptable if there's one built version. - cp(`${location}/dist/**/*.mpk`, `${projectDir}/widgets`); - } - }); - - // When running on CI pull the docker image from Github Container Registry - if (ghcr) { - console.log(`Pulling mxbuild docker image from Github Container Registry...`); - execSync(`docker pull ${ghcr}mxbuild:${mendixVersion}`); - } - - const existingImages = execSync(`docker image ls -q ${ghcr}mxbuild:${mendixVersion}`).toString().trim(); - const scriptsPath = join(root, "scripts/automation"); - - if (!existingImages) { - console.log(`Creating new mxbuild docker image...`); - execSync( - `docker build -f ${join(scriptsPath, "mxbuild.Dockerfile")} ` + - `--build-arg MENDIX_VERSION=${mendixVersion} ` + - `-t mxbuild:${mendixVersion} ${scriptsPath}`, - { stdio: "inherit" } - ); - } - - if (ghcr) { - console.log(`Pulling mxruntime docker image from Github Container Registry...`); - execSync(`docker pull ${ghcr}mxruntime:${mendixVersion}`); - } - - const existingRuntimeImages = execSync(`docker image ls -q ${ghcr}mxruntime:${mendixVersion}`).toString().trim(); - if (!existingRuntimeImages) { - console.log(`Creating new runtime docker image...`); - execSync( - `docker build -f ${join(scriptsPath, "runtime.Dockerfile")} ` + - `--build-arg MENDIX_VERSION=${mendixVersion} ` + - `-t mxruntime:${mendixVersion} ${scriptsPath}`, - { stdio: "inherit" } - ); - } - - let runtimeContainerId; - let mxbuildContainerId; - try { - // Build testProject via mxbuild - const projectFile = "/source/tests/testProject/NativeComponentsTestProject.mpr"; - mxbuildContainerId = execSync( - `docker run -p 8083:8083 -td -v ${root}:/source --rm ${ghcr}mxbuild:${mendixVersion} bash` - ) - .toString() - .trim(); - - console.log("Updating widgets with mx util..."); - execSync( - `docker exec -t ${mxbuildContainerId} bash -c "mx update-widgets --loose-version-check ${projectFile}"`, - { - stdio: "inherit" - } - ); - - console.log("Building project with mxbuild..."); - execSync(`docker exec -t ${mxbuildContainerId} bash -c "mxbuild -o /tmp/automation.mda ${projectFile}"`, { - stdio: "inherit" - }); - console.log("All widgets are updated and project .mpr created."); - - console.log("Starting metro..."); - execSync( - `docker exec -td ${mxbuildContainerId} bash -c "cd /source/tests/testProject/deployment/native && ` + - `/tmp/mxbuild/modeler/tools/node/node /tmp/mxbuild/modeler/tools/node/node_modules/react-native/local-cli/cli.js ` + - `start --port '8083' --config '/source/tests/testProject/deployment/native/metro.config.json' --no-interactive"`, - { stdio: "inherit" } - ); - - // wait until metro bundler is alive - let metroRequestAttempts = 60; - for (; metroRequestAttempts > 0; --metroRequestAttempts) { - try { - const response = await fetch(`http://localhost:8083/status`); - if (response.ok) { - break; - } - } catch (e) { - console.log(`Could not reach Metro, trying again...`); - } - await new Promise(resolve => setTimeout(resolve, 3000)); - } - - if (metroRequestAttempts === 0) { - throw new Error("Metro bundler did not start in time..."); - } - console.log("Metro started."); - - console.log("Preheating bundler for Android dev=false minify=true"); - await Promise.race([ - fetch("http://localhost:8083/index.bundle?platform=android&dev=false&minify=true"), - new Promise((_, reject) => - setTimeout(() => reject(new Error("Preheating call timed out!")), 10 * 60 * 1000) - ) - ]); - console.log("Preheating done!"); - - // Spin up the runtime and run testProject - runtimeContainerId = execSync( - `docker run -td -v ${root}:/source -v ${scriptsPath}:/shared:ro -w /source -p 8080:8080 ` + - `-e MENDIX_VERSION=${mendixVersion} --entrypoint /bin/bash ` + - `--rm ${ghcr}mxruntime:${mendixVersion} /shared/runtime.sh` - ) - .toString() - .trim(); - - // wait until runtime is alive - let attempts = 60; - for (; attempts > 0; --attempts) { - try { - const response = await fetch(`http://localhost:8083`); - if (response.ok) { - break; - } - } catch (e) { - console.log(`Could not reach http://localhost:8083, trying again...`); - } - await new Promise(resolve => setTimeout(resolve, 3000)); - } - - if (attempts === 0) { - throw new Error("Runtime didn't start in time, existing now..."); - } - const changedPackages = packages.map(package => package.name).join(","); - console.log("Setup for android..."); - execSync("yarn setup-android"); - console.log("Android successfully setup"); - // https://github.com/lerna/lerna/issues/1846 - // execSync(`npx lerna run test:e2e:local:android --stream --concurrency 1 --scope '{${changedPackages},}'`); - execSync(`yarn workspaces run test:e2e:local:android --from '{bar-chart-native,}'`); - } catch (e) { - try { - execSync(`docker logs ${mxbuildContainerId}`, { stdio: "inherit" }); - execSync( - `docker exec -td ${mxbuildContainerId} bash -c "cat /source/tests/testProject/deployment/log/native_packager_log.txt"`, - { stdio: "inherit" } - ); - execSync(`docker logs ${runtimeContainerId}`, { stdio: "inherit" }); - } catch (_) {} - if (runtimeContainerId) { - console.log(cat("results/runtime.log").toString()); - } - throw e; - } finally { - execSync(`docker rm -f ${runtimeContainerId}`); - execSync(`docker rm -f ${mxbuildContainerId}`); - } -} - -async function getTestProject(repository, branch) { - const downloadedArchivePath = join(tmpdir(), `testProject.zip`); - - if (!repository.includes("github.com")) { - throw new Error("githubUrl is not a valid github repository!"); - } - - try { - await promisify(pipeline)( - ( - await fetch(`${repository}/archive/refs/heads/${branch}.zip`) - ).body, - createWriteStream(downloadedArchivePath) - ); - return downloadedArchivePath; - } catch (e) { - console.log(`Url is not available :(`); - rm("-f", downloadedArchivePath); - } - throw new Error("Cannot find test project in GitHub repository. Try again later."); -} - -async function getMendixVersion() { - const mendixOptionIndex = process.argv.indexOf("--mx-version"); - const targetMendixVersion = mendixOptionIndex >= 0 ? process.argv[mendixOptionIndex + 1] : undefined; - let mendixVersion; - - if (process.env.MENDIX_VERSION) { - return process.env.MENDIX_VERSION; - } - try { - const mendixVersions = await fetch( - "https://raw.githubusercontent.com/mendix/native-widgets/master/configs/e2e/mendix-versions.json" - ); - - const mendixVersionsJson = await mendixVersions.json(); - - if (targetMendixVersion && targetMendixVersion in mendixVersionsJson) { - mendixVersion = mendixVersionsJson[targetMendixVersion]; - } else { - mendixVersion = mendixVersionsJson.latest; - } - } catch (e) { - throw new Error("Couldn't reach github.com. Make sure you are connected to internet."); - } - if (!mendixVersion) { - throw new Error("Couldn't retrieve Mendix version from github.com. Try again later."); - } - - return mendixVersion; -} diff --git a/yarn.lock b/yarn.lock index 57458291e..b2b42612c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2587,15 +2587,6 @@ __metadata: languageName: node linkType: hard -"@notifee/react-native@npm:9.1.8": - version: 9.1.8 - resolution: "@notifee/react-native@npm:9.1.8" - peerDependencies: - react-native: "*" - checksum: 10/7c5237fba99906d8da02146afbfe8ff6de9f4047eecd806dea889bfd76b1cfe7ad3c181881bf2729aa348b83e035f4d02cfc3ac8eb8c4ba3a4415b445b439c38 - languageName: node - linkType: hard - "@npmcli/agent@npm:^3.0.0": version: 3.0.0 resolution: "@npmcli/agent@npm:3.0.0" @@ -2995,6 +2986,18 @@ __metadata: languageName: node linkType: hard +"@react-native-community/push-notification-ios@npm:1.10.1": + version: 1.10.1 + resolution: "@react-native-community/push-notification-ios@npm:1.10.1" + dependencies: + invariant: "npm:^2.2.4" + peerDependencies: + react: ">=16.6.3" + react-native: ">=0.58.4" + checksum: 10/5b02066ebad4200957bbb60634d42f4a2ea647d9d84d69adcf6fa71acf72063110d2f7b7b1e45d4153d94a3592806f5de9626fb33897707197c03a14ea299a55 + languageName: node + linkType: hard + "@react-native-firebase/app@npm:17.3.0": version: 17.3.0 resolution: "@react-native-firebase/app@npm:17.3.0" @@ -3447,7 +3450,7 @@ __metadata: languageName: node linkType: hard -"@swan-io/react-native-browser@npm:0.4.1": +"@swan-io/react-native-browser@npm:^0.4.1": version: 0.4.1 resolution: "@swan-io/react-native-browser@npm:0.4.1" peerDependencies: @@ -4042,6 +4045,13 @@ __metadata: languageName: node linkType: hard +"@types/react-native-push-notification@npm:8.1.1": + version: 8.1.1 + resolution: "@types/react-native-push-notification@npm:8.1.1" + checksum: 10/67606daf7cd38e1e8d7d82dee49741ebe8cf59cd2002579ba287ce9e98c461d11f84cf746f90cbbb7884701fe9bc758673ef2d9559cb0c73ca82307952558199 + languageName: node + linkType: hard + "@types/react-native-snap-carousel@npm:^3.7.4": version: 3.8.11 resolution: "@types/react-native-snap-carousel@npm:3.8.11" @@ -4072,16 +4082,6 @@ __metadata: languageName: node linkType: hard -"@types/react-native-video@npm:^5.0.4": - version: 5.0.20 - resolution: "@types/react-native-video@npm:5.0.20" - dependencies: - "@types/react": "npm:*" - react-native: "npm:*" - checksum: 10/4923c81c2896359d223f2f75a808670aa75ec1534c5cd4320fa809653a0963384d4d8063d1a00bdd619aef411644c12d35e25065cb2d6f2b4c7fc8bfee25aa3b - languageName: node - linkType: hard - "@types/react-native@npm:0.73.0": version: 0.73.0 resolution: "@types/react-native@npm:0.73.0" @@ -5166,7 +5166,7 @@ __metadata: "@mendix/piw-utils-internal": "npm:*" "@mendix/pluggable-widgets-tools": "npm:~10.0.1" eslint: "npm:^7.32.0" - react-native-linear-gradient: "npm:2.8.3" + react-native-linear-gradient: "npm:2.5.6" languageName: unknown linkType: soft @@ -5303,7 +5303,7 @@ __metadata: "@types/react-native-actionsheet": "npm:^2.4.1" "@types/react-native-modal": "npm:^4.1.1" eslint: "npm:^7.32.0" - react-native-device-info: "npm:14.0.4" + react-native-device-info: "npm:13.0.0" react-native-gesture-handler: "npm:2.24.0" react-native-reanimated: "npm:3.16.1" languageName: unknown @@ -8329,7 +8329,7 @@ __metadata: "@mendix/piw-utils-internal": "npm:*" "@mendix/pluggable-widgets-tools": "npm:~10.0.1" eslint: "npm:^7.32.0" - react-native-device-info: "npm:14.0.4" + react-native-device-info: "npm:13.0.0" languageName: unknown linkType: soft @@ -9150,7 +9150,7 @@ __metadata: "@mendix/pluggable-widgets-tools": "npm:~10.0.1" "@react-native-async-storage/async-storage": "npm:2.0.0" eslint: "npm:^7.32.0" - react-native-device-info: "npm:14.0.4" + react-native-device-info: "npm:13.0.0" languageName: unknown linkType: soft @@ -12174,25 +12174,27 @@ __metadata: resolution: "mobile-resources-native@workspace:packages/jsActions/mobile-resources-native" dependencies: "@mendix/pluggable-widgets-tools": "npm:^10.0.1" - "@notifee/react-native": "npm:9.1.8" "@react-native-camera-roll/camera-roll": "npm:7.4.0" + "@react-native-community/push-notification-ios": "npm:1.10.1" "@react-native-firebase/messaging": "npm:17.3.0" - "@swan-io/react-native-browser": "npm:0.4.1" + "@swan-io/react-native-browser": "npm:^0.4.1" "@types/querystringify": "npm:^2.0.0" + "@types/react-native-push-notification": "npm:8.1.1" "@types/url-parse": "npm:^1.4.3" eslint: "npm:^7.32.0" fbjs: "npm:3.0.4" mendix: "npm:~10.0.9976" mime: "npm:3.0.0" - react-native-biometrics: "npm:3.0.1" react-native-blob-util: "npm:0.21.2" - react-native-device-info: "npm:14.0.4" + react-native-device-info: "npm:13.0.0" react-native-file-viewer: "npm:2.1.5" react-native-image-picker: "npm:7.2.3" react-native-localize: "npm:3.2.1" react-native-permissions: "npm:4.1.5" + react-native-push-notification: "npm:8.1.1" react-native-schedule-exact-alarm-permission: "npm:^0.1.3" react-native-sound: "npm:0.11.0" + react-native-touch-id: "npm:4.4.1" rimraf: "npm:^4.4.1" rollup: "npm:^2.79.2" url-parse: "npm:^1.4.7" @@ -12546,10 +12548,10 @@ __metadata: dependencies: "@mendix/piw-utils-internal": "npm:*" "@mendix/pluggable-widgets-tools": "npm:~10.0.1" - "@notifee/react-native": "npm:9.1.8" "@react-native-firebase/app": "npm:17.3.0" "@react-native-firebase/messaging": "npm:17.3.0" eslint: "npm:^7.32.0" + react-native-push-notification: "npm:8.1.1" languageName: unknown linkType: soft @@ -14125,15 +14127,6 @@ __metadata: languageName: node linkType: hard -"react-native-biometrics@npm:3.0.1": - version: 3.0.1 - resolution: "react-native-biometrics@npm:3.0.1" - peerDependencies: - react-native: ">=0.60.0" - checksum: 10/abbbe0b4ba0470ae6b8acdc9f1914b8356349096c58abd3b195d832ae7f007b9876191d08dd88b27c1cc9b69a43f4cd3b320307cd7f066e4475da4dfd696e198 - languageName: node - linkType: hard - "react-native-blob-util@npm:0.21.2": version: 0.21.2 resolution: "react-native-blob-util@npm:0.21.2" @@ -14170,12 +14163,12 @@ __metadata: languageName: node linkType: hard -"react-native-device-info@npm:14.0.4": - version: 14.0.4 - resolution: "react-native-device-info@npm:14.0.4" +"react-native-device-info@npm:13.0.0": + version: 13.0.0 + resolution: "react-native-device-info@npm:13.0.0" peerDependencies: react-native: "*" - checksum: 10/bf031048551597b1a9ab2965d498cbd073eacf50005dffa4e3496286578734a45854141d47654e7e58ef8531b8c2cd6d1670bfd75625271c91aab3b3b8d0a8d8 + checksum: 10/56cf41aa1d533d81b182973939cc3663285c7a6a93e6465b88feedefc1a7809a5d937f3588e145a445a1e0a74eda8242a46e1e67b33753909ad71e3e1216aeb1 languageName: node linkType: hard @@ -14238,13 +14231,12 @@ __metadata: languageName: node linkType: hard -"react-native-linear-gradient@npm:2.8.3": - version: 2.8.3 - resolution: "react-native-linear-gradient@npm:2.8.3" +"react-native-linear-gradient@npm:2.5.6": + version: 2.5.6 + resolution: "react-native-linear-gradient@npm:2.5.6" peerDependencies: - react: "*" - react-native: "*" - checksum: 10/db18c7ae4b68afe8b6f12c67defeeccda7a3cff4ee14a0b2d92ff2581d53bd2e65bf29837cf2828abb3d8d1f3cef3f808e8cc1c5d4c8da5dd6f1d09e2b9c2c55 + react-native: ">=0.55" + checksum: 10/a3ab9806b99c68b697c1240a288117a48ea6e070f515fd17d39935d24fb046f0a99964158b995f3daecfbbcad16dfb63f13b3840fa830d36d7c47563aa563a08 languageName: node linkType: hard @@ -14326,6 +14318,16 @@ __metadata: languageName: node linkType: hard +"react-native-push-notification@npm:8.1.1": + version: 8.1.1 + resolution: "react-native-push-notification@npm:8.1.1" + peerDependencies: + "@react-native-community/push-notification-ios": ^1.10.1 + react-native: ">=0.33" + checksum: 10/c03b517743b1a5bf022e7c0c0ee2001bad9478d384c6e05ec926b81ca21125dd72ccdb28930386e8bb2b26701369921e764e8a196ed113f208d9ef37c5c6d9c7 + languageName: node + linkType: hard + "react-native-qrcode-svg@npm:6.0.6": version: 6.0.6 resolution: "react-native-qrcode-svg@npm:6.0.6" @@ -14454,6 +14456,13 @@ __metadata: languageName: node linkType: hard +"react-native-touch-id@npm:4.4.1": + version: 4.4.1 + resolution: "react-native-touch-id@npm:4.4.1" + checksum: 10/68973f838a42077fb3b7a7b5f1855f92d9aab82474f566c8f22a6354c9257fb489a221b2e4ff82d549bc2f2caa5335fbd196b23bdf0b197fa2eb27f1c90f6302 + languageName: node + linkType: hard + "react-native-vector-icons@npm:10.2.0": version: 10.2.0 resolution: "react-native-vector-icons@npm:10.2.0" @@ -14469,13 +14478,13 @@ __metadata: languageName: node linkType: hard -"react-native-video@npm:6.4.5": - version: 6.4.5 - resolution: "react-native-video@npm:6.4.5" +"react-native-video@npm:6.10.0": + version: 6.10.0 + resolution: "react-native-video@npm:6.10.0" peerDependencies: react: "*" react-native: "*" - checksum: 10/dfaf802c5dbde81d022528e325babd443bd0d08e77eef3cc959c7c2a9087632dd4b7b35efa2ba92dab202f2f3aeb52aa97334d2499b532d13cfd78d6599a787e + checksum: 10/adec35c675a509b363e3c8ba8bc52a3a169e51de36b630bde0218b6b18713f05486154075562b06a35db8411f4fd3cb0f84f4cf0299194bd855126be71617eb2 languageName: node linkType: hard @@ -17676,12 +17685,11 @@ __metadata: "@mendix/piw-native-utils-internal": "npm:*" "@mendix/piw-utils-internal": "npm:1.0.0" "@mendix/pluggable-widgets-tools": "npm:~10.0.1" - "@types/react-native-video": "npm:^5.0.4" deprecated-react-native-prop-types: "npm:^4.0.0" eslint: "npm:^7.32.0" react-native-system-navigation-bar: "npm:2.6.3" react-native-vector-icons: "npm:10.2.0" - react-native-video: "npm:6.4.5" + react-native-video: "npm:6.10.0" languageName: unknown linkType: soft