Compare commits

..

1 Commits

Author SHA1 Message Date
b9058b4ad5 Release 4.57.0 2024-07-22 17:25:56 +03:00
1252 changed files with 32769 additions and 51345 deletions

View File

@ -99,12 +99,12 @@ executors:
wpcli_php_max_wporg:
<<: *default_job_config
docker:
- image: mailpoet/wordpress:8.1_20230307.1 # We need to use 8.1 to emulate the WP.org environment
- image: mailpoet/wordpress:8.1_20230307.1
wpcli_php_latest:
<<: *default_job_config
docker:
- image: mailpoet/wordpress:8.2_20241126.1
- image: mailpoet/wordpress:8.1_20230307.1
wpcli_php_mysql_oldest:
<<: *default_job_config
@ -115,7 +115,7 @@ executors:
wpcli_php_mysql_latest:
<<: *default_job_config
docker:
- image: mailpoet/wordpress:8.2_20241126.1
- image: mailpoet/wordpress:8.1_20230307.1
- image: cimg/mysql:8.0
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_520_ci
@ -141,8 +141,6 @@ jobs:
key: composer-{{ checksum "tasks/code_sniffer/composer.json" }}-{{ checksum "tasks/code_sniffer/composer.lock" }}
- restore_cache:
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
- restore_cache:
key: composer-{{ checksum "../tests_env/composer.json" }}-{{ checksum "../tests_env/composer.lock" }}
- restore_cache:
key: composer-prefixed-{{ checksum "prefixer-checksum" }}
- restore_cache:
@ -157,9 +155,9 @@ jobs:
./tools/vendor/composer.phar validate --no-check-all --no-check-publish --working-dir=prefixer
touch .env
./do install
./do compile:all --env production --skip-tests
./do compile:all --env production
./do doctrine:generate-cache
../tests_env/vendor/bin/codecept build
vendor/bin/codecept build
./do twig:generate-cache
- run:
name: 'Check Prettier formatting'
@ -180,10 +178,6 @@ jobs:
key: composer-{{ checksum "composer.json" }}-{{ checksum "composer.lock" }}
paths:
- vendor
- save_cache:
key: composer-{{ checksum "../tests_env/composer.json" }}-{{ checksum "../tests_env/composer.lock" }}
paths:
- ../tests_env/vendor
- save_cache:
key: composer-prefixed-{{ checksum "prefixer-checksum" }}
paths:
@ -197,10 +191,10 @@ jobs:
- run:
name: Download additional WP Plugins for tests
command: |
./do download:woo-commerce-zip 9.6.1
./do download:woo-commerce-subscriptions-zip 7.1.0
./do download:woo-commerce-zip 9.1.2
./do download:woo-commerce-subscriptions-zip 6.5.0
./do download:woo-commerce-memberships-zip 1.26.5
./do download:automate-woo-zip 6.1.5
./do download:automate-woo-zip 6.0.29
- run:
name: Dump tests ENV variables for acceptance tests
command: |
@ -336,7 +330,6 @@ jobs:
name: 'JS Newsletter Editor Tests'
command: |
mkdir test-results/mocha
./do compile:js --env production --only-tests
./do t:newsletter-editor test-results/mocha/newsletter_editor_junit.xml
- run:
name: 'JS Tests'
@ -402,15 +395,11 @@ jobs:
use_woocommerce_beta:
type: boolean
default: false
wordpress_version:
type: string
default: ''
environment:
MYSQL_COMMAND: << parameters.mysql_command >>
MYSQL_IMAGE: << parameters.mysql_image >>
CODECEPTION_IMAGE_VERSION: << parameters.codeception_image_version >>
WORDPRESS_IMAGE_VERSION: << parameters.wordpress_image_version >>
WORDPRESS_VERSION: << parameters.wordpress_version >>
steps:
- attach_workspace:
at: /home/circleci
@ -426,7 +415,7 @@ jobs:
echo "No latest beta version found. Ending job early."
circleci-agent step halt
else
echo "export WORDPRESS_VERSION=$LATEST_WP_BETA" >> $BASH_ENV
echo "export LATEST_WP_BETA=$LATEST_WP_BETA" >> $BASH_ENV
echo "Using WordPress Beta Version: $LATEST_WP_BETA"
fi
else
@ -451,51 +440,51 @@ jobs:
- run:
name: 'Pull test docker images'
# Pull docker images with 3 retries
command: i='0';while ! docker compose -f ../tests_env/docker/docker-compose.yml pull && ((i < 3)); do sleep 3 && i=$[$i+1]; done
command: i='0';while ! docker-compose -f tests/docker/docker-compose.yml pull && ((i < 3)); do sleep 3 && i=$[$i+1]; done
- run:
name: Create docker containers for test
# We experienced some failures when creating containers so we do it explicitly with one retry
command: |
cd ../tests_env/docker
docker compose create || docker compose create
cd tests/docker
docker-compose create || docker-compose create
- run:
# Some tools we use may need different version based on PHP version used in docker
name: Ensure correct versions of tools
command: |
cd ../tests_env/docker
docker compose run --rm -w /project -e COMPOSER_DEV_MODE=1 --entrypoint "php tools/install.php" codeception_acceptance
cd tests/docker
docker-compose run --rm -w /project -e COMPOSER_DEV_MODE=1 --entrypoint "php tools/install.php" codeception_acceptance
- when:
condition: ${WOOCOMMERCE_VERSION}
steps:
- run:
name: Download WooCommerce Core
command: |
cd ../tests_env/docker
docker compose run --rm -w /project --entrypoint "./do download:woo-commerce-zip ${WOOCOMMERCE_VERSION}" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_acceptance
cd tests/docker
docker-compose run --rm -w /project --entrypoint "./do download:woo-commerce-zip ${WOOCOMMERCE_VERSION}" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_acceptance
- when:
condition: << parameters.woo_subscriptions_version >>
steps:
- run:
name: Download WooCommerce Subscriptions
command: |
cd ../tests_env/docker
docker compose run --rm -w /project --entrypoint "./do download:woo-commerce-subscriptions-zip << parameters.woo_subscriptions_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_acceptance
cd tests/docker
docker-compose run --rm -w /project --entrypoint "./do download:woo-commerce-subscriptions-zip << parameters.woo_subscriptions_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_acceptance
- when:
condition: << parameters.woo_memberships_version >>
steps:
- run:
name: Download WooCommerce Memberships
command: |
cd ../tests_env/docker
docker compose run --rm -w /project --entrypoint "./do download:woo-commerce-memberships-zip << parameters.woo_memberships_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_acceptance
cd tests/docker
docker-compose run --rm -w /project --entrypoint "./do download:woo-commerce-memberships-zip << parameters.woo_memberships_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_acceptance
- when:
condition: << parameters.automate_woo_version >>
steps:
- run:
name: Download AutomateWoo
command: |
cd ../tests_env/docker
docker compose run --rm -w /project --entrypoint "./do download:automate-woo-zip << parameters.automate_woo_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_acceptance
cd tests/docker
docker-compose run --rm -w /project --entrypoint "./do download:automate-woo-zip << parameters.automate_woo_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_acceptance
- run:
name: Group acceptance tests
command: |
@ -515,7 +504,7 @@ jobs:
name: Run acceptance tests
command: |
mkdir -m 777 -p tests/_output/exceptions
cd ../tests_env/docker
cd tests/docker
args=(
--steps
--debug
@ -524,7 +513,7 @@ jobs:
--xml
-g circleci_split_group
)
docker compose run -e SKIP_DEPS=1 \
docker-compose run -e SKIP_DEPS=1 \
-e CIRCLE_BRANCH=${CIRCLE_BRANCH} \
-e CIRCLE_JOB=${CIRCLE_JOB} \
-e MULTISITE=<< parameters.multisite >> \
@ -532,7 +521,7 @@ jobs:
-e ENABLE_HPOS=<< parameters.enable_hpos >> \
-e ENABLE_HPOS_SYNC=<< parameters.enable_hpos_sync >> \
-e DISABLE_HPOS=<< parameters.disable_hpos >> \
-e WORDPRESS_VERSION=${WORDPRESS_VERSION} \
-e LATEST_BETA=${LATEST_WP_BETA} \
codeception_acceptance "${args[@]}"
- run:
name: Check exceptions
@ -583,13 +572,13 @@ jobs:
- run:
name: 'Pull test docker images'
# Pull docker images with 3 retries
command: i='0';while ! docker compose -f tests/performance/docker-compose.yml pull && ((i < 3)); do sleep 3 && i=$[$i+1]; done
command: i='0';while ! docker-compose -f tests/performance/docker-compose.yml pull && ((i < 3)); do sleep 3 && i=$[$i+1]; done
- run:
name: Create docker containers for test
# We experienced some failures when creating containers so we do it explicitly with one retry
command: |
cd tests/performance
docker compose create || docker compose create
docker-compose create || docker-compose create
- run:
name: Run performance tests
command: |
@ -653,15 +642,10 @@ jobs:
CODECEPTION_IMAGE_VERSION: << parameters.codeception_image_version >>
MYSQL_COMMAND: << parameters.mysql_command >>
MYSQL_IMAGE: << parameters.mysql_image >>
WORDPRESS_IMAGE_VERSION: << parameters.wordpress_image_version >>
WORDPRESS_VERSION: << parameters.wordpress_version >>
parameters:
codeception_image_version:
type: string
default: ''
wordpress_image_version:
type: string
default: ''
group:
type: string
default: ''
@ -707,9 +691,6 @@ jobs:
use_woocommerce_beta:
type: boolean
default: false
wordpress_version:
type: string
default: ''
steps:
- attach_workspace:
at: /home/circleci
@ -722,7 +703,7 @@ jobs:
echo "No latest beta version found. Ending job early."
circleci-agent step halt
else
echo "export WORDPRESS_VERSION=$LATEST_WP_BETA" >> $BASH_ENV
echo "export LATEST_WP_BETA=$LATEST_WP_BETA" >> $BASH_ENV
echo "Using WordPress Beta Version: $LATEST_WP_BETA"
fi
else
@ -747,56 +728,56 @@ jobs:
- run:
name: 'Pull test docker images'
# Pull docker images with 3 retries
command: i='0';while ! docker compose -f ../tests_env/docker/docker-compose.yml pull && ((i < 3)); do sleep 3 && i=$[$i+1]; done
command: i='0';while ! docker-compose -f tests/docker/docker-compose.yml pull && ((i < 3)); do sleep 3 && i=$[$i+1]; done
- run:
name: Create docker containers for test
# We experienced some failures when creating containers so we do it explicitly with one retry
command: |
cd ../tests_env/docker
docker compose create || docker compose create
cd tests/docker
docker-compose create || docker-compose create
- run:
# Some tools we use may need different version based on PHP version used in docker
name: Ensure correct versions of tools
command: |
cd ../tests_env/docker
docker compose run --rm -w /project -e COMPOSER_DEV_MODE=1 --entrypoint "php tools/install.php" codeception_integration
cd tests/docker
docker-compose run --rm -w /project -e COMPOSER_DEV_MODE=1 --entrypoint "php tools/install.php" codeception_integration
- when:
condition: ${WOOCOMMERCE_VERSION}
steps:
- run:
name: Download WooCommerce Core
command: |
cd ../tests_env/docker
docker compose run --rm -w /project --entrypoint "./do download:woo-commerce-zip ${WOOCOMMERCE_VERSION}" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_integration
cd tests/docker
docker-compose run --rm -w /project --entrypoint "./do download:woo-commerce-zip ${WOOCOMMERCE_VERSION}" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_integration
- when:
condition: << parameters.woo_subscriptions_version >>
steps:
- run:
name: Download WooCommerce Subscriptions
command: |
cd ../tests_env/docker
docker compose run --rm -w /project --entrypoint "./do download:woo-commerce-subscriptions-zip << parameters.woo_subscriptions_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_integration
cd tests/docker
docker-compose run --rm -w /project --entrypoint "./do download:woo-commerce-subscriptions-zip << parameters.woo_subscriptions_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_integration
- when:
condition: << parameters.woo_memberships_version >>
steps:
- run:
name: Download WooCommerce Memberships
command: |
cd ../tests_env/docker
docker compose run --rm -w /project --entrypoint "./do download:woo-commerce-memberships-zip << parameters.woo_memberships_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_integration
cd tests/docker
docker-compose run --rm -w /project --entrypoint "./do download:woo-commerce-memberships-zip << parameters.woo_memberships_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_integration
- when:
condition: << parameters.automate_woo_version >>
steps:
- run:
name: Download AutomateWoo
command: |
cd ../tests_env/docker
docker compose run --rm -w /project --entrypoint "./do download:automate-woo-zip << parameters.automate_woo_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_integration
cd tests/docker
docker-compose run --rm -w /project --entrypoint "./do download:automate-woo-zip << parameters.automate_woo_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_integration
- run:
name: 'PHP Integration tests'
command: |
mkdir -m 777 -p tests/_output/exceptions
cd ../tests_env/docker
cd tests/docker
args=(
--steps
--debug
@ -810,7 +791,7 @@ jobs:
if [[ -n '<< parameters.skip_group >>' ]]; then
args+=(--skip-group << parameters.skip_group >>)
fi
docker compose run -e SKIP_DEPS=1 \
docker-compose run -e SKIP_DEPS=1 \
-e CIRCLE_BRANCH=${CIRCLE_BRANCH} \
-e CIRCLE_JOB=${CIRCLE_JOB} \
-e SKIP_PLUGINS=<< parameters.skip_plugins >> \
@ -830,7 +811,7 @@ jobs:
-e ENABLE_HPOS=<< parameters.enable_hpos >> \
-e ENABLE_HPOS_SYNC=<< parameters.enable_hpos_sync >> \
-e DISABLE_HPOS=<< parameters.disable_hpos >> \
-e WORDPRESS_VERSION=${WORDPRESS_VERSION} \
-e LATEST_BETA=${LATEST_WP_BETA} \
codeception_integration "${args[@]}"
- store_test_results:
path: tests/_output
@ -863,30 +844,6 @@ jobs:
root: /home/circleci/mailpoet
paths:
- mailpoet/release_zip_build_number.txt
- mailpoet/mailpoet.zip
qit_security_scan:
executor: wpcli_php_latest
steps:
- attach_workspace:
at: /home/circleci
- run:
name: 'Set up environment'
command: |
# Copy built ZIP to local directory for easier access from QIT
cp /home/circleci/mailpoet/mailpoet.zip .
# Authenticate in QIT
./vendor/bin/qit partner:add --user="${QIT_PARTNER_USER}" --application_password="${QIT_PARTNER_SECRET}"
- run:
name: 'QIT Security Test'
command: ./do qa:qit-security | tee tests/_output/qit-security
- run:
name: 'Retrieve test results'
command: |
# Download HTML report from QIT servers
grep "Result Url" tests/_output/qit-security | awk '{ print $3 }' | xargs curl -o tests/_output/report.html
when: always
- store_artifacts:
path: tests/_output
workflows:
build_and_test:
@ -940,28 +897,48 @@ workflows:
name: acceptance_tests_base_and_woo
enable_hpos: 1
requires:
- build
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
name: acceptance_tests_woo_hpos_sync_on
group: woo
enable_hpos_sync: 1
requires:
- build
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
name: acceptance_tests_woo_hpos_off
group: woo
disable_hpos: 1
requires:
- build
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
name: acceptance_tests_blockbased_theme
group: frontend
blockbased_theme: 1
requires:
- build
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- performance_tests:
<<: *slack-fail-post-step
name: performance_tests
requires:
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- js_tests:
<<: *slack-fail-post-step
requires:
@ -972,41 +949,55 @@ workflows:
enable_hpos_sync: 1
name: integration_test_woo_hpos_sync_on
requires:
- build
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- integration_tests:
<<: *slack-fail-post-step
group: woo
name: integration_test_woo_hpos_on
enable_hpos: 1
requires:
- build
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- integration_tests:
<<: *slack-fail-post-step
group: woo
disable_hpos: 1
name: integration_test_woo_hpos_off
requires:
- build
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- integration_tests:
<<: *slack-fail-post-step
skip_group: woo
skip_plugins: 1
name: integration_test_base
requires:
- build
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
<<: *multisite_acceptance_config
name: acceptance_tests_multisite
requires:
- build
- integration_tests:
<<: *slack-fail-post-step
<<: *only_trunk_and_release
multisite: 1
name: integration_tests_multisite
requires:
- build
- unit_tests
- static_analysis_php7
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
<<: *only_release
@ -1035,22 +1026,10 @@ workflows:
- integration_test_woo_hpos_on
- integration_test_woo_hpos_off
- integration_test_woo_hpos_sync_on
- integration_with_premium_latest
- acceptance_tests_woo_hpos_sync_on
- acceptance_tests_woo_hpos_off
- acceptance_tests_blockbased_theme
- static_analysis_php8
- static_analysis_php7
- unit_tests
- qa_js
- qa_php
- qa_php_oldest
- security_analysis
- qa_php_max_wporg
- qit_security_scan:
<<: *slack-fail-post-step
requires:
- build_release_zip
- performance_tests
nightly:
triggers:
@ -1082,15 +1061,14 @@ workflows:
- acceptance_tests:
<<: *slack-fail-post-step
name: acceptance_oldest
woo_core_version: 9.5.2
woo_subscriptions_version: 7.0.0
woo_core_version: 9.0.2
woo_subscriptions_version: 6.4.1
woo_memberships_version: 1.25.2
automate_woo_version: 6.0.33
mysql_command: --max_allowed_packet=100M
automate_woo_version: 5.8.5
mysql_command: --max_allowed_packet=100M --default-storage-engine=MYISAM
mysql_image: mysql:5.5
codeception_image_version: 7.4-cli_20220605.0
wordpress_image_version: 6.1.1-php7.4 # We use image with PHP 7.4 and install required WordPress version via CLI
wordpress_version: 6.6.2
wordpress_image_version: 6.5.5-php8.1
requires:
- build
- performance_tests:
@ -1123,14 +1101,12 @@ workflows:
- integration_tests:
<<: *slack-fail-post-step
name: integration_oldest
woo_core_version: 9.5.2
woo_subscriptions_version: 7.0.0
woo_core_version: 9.0.2
woo_subscriptions_version: 6.4.1
woo_memberships_version: 1.25.2
automate_woo_version: 6.0.33
automate_woo_version: 5.8.5
codeception_image_version: 7.4-cli_20220605.0
wordpress_image_version: 6.1.1-php7.4 # We use image with PHP 7.4 and install required WordPress version via CLI # We use image with PHP 7.4 and install required WordPress version via CLI
wordpress_version: 6.6.2
mysql_command: --max_allowed_packet=100M
mysql_command: --max_allowed_packet=100M --default-storage-engine=MYISAM
mysql_image: mysql:5.5
requires:
- build
@ -1186,26 +1162,23 @@ workflows:
- acceptance_tests:
<<: *slack-fail-post-step
name: acceptance_with_premium_oldest
woo_core_version: 9.5.2
woo_subscriptions_version: 7.0.0
woo_core_version: 9.0.2
woo_subscriptions_version: 6.4.1
woo_memberships_version: 1.25.2
automate_woo_version: 6.0.33
automate_woo_version: 5.8.5
codeception_image_version: 7.4-cli_20220605.0
wordpress_image_version: 6.1.1-php7.4 # We use image with PHP 7.4 and install required WordPress version via CLI
wordpress_version: 6.6.2
wordpress_image_version: 6.5.5-php8.1
requires:
- build_premium
- integration_tests:
<<: *slack-fail-post-step
name: integration_with_premium_oldest
woo_core_version: 9.5.2
woo_subscriptions_version: 7.0.0
woo_core_version: 9.0.2
woo_subscriptions_version: 6.4.1
woo_memberships_version: 1.25.2
automate_woo_version: 6.0.33
automate_woo_version: 5.8.5
codeception_image_version: 7.4-cli_20220605.0
wordpress_image_version: 6.1.1-php7.4 # We use image with PHP 7.4 and install required WordPress version via CLI
wordpress_version: 6.6.2
mysql_command: --max_allowed_packet=100M
mysql_command: --max_allowed_packet=100M --default-storage-engine=MYISAM
mysql_image: mysql:5.5
requires:
- build_premium

View File

@ -10,12 +10,6 @@ indent_size = 2
ij_smart_tabs = false
max_line_length = off
[packages/php/email-editor/**]
indent_style = tab
[packages/js/email-editor/**.{js,jsx,ts,tsx,scss}]
indent_style = tab
[*.php]
ij_php_align_key_value_pairs = false
ij_php_align_multiline_chained_methods = false
@ -61,5 +55,3 @@ ij_php_space_after_for_semicolon = true
ij_php_space_after_colon_in_return_type = true
ij_php_space_before_else_keyword = true
ij_php_for_statement_new_line_after_left_paren = true
ij_php_class_brace_style = end_of_line
ij_php_comma_after_last_array_element = true

View File

@ -39,15 +39,3 @@ e66c76133ec3ef667e382203426d91a4b4aa5174
# Prettier autoformatting
ab27eaee2df740c0add4331a7f8c115a87ecfa2b
# Move email editor to JS packages folder
912282f57ccc839491ff951ec5cf7aa10c14f429
# Switch email editor js packages to WP coding style
b2fb96f8793b63db629d5237010d87332330c51e
# Email editor Prettier autoformatting
8c604453b1d82e3a2c731241e1c96ea8b32ec716
# Move email editor components out of the engine folder
1c3ea9cd0a5fc8848a64d840e2fa16a6c7d8c1fe

View File

@ -1,212 +0,0 @@
name: Email Editor Package Tests
on:
push:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['7.4', '8.2']
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Cache Composer vendor dependencies for MailPoet
id: composer-mailpoet-cache
uses: actions/cache@v4
with:
path: mailpoet/vendor
key: ${{ runner.os }}-composer-mailpoet-${{ matrix.php-version }}-${{ hashFiles('mailpoet/composer.lock') }}-${{ hashFiles('mailpoet/composer.json') }}
- name: Cache Composer vendor-prefixed dependencies for MailPoet
id: vendor-prefixed-cache
uses: actions/cache@v4
with:
path: mailpoet/vendor-prefixed
key: ${{ runner.os }}-vendor-prefixed-${{ matrix.php-version }}-${{ hashFiles('mailpoet/prefixer/composer.lock') }}-${{ hashFiles('mailpoet/prefixer/composer.json') }}
- name: Cache Composer vendor for test environment
id: composer-tests-env-cache
uses: actions/cache@v4
with:
path: tests_env/vendor
key: ${{ runner.os }}-composer-mailpoet-${{ matrix.php-version }}-${{ hashFiles('tests_env/composer.lock') }}-${{ hashFiles('tests_env/composer.json') }}
- name: Cache Composer dependencies for Email Editor
id: composer-email-editor-cache
uses: actions/cache@v4
with:
path: packages/php/email-editor/vendor
key: ${{ runner.os }}-composer-email-editor-${{ matrix.php-version }}-${{ hashFiles('packages/php/email-editor/composer.lock') }}-${{ hashFiles('packages/php/email-editor/composer.json') }}
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: gd
- name: Install tools
run: |
COMPOSER_DEV_MODE=1 php tools/install.php
touch .env
working-directory: mailpoet
# Install Test Environment dependencies only if the cache was not hit
- name: Install test environment dependencies
if: steps.composer-tests-env-cache.outputs.cache-hit != 'true'
run: ../mailpoet/tools/vendor/composer.phar install
working-directory: tests_env
# Install MailPoet dependencies only if the cache was not hit
- name: Install mailpoet dependencies
if: |
steps.composer-mailpoet-cache.outputs.cache-hit != 'true' || steps.vendor-prefixed-cache.outputs.cache-hit != 'true'
run: ./tools/vendor/composer.phar install
working-directory: mailpoet
# Install Email Editor dependencies only if the cache was not hit
- name: Install email-editor dependencies
if: steps.composer-email-editor-cache.outputs.cache-hit != 'true'
run: ../../../mailpoet/tools/vendor/composer.phar install
working-directory: packages/php/email-editor
# Dump Email Editor autoload
# This is needed to refresh classmap autoload when the composer cache is hit
- name: Dump email-editor autoload
run: ../../../mailpoet/tools/vendor/composer.phar dump-autoload
working-directory: packages/php/email-editor
# Dump MailPoet autoload
# This is needed to refresh classmap autoload when the composer cache is hit
- name: Dump MailPoet autoload
run: ./tools/vendor/composer.phar dump-autoload
working-directory: mailpoet
# Run Email Editor unit tests
- name: Run email-editor package unit tests
run: ../../../tests_env/vendor/bin/codecept build && ../../../mailpoet/tools/vendor/composer.phar unit-test
working-directory: packages/php/email-editor
- name: Run email-editor package integration tests
run: ../../../mailpoet/tools/vendor/composer.phar integration-test
working-directory: packages/php/email-editor
code-style:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Install tools
run: |
COMPOSER_DEV_MODE=1 php tools/install.php
touch .env
working-directory: mailpoet
- name: Install composer dependencies
run: ../../tools/vendor/composer.phar install
working-directory: mailpoet/tasks/code_sniffer
- name: Run code style check
run: ../../../mailpoet/tools/vendor/composer.phar code-style
working-directory: packages/php/email-editor
phpstan-static-analysis:
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['7.4', '8.2']
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Cache Composer vendor dependencies for MailPoet
id: composer-mailpoet-cache
uses: actions/cache@v4
with:
path: mailpoet/vendor
key: ${{ runner.os }}-composer-mailpoet-${{ matrix.php-version }}-${{ hashFiles('mailpoet/composer.lock') }}-${{ hashFiles('mailpoet/composer.json') }}
- name: Cache Composer vendor-prefixed dependencies for MailPoet
id: vendor-prefixed-cache
uses: actions/cache@v4
with:
path: mailpoet/vendor-prefixed
key: ${{ runner.os }}-vendor-prefixed-${{ matrix.php-version }}-${{ hashFiles('mailpoet/prefixer/composer.lock') }}-${{ hashFiles('mailpoet/prefixer/composer.json') }}
- name: Cache Composer vendor for test environment
id: composer-tests-env-cache
uses: actions/cache@v4
with:
path: tests_env/vendor
key: ${{ runner.os }}-composer-mailpoet-${{ matrix.php-version }}-${{ hashFiles('tests_env/composer.lock') }}-${{ hashFiles('tests_env/composer.json') }}
- name: Cache Composer dependencies for Email Editor
id: composer-email-editor-cache
uses: actions/cache@v4
with:
path: packages/php/email-editor/vendor
key: ${{ runner.os }}-composer-email-editor-${{ matrix.php-version }}-${{ hashFiles('packages/php/email-editor/composer.lock') }}-${{ hashFiles('packages/php/email-editor/composer.json') }}
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: gd
- name: Install tools
run: |
COMPOSER_DEV_MODE=1 php tools/install.php
touch .env
working-directory: mailpoet
# Install Test Environment dependencies only if the cache was not hit
- name: Install test environment dependencies
if: steps.composer-tests-env-cache.outputs.cache-hit != 'true'
run: ../mailpoet/tools/vendor/composer.phar install
working-directory: tests_env
# Install MailPoet dependencies only if the cache was not hit
- name: Install mailpoet dependencies
if: |
steps.composer-mailpoet-cache.outputs.cache-hit != 'true' || steps.vendor-prefixed-cache.outputs.cache-hit != 'true'
run: ./tools/vendor/composer.phar install
working-directory: mailpoet
# Install Email Editor dependencies only if the cache was not hit
- name: Install email-editor dependencies
if: steps.composer-email-editor-cache.outputs.cache-hit != 'true'
run: ../../../mailpoet/tools/vendor/composer.phar install
working-directory: packages/php/email-editor
- name: Install composer dependencies
run: ../../tools/vendor/composer.phar install
working-directory: mailpoet/tasks/phpstan
# Dump Email Editor autoload
# This is needed to refresh classmap autoload when the composer cache is hit
- name: Dump email-editor autoload
run: ../../../mailpoet/tools/vendor/composer.phar dump-autoload
working-directory: packages/php/email-editor
# Dump MailPoet autoload
# This is needed to refresh classmap autoload when the composer cache is hit
- name: Dump MailPoet autoload
run: ./tools/vendor/composer.phar dump-autoload
working-directory: mailpoet
- name: Run code phpstan
run: ../../../mailpoet/tools/vendor/composer.phar phpstan -- --php-version=${{ matrix.php-version == '7.4' && '70400' || '80200' }}
working-directory: packages/php/email-editor

View File

@ -65,7 +65,7 @@ function getLatestAndPreviousVersions(array $sortedVersions): array {
*/
function replaceLatestWordPressVersion(string $latestVersion): void {
replaceVersionInFile(
__DIR__ . './../../../tests_env/docker/docker-compose.yml',
__DIR__ . './../../../mailpoet/tests/docker/docker-compose.yml',
'/(wordpress:\${WORDPRESS_IMAGE_VERSION:-\s*)\d+\.\d+\.?\d*-php\d+\.\d+(})/',
'${1}' . $latestVersion . '${2}'
);
@ -77,7 +77,7 @@ function replaceLatestWordPressVersion(string $latestVersion): void {
function replacePreviousWordPressVersion(string $previousVersion): void {
replaceVersionInFile(
__DIR__ . './../../../.circleci/config.yml',
'/(wordpress_version: )\d+\.\d+\.?\d*/',
'/(wordpress_image_version: )\d+\.\d+\.?\d*-php\d+\.\d+/',
'${1}' . $previousVersion
);
}
@ -113,8 +113,6 @@ if ($latestVersion) {
if ($previousVersion) {
echo "Replacing the previous version in the config file...\n";
// We install previous WordPress version via CLI so we need a version without PHP in the name.
$previousVersion = preg_replace('/-php\d+\.\d+$/', '', $previousVersion);
replacePreviousWordPressVersion($previousVersion);
} else {
echo "No previous version found.\n";

View File

@ -155,17 +155,10 @@ jobs:
git commit -m $'Update used WooCommerce Memberships plugin in Circle CI\n\n - latest version: ${{ env.WOOCOMMERCE_MEMBERSHIPS_LATEST_VERSION }}\n - previous version: ${{ env.WOOCOMMERCE_MEMBERSHIPS_PREVIOUS_VERSION }}'
# Push all changes at the end if any changes were detected
#
# For local testing with act tool add following:
# env:
# GH_PAT: ${{ secrets.GH_TOKEN }}
# run: |
# git remote set-url origin https://${GH_PAT}@github.com/mailpoet/mailpoet
# git push -f origin HEAD:refs/heads/update-plugins-and-wordpress-test
- name: Push changes
if: env.CHANGES_DETECTED == 'true'
run: |
git push -f origin HEAD:refs/heads/update-plugins-and-wordpress
git push origin HEAD:refs/heads/update-plugins-and-wordpress
# Create a pull request if there are changes
- name: Create Pull Request
@ -174,9 +167,5 @@ jobs:
with:
token: ${{ secrets.GH_TOKEN }}
branch: update-plugins-and-wordpress
title: Update WordPress and plugins in CI jobs
title: 'Update used WordPress Docker image and used plugin versions in Circle CI jobs'
base: trunk
labels: automated, check-versions
body: |
1. If all checks passed, you can merge this PR.
2. If the build failed, please investigate the failure and either address the issues or delegate the job. Then, make sure these changes are merged.

View File

@ -1,27 +0,0 @@
name: Add link to WordPress Playground preview
on:
pull_request:
types: [opened, reopened, synchronize]
jobs:
add-wp-playground-link:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Check and append description
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_NUMBER="${{ github.event.pull_request.number }}"
BRANCH_NAME="${{ github.head_ref }}"
DESCRIPTION="$(gh pr view $PR_NUMBER --json body -q .body)"
HEADING="## Preview"
CONTENT="$(printf "${HEADING}\n\n[Preview in WordPress Playground](https://account.mailpoet.com/playground/new/branch:${BRANCH_NAME})\n\n_The latest successful build from \`${BRANCH_NAME}\` will be used. If none is available, the link won't work._")"
if [[ "$DESCRIPTION" != *"$HEADING"* ]]; then
gh pr edit $PR_NUMBER --body "$(printf "${DESCRIPTION}\n\n${CONTENT}")"
fi

2
.gitignore vendored
View File

@ -9,5 +9,3 @@ npm-debug.log
mailpoet-premium
tsconfig.tsbuildinfo
/wordpress
packages/php/*/vendor
tests_env/vendor

View File

@ -7,6 +7,7 @@ export MP_GIT_HOOKS_ESLINT="${MP_GIT_HOOKS_ESLINT:-true}"
export MP_GIT_HOOKS_STYLELINT="${MP_GIT_HOOKS_STYLELINT:-true}"
export MP_GIT_HOOKS_PHPLINT="${MP_GIT_HOOKS_PHPLINT:-true}"
export MP_GIT_HOOKS_CODE_SNIFFER="${MP_GIT_HOOKS_CODE_SNIFFER:-true}"
export MP_GIT_HOOKS_MINIMAL_PLUGIN_STANDARDS="${MP_GIT_HOOKS_MINIMAL_PLUGIN_STANDARDS:-true}"
export MP_GIT_HOOKS_PHPSTAN="${MP_GIT_HOOKS_PHPSTAN:-true}"
export MP_GIT_HOOKS_INSTALL_JS="${MP_GIT_HOOKS_INSTALL_JS:-false}"
export MP_GIT_HOOKS_INSTALL_PHP="${MP_GIT_HOOKS_INSTALL_PHP:-false}"

View File

@ -4,5 +4,3 @@
[ "$MP_GIT_HOOKS_ENABLE" != "true" ] && exit 0
installIfUpdates
./do cleanup:cached-files

View File

@ -1,8 +1,7 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
. "$(dirname "$0")/common.sh"
[ "$MP_GIT_HOOKS_ENABLE" != "true" ] && exit 0
npx lint-staged -c mailpoet/package.json --cwd mailpoet
npx lint-staged -c package.json
npx lint-staged -c packages/js/email-editor/package.json --cwd packages/js/email-editor
npx lint-staged -c packages/php/email-editor/.lintstagedrc.json --cwd packages/php/email-editor

View File

@ -25,5 +25,3 @@ vendor-prefixed
/mailpoet/views
/mailpoet-premium
/wordpress
/packages/php/email-editor
/packages/js/email-editor

View File

@ -1,30 +0,0 @@
clone:
git:
image: woodpeckerci/plugin-git
settings:
depth: 1
steps:
build:
image: node:current-bookworm-slim
commands:
- apt update
- apt install php php-symfony bash -y
- npm install pnpm
- cd mailpoet
- bash build.sh
- mkdir ../output
- mv mailpoet.zip ../output
- cd ..
release:
image: woodpeckerci/plugin-gitea-release:latest
settings:
base_url: https://git.cavemanon.xyz
api_key:
from_secret: releasesmithapikey
files: "output/"
prerelease: false
title: "${CI_COMMIT_TAG}"
when:
- event: tag

View File

@ -85,7 +85,7 @@ mailpoet/vendor/bin/codecept -> /project/vendor/bin/codecept
mailpoet/vendor/bin/wp -> /usr/local/bin/wp
```
- Add `XDEBUG_TRIGGER: 1` environment to `tests_env/docker/docker-compose.yml` -> codeception service to start triggering Xdebug
- Add `XDEBUG_TRIGGER: 1` environment to `mailpoet/tests/docker/docker-compose.yml` -> codeception service to start triggering Xdebug
- Make PHPStorm listen to connections by clicking on the phone icon
## Local development
@ -103,8 +103,8 @@ Then create a Docker Compose override file with NFS settings and restart contain
```shell
cp docker-compose.override.macos-sample.yml docker-compose.override.yml
docker compose down -v --remove-orphans
docker compose up -d
docker-compose down -v --remove-orphans
docker-compose up -d
```
**NOTE:** If you are on MacOS Catalina or newer, make sure to put the repository
@ -163,10 +163,10 @@ To switch the environment to a different PHP version:
dockerfile: dev/{PHP_VERSION}/Dockerfile
```
3. Run `docker compose build wordpress`.
3. Run `docker-compose build wordpress`.
4. Start the stack with `./do start`.
To switch back to the default PHP version remove what was added in 2) and, run `docker compose build wordpress` for application container and `docker compose build test_wordpress` for tests container,
To switch back to the default PHP version remove what was added in 2) and, run `docker-compose build wordpress` for application container and `docker-compose build test_wordpress` for tests container,
and start the stack using `./do start`.
### Disabling the Tracy panel

View File

@ -21,7 +21,7 @@ mkdir -p wordpress/wp-content/plugins/mailpoet-premium
mkdir -p dev/data/mailhog
for plugin in "mailpoet" "mailpoet-premium"; do
docker compose run --rm wordpress /bin/sh -c "
docker-compose run --rm wordpress /bin/sh -c "
[ -d /var/www/html/wp-content/plugins/$plugin ] &&
cd /var/www/html/wp-content/plugins/$plugin &&
./do install &&
@ -29,7 +29,7 @@ for plugin in "mailpoet" "mailpoet-premium"; do
"
done
docker compose run --rm wordpress /bin/sh -c "
docker-compose run --rm wordpress /bin/sh -c "
cd /var/www/templates &&
mkdir assets classes exported
"

View File

@ -29,6 +29,6 @@ cat <<EOT
NFS volume sharing is set up. Recreate your containers and volumes using:
cp docker-compose.override.macos-sample.yml docker-compose.override.yml
docker compose down -v --remove-orphans
docker compose up -d
docker-compose down -v --remove-orphans
docker-compose up -d
EOT

16
do
View File

@ -3,8 +3,8 @@
function syntax {
cat << EOF
./do setup Setup the dev environment.
./do start Start the docker containers (docker compose up -d).
./do stop Stop the docker containers (docker compose stop).
./do start Start the docker containers (docker-compose up -d).
./do stop Stop the docker containers (docker-compose stop).
./do ssh [--test] Run an interactive bash shell inside the plugin directory.
./do run [--test] <command> Run a custom bash command in the wordpress container.
./do acceptance [--premium] Run acceptance tests.
@ -21,7 +21,7 @@ EOF
function ssh_and_run {
params=("$@")
params=("${params[@]:1}")
docker compose exec $1 bash -c "${params[@]}"
docker-compose exec $1 bash -c "${params[@]}"
}
if [ "$1" = "" -o "$1" = "--help" ]; then
@ -31,10 +31,10 @@ elif [ "$1" = "setup" ]; then
./dev/initial-setup.sh
elif [ "$1" = "start" ]; then
docker compose up -d
docker-compose up -d
elif [ "$1" = "stop" ]; then
docker compose stop
docker-compose stop
elif [ "$1" = "run" ]; then
params=("$@")
@ -54,9 +54,9 @@ elif [ "$1" = "ssh" ]; then
fi
if [ "$2" = "--test" ] || [ "$3" = "--test" ]; then
docker compose exec --workdir $dir test_wordpress bash
docker-compose exec --workdir $dir test_wordpress bash
else
docker compose exec --workdir $dir wordpress bash
docker-compose exec --workdir $dir wordpress bash
fi
elif [ "$1" = "acceptance" ]; then
@ -65,7 +65,7 @@ elif [ "$1" = "acceptance" ]; then
else
cd mailpoet
fi
COMPOSE_HTTP_TIMEOUT=200 docker compose run codeception_acceptance -e KEEP_DEPS=1 --steps --debug -vvv
COMPOSE_HTTP_TIMEOUT=200 docker-compose run codeception_acceptance -e KEEP_DEPS=1 --steps --debug -vvv
cd ..
elif [ "$1" = "build" ]; then

View File

@ -27,7 +27,6 @@ Class `\MailPoet\API\API` becomes available once MailPoet plugin is loaded by Wo
- [Add List (addList)](api_methods/AddList.md)
- [Add Subscriber (addSubscriber)](api_methods/AddSubscriber.md)
- [Update Subscriber (updateSubscriber)](api_methods/UpdateSubscriber.md)
- [Add Subscriber Field (addSubscriberField)](api_methods/AddSubscriberField.md)
- [Delete List (deleteList)](api_methods/DeleteList.md)
- [Get Lists (getLists)](api_methods/GetLists.md)

View File

@ -1,33 +0,0 @@
[back to list](../Readme.md)
# Update Subscriber
## `array updateSubscriber($subscriberIdOrEmail, array $subscriber): array`
This method allows a subscriber to be updated.
The argument `$subscriber` is similar to [Add Subscriber](AddSubscriber.md) method, but the subscriber is updated instead of created.
It returns the updated subscriber. See [Get Subscriber](GetSubscriber.md) for a subscriber data structure.
If the subscriber is a WordPress user, the method does not allow updating `email`, `first_name` and `last_name`. It needs to be updated in the `wp_users` and MailPoet will synchronise the new values.
## Arguments
| Argument | Type | Description |
| -------------------- | ------------- | ----------------------------------------- |
| $subscriberIdOrEmail | string or int | An id or email of an existing subscriber. |
| $subscriber | array | Subscriber data that will be updated |
## Error handling
All expected errors from the API are exceptions of class `\MailPoet\API\MP\v1\APIException`.
Code of the exception is populated to distinguish between different errors.
An exception of base class `\Exception` can be thrown when something unexpected happens.
Codes description:
| Code | Description |
| ---- | -------------------------------------------------- |
| 4 | Updating a subscriber that does not exist. |
| 13 | The subscriber couldnt be updated in the database |

View File

@ -1,3 +1,5 @@
version: '3.8'
services:
# for M1 Macs
db:

View File

@ -25,7 +25,7 @@ services:
container_name: mp-wp
build:
context: .
dockerfile: dev/php82/Dockerfile
dockerfile: dev/php81/Dockerfile
args:
UID: ${UID:-1000}
GID: ${GID:-1000}
@ -49,12 +49,10 @@ services:
volumes:
- './wordpress:/var/www/html'
- './tsconfig.base.json:/var/www/html/wp-content/plugins/tsconfig.base.json:ro'
- './.npmrc:/var/www/html/wp-content/plugins/.npmrc'
- './package.json:/var/www/html/wp-content/plugins/package.json'
- './pnpm-lock.yaml:/var/www/html/wp-content/plugins/pnpm-lock.yaml'
- './pnpm-workspace.yaml:/var/www/html/wp-content/plugins/pnpm-workspace.yaml'
- './patches:/var/www/html/wp-content/plugins/patches'
- './tests_env:/var/www/html/wp-content/plugins/tests_env'
- './mailpoet:/var/www/html/wp-content/plugins/mailpoet'
- './mailpoet-premium:/var/www/html/wp-content/plugins/mailpoet-premium'
- './packages:/var/www/html/wp-content/plugins/packages'

View File

@ -51,6 +51,7 @@ MP_GIT_HOOKS_ESLINT=true
MP_GIT_HOOKS_STYLELINT=true
MP_GIT_HOOKS_PHPLINT=true
MP_GIT_HOOKS_CODE_SNIFFER=true
MP_GIT_HOOKS_MINIMAL_PLUGIN_STANDARDS=true
MP_GIT_HOOKS_PHPSTAN=true
MP_GIT_HOOKS_INSTALL_JS=false
MP_GIT_HOOKS_INSTALL_PHP=false

2616
mailpoet/CHANGELOG.md Normal file

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,6 @@ class RoboFile extends \Robo\Tasks {
return $this->taskExecStack()
->stopOnFail()
->exec('./tools/vendor/composer.phar install')
->exec('cd ../packages/php/email-editor && ../../../mailpoet/tools/vendor/composer.phar install && cd -')
->exec('cd .. && pnpm install --frozen-lockfile --prefer-offline')
->addCode([$this, 'cleanupCachedFiles'])
->run();
@ -33,7 +32,6 @@ class RoboFile extends \Robo\Tasks {
return $this->taskExecStack()
->stopOnFail()
->exec('./tools/vendor/composer.phar install')
->exec('cd ../packages/php/email-editor && ../../../mailpoet/tools/vendor/composer.phar install && cd -')
->addCode([$this, 'cleanupCachedFiles'])
->run();
}
@ -189,7 +187,7 @@ class RoboFile extends \Robo\Tasks {
$this->_exec('./node_modules/webpack/bin/webpack.js --watch');
}
public function compileAll($opts = ['env' => null, 'skip-tests' => false, 'only-tests' => false]) {
public function compileAll($opts = ['env' => null, 'skip-tests' => false]) {
$collection = $this->collectionBuilder();
$collection->addCode(function() use ($opts) {
return call_user_func([$this, 'compileJs'], $opts);
@ -200,17 +198,15 @@ class RoboFile extends \Robo\Tasks {
return $collection->run();
}
public function compileJs($opts = ['env' => null, 'skip-tests' => false, 'only-tests' => false]) {
public function compileJs($opts = ['env' => null, 'skip-tests' => false]) {
if (!is_dir('assets/dist/js')) {
mkdir('assets/dist/js', 0777, true);
}
if (!$opts['only-tests']) {
$this->_exec('rm -rf ' . __DIR__ . '/assets/dist/js/*');
}
$this->_exec('rm -rf ' . __DIR__ . '/assets/dist/js/*');
$env = ($opts['env']) ?
sprintf('./node_modules/.bin/cross-env NODE_ENV="%s"', $opts['env']) :
null;
return $this->_exec($env . ' ./node_modules/webpack/bin/webpack.js --env BUILD_TESTS=' . ($opts['skip-tests'] ? 'skip' : 'build') . ' --env BUILD_ONLY_TESTS=' . ($opts['only-tests'] ? 'true' : 'false'));
return $this->_exec($env . ' ./node_modules/webpack/bin/webpack.js --env BUILD_TESTS=' . ($opts['skip-tests'] ? 'skip' : 'build'));
}
public function compileCss($opts = ['env' => null]) {
@ -222,7 +218,7 @@ class RoboFile extends \Robo\Tasks {
$compilationResult = $this->taskExecStack()
->exec('pnpm run stylelint-check -- "assets/css/src/**/*.scss"')
->exec('pnpm run scss' . ($opts['env'] === 'production' ? ' --no-source-map' : ''))
->exec('pnpm run scss')
->exec('pnpm run autoprefixer')
->run();
@ -332,7 +328,7 @@ class RoboFile extends \Robo\Tasks {
}
public function testUnit(array $opts = ['file' => null, 'xml' => false, 'multisite' => false, 'debug' => false]) {
$command = '../tests_env/vendor/bin/codecept run unit';
$command = 'vendor/bin/codecept run unit';
if ($opts['file']) {
$command .= ' -f ' . $opts['file'];
@ -349,7 +345,7 @@ class RoboFile extends \Robo\Tasks {
return $this->_exec($command);
}
public function testIntegration(array $opts = ['file' => null, 'group' => null, 'skip-group' => null, 'xml' => false, 'multisite' => false, 'debug' => false, 'skip-deps' => false, 'skip-plugins' => false, 'disable-hpos' => false, 'enable-hpos-sync' => false, 'enable-hpos' => false, 'stop-on-fail' => false, 'wordpress-version' => null]) {
public function testIntegration(array $opts = ['file' => null, 'group' => null, 'skip-group' => null, 'xml' => false, 'multisite' => false, 'debug' => false, 'skip-deps' => false, 'skip-plugins' => false, 'disable-hpos' => false, 'enable-hpos-sync' => false, 'enable-hpos' => false, 'stop-on-fail' => false, 'beta-version' => null]) {
return $this->runTestsInContainer(array_merge($opts, ['test_type' => 'integration']));
}
@ -406,7 +402,7 @@ class RoboFile extends \Robo\Tasks {
return $this->testIntegration($opts);
}
public function testAcceptance($opts = ['file' => null, 'skip-deps' => false, 'group' => null, 'timeout' => null, 'disable-hpos' => false, 'enable-hpos-sync' => false, 'enable-hpos' => false, 'wordpress-version' => null, 'skip-plugins' => false]) {
public function testAcceptance($opts = ['file' => null, 'skip-deps' => false, 'group' => null, 'timeout' => null, 'disable-hpos' => false, 'enable-hpos-sync' => false, 'enable-hpos' => false, 'beta-version' => null]) {
return $this->runTestsInContainer($opts);
}
@ -422,7 +418,7 @@ class RoboFile extends \Robo\Tasks {
->option('env', 'US=' . $opts['us'])
->option('env', 'PW=' . $opts['pw'])
->option('env', 'K6_BROWSER_HEADLESS=' . ($opts['head'] ? 'false' : 'true'))
->option('env', 'K6_BROWSER_TIMEOUT=' . getenv('K6_BROWSER_TIMEOUT'))
->option('env', 'K6_BROWSER_TIMEOUT=120s')
->option('env', 'SCENARIO=' . $opts['scenario'])
->arg($path ?? "$dir/tests/performance/scenarios.js")
->dir($dir)->run();
@ -439,7 +435,6 @@ class RoboFile extends \Robo\Tasks {
->option('env', 'SCENARIO=' . $opts['scenario'])
->option('env', 'K6_CLOUD_TOKEN=' . getenv('K6_CLOUD_TOKEN'))
->option('env', 'K6_CLOUD_ID=' . getenv('K6_CLOUD_ID'))
->option('env', 'K6_BROWSER_TIMEOUT=' . getenv('K6_BROWSER_TIMEOUT'))
->option('env', 'K6_PROJECT_NAME=' . $opts['scenario'])
->option('out', 'cloud')
->arg($path ?? "$dir/tests/performance/scenarios.js")
@ -476,14 +471,14 @@ class RoboFile extends \Robo\Tasks {
// import data & run WordPress setup
$this->say('Importing data and running a WordPress setup...');
$this->taskExec('COMPOSE_HTTP_TIMEOUT=200 docker compose run --rm -it setup')
$this->taskExec('COMPOSE_HTTP_TIMEOUT=200 docker-compose run --rm -it setup')
->dir(__DIR__ . '/tests/performance')
->run();
$this->say('Data imported, WordPress set up.');
}
public function testPerformanceClean() {
$this->taskExec('COMPOSE_HTTP_TIMEOUT=200 docker compose down --remove-orphans -v')
$this->taskExec('COMPOSE_HTTP_TIMEOUT=200 docker-compose down --remove-orphans -v')
->dir(__DIR__ . '/tests/performance')
->run();
}
@ -497,8 +492,8 @@ class RoboFile extends \Robo\Tasks {
*/
public function deleteDocker() {
return $this->taskExec(
'docker compose down -v --remove-orphans --rmi all'
)->dir(__DIR__ . '/../tests_env/docker')->run();
'docker-compose down -v --remove-orphans --rmi all'
)->dir(__DIR__ . '/tests/docker')->run();
}
/**
@ -507,20 +502,20 @@ class RoboFile extends \Robo\Tasks {
public function resetTestDocker() {
return $this
->taskExec(
'docker compose down -v --remove-orphans'
)->dir(__DIR__ . '/../tests_env/docker')
'docker-compose down -v --remove-orphans'
)->dir(__DIR__ . '/tests/docker')
->addCode([$this, 'cleanupCachedFiles'])
->run();
}
public function testFailedUnit() {
$this->_exec('../tests_env/vendor/bin/codecept build');
return $this->_exec('../tests_env/vendor/bin/codecept run unit -g failed');
$this->_exec('vendor/bin/codecept build');
return $this->_exec('vendor/bin/codecept run unit -g failed');
}
public function testFailedIntegration() {
$this->_exec('../tests_env/vendor/bin/codecept build');
return $this->_exec('../tests_env/vendor/bin/codecept run integration -g failed');
$this->_exec('vendor/bin/codecept build');
return $this->_exec('vendor/bin/codecept run integration -g failed');
}
public function containerDump() {
@ -624,6 +619,9 @@ class RoboFile extends \Robo\Tasks {
$collection->addCode(function() {
return $this->qaCodeSniffer([]);
});
$collection->addCode(function() {
return $this->qaMinimalPluginStandard([]);
});
return $collection->run();
}
@ -650,7 +648,7 @@ class RoboFile extends \Robo\Tasks {
'lib/',
'lib-3rd-party/',
'vendor/composer',
'vendor/dragonmantank',
'vendor/mtdowling',
'vendor-prefixed/',
'vendor-prefixed/soundasleep',
'mailpoet.php',
@ -666,7 +664,7 @@ class RoboFile extends \Robo\Tasks {
'vendor-prefixed/cerdic/css-tidy/COPYING',
'vendor-prefixed/cerdic/css-tidy/NEWS',
'vendor-prefixed/cerdic/css-tidy/testing',
'vendor/dragonmantank/cron-expression/tests',
'vendor/mtdowling/cron-expression/tests',
'vendor/phpmailer/phpmailer/test',
'vendor-prefixed/psr/log/Psr/Log/Test',
'vendor-prefixed/sabberworm/php-css-parser/tests',
@ -686,21 +684,11 @@ class RoboFile extends \Robo\Tasks {
}
public function qaLintJavascript() {
$collection = $this->collectionBuilder();
return $collection->taskExecStack()
->stopOnFail()
->exec('pnpm run check-types && pnpm run lint')
->exec('cd .. && cd packages/js/email-editor && pnpm run check-types && pnpm run lint:js')
->run();
return $this->_exec('pnpm run check-types && pnpm run lint');
}
public function qaLintCss() {
$collection = $this->collectionBuilder();
return $collection->taskExecStack()
->stopOnFail()
->exec('pnpm run stylelint-check -- "assets/css/src/**/*.scss"')
->exec('cd .. && cd packages/js/email-editor && pnpm run lint:css')
->run();
return $this->_exec('pnpm run stylelint-check -- "assets/css/src/**/*.scss"');
}
public function qaCodeSniffer(array $filesToCheck, $opts = ['severity' => 'all']) {
@ -729,7 +717,6 @@ class RoboFile extends \Robo\Tasks {
'tasks/code_sniffer/vendor',
'tasks/phpstan/vendor',
'tasks/makepot',
'tasks/minimal-plugin-standard/vendor',
'tools/vendor',
'tools/wpscan-semgrep-rules',
'temp',
@ -754,6 +741,58 @@ class RoboFile extends \Robo\Tasks {
->run();
}
public function qaMinimalPluginStandard(array $filesToCheck, $opts = ['severity' => 'all']) {
$severityFlag = $opts['severity'] === 'all' ? '-w' : '-n';
$task = implode(' ', [
'php -d memory_limit=-1',
'./tasks/code_sniffer/vendor/bin/phpcs',
'--parallel=' . $this->getParallelism(),
'--extensions=php',
$severityFlag,
'--standard=tasks/code_sniffer/vendor/wporg/plugin-directory/MinimalPluginStandard',
'-s',
]);
$ignorePaths = [
'.mp_svn',
'assets',
'doc',
'generated',
'lib/Config/PopulatorData/Templates',
'lib-3rd-party',
'node_modules',
'plugin_repository',
'prefixer/build',
'prefixer/vendor',
'tasks/code_sniffer/vendor',
'tasks/phpstan/vendor',
'tasks/makepot',
'tools/vendor',
'tools/wpscan-semgrep-rules',
'temp',
'tests/_data',
'tests/_output',
'tests/_support/_generated',
'vendor',
'vendor-prefixed',
'views',
];
// the "--ignore" arg takes a list of regexes, we need to anchor and escape them
$ignorePatterns = array_map(function (string $path): string {
return '^' . preg_quote(__DIR__ . DIRECTORY_SEPARATOR . $path);
}, $ignorePaths);
$stringFilesToCheck = !empty($filesToCheck) ? implode(' ', $filesToCheck) : '.';
return $this
->taskExec($task)
->arg('--ignore=' . implode(',', $ignorePatterns))
->rawArg($stringFilesToCheck)
->run();
}
public function qaFixFile($filePath) {
$extension = pathinfo($filePath, PATHINFO_EXTENSION);
if ($extension === 'php') {
@ -761,7 +800,7 @@ class RoboFile extends \Robo\Tasks {
return $this->collectionBuilder()
->taskExec(
'./tasks/code_sniffer/vendor/bin/phpcbf ' .
'--standard=tasks/code_sniffer/MailPoet/free-ruleset.xml ' .
'--standard=./tasks/code_sniffer/MailPoet ' .
'--runtime-set testVersion 7.4-8.2 ' .
$filePath . ' -n'
)
@ -787,7 +826,7 @@ class RoboFile extends \Robo\Tasks {
}
// make sure Codeception support files are present to avoid invalid errors when running PHPStan
$this->_exec('../tests_env/vendor/bin/codecept build');
$this->_exec('vendor/bin/codecept build');
// PHPStan must be run out of main plugin directory to avoid its autoloading
// from vendor/autoload.php where some dev dependencies cause conflicts.
@ -811,10 +850,6 @@ class RoboFile extends \Robo\Tasks {
return $this->_exec('./tools/semgrep.sh lib/ lib-3rd-party/');
}
public function qaQitSecurity() {
return $this->_exec('./vendor/bin/qit run:security mailpoet --zip=mailpoet.zip --wait');
}
public function svnCheckout() {
$svnDir = ".mp_svn";
@ -1091,9 +1126,6 @@ class RoboFile extends \Robo\Tasks {
->addCode(function () {
return $this->releaseDownloadZip();
})
->addCode(function () use ($version) {
return $this->releaseVerifyDownloadedZip($version);
})
->addCode(function () {
return $this->translationsGetPotFileFromBuild();
})
@ -1118,9 +1150,6 @@ class RoboFile extends \Robo\Tasks {
->addCode(function () {
return $this->releaseMergePullRequest(\MailPoetTasks\Release\GitHubController::RELEASE_SOURCE_BRANCH);
})
->addCode(function () {
return $this->releaseDeleteDownloadedZip();
})
->run();
}
@ -1279,29 +1308,6 @@ class RoboFile extends \Robo\Tasks {
$this->say("IMPORTANT NOTES \n" . ($outputs[2] ?: 'none'));
}
public function releaseVerifyDownloadedZip($version) {
$this->say('Verifying ZIP file');
$zip = new ZipArchive();
$versionFound = false;
if ($zip->open(self::ZIP_BUILD_PATH) === true) {
$fileContent = $zip->getFromName('mailpoet/readme.txt');
if ($fileContent !== false) {
$versionFound = strpos($fileContent, 'Stable tag: ' . $version);
}
$zip->close();
} else {
$this->yell('ZIP file could not be opened!', 40, 'red');
exit(1);
}
if (!$versionFound) {
$this->yell('ZIP file does not contain required version: "' . $version . '" in readme.txt! ', 40, 'red');
exit(1);
}
$this->say('ZIP file contains required version: "' . $version . '" in readme.txt.');
}
public function releaseDownloadZip() {
$circleciController = $this->createCircleCiController();
$path = $circleciController->downloadLatestBuild(self::ZIP_BUILD_PATH);
@ -1309,12 +1315,6 @@ class RoboFile extends \Robo\Tasks {
$this->say(sprintf('Release ZIP file size: %.2F MB', filesize($path) / pow(1024, 2)));
}
public function releaseDeleteDownloadedZip() {
$this->say('Delete downloaded ZIP: ' . self::ZIP_BUILD_PATH);
$this->taskExec('rm -f ' . self::ZIP_BUILD_PATH)->run();
$this->say('ZIP file was deleted');
}
public function releasePublishGithub($version = null) {
$jiraController = $this->createJiraController();
$version = $jiraController->getVersion($version);
@ -1611,9 +1611,9 @@ class RoboFile extends \Robo\Tasks {
}
$annotationReaderProvider = new \MailPoet\Doctrine\Annotations\AnnotationReaderProvider();
$configuration = (new \MailPoet\Doctrine\ConfigurationFactory($annotationReaderProvider, true))->createConfiguration();
$platformClass = \MailPoetVendor\Doctrine\DBAL\Platforms\MySQLPlatform::class;
$platformClass = \MailPoet\Doctrine\ConnectionFactory::PLATFORM_CLASS;
return \MailPoetVendor\Doctrine\ORM\EntityManager::create([
'driverClass' => \MailPoet\Doctrine\ConnectionFactory::DRIVER_CLASS,
'driver' => \MailPoet\Doctrine\ConnectionFactory::DRIVER,
'platform' => new $platformClass,
], $configuration);
}
@ -1622,8 +1622,8 @@ class RoboFile extends \Robo\Tasks {
$testType = $opts['test_type'] ?? 'acceptance';
$this->doctrineGenerateCache();
return $this->taskExec(
'COMPOSE_HTTP_TIMEOUT=200 docker compose run ' .
(isset($opts['wordpress-version']) && $opts['wordpress-version'] ? '-e WORDPRESS_VERSION=' . $opts['wordpress-version'] . ' ' : '') .
'COMPOSE_HTTP_TIMEOUT=200 docker-compose run ' .
(isset($opts['beta-version']) && $opts['beta-version'] ? '-e LATEST_BETA=' . $opts['beta-version'] . ' ' : '') .
(isset($opts['skip-deps']) && $opts['skip-deps'] ? '-e SKIP_DEPS=1 ' : '') .
(isset($opts['disable-hpos']) && $opts['disable-hpos'] ? '-e DISABLE_HPOS=1 ' : '') .
(isset($opts['enable-hpos-sync']) && $opts['enable-hpos-sync'] ? '-e ENABLE_HPOS_SYNC=1 ' : '') .
@ -1637,7 +1637,7 @@ class RoboFile extends \Robo\Tasks {
(isset($opts['skip-group']) && $opts['skip-group'] ? '--skip-group ' . $opts['skip-group'] . ' ' : '') .
(isset($opts['stop-on-fail']) && $opts['stop-on-fail'] ? '-f ' : '') .
(isset($opts['file']) && $opts['file'] ? $opts['file'] : '')
)->dir(__DIR__ . '/../tests_env/docker')->run();
)->dir(__DIR__ . '/tests/docker')->run();
}
private function getParallelism(int $multiplier = 1, int $min = 4, int $max = 32): int {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -9,11 +9,6 @@
.mailpoet-automation-editor-automation-wrapper {
padding: 0 20px 50px;
// Fix for action selector popup on small devices
.components-popover__content {
min-width: 280px;
}
}
.mailpoet-automation-editor-automation-flow {

View File

@ -1,16 +1,11 @@
.mailpoet_history_wrapper {
display: grid;
grid-gap: $grid-gap;
grid-template-columns: 26px 26px auto;
display: flex;
padding: 12px 20px;
.mailpoet_reset_template {
justify-self: end;
}
}
.mailpoet_history_arrow {
cursor: pointer;
margin-right: 20px;
svg {
display: inline-block;

View File

@ -155,8 +155,3 @@
.mailpoet_popup .mailpoet_browser_preview_toggle {
top: -30px;
}
.mailpoet_newsletter_styles label {
display: block;
margin-bottom: $grid-gap-half;
}

View File

@ -0,0 +1,61 @@
.mailpoet_feature_announcement {
float: right;
}
.button.mailpoet_feature_announcement_button {
height: 28px;
min-height: auto;
padding: 0 5px 1px;
position: relative;
@include respond-to(small-screen) {
margin-top: 10px;
}
}
.mailpoet_feature_announcement_icon {
line-height: 28px;
}
.mailpoet_feature_announcement_dot:before {
background: #d54e21;
border-radius: 10px;
content: '';
display: block;
height: 10px;
position: absolute;
right: -4px;
top: -4px;
width: 10px;
}
.mailpoet_in_beamer_update_notice {
background: #f00;
bottom: 0;
box-sizing: border-box;
color: #fff;
font-size: 20px;
margin: 0;
padding: 20px 10px;
position: fixed;
right: -400px;
text-align: center;
transition: right 0.2s ease-in;
width: 400px;
z-index: 10000000000; // really has to be this high
a {
color: #fff;
text-decoration: underline;
&:hover,
&:focus {
color: #fff;
text-decoration: none;
}
}
.beamer_show & {
right: 0;
}
}

View File

@ -95,6 +95,10 @@ h1.title.mailpoet-newsletter-listing-heading {
#mailpoet_editor_steps_heading {
.mailpoet-top-bar {
left: 0;
.mailpoet-top-bar-beamer {
top: 4px;
}
}
}

View File

@ -1,17 +1,7 @@
.mailpoet-logs-message {
.mailpoet-logs-full-message {
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.mailpoet-logs-message-full {
white-space: normal;
}
.mailpoet-logs-min-width {
white-space: nowrap;
width: 1px;
height: 120px;
width: 100%;
}
.mailpoet-logs {

View File

@ -30,11 +30,6 @@
}
}
.mailpoet-template-preview-image {
max-width: 100%;
width: 700px;
}
.mailpoet-template-info {
align-items: center;
display: flex;

View File

@ -90,19 +90,14 @@
width: max-content;
}
.mailpoet-re-engagement-scheduling {
display: grid;
grid-template-columns: 5fr 2fr 3fr;
.mailpoet-form-input {
width: auto;
}
}
.mailpoet-re-engagement-scheduling-note {
color: $color-input-error;
}
.mailpoet-re-engagement-scheduling .mailpoet-form-input-small {
width: 150px;
}
[data-type='re_engagement'] .mailpoet-newsletter-type-image {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 178.78 177.29'%3E%3Cpath fill='%23fb8959' d='M147 35.1a.15.15 0 00-.05-.28l-2.28-.5a4.12 4.12 0 00-.68-1 4.34 4.34 0 00-.72-.62c-.1-.08-.2-.14-.29-.2l-.11-.07a4.3 4.3 0 00-.57-.28 3.82 3.82 0 00-2-.16c1.76-6.91-1.65-14.3-1.65-14.3L130 33l-14.63-11.19a21 21 0 00-.57 7v.38a14.93 14.93 0 003.95 8.81s.22.22.59.56a16 16 0 001.58 1.28 13.83 13.83 0 002.56 1.55c-1.16.86-2 1.55-2.51 1.92l-1.56 1.17-3 2.3-4.37 3.3s2.22.4 3.28-.51c0 0-1.36 1.45-1 2.86l4.17-3.37 4.55-3.67a20.58 20.58 0 002.85 1.67q.39.2.78.36h.1c.51.21 1 .39 1.49.54h.09a13.41 13.41 0 001.43.34h.08a9.48 9.48 0 001.36.16h.08a10.9 10.9 0 001.28 0h.08a9.77 9.77 0 001.21-.16h.07c.39-.08.77-.17 1.14-.28h.07a11.07 11.07 0 001.06-.4h.07q.53-.22 1-.48h.07l.47-.27.43-.28h.07l.43-.3.39-.3.06-.05c.14-.1.27-.21.4-.32l.35-.32.37-.34c.12-.1.22-.21.33-.32l.33-.35.29-.33.3-.35.43-.61.27-.34c.57-.74 1-1.4 1.34-1.9a8.91 8.91 0 001.39-3.58 2.47 2.47 0 00.07-.61 1.09 1.09 0 000-.18z'/%3E%3Cpath fill='%23a73e27' d='M76.9 67.52l23.39-41.74s22.9 49.52-21.93 65.53z'/%3E%3Cpath fill='%23fb8959' d='M86.34 74.31l-49-37.48S25.82 76.07 61.74 90.9z'/%3E%3Cpath fill='%23f86937' d='M84 73.17s-21.38 11.94-37.62 7.58c0 0 7.81 7.81 15.36 10.15z'/%3E%3Cpath fill='%23fb8959' d='M51.39 95.92s45.69-36.64 58.83-31c9.41 4 9.37 14.38 3.64 23.23s-26.35 38.28-62.47 7.77z'/%3E%3Cpath fill='%23fb8959' d='M55.52 92.76L28 113.55s6 1.09 8.88-1.4c0 0-3.68 3.95-2.66 7.77l26.83-21.69z'/%3E%3Cpath fill='%23a73e27' d='M115.62 70.48l7.19 1.6a.42.42 0 01.15.76l-5.57 3.78a5.27 5.27 0 00-1.77-6.14z'/%3E%3Cpath fill='%237e9ffc' d='M117.7 78.41s-10.67 10-18.61 5.21c-3.67-2.23-4.47-10.94 2.09-10.81 8.17.17 9-7.87 9-7.87s9.22 3.45 7.52 13.47z'/%3E%3Ccircle fill='%230a0851' cx='111.39' cy='72.88' r='1.46'/%3E%3Cpath fill='%23f86937' d='M57.78 100.81s-6-4.2-6.39-4.89l-3.32 2.47z'/%3E%3Cpath fill='%23f5a278' opacity='.55' d='M114.54 134.69l-2.43-1.4a1.73 1.73 0 000-.68 3 3 0 00-1.61-1.67 13.58 13.58 0 00-4.09-1.21 26.84 26.84 0 00-4.4-.23c4-3.54 7.92-7.83 0-10.86-5.93 2.78-13.18 5.3-16.88 8.58l-3.35 2.26-1.34.91-30.95-9s-8.56 11 17.13 15.62c-2.5.7-4.4 1.26-5.4 1.55l-19 5.43s4.69.32 6.92-.41c0 0-2.87 1.17-2.07 2.29l18.38-5.62c25 6.5 39.47-1.28 43.66-3.73a10.79 10.79 0 001.78-1.28z'/%3E%3Cpath fill='%23a73e27' d='M35.76 55.86s6.46 6 14.46 5.21c0 0-7.75 1.91-14.17-3.09zM37.16 63.77s7.24 5.67 15.37 3.14a17 17 0 01-14.68-1z'/%3E%3Cpath fill='%23f86937' d='M94.88 95.61c-4.4 8.61-22.37 9.68-29.33 9.77 24.07 11.66 39.33-4.57 46-13.85-1.29-4.35-11.76-5.53-16.67 4.08z'/%3E%3Cpath fill='%23a73e27' d='M45.51 110.79l-11.29 9.13c-1-3.82 2.66-7.77 2.66-7.77-2.86 2.49-8.88 1.4-8.88 1.4l11.83-8.94s-1.08 5.94 5.68 6.18z'/%3E%3Cpath fill='%230a0851' d='M117.89 76.75S107 87 99.09 82.14a6.8 6.8 0 01-2.76-5.07c-.26 2.51.86 5.39 2.76 6.55 7.94 4.81 18.61-5.21 18.61-5.21a7.87 7.87 0 00.19-1.66z'/%3E%3Cpath fill='%23fb8959' d='M73 34.31c.25-.08.49-.17.73-.27.24-.11.47-.22.69-.34l.33-.19.3-.19.3-.21.27-.21.28-.22.24-.22.2-.19c5.15 3.35 12.35.38 12.35.38l-9.08-5.59v-.15a2.19 2.19 0 000-.43v-.13l1.32-.9a.11.11 0 000-.19l-1.6-.36A3.14 3.14 0 0078 23.28c-1.3-.56-3.84.5-6.48 2a2.46 2.46 0 00-3.08.88l-1.29 1.94C64.76 29.76 63 31.2 63 31.2h.05l-6.55 1.16a3.29 3.29 0 002.19.73s-1.3.46-1.52 1.45l6.59-1.37-2.65 4s6.66 2.16 11.15-2.66l.68-.17zm6.92-8.44a3.82 3.82 0 00-.12-.66 1.43 1.43 0 01.12.66z'/%3E%3C/svg%3E%0A");
}

View File

@ -161,12 +161,3 @@ ul.sending-method-benefits {
.mailpoet_install_premium_message {
margin-bottom: $grid-gap-medium;
}
.mailpoet-verify-key-button {
height: 36px;
}
.mailpoet-premium-key-toggle {
height: 34px;
padding: 0 10px !important;
}

View File

@ -559,3 +559,38 @@ h2.mailpoet-heading {
font-size: 85%;
}
}
// screen-reader-text CSS class only exists within the WordPress environment
// the class does not exist when using iFrame forms due to these being used outside WordPress
// prefixing with mailpoet-* to not interfere with the default WordPress screen-reader-text class
.mailpoet-screen-reader-text {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
-webkit-clip-path: inset(50%);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
word-wrap: normal !important;
}
.mailpoet-screen-reader-text:focus {
background-color: #ddd;
clip: auto !important;
-webkit-clip-path: none;
clip-path: none;
color: #444;
display: block;
font-size: 1em;
height: auto;
line-height: normal;
padding: 15px 23px 14px;
right: 5px;
text-decoration: none;
top: 5px;
width: auto;
z-index: 100000;
}

View File

@ -10,15 +10,3 @@
}
}
}
// WP registration form
form#registerform .g-recaptcha:not([data-size='invisible']) {
scale: 0.9;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
}
// WC registration form
form.woocommerce-form-register .g-recaptcha {
padding-inline-start: 3px;
}

View File

@ -16,7 +16,7 @@ textarea.parsley-error {
.parsley-errors-list {
color: #900;
font-size: 0.8rem;
font-size: 13px;
line-height: 1em;
list-style-type: none;
margin: 8px 0 3px;

View File

@ -1,3 +1,5 @@
$beamer-dot-size: 8px;
.mailpoet-top-bar {
align-items: center;
background-color: $color-white;
@ -81,7 +83,7 @@
}
}
.mailpoet-top-bar-tutorial {
.mailpoet-top-bar-beamer {
align-items: center;
background-color: $color-white;
border: none;
@ -94,7 +96,6 @@
position: relative;
text-align: center;
text-decoration: none;
top: 4px;
width: 75px;
svg {
@ -102,3 +103,15 @@
width: 100%;
}
}
.mailpoet-top-bar-beamer-dot:before {
background: $color-editor-warning;
border-radius: $beamer-dot-size;
content: '';
display: block;
height: $beamer-dot-size;
position: absolute;
right: 2px;
top: 2px;
width: $beamer-dot-size;
}

View File

@ -21,7 +21,7 @@
&:focus {
~ .mailpoet-form-checkbox-control {
border-color: $color-input-border-focus;
border: 2px solid $color-input-border;
}
}
}

View File

@ -81,6 +81,7 @@
input,
select {
font-size: $font-size-small;
line-height: $form-control-line-height-small;
}
svg {

View File

@ -21,7 +21,7 @@
&:focus {
~ .mailpoet-form-radio-control {
border-color: $color-input-border-focus;
border: 2px solid $color-input-border;
}
}
}

View File

@ -9,15 +9,9 @@
input {
height: 1px;
opacity: 0;
position: absolute;
visibility: hidden;
width: 1px;
&:focus {
~ .mailpoet-form-toggle-control {
border-color: $color-input-border-focus;
}
}
}
}

View File

@ -22,16 +22,9 @@
input {
height: 1px;
opacity: 0;
position: absolute;
visibility: hidden;
width: 1px;
&:focus {
~ .mailpoet-form-yesno-control {
box-shadow: 0 0 0 1px $color-input-border-focus;
z-index: 1;
}
}
}
}

View File

@ -110,3 +110,10 @@ span.mailpoet-gap-half {
height: 6px;
width: 8px;
}
.mailpoet-is-dragging {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}

View File

@ -4,36 +4,6 @@
line-height: $line-height;
}
h1,
h2,
h3,
h4,
h5,
h6,
caption,
figcaption {
// https://developer.chrome.com/docs/css-ui/css-text-wrap-balance
text-wrap: balance;
// Skip in email editor to preserve WYSIWYG functionality
.mailpoet_newsletter_wrapper & {
text-wrap: wrap;
}
}
p,
ul,
ol,
blockquote {
// https://developer.chrome.com/blog/css-text-wrap-pretty/
text-wrap: pretty;
// Skip in email editor to preserve WYSIWYG functionality
.mailpoet_newsletter_wrapper & {
text-wrap: wrap;
}
}
.admin_page_mailpoet-form-editor #wpbody {
color: inherit;
}

View File

@ -87,6 +87,7 @@
@import 'components-plugin/newsletter-types';
@import 'components-plugin/newsletter-template-styles';
@import 'components-plugin/welcome-wizard';
@import 'components-plugin/feature-announcement';
@import 'components-plugin/newsletter-congratulate';
@import 'components-plugin/discounts';
@import 'components-plugin/review-request';

View File

@ -31,7 +31,6 @@ $color-tertiary-hover: darken($color-tertiary, 10%);
$color-tertiary-light: #dcdcde;
$color-grey-0: #f6f7f7;
$color-tertiary-light-hover: darken($color-tertiary-light, 10%);
$color-tertiary-light-focus: #777;
$color-tertiary-light-background: rgba($color-tertiary-light, 0.3);
$color-destructive: #b52727;
$color-destructive-hover: #a02222;
@ -47,7 +46,6 @@ $color-text-dark: #2c3338;
// Form colors
$color-input-background: #fdfdff;
$color-input-border: $color-tertiary-light-hover;
$color-input-border-focus: $color-tertiary-light-focus;
$color-input-error: #f00;
$color-input-success: #7ed321;

View File

@ -53,7 +53,7 @@ function exportMixpanel() {
if (
window.mailpoet_analytics_enabled &&
window.mailpoet_3rd_party_libs_enabled
window.MailPoet.libs3rdPartyEnabled
) {
window.MailPoet.trackEvent = track;
} else {
@ -104,30 +104,11 @@ function cacheEvent(forced, name, data, options, callback) {
}
export function initializeMixpanelWhenLoaded() {
const MAX_RETRY = 5;
let intervalId;
let retryCount = 0;
const setupMixpanel = () => {
if (typeof window.mixpanel === 'object') {
exportMixpanel();
trackCachedEvents();
};
if (typeof window.mixpanel === 'object') {
setupMixpanel();
} else {
intervalId = setInterval(() => {
if (typeof window.mixpanel === 'object') {
clearInterval(intervalId);
setupMixpanel();
} else {
retryCount += 1;
}
if (retryCount > MAX_RETRY) {
clearInterval(intervalId);
}
}, 100);
setTimeout(initializeMixpanelWhenLoaded, 100);
}
}

View File

@ -0,0 +1,33 @@
import classnames from 'classnames';
import { MailPoet } from 'mailpoet';
import { withFeatureAnnouncement } from './with-feature-announcement';
type Props = {
hasNews: boolean;
onBeamerClick: () => void;
};
function FeatureAnnouncementComponent({ hasNews, onBeamerClick }: Props) {
const buttonClasses = classnames(
'button mailpoet_feature_announcement_button',
hasNews ? 'mailpoet_feature_announcement_dot' : '',
);
return (
<div className="mailpoet_feature_announcement">
<button
type="button"
onClick={onBeamerClick}
className={buttonClasses}
title={MailPoet.I18n.t('whatsNew')}
>
<span className="mailpoet_feature_announcement_icon dashicons dashicons-carrot" />
</button>
<span id="beamer-empty-element" />
</div>
);
}
const FeatureAnnouncement = withFeatureAnnouncement(
FeatureAnnouncementComponent,
);
export { FeatureAnnouncement };

View File

@ -0,0 +1,111 @@
import { ComponentType, FC } from 'react';
import { MailPoet } from 'mailpoet';
import ReactStringReplace from 'react-string-replace';
import jQuery from 'jquery';
import { noop } from 'lodash';
interface FeatureAnnouncementWindow extends Window {
Beamer: {
show: () => void;
};
mailpoet_feature_announcement_has_news: boolean;
mailpoet_update_available: boolean;
beamer_config: {
product_id: string;
selector: string;
language: string;
callback: () => void;
filter?: string;
};
mailpoet_user_locale: string;
}
declare let window: FeatureAnnouncementWindow;
export const withFeatureAnnouncement = <P extends Record<string, unknown>>(
Component: ComponentType<P>,
): FC<Omit<P, 'hasNews' | 'onBeamerClick'>> => {
const isBeamerInitialized = () => typeof window.Beamer !== 'undefined';
let showDot = window.mailpoet_feature_announcement_has_news;
let beamerCallback;
function showPluginUpdateNotice() {
if (
!window.mailpoet_update_available ||
document.getElementById('mailpoet_update_notice')
) {
return;
}
const updateMailPoetNotice = ReactStringReplace(
MailPoet.I18n.t('updateMailPoetNotice'),
/\[link\](.*?)\[\/link\]/,
(match) => `<a href="update-core.php">${match}</a>`,
).join('');
jQuery('#beamerOverlay').append(
`<p id="mailpoet_update_notice" class="mailpoet_in_beamer_update_notice">${updateMailPoetNotice}</p>`,
);
}
function updateLastAnnouncementSeenValue() {
const data = { last_announcement_seen: Math.floor(Date.now() / 1000) };
void MailPoet.Ajax.post({
api_version: MailPoet.apiVersion,
endpoint: 'user_flags',
action: 'set',
data,
});
}
function loadBeamer() {
window.beamer_config = {
product_id: 'VvHbhYWy7118',
selector: '#beamer-empty-element',
language: window.mailpoet_user_locale,
callback: beamerCallback,
};
if (MailPoet.isWoocommerceActive) {
window.beamer_config.filter = 'woocommerce';
}
MailPoet.Modal.loading(true);
window.mailpoet_feature_announcement_has_news = false;
const s = document.createElement('script');
s.type = 'text/javascript';
s.src = 'https://app.getbeamer.com/js/beamer-embed.js';
document.getElementsByTagName('body')[0].appendChild(s);
}
function showBeamer(event = null) {
if (event) {
event.preventDefault();
}
if (!isBeamerInitialized()) {
loadBeamer();
return;
}
showDot = false;
beamerCallback = noop; // We show Beamer panel only on first callback after initialization
MailPoet.Modal.loading(false);
window.Beamer.show();
updateLastAnnouncementSeenValue();
showPluginUpdateNotice();
}
beamerCallback = () => {
if (!isBeamerInitialized()) {
return;
}
showBeamer();
};
return function withFeatureAnnouncementRenderer({
...props
}: Omit<P, 'hasNews' | 'onBeamerClick'>) {
return (
<Component
{...(props as P)}
onBeamerClick={(e) => showBeamer(e)}
hasNews={showDot}
/>
);
};
};

View File

@ -16,11 +16,7 @@ export type ApiError = {
export const initializeApi = () => {
apiFetch.use((options, next) => {
if (
options.path &&
(options.path.startsWith('/wc-analytics/') ||
options.path.startsWith('/wp/v2/'))
) {
if (options.path && options.path.startsWith('/wc-analytics/')) {
return apiFetch.createRootURLMiddleware(`${api.root}/`)(options, next);
}
return apiFetch.createRootURLMiddleware(apiUrl)(options, next);

View File

@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { TopBarWithBoundary } from 'common/top-bar/top-bar';
import { TopBarWithBeamer } from 'common/top-bar/top-bar';
import { SlotFillProvider } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { registerTranslations } from 'common';
@ -72,7 +72,7 @@ function Automations(): JSX.Element {
return (
<>
<TopBarWithBoundary />
<TopBarWithBeamer />
<GlobalNotices />
<Notices />
<MssAccessNotices />

View File

@ -3,23 +3,14 @@ import { FlowSeparator } from './flow-separator';
import { Step as StepData } from './types';
type Props = {
previousStepData: StepData;
stepData: StepData;
index: number;
nextStepData?: StepData;
};
export function FlowEnding({
previousStepData,
index,
nextStepData,
}: Props): JSX.Element {
export function FlowEnding({ stepData, index }: Props): JSX.Element {
return (
<div className="mailpoet-automation-editor-step-wrapper">
<FlowSeparator
previousStepData={previousStepData}
nextStepData={nextStepData}
index={index}
/>
<FlowSeparator stepData={stepData} index={index} />
<Icon
className="mailpoet-automation-editor-automation-end"
icon={check}

View File

@ -6,9 +6,8 @@ import { Step as StepData } from './types';
import { RenderStepSeparatorType } from '../../../types/filters';
type Props = {
previousStepData: StepData;
stepData: StepData;
index: number;
nextStepData?: StepData;
};
export function FlowSeparator(props: Props): JSX.Element {
@ -36,9 +35,5 @@ export function FlowSeparator(props: Props): JSX.Element {
),
[context],
);
return renderSeparator(
props.previousStepData,
props.index,
props.nextStepData,
);
return renderSeparator(props.stepData, props.index);
}

View File

@ -40,24 +40,13 @@ export function Flow({ stepData, row }: Props): JSX.Element {
return nextStepData ? (
<div key={id}>
{row > 0 && (
<FlowSeparator
previousStepData={stepData}
index={i}
nextStepData={nextStepData}
/>
)}
{row > 0 && <FlowSeparator stepData={stepData} index={i} />}
<FlowStep stepData={nextStepData} index={i} />
<Flow stepData={nextStepData} row={row + 1} />
</div>
) : (
<FlowEnding
// eslint-disable-next-line react/no-array-index-key
key={i}
previousStepData={stepData}
index={i}
nextStepData={nextStepData}
/>
// eslint-disable-next-line react/no-array-index-key
<FlowEnding key={i} stepData={stepData} index={i} />
);
})}
</div>

View File

@ -37,9 +37,8 @@ export function InserterPopover(): JSX.Element | null {
return (
<>
<Popover
placement="bottom"
ref={popoverRef}
anchor={inserterPopover.anchor}
anchorRect={inserterPopover.anchor.getBoundingClientRect()}
onClose={() => {
if (!showModal) {
void setInserterPopover(undefined);

View File

@ -143,7 +143,6 @@ export function* activate() {
return {
type: 'ACTIVATE',
automation: data?.data ?? automation,
saved: !!data?.data,
} as const;
}

View File

@ -41,15 +41,11 @@ export function reducer(state: State, action): State {
savedState: 'saved',
};
case 'ACTIVATE':
return action.saved
? {
...state,
automationData: action.automation,
savedState: 'saved',
}
: {
...state,
};
return {
...state,
automationData: action.automation,
savedState: 'saved',
};
case 'DEACTIVATE':
return {
...state,

View File

@ -50,7 +50,6 @@ export function initHooks() {
return function StatisticSeparatorWrapper(
previousStepData: StepData,
index: number,
nextStepData: StepData,
) {
return (
<>
@ -63,11 +62,7 @@ export function initHooks() {
}
/>
)}
<StatisticSeparator
previousStep={previousStepData}
nextStep={nextStepData}
index={index}
/>
<StatisticSeparator previousStep={previousStepData} index={index} />
</>
);
};

View File

@ -8,13 +8,11 @@ import { Step } from '../../../../../../editor/components/automation/types';
type Props = {
previousStep: Step;
index: number;
nextStep?: Step;
};
export function StatisticSeparator({
previousStep,
index,
nextStep,
}: Props): JSX.Element | null {
const { section, stepType } = useSelect(
(s) => ({
@ -54,34 +52,15 @@ export function StatisticSeparator({
);
}
const completed = data.step_data?.completed || {};
const failed = data.step_data?.failed || {};
const waiting = data.step_data?.waiting || {};
const calculateTotals = (id) =>
(completed[id] ?? 0) + (failed[id] ?? 0) + (waiting[id] ?? 0);
let totalEntered = 0;
if (nextStep) {
totalEntered = calculateTotals(nextStep.id);
} else if (previousStep.next_steps.length === 2) {
// When there is no next step and the previous step has 2+ next steps we are
// in an empty if/else branch. To calculate the total we need to subtract
// totalEntered of the sibling step from totalEntered of previousStep
const siblingStep = previousStep.next_steps.find((step) => step.id);
const totalEnteredSibling = siblingStep
? calculateTotals(siblingStep.id)
: 0;
const totalEnteredPrevious = completed[previousStep.id] ?? 0;
totalEntered = totalEnteredPrevious - totalEnteredSibling;
} else {
totalEntered = completed[previousStep.id] ?? 0;
}
const flow = data.step_data?.flow;
const value = flow !== undefined ? flow[previousStep.id] ?? 0 : 0;
const percent =
data.step_data.total > 0
? Math.round((totalEntered / data.step_data.total) * 100)
? Math.round((value / data.step_data.total) * 100)
: 0;
const formattedValue = Intl.NumberFormat(locale.toString(), {
notation: 'compact',
}).format(totalEntered);
}).format(value);
const formattedPercent = Intl.NumberFormat(locale.toString(), {
style: 'percent',
}).format(percent / 100);

View File

@ -29,20 +29,6 @@ export function Tabs(): JSX.Element {
className: 'mailpoet-analytics-tab-flow',
title: __('Automation flow', 'mailpoet'),
},
{
name: 'automation-subscribers',
className: classNames(
'mailpoet-analytics-tab-subscribers',
!MailPoet.capabilities.detailedAnalytics.isRestricted
? 'is-unlocked'
: '',
),
title: (
<>
{__('Subscribers', 'mailpoet')} <Icon icon={lockSmall} />
</>
) as unknown as string,
},
];
if (hasEmails) {
tabs.push({
@ -68,6 +54,20 @@ export function Tabs(): JSX.Element {
) as unknown as string,
});
}
tabs.push({
name: 'automation-subscribers',
className: classNames(
'mailpoet-analytics-tab-subscribers',
!MailPoet.capabilities.detailedAnalytics.isRestricted
? 'is-unlocked'
: '',
),
title: (
<>
{__('Subscribers', 'mailpoet')} <Icon icon={lockSmall} />
</>
) as unknown as string,
});
}
const updateUrlSearchString = useCallback(

View File

@ -1,6 +1,6 @@
import { Modal, Spinner } from '@wordpress/components';
import { useNavigate, useLocation } from 'react-router-dom';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useEffect, useMemo, useState } from 'react';
import { Table } from '@woocommerce/components';
import apiFetch from '@wordpress/api-fetch';
import { addQueryArgs } from '@wordpress/url';
@ -32,12 +32,12 @@ export function ActivityModal(): JSX.Element {
const [state, setState] = useState<ActivityModalState>('hidden');
const [run, setRun] = useState<RunData | null>(null);
const closeModal = useCallback(() => {
const closeModal = () => {
setState('hidden');
setRun(null);
pageParams.delete('runId');
navigate({ search: pageParams.toString() });
}, [navigate, pageParams]);
};
useEffect(() => {
const controller = new AbortController();
@ -64,7 +64,7 @@ export function ActivityModal(): JSX.Element {
setState('loaded');
} catch (error) {
if (!controller.signal?.aborted) {
closeModal();
setState('hidden');
}
}
};
@ -75,7 +75,7 @@ export function ActivityModal(): JSX.Element {
setState('hidden');
controller.abort();
};
}, [runId, closeModal]);
}, [runId]);
if (state === 'hidden') {
return null;
@ -104,10 +104,14 @@ export function ActivityModal(): JSX.Element {
<Table
className="mailpoet-analytics-activity-modal-table"
headers={headers}
rows={transformLogsToRows(run.logs, run.automation.steps)}
rows={transformLogsToRows(
run.logs,
run.automation.steps,
run.next_step,
)}
/>
<Footer run={run.run} />
<Footer runStatus={run.run.status} />
</Modal>
);
}

View File

@ -1,39 +1,8 @@
import { __ } from '@wordpress/i18n';
import { createInterpolateElement } from '@wordpress/element';
import { AutomationEndedIcon, AutomationInProgressIcon } from './icons';
import { Run } from '../../../../store';
export function Footer({ run }: { run: Run }) {
if (run.is_past_due) {
const automationRunFilterValue = encodeURIComponent(
`"automation_run_id":${run.id}`,
);
const pastDueActionsUrl = `/wp-admin/tools.php?page=action-scheduler&status=past-due&s=${automationRunFilterValue}`;
return (
<div className="mailpoet-analytics-activity-modal-footer">
<AutomationInProgressIcon />
<span>
{createInterpolateElement(
__(
'Automation stuck. Run <link>past due actions</link> manually.',
'mailpoet',
),
{
link: (
// eslint-disable-next-line jsx-a11y/anchor-has-content, jsx-a11y/control-has-associated-label
<a
href={pastDueActionsUrl}
target="_blank"
rel="noopener noreferrer"
/>
),
},
)}
</span>
</div>
);
}
if (run.status === 'running') {
export function Footer({ runStatus }: { runStatus: string }) {
if (runStatus === 'running') {
return (
<div className="mailpoet-analytics-activity-modal-footer">
<AutomationInProgressIcon />

View File

@ -3,7 +3,7 @@ import { Steps } from '../../../../../../../editor/components/automation/types';
import { MailPoet } from '../../../../../../../../mailpoet';
import { StepCell } from '../cells/step';
import { AutomationRunStatus } from '../../../../../../../components/status';
import { Log } from '../../../../store';
import { Log, NextStep } from '../../../../store';
export const headers = [
{
@ -37,43 +37,64 @@ function StatusInfo({ info }: { info: string | null }): JSX.Element {
);
}
export function transformLogsToRows(logs: Log[], steps: Steps) {
return logs.map((log) => {
const timeLeft = log.time_left
? // translators: "Time left: 1 hour" or "Time left: 1 minute", uses WordPress' human_time_diff() to get the value
sprintf(__('Time left: %s', 'mailpoet'), log.time_left)
: null;
let statusInfo = null;
if (log.error) {
statusInfo = log.error.message ? log.error.message : null;
} else {
statusInfo = timeLeft;
}
return [
export function transformLogsToRows(
logs: Log[],
steps: Steps,
nextStep: NextStep,
) {
const items = logs.map((log) => [
{
display: <StepCell name={log.step_name} data={steps[log.step_id]} />,
value: log.step_name,
},
{
display: MailPoet.Date.format(new Date(log.started_at)),
value: log.started_at,
},
{
display:
log.status === 'complete'
? MailPoet.Date.format(new Date(log.updated_at))
: '-',
value: log.updated_at,
},
{
display: (
<>
<AutomationRunStatus status={log.status} />
<StatusInfo info={log.error && log.error.message} />
</>
),
},
]);
if (nextStep) {
// translators: "Time left: 1 hour" or "Time left: 1 minute", uses WordPress' human_time_diff() to get the value
const timeLeft = sprintf(
__('Time left: %s', 'mailpoet'),
nextStep.time_left,
);
items.push([
{
display: <StepCell name={log.step_name} data={steps[log.step_id]} />,
value: log.step_name,
display: <StepCell name={nextStep.name} data={nextStep.step} />,
value: nextStep.name,
},
{
display: MailPoet.Date.format(new Date(log.started_at)),
value: log.started_at,
display: MailPoet.Date.format(new Date(logs.at(-1).updated_at)),
value: logs.at(-1).updated_at,
},
{
display:
log.status === 'complete'
? MailPoet.Date.format(new Date(log.updated_at))
: '-',
value: log.updated_at,
display: '-',
value: '',
},
{
display: (
<>
<AutomationRunStatus status={log.status} />
<StatusInfo info={statusInfo} />
<AutomationRunStatus status="running" />
<StatusInfo info={timeLeft} />
</>
),
},
];
});
]);
}
return items;
}

View File

@ -2,7 +2,7 @@ import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { dispatch, select, useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { TopBarWithBoundary } from '../../../../common/top-bar/top-bar';
import { TopBarWithBeamer } from '../../../../common/top-bar/top-bar';
import { Notices } from '../../../listing/components/notices';
import { Header } from './components/header';
import { Overview } from './components/overview';
@ -49,7 +49,7 @@ function TopBarWithBreadcrumb(): JSX.Element {
}));
return (
<TopBarWithBoundary>
<TopBarWithBeamer>
<p className="mailpoet-automation-analytics-title">
<a href={MailPoet.urls.automationListing}>
{__('Automations', 'mailpoet')}
@ -57,7 +57,7 @@ function TopBarWithBreadcrumb(): JSX.Element {
<strong>{automation.name}</strong>
<AutomationStatus status={automation.status} />
</p>
</TopBarWithBoundary>
</TopBarWithBeamer>
);
}

Some files were not shown because too many files have changed in this diff Show More