diff --git a/.github/actions/tool-setup/action.yml b/.github/actions/tool-setup/action.yml index 86402e50cfc3b..39f1f2faf1824 100644 --- a/.github/actions/tool-setup/action.yml +++ b/.github/actions/tool-setup/action.yml @@ -89,7 +89,7 @@ runs: - name: Setup pnpm if: steps.versions.outputs.node-version != 'false' - uses: pnpm/action-setup@v3.0.0 + uses: pnpm/action-setup@v4.0.0 with: version: ${{ steps.versions.outputs.pnpm-version }} - name: Setup Node diff --git a/.github/files/build-reminder-comment/check-test-reminder-comment.js b/.github/files/build-reminder-comment/check-test-reminder-comment.js index f9f8a8f4df83a..cd9a4b43eca60 100644 --- a/.github/files/build-reminder-comment/check-test-reminder-comment.js +++ b/.github/files/build-reminder-comment/check-test-reminder-comment.js @@ -9,12 +9,12 @@ const getCheckComments = require( './get-check-comments.js' ); * meaning that Jetpack is being built. Or `packages/jetpack-mu-wpcom`, * for the jetpack-mu-wpcom-plugin used on WordPress.com is being built. * - * @param {GitHub} github - Initialized Octokit REST client. - * @param {string} owner - Repository owner. - * @param {string} repo - Repository name. - * @param {string} number - PR number. - * @param {Core} core - A reference to the @actions/core package - * @returns {Promise} Promise resolving to an array of project strings needing testing. + * @param {GitHub} github - Initialized Octokit REST client. + * @param {string} owner - Repository owner. + * @param {string} repo - Repository name. + * @param {string} number - PR number. + * @param {Core} core - A reference to the @actions/core package + * @return {Promise} Promise resolving to an array of project strings needing testing. */ async function touchedProjectsNeedingTesting( github, owner, repo, number, core ) { const changed = JSON.parse( process.env.CHANGED ); @@ -46,7 +46,7 @@ async function touchedProjectsNeedingTesting( github, owner, repo, number, core * @param {github} github - Pre-authenticated octokit/rest.js client with pagination plugins * @param {object} context - Context of the workflow run * @param {core} core - A reference to the @actions/core package - * @returns {Promise} Promise resolving to an object with the following properties: + * @return {Promise} Promise resolving to an object with the following properties: * - {commentId} - a comment ID, or 0 if no comment is found. * - {projects} - an array of project strings needing testing. */ diff --git a/.github/files/build-reminder-comment/get-check-comments.js b/.github/files/build-reminder-comment/get-check-comments.js index 2c81c8552c6e9..6d040422ac6ec 100644 --- a/.github/files/build-reminder-comment/get-check-comments.js +++ b/.github/files/build-reminder-comment/get-check-comments.js @@ -10,7 +10,7 @@ const cache = {}; * @param {string} number - Issue number. * @param {string} testCommentIndicator - A piece of text unique to all test reminder comments. * @param {core} core - A reference to the @actions/core package - * @returns {Promise} Promise resolving to an array of comment IDs. + * @return {Promise} Promise resolving to an array of comment IDs. */ async function getCheckComments( github, owner, repo, number, testCommentIndicator, core ) { const testCommentIDs = []; @@ -30,11 +30,11 @@ async function getCheckComments( github, owner, repo, number, testCommentIndicat issue_number: +number, per_page: 100, } ) ) { - response.data.map( comment => { + for ( const comment of response.data ) { if ( comment.body.includes( testCommentIndicator ) ) { testCommentIDs.push( comment.id ); } - } ); + } } cache[ cacheKey ] = testCommentIDs; diff --git a/.github/files/gh-autorelease/files/autorelease.sh b/.github/files/gh-autorelease/files/autorelease.sh index cf26c71e6bb21..45e6a75475798 100755 --- a/.github/files/gh-autorelease/files/autorelease.sh +++ b/.github/files/gh-autorelease/files/autorelease.sh @@ -2,32 +2,42 @@ set -eo pipefail +: "${GH_TOKEN:?Build argument needs to be set and non-empty.}" : "${GITHUB_REF:?Build argument needs to be set and non-empty.}" : "${GITHUB_SHA:?Build argument needs to be set and non-empty.}" -: "${API_TOKEN_GITHUB:?Build argument needs to be set and non-empty.}" -: "${GITHUB_API_URL:?Build argument needs to be set and non-empty.}" -: "${GITHUB_REPOSITORY:?Build argument needs to be set and non-empty.}" -## Determine tag -if [[ ! "$GITHUB_REF" =~ ^refs/tags/v?[0-9]+(\.[0-9]+)+(-[a-z0-9._-]+)?$ ]]; then - echo "::error::Expected GITHUB_REF like \`refs/tags/v1.2.3\` or \`refs/tags/1.2.3\`, got \`$GITHUB_REF\`" +if [[ ! -f composer.json ]]; then + echo '::error::No composer.json. Did it get excluded from the mirror?' exit 1 fi -TAG="${GITHUB_REF#refs/tags/}" -## Check for alphas -if [[ "$TAG" =~ -(alpha|a\.[0-9]*[02468])$ ]]; then - echo "Not creating a release for alpha version $TAG" - exit 0 -fi -echo "Creating release for $TAG" +## Determine tag +ROLLING_MODE= +if [[ "$GITHUB_REF" =~ ^refs/tags/v?[0-9]+(\.[0-9]+)+(-[a-z0-9._-]+)?$ ]]; then + TAG="${GITHUB_REF#refs/tags/}" -## Determine slug and title format. -if [[ ! -f composer.json ]]; then - echo '::error::No composer.json. Did it get excluded from the mirror?' + ## Check for alphas + if [[ "$TAG" =~ -(alpha|a\.[0-9]*[02468])$ ]]; then + echo "Not creating a release for alpha version $TAG" + exit 0 + fi +elif [[ "$GITHUB_REF" == "refs/heads/trunk" ]]; then + if ! jq -e '.extra.autorelease["rolling-release"]? // false' composer.json > /dev/null; then + echo "::notice::Skipping trunk release because autorelease rolling mode is not enabled." + exit 0 + fi + ROLLING_MODE=true + CURRENT_VER=$( sed -nEe 's/^## \[?([^]]*)\]? - .*/\1/;T;p;q' CHANGELOG.md || true ) + GIT_SUFFIX=$( git log -1 --format=%h . ) + TAG="$CURRENT_VER+rolling.$GIT_SUFFIX" +else + echo "::error::Expected GITHUB_REF like \`refs/tags/v1.2.3\` or \`refs/tags/1.2.3\` or \`refs/heads/trunk\` for rolling releases, got \`$GITHUB_REF\`" exit 1 fi +echo "Creating release for $TAG" + +## Determine slug and title format. SLUG="$(jq -r '.extra.autorelease.slug? // .extra["wp-plugin-slug"] // .extra["beta-plugin-slug"] // ( .name | sub( "^.*/"; "" ) )' composer.json)" if [[ -z "$SLUG" ]]; then echo '::error::Failed to get slug from composer.json.' @@ -48,76 +58,75 @@ echo "::group::Creating $SLUG.zip" git archive -v --output="$SLUG.zip" --prefix="$SLUG/" HEAD 2>&1 echo "::endgroup::" -## Create the release note. -# Extract the changelog section. -echo "::group::Extracting release notes" -if [[ ! -f CHANGELOG.md ]]; then - echo '::endgroup::' - echo '::error::No CHANGELOG.md for release notes.' - exit 1 -fi -SCRIPT=" - /^## \\[?$(sed 's/[.\[\]\\*^$\/()+?{}|]/\\&/g' <<<"${TAG#v}")\\]? - / { - bc +if [[ -z "$ROLLING_MODE" ]]; then + ## Create the release note. + # Extract the changelog section. + echo "::group::Extracting release notes" + if [[ ! -f CHANGELOG.md ]]; then + echo '::endgroup::' + echo '::error::No CHANGELOG.md for release notes.' + exit 1 + fi + SCRIPT=" + /^## \\[?$(sed 's/[.\[\]\\*^$\/()+?{}|]/\\&/g' <<<"${TAG#v}")\\]? - / { + bc + :a + n + /^## / { + q + } + :c + s/^## \[([^]]+)\]/## \1/ + p + ba + } + " + ENTRY=$(sed -n -E -e "$SCRIPT" CHANGELOG.md) + if [[ -z "$ENTRY" ]]; then + echo '::endgroup::' + echo "::error::Failed to find section for ${TAG#v} in CHANGELOG.md" + exit 1 + fi + + # Strip unwanted sections. + SCRIPT=" :a - n - /^## / { - q + /^### .* This section will not be copied to readme\.txt/ { + :b + n + /^#/ ba + bb } - :c - s/^## \[([^]]+)\]/## \1/ p - ba - } -" -ENTRY=$(sed -n -E -e "$SCRIPT" CHANGELOG.md) -if [[ -z "$ENTRY" ]]; then - echo '::endgroup::' - echo "::error::Failed to find section for ${TAG#v} in CHANGELOG.md" - exit 1 + " + ENTRY=$(sed -n -E -e "$SCRIPT" <<<"$ENTRY") + + echo "Release notes:" + echo "-----" + echo "$ENTRY" + echo "-----" + echo "::endgroup::" +else + ## Using a brief explanation for the rolling release note. + ENTRY="### Rolling release based on the trunk branch." +fi + +if [[ -n "$ROLLING_MODE" ]]; then + echo "::group::Deleting stale rolling release" + + for R in $( gh release list --limit 100 --json tagName --jq '.[].tagName | select( contains( "rolling" ) )' ); do + echo "Found $R, deleting" + gh release delete "$R" --cleanup-tag --yes + done + + echo "::endgroup::" fi -# Strip unwanted sections. -SCRIPT=" - :a - /^### .* This section will not be copied to readme\.txt/ { - :b - n - /^#/ ba - bb - } - p -" -ENTRY=$(sed -n -E -e "$SCRIPT" <<<"$ENTRY") - -echo "Release notes:" -echo "-----" -echo "$ENTRY" -echo "-----" -echo "::endgroup::" echo "::group::Creating release" -curl -v -L \ - --write-out '%{response_code}' \ - --output out.json \ - --request POST \ - --header "authorization: Bearer $API_TOKEN_GITHUB" \ - --header 'content-type: application/json' \ - --header 'accept: application/vnd.github.v3+json' \ - --url "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases" \ - --data "$(jq -n --arg tag "$TAG" --arg sha "$GITHUB_SHA" --arg title "$TITLE" --arg body "$ENTRY" '{ tag_name: $tag, target_commitish: $sha, name: $title, body: $body}')" \ - 2>&1 > code.txt -cat out.json -echo -[[ "$(&1 echo "::endgroup::" diff --git a/.github/files/gh-autorelease/workflows/autorelease.yml b/.github/files/gh-autorelease/workflows/autorelease.yml index 7fb76b4f8ae94..5109e151dd388 100644 --- a/.github/files/gh-autorelease/workflows/autorelease.yml +++ b/.github/files/gh-autorelease/workflows/autorelease.yml @@ -9,6 +9,8 @@ on: - 'v?[0-9]+.[0-9]+.[0-9]+-*' - 'v?[0-9]+.[0-9]+.[0-9]+.[0-9]+' - 'v?[0-9]+.[0-9]+.[0-9]+.[0-9]+-*' + branches: + - 'trunk' jobs: publish: @@ -18,5 +20,5 @@ jobs: - uses: actions/checkout@v4 - name: Create release env: - API_TOKEN_GITHUB: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: ./.github/files/autorelease.sh diff --git a/.github/files/pr-update-to.sh b/.github/files/pr-update-to.sh index 40946335b1f40..5458931c39f41 100755 --- a/.github/files/pr-update-to.sh +++ b/.github/files/pr-update-to.sh @@ -27,19 +27,6 @@ function update_tag { cd $(dirname "${BASH_SOURCE[0]}")/../.. BASE="$PWD" -# If this commit updated a changelog, assume it was a release and update the tag. -echo "Checking for changes to changelogs..." -FILES=() -for FILE in projects/*/*/composer.json; do - PROJECT="${FILE%/composer.json}" - cd "$BASE/$PROJECT" - FILES+=( "$(realpath -m --relative-to="$BASE" "$(jq -r '.extra.changelogger.changelog // "CHANGELOG.md"' composer.json)")" ) -done -cd "$BASE" -for F in $(git -c core.quotepath=off diff --name-only HEAD^..HEAD "${FILES[@]}"); do - update_tag "pr-update-to-${F%/*}" -done - # If this commit changed tool versions, update the tag so PRs get rechecked with the new versions. echo "Checking for changes to .github/versions.sh..." git diff --exit-code --name-only HEAD^..HEAD .github/versions.sh || update_tag "pr-update-to" diff --git a/.github/files/renovate-post-upgrade.sh b/.github/files/renovate-post-upgrade.sh index 2e15d16f93d7b..6f6aaef839d24 100755 --- a/.github/files/renovate-post-upgrade.sh +++ b/.github/files/renovate-post-upgrade.sh @@ -60,16 +60,7 @@ for DIR in $(git -c core.quotepath=off diff --name-only HEAD | sed -nE 's!^(proj echo "Adding change file for $SLUG" cd "$DIR" - CHANGES_DIR="$(jq -r '.extra.changelogger["changes-dir"] // "changelog"' composer.json)" - if [[ -d "$CHANGES_DIR" && "$(ls -- "$CHANGES_DIR")" ]]; then - changelogger_add 'Updated package dependencies.' '' --filename="${CHANGEFILE}" --filename-auto-suffix - else - changelogger_add 'Updated package dependencies.' '' --filename="${CHANGEFILE}" --filename-auto-suffix - echo "Updating version for $SLUG" - PRERELEASE=$(alpha_tag composer.json 0) - VER=$(changelogger version next --default-first-version --prerelease="$PRERELEASE") || { echo "$VER"; exit 1; } - "$BASE/tools/project-version.sh" -u "$VER" "$SLUG" - fi + changelogger_add 'Updated package dependencies.' '' --filename="${CHANGEFILE}" --filename-auto-suffix cd "$BASE" done diff --git a/.github/workflows/block-performance.yml b/.github/workflows/block-performance.yml index 60fee1fca10ff..8e553204cc1ac 100644 --- a/.github/workflows/block-performance.yml +++ b/.github/workflows/block-performance.yml @@ -3,6 +3,7 @@ name: Jetpack block performance on: schedule: - cron: '0 */12 * * *' + workflow_dispatch: env: # Work around a bug in node 18.18.0. See https://github.com/webpack-contrib/thread-loader/issues/191 for details. @@ -18,20 +19,13 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: 16 + node-version: 20 - uses: actions/checkout@v4 with: repository: 'WordPress/gutenberg' path: 'gutenberg' - - name: Build Gutenberg - working-directory: gutenberg - run: | - npm ci - npx playwright install chromium --with-deps - npm run build:packages - - uses: actions/cache@v4 with: path: ~/.npm @@ -39,6 +33,13 @@ jobs: restore-keys: | ${{ runner.os }}-node- + - name: Build Gutenberg + working-directory: gutenberg + run: | + npm ci + npx playwright install chromium --with-deps + npm run build:packages + - name: Setup tools for J uses: ./.github/actions/tool-setup @@ -87,6 +88,7 @@ jobs: with: name: test-output-block-perf path: tools/e2e-commons/results + include-hidden-files: true test-reports: name: "Trigger test report workflow" diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 3a4ba63d35b78..9ed172916a650 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -88,7 +88,7 @@ jobs: org.opencontainers.image.documentation=${{ github.server_url }}/${{ github.repository }}/blob/trunk/tools/docker/README.md - name: Build and push Docker image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: tools/docker platforms: linux/amd64,linux/arm64 diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 655c07f4bac79..43b0038a0df38 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -304,6 +304,7 @@ jobs: with: name: test-output-${{ matrix.project }} path: ${{ matrix.path }}/output + include-hidden-files: true test-report: name: "Test report" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 39e20a92f7aee..caef4109236b8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -220,6 +220,7 @@ jobs: with: name: ${{ matrix.artifact }} path: artifacts + include-hidden-files: true retention-days: 7 storybook-test: diff --git a/.husky/pre-push b/.husky/pre-push index fcd9111b104f4..300e69f5b8f78 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -4,4 +4,4 @@ if test -c /dev/tty && sh -c ': < /dev/tty' >/dev/null 2>/dev/null; then exec < /dev/tty fi -node tools/js-tools/git-hooks/pre-push-hook.js +node tools/js-tools/git-hooks/pre-push-hook.mjs diff --git a/.pnpmfile.cjs b/.pnpmfile.cjs index 56644644bfeeb..5512a5b502207 100644 --- a/.pnpmfile.cjs +++ b/.pnpmfile.cjs @@ -4,7 +4,7 @@ * We could generally do the same with pnpm.overrides in packages.json, but this allows for comments. * * @param {object} pkg - Dependency package.json contents. - * @returns {object} Modified pkg. + * @return {object} Modified pkg. */ function fixDeps( pkg ) { // Deps tend to get outdated due to a slow release cycle. @@ -120,7 +120,7 @@ function fixDeps( pkg ) { * This can't be done with pnpm.overrides. * * @param {object} pkg - Dependency package.json contents. - * @returns {object} Modified pkg. + * @return {object} Modified pkg. */ function fixPeerDeps( pkg ) { // Indirect deps that still depend on React <18. @@ -165,9 +165,9 @@ function fixPeerDeps( pkg ) { * Pnpm package hook. * * @see https://pnpm.io/pnpmfile#hooksreadpackagepkg-context-pkg--promisepkg - * @param {object} pkg - Dependency package.json contents. + * @param {object} pkg - Dependency package.json contents. * @param {object} context - Pnpm object of some sort. - * @returns {object} Modified pkg. + * @return {object} Modified pkg. */ function readPackage( pkg, context ) { if ( pkg.name ) { @@ -182,7 +182,7 @@ function readPackage( pkg, context ) { * * @see https://pnpm.io/pnpmfile#hooksafterallresolvedlockfile-context-lockfile--promiselockfile * @param {object} lockfile - Lockfile data. - * @returns {object} Modified lockfile. + * @return {object} Modified lockfile. */ function afterAllResolved( lockfile ) { // If there's only one "importer", it's probably pnpx rather than the monorepo. Don't interfere. diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000000..a4829d5b4839e --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,14 @@ +{ + /** + * List of recommended extensions to use for this workspace. + * The identifier of an extension is always `${publisher}.${name}`, + * which is a part of the URL, e.g. https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint + * You can view these extensions using the command `Extensions: Show Recommended Extensions`. + */ + "recommendations": [ + "bmewburn.vscode-intelephense-client", // PHP Intelephense + "dbaeumer.vscode-eslint", // ESLint + "esbenp.prettier-vscode", // Prettier - Code formatter + "obliviousharmony.vscode-php-codesniffer" // PHP_CodeSniffer + ] +} diff --git a/.vscode/settings.dist.jsonc b/.vscode/settings.dist.jsonc index 5e14562fb29b5..ebe28cdd6b8fe 100644 --- a/.vscode/settings.dist.jsonc +++ b/.vscode/settings.dist.jsonc @@ -37,6 +37,16 @@ "**/jetpack_vendor/**", "**/vendor/**" ], + // Custom settings for PHP files. + "[php]": { + // Ensure that PHP files are formatted with PHPCS. + "editor.formatOnSave": true, + "editor.defaultFormatter": "obliviousharmony.vscode-php-codesniffer" + }, + // Run Code Actions for the editor. + "editor.codeActionsOnSave": { + "source.fixAll": "explicit" + }, // Use this wp-prettier from this path. "prettier.prettierPath": "tools/js-tools/node_modules/prettier/index.cjs" } diff --git a/composer.json b/composer.json index ba10cc928cda0..2d5f3a9e63855 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "php-stubs/wordpress-stubs": ">=6.5", "php-stubs/wordpress-tests-stubs": ">=6.5", "php-stubs/wp-cli-stubs": "^2.10", - "sirbrillig/phpcs-changed": "2.11.4", + "sirbrillig/phpcs-changed": "^2.11.5", "squizlabs/php_codesniffer": "^3.6.2" }, "scripts": { diff --git a/composer.lock b/composer.lock index 2a15d22e878bc..9984862038b01 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "700fde8d8373ed5610bfc08d87e10fc2", + "content-hash": "c9fc8342729e916410c963d050a22782", "packages": [], "packages-dev": [ { @@ -13,14 +13,14 @@ "dist": { "type": "path", "url": "projects/packages/ignorefile", - "reference": "8bec1af06b593110bf4aeca06b05c1ba1841960c" + "reference": "7c4c4f2d0cf54ddfdccfc65095777552daa9f85d" }, "require": { "php": ">=7.0" }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "type": "library", "extra": { @@ -30,7 +30,7 @@ }, "autotagger": true, "branch-alias": { - "dev-trunk": "2.1.x-dev" + "dev-trunk": "2.0.x-dev" } }, "autoload": { @@ -60,7 +60,7 @@ "dist": { "type": "path", "url": "projects/packages/codesniffer", - "reference": "a717fa4e4939a9aa751bc7601a1ca2d5ece799c7" + "reference": "063d36d1b969cf188a2a0a4c363c0ae2d09011c8" }, "require": { "automattic/vipwpcs": "^3.0", @@ -73,7 +73,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "type": "phpcodesniffer-standard", "extra": { @@ -83,7 +83,7 @@ "link-template": "https://github.com/Automattic/jetpack-codesniffer/compare/v${old}...v${new}" }, "branch-alias": { - "dev-trunk": "4.0.x-dev" + "dev-trunk": "3.0.x-dev" } }, "autoload": { @@ -124,7 +124,7 @@ "dist": { "type": "path", "url": "projects/packages/phan-plugins", - "reference": "17f7a7b60e88906fb6efe77474cebf2214ba6b53" + "reference": "d7a0268045b235a3158435f2b83179d7fecada39" }, "require": { "phan/phan": "^5.4", @@ -132,7 +132,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "type": "library", "extra": { @@ -178,7 +178,7 @@ "dist": { "type": "path", "url": "projects/packages/phpcs-filter", - "reference": "f1db07c15d87025728fe8c7ceffed4a2dea848b4" + "reference": "8eec63259d8259729921c7ce48393890cb9babdd" }, "require": { "automattic/ignorefile": "@dev", @@ -187,7 +187,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "type": "library", "extra": { @@ -1969,16 +1969,16 @@ }, { "name": "sirbrillig/phpcs-changed", - "version": "v2.11.4", + "version": "v2.11.5", "source": { "type": "git", "url": "https://github.com/sirbrillig/phpcs-changed.git", - "reference": "acc946731ec65053e49cb0d3185c8ffe74895f93" + "reference": "aaa144eb4f14697b6b06e3dcf74081b5a02f85f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sirbrillig/phpcs-changed/zipball/acc946731ec65053e49cb0d3185c8ffe74895f93", - "reference": "acc946731ec65053e49cb0d3185c8ffe74895f93", + "url": "https://api.github.com/repos/sirbrillig/phpcs-changed/zipball/aaa144eb4f14697b6b06e3dcf74081b5a02f85f6", + "reference": "aaa144eb4f14697b6b06e3dcf74081b5a02f85f6", "shasum": "" }, "require": { @@ -2017,9 +2017,9 @@ "description": "Run phpcs on files, but only report warnings/errors from lines which were changed.", "support": { "issues": "https://github.com/sirbrillig/phpcs-changed/issues", - "source": "https://github.com/sirbrillig/phpcs-changed/tree/v2.11.4" + "source": "https://github.com/sirbrillig/phpcs-changed/tree/v2.11.5" }, - "time": "2023-09-29T21:27:51+00:00" + "time": "2024-05-23T20:01:41+00:00" }, { "name": "sirbrillig/phpcs-variable-analysis", diff --git a/docs/development-environment.md b/docs/development-environment.md index 4ec862476f509..79a541d12811c 100644 --- a/docs/development-environment.md +++ b/docs/development-environment.md @@ -164,7 +164,7 @@ If you're ready to start, you should see all green `SUCCESS` messages. If the sc Once you're all set here, you can continue developing. If you're setting up an local environment and want to start testing immediately, please ensure you build the projects you need. -`jetpack build` will provide prompts to determine the project you need or you can pass it a complete command, like `jetpack build plugins/jetpack --with-deps` +`jetpack build` will provide prompts to determine the project you need or you can pass it a complete command, like `jetpack build plugins/jetpack --deps` ### Testing Jetpack cloud features diff --git a/docs/quick-start.md b/docs/quick-start.md index 281da4710e742..4983dfd9db3dd 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -102,7 +102,7 @@ Note: This is for Automattician use only. For other methods, check out [ngrok](. Once you have a local copy of Jetpack and all development tools installed, you can start developing. 1. Make sure the plugin you're developing is activated on your WordPress site. -2. [Build your project](#building-your-project) using `jetpack build [type/project]`, such as `jetpack build plugins/jetpack` +2. [Build your project](development-environment.md#building-your-project) using `jetpack build [type/project]` and including its dependencies, such as `jetpack build plugins/jetpack --deps` 3. Access the plugin's dashboard in your browser. By default the development build above will run once and if you change any of the files, you need to run `jetpack build` again to see the changes on the site. If you want to avoid that, you can run a continuous build that will rebuild anytime it sees any changes on your local filesystem. To run it, use: diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 96995a9007a03..4066146279aaf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,7 +4,7 @@ settings: autoInstallPeers: false excludeLinksFromLockfile: false -pnpmfileChecksum: hogs2xjgnkyiea7znn3abfx4o4 +pnpmfileChecksum: 3fczoaai2pdpha422df6rcexqm importers: @@ -273,11 +273,11 @@ importers: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/js-packages/components: dependencies: @@ -415,11 +415,11 @@ importers: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/js-packages/config: devDependencies: @@ -594,11 +594,11 @@ importers: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0 + specifier: 5.94.0 + version: 5.94.0 webpack-dev-middleware: specifier: 5.3.4 - version: 5.3.4(webpack@5.76.0) + version: 5.3.4(webpack@5.94.0) projects/js-packages/eslint-changed: dependencies: @@ -619,8 +619,8 @@ importers: projects/js-packages/eslint-config-target-es: dependencies: '@mdn/browser-compat-data': - specifier: 5.5.33 - version: 5.5.33 + specifier: 5.5.47 + version: 5.5.47 browserslist: specifier: ^4.17.6 version: 4.23.1 @@ -638,8 +638,8 @@ importers: specifier: 8.57.0 version: 8.57.0 eslint-plugin-es-x: - specifier: 7.7.0 - version: 7.7.0(eslint@8.57.0) + specifier: 7.8.0 + version: 7.8.0(eslint@8.57.0) globals: specifier: 15.4.0 version: 15.4.0 @@ -663,11 +663,11 @@ importers: specifier: 29.7.0 version: 29.7.0 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/js-packages/i18n-loader-webpack-plugin: dependencies: @@ -677,7 +677,7 @@ importers: devDependencies: '@wordpress/dependency-extraction-webpack-plugin': specifier: 6.5.0 - version: 6.5.0(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.5.0(webpack@5.94.0(webpack-cli@4.9.1)) '@wordpress/i18n': specifier: 5.5.0 version: 5.5.0 @@ -685,11 +685,11 @@ importers: specifier: 29.7.0 version: 29.7.0 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/js-packages/idc: dependencies: @@ -818,11 +818,11 @@ importers: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/js-packages/licensing: dependencies: @@ -1005,6 +1005,9 @@ importers: '@wordpress/data': specifier: 10.5.0 version: 10.5.0(react@18.3.1) + '@wordpress/date': + specifier: 5.5.0 + version: 5.5.0 '@wordpress/edit-post': specifier: 8.5.0 version: 8.5.0(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1127,11 +1130,11 @@ importers: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) zod: specifier: 3.22.3 version: 3.22.3 @@ -1146,11 +1149,11 @@ importers: specifier: 29.7.0 version: 29.7.0 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/js-packages/scan: dependencies: @@ -1402,7 +1405,7 @@ importers: version: 8.2.9(storybook@8.2.9) '@storybook/addon-webpack5-compiler-babel': specifier: ^3.0.3 - version: 3.0.3(webpack@5.76.0(webpack-cli@4.9.1)) + version: 3.0.3(webpack@5.94.0(webpack-cli@4.9.1)) '@storybook/blocks': specifier: 8.2.9 version: 8.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.9) @@ -1417,7 +1420,7 @@ importers: version: 8.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.9)(typescript@5.0.4) '@storybook/react-webpack5': specifier: 8.2.9 - version: 8.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.9)(typescript@5.0.4)(webpack-cli@4.9.1(webpack@5.76.0)) + version: 8.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.9)(typescript@5.0.4)(webpack-cli@4.9.1(webpack@5.94.0)) '@storybook/source-loader': specifier: 8.2.9 version: 8.2.9(storybook@8.2.9) @@ -1456,16 +1459,16 @@ importers: version: 2.9.2 babel-loader: specifier: 9.1.2 - version: 9.1.2(@babel/core@7.24.7)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 9.1.2(@babel/core@7.24.7)(webpack@5.94.0(webpack-cli@4.9.1)) babel-plugin-inline-json-import: specifier: 0.3.2 version: 0.3.2 css-loader: specifier: 6.5.1 - version: 6.5.1(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.5.1(webpack@5.94.0(webpack-cli@4.9.1)) esbuild-loader: specifier: 3.0.1 - version: 3.0.1(webpack@5.76.0(webpack-cli@4.9.1)) + version: 3.0.1(webpack@5.94.0(webpack-cli@4.9.1)) jest: specifier: 29.7.0 version: 29.7.0 @@ -1477,7 +1480,7 @@ importers: version: 8.4.31 postcss-loader: specifier: 6.2.0 - version: 6.2.0(postcss@8.4.31)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.2.0(postcss@8.4.31)(webpack@5.94.0(webpack-cli@4.9.1)) react: specifier: 18.3.1 version: 18.3.1 @@ -1495,7 +1498,7 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) storybook: specifier: 8.2.9 version: 8.2.9 @@ -1504,7 +1507,7 @@ importers: version: 5.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) style-loader: specifier: 2.0.0 - version: 2.0.0(webpack@5.76.0(webpack-cli@4.9.1)) + version: 2.0.0(webpack@5.94.0(webpack-cli@4.9.1)) ts-dedent: specifier: 2.2.0 version: 2.2.0 @@ -1512,11 +1515,11 @@ importers: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/js-packages/svelte-data-sync-client: devDependencies: @@ -1542,11 +1545,11 @@ importers: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) zod: specifier: 3.22.3 version: 3.22.3 @@ -1575,11 +1578,11 @@ importers: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/js-packages/webpack-config: dependencies: @@ -1597,7 +1600,7 @@ importers: version: link:../i18n-loader-webpack-plugin '@automattic/webpack-rtl-plugin': specifier: 6.0.0 - version: 6.0.0(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.0.0(webpack@5.94.0(webpack-cli@4.9.1)) '@babel/compat-data': specifier: 7.24.7 version: 7.24.7 @@ -1618,37 +1621,37 @@ importers: version: 7.24.7(@babel/core@7.24.7) '@cerner/duplicate-package-checker-webpack-plugin': specifier: 2.3.0 - version: 2.3.0(webpack@5.76.0(webpack-cli@4.9.1)) + version: 2.3.0(webpack@5.94.0(webpack-cli@4.9.1)) '@wordpress/browserslist-config': specifier: 6.5.0 version: 6.5.0 '@wordpress/dependency-extraction-webpack-plugin': specifier: 6.5.0 - version: 6.5.0(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.5.0(webpack@5.94.0(webpack-cli@4.9.1)) babel-loader: specifier: 9.1.2 - version: 9.1.2(@babel/core@7.24.7)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 9.1.2(@babel/core@7.24.7)(webpack@5.94.0(webpack-cli@4.9.1)) browserslist: specifier: 4.23.1 version: 4.23.1 css-loader: specifier: 6.5.1 - version: 6.5.1(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.5.1(webpack@5.94.0(webpack-cli@4.9.1)) css-minimizer-webpack-plugin: specifier: 5.0.1 - version: 5.0.1(webpack@5.76.0(webpack-cli@4.9.1)) + version: 5.0.1(webpack@5.94.0(webpack-cli@4.9.1)) fork-ts-checker-webpack-plugin: specifier: 9.0.2 - version: 9.0.2(typescript@5.0.4)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 9.0.2(typescript@5.0.4)(webpack@5.94.0(webpack-cli@4.9.1)) mini-css-extract-plugin: specifier: 2.4.5 - version: 2.4.5(webpack@5.76.0(webpack-cli@4.9.1)) + version: 2.4.5(webpack@5.94.0(webpack-cli@4.9.1)) terser-webpack-plugin: specifier: 5.3.3 - version: 5.3.3(webpack@5.76.0(webpack-cli@4.9.1)) + version: 5.3.3(webpack@5.94.0(webpack-cli@4.9.1)) thread-loader: specifier: 3.0.4 - version: 3.0.4(webpack@5.76.0(webpack-cli@4.9.1)) + version: 3.0.4(webpack@5.94.0(webpack-cli@4.9.1)) devDependencies: '@babel/core': specifier: 7.24.7 @@ -1660,11 +1663,11 @@ importers: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/admin-ui: {} @@ -1690,11 +1693,11 @@ importers: specifier: 1.8.2 version: 1.8.2 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/backup: dependencies: @@ -1782,13 +1785,13 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/blaze: dependencies: @@ -1852,13 +1855,13 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/boost-core: {} @@ -1882,13 +1885,13 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/chatbot: {} @@ -1911,7 +1914,7 @@ importers: version: 6.5.0 '@wordpress/dependency-extraction-webpack-plugin': specifier: 6.5.0 - version: 6.5.0(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.5.0(webpack@5.94.0(webpack-cli@4.9.1)) autoprefixer: specifier: 10.4.14 version: 10.4.14(postcss@8.4.31) @@ -1926,19 +1929,19 @@ importers: version: 8.4.31 postcss-loader: specifier: 6.2.0 - version: 6.2.0(postcss@8.4.31)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.2.0(postcss@8.4.31)(webpack@5.94.0(webpack-cli@4.9.1)) sass: specifier: 1.64.1 version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/connection: dependencies: @@ -1981,13 +1984,13 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/explat: dependencies: @@ -2032,11 +2035,11 @@ importers: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/forms: dependencies: @@ -2081,7 +2084,7 @@ importers: version: 2.1.1 copy-webpack-plugin: specifier: 11.0.0 - version: 11.0.0(webpack@5.76.0(webpack-cli@4.9.1)) + version: 11.0.0(webpack@5.94.0(webpack-cli@4.9.1)) email-validator: specifier: 2.0.4 version: 2.0.4 @@ -2113,11 +2116,11 @@ importers: specifier: 7.5.2 version: 7.5.2 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) optionalDependencies: react: specifier: 18.3.1 @@ -2185,10 +2188,10 @@ importers: version: 8.4.31 postcss-loader: specifier: 6.2.0 - version: 6.2.0(postcss@8.4.31)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.2.0(postcss@8.4.31)(webpack@5.94.0(webpack-cli@4.9.1)) sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) typescript: specifier: 5.0.4 version: 5.0.4 @@ -2338,16 +2341,16 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) typescript: specifier: ^5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/jitm: devDependencies: @@ -2362,13 +2365,13 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/masterbar: dependencies: @@ -2399,7 +2402,7 @@ importers: version: 6.5.0 '@wordpress/dependency-extraction-webpack-plugin': specifier: 6.5.0 - version: 6.5.0(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.5.0(webpack@5.94.0(webpack-cli@4.9.1)) autoprefixer: specifier: 10.4.14 version: 10.4.14(postcss@8.4.31) @@ -2414,19 +2417,19 @@ importers: version: 8.4.31 postcss-loader: specifier: 6.2.0 - version: 6.2.0(postcss@8.4.31)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.2.0(postcss@8.4.31)(webpack@5.94.0(webpack-cli@4.9.1)) sass: specifier: 1.64.1 version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/my-jetpack: dependencies: @@ -2556,7 +2559,7 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) storybook: specifier: 8.2.9 version: 8.2.9(@babel/preset-env@7.24.7(@babel/core@7.24.7)) @@ -2564,11 +2567,11 @@ importers: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/plans: {} @@ -2582,7 +2585,7 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) tslib: specifier: 2.5.0 version: 2.5.0 @@ -2590,11 +2593,11 @@ importers: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/protect-models: {} @@ -2616,11 +2619,11 @@ importers: specifier: 7.6.0 version: 7.6.0 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/search: dependencies: @@ -2756,7 +2759,7 @@ importers: version: 6.5.0 '@wordpress/dependency-extraction-webpack-plugin': specifier: 6.5.0 - version: 6.5.0(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.5.0(webpack@5.94.0(webpack-cli@4.9.1)) autoprefixer: specifier: 10.4.14 version: 10.4.14(postcss@8.4.31) @@ -2783,7 +2786,7 @@ importers: version: 12.1.7(postcss@8.4.31) postcss-loader: specifier: 6.2.0 - version: 6.2.0(postcss@8.4.31)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.2.0(postcss@8.4.31)(webpack@5.94.0(webpack-cli@4.9.1)) prettier: specifier: npm:wp-prettier@3.0.3 version: wp-prettier@3.0.3 @@ -2792,16 +2795,16 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) size-limit: specifier: 11.1.4 version: 11.1.4(@size-limit/preset-app@11.1.4) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/stats-admin: {} @@ -2953,7 +2956,7 @@ importers: version: 10.4.14(postcss@8.4.31) copy-webpack-plugin: specifier: 11.0.0 - version: 11.0.0(webpack@5.76.0(webpack-cli@4.9.1)) + version: 11.0.0(webpack@5.94.0(webpack-cli@4.9.1)) jest: specifier: 29.7.0 version: 29.7.0 @@ -2968,7 +2971,7 @@ importers: version: 12.1.7(postcss@8.4.31) postcss-loader: specifier: 6.2.0 - version: 6.2.0(postcss@8.4.31)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.2.0(postcss@8.4.31)(webpack@5.94.0(webpack-cli@4.9.1)) require-from-string: specifier: 2.0.2 version: 2.0.2 @@ -2977,7 +2980,7 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) storybook: specifier: 8.2.9 version: 8.2.9 @@ -2985,11 +2988,11 @@ importers: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/wordads: dependencies: @@ -3113,7 +3116,7 @@ importers: version: 6.5.0 '@wordpress/dependency-extraction-webpack-plugin': specifier: 6.5.0 - version: 6.5.0(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.5.0(webpack@5.94.0(webpack-cli@4.9.1)) babel-jest: specifier: 29.4.3 version: 29.4.3(@babel/core@7.24.7) @@ -3137,13 +3140,13 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/packages/wp-js-data-sync: {} @@ -3203,13 +3206,13 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/plugins/automattic-for-agencies-client: dependencies: @@ -3288,13 +3291,13 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/plugins/automattic-for-agencies-client/tests/e2e: devDependencies: @@ -3345,7 +3348,7 @@ importers: version: 2.1.1 copy-webpack-plugin: specifier: 11.0.0 - version: 11.0.0(webpack@5.76.0(webpack-cli@4.9.1)) + version: 11.0.0(webpack@5.94.0(webpack-cli@4.9.1)) history: specifier: 5.3.0 version: 5.3.0 @@ -3433,7 +3436,7 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) storybook: specifier: 8.2.9 version: 8.2.9(@babel/preset-env@7.24.7(@babel/core@7.24.7)) @@ -3444,11 +3447,11 @@ importers: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/plugins/boost/tests/e2e: devDependencies: @@ -3533,13 +3536,13 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/plugins/classic-theme-helper-plugin/tests/e2e: devDependencies: @@ -3642,7 +3645,7 @@ importers: version: 29.3.1(@babel/core@7.24.7) css-loader: specifier: 6.5.1 - version: 6.5.1(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.5.1(webpack@5.94.0(webpack-cli@4.9.1)) glob: specifier: 10.4.1 version: 10.4.1 @@ -3657,16 +3660,16 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) typescript: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/plugins/inspect: dependencies: @@ -3853,7 +3856,7 @@ importers: version: 0.4.1 copy-webpack-plugin: specifier: 11.0.0 - version: 11.0.0(webpack@5.76.0(webpack-cli@4.9.1)) + version: 11.0.0(webpack@5.94.0(webpack-cli@4.9.1)) crypto-js: specifier: 4.2.0 version: 4.2.0 @@ -3936,11 +3939,11 @@ importers: specifier: 2.3.0 version: 2.3.0 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) optionalDependencies: react: specifier: 18.3.1 @@ -4071,13 +4074,13 @@ importers: version: 8.4.31 postcss-loader: specifier: 6.2.0 - version: 6.2.0(postcss@8.4.31)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.2.0(postcss@8.4.31)(webpack@5.94.0(webpack-cli@4.9.1)) regenerator-runtime: specifier: 0.13.9 version: 0.13.9 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) typescript: specifier: 5.0.4 version: 5.0.4 @@ -4165,13 +4168,13 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/plugins/migration/tests/e2e: devDependencies: @@ -4279,16 +4282,16 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) typescript: specifier: 5.0.4 version: 5.0.4 webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/plugins/search: {} @@ -4417,19 +4420,19 @@ importers: version: 12.1.7(postcss@8.4.31) postcss-loader: specifier: 6.2.0 - version: 6.2.0(postcss@8.4.31)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 6.2.0(postcss@8.4.31)(webpack@5.94.0(webpack-cli@4.9.1)) sass: specifier: 1.64.1 version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/plugins/social/tests/e2e: devDependencies: @@ -4514,13 +4517,13 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/plugins/starter-plugin/tests/e2e: devDependencies: @@ -4619,13 +4622,13 @@ importers: version: 1.64.1 sass-loader: specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)) + version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) webpack: - specifier: 5.76.0 - version: 5.76.0(webpack-cli@4.9.1) + specifier: 5.94.0 + version: 5.94.0(webpack-cli@4.9.1) webpack-cli: specifier: 4.9.1 - version: 4.9.1(webpack@5.76.0) + version: 4.9.1(webpack@5.94.0) projects/plugins/videopress/tests/e2e: devDependencies: @@ -4827,7 +4830,7 @@ importers: version: 6.21.0(eslint@8.57.0)(typescript@5.0.4) '@wordpress/eslint-plugin': specifier: 20.2.0 - version: 20.2.0(mikchdjuqfweuug63xtkjtmioa) + version: 20.2.0(2g4wiqq3ubewvaaot6et2pay5m) '@wordpress/jest-console': specifier: 8.5.0 version: 8.5.0(jest@29.7.0) @@ -4853,8 +4856,8 @@ importers: specifier: 1.0.0-beta.5 version: 1.0.0-beta.5(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.0.4))(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-es-x: - specifier: 7.7.0 - version: 7.7.0(eslint@8.57.0) + specifier: 7.8.0 + version: 7.8.0(eslint@8.57.0) eslint-plugin-import: specifier: 2.29.1 version: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.0.4))(eslint@8.57.0) @@ -4865,11 +4868,11 @@ importers: specifier: 5.4.0 version: 5.4.0(eslint@8.57.0) eslint-plugin-jsdoc: - specifier: 46.10.1 - version: 46.10.1(eslint@8.57.0) + specifier: 48.8.3 + version: 48.8.3(eslint@8.57.0) eslint-plugin-jsx-a11y: - specifier: 6.8.0 - version: 6.8.0(eslint@8.57.0) + specifier: 6.9.0 + version: 6.9.0(eslint@8.57.0) eslint-plugin-lodash: specifier: 7.4.0 version: 7.4.0(eslint@8.57.0) @@ -4877,20 +4880,20 @@ importers: specifier: 0.22.2 version: 0.22.2(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.0.4))(eslint@8.57.0)(typescript@5.0.4))(eslint@8.57.0)(jest@29.7.0)(typescript@5.0.4))(eslint@8.57.0) eslint-plugin-prettier: - specifier: 5.1.3 - version: 5.1.3(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(wp-prettier@3.0.3) + specifier: 5.2.1 + version: 5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(wp-prettier@3.0.3) eslint-plugin-react: - specifier: 7.34.2 - version: 7.34.2(eslint@8.57.0) + specifier: 7.35.0 + version: 7.35.0(eslint@8.57.0) eslint-plugin-react-hooks: specifier: 4.6.2 version: 4.6.2(eslint@8.57.0) eslint-plugin-svelte: - specifier: 2.41.0 - version: 2.41.0(eslint@8.57.0)(svelte@4.2.18) + specifier: 2.43.0 + version: 2.43.0(eslint@8.57.0)(svelte@4.2.18) eslint-plugin-testing-library: - specifier: 6.2.2 - version: 6.2.2(eslint@8.57.0)(typescript@5.0.4) + specifier: 6.3.0 + version: 6.3.0(eslint@8.57.0)(typescript@5.0.4) glob: specifier: 10.4.1 version: 10.4.1 @@ -5787,8 +5790,8 @@ packages: '@emotion/weak-memoize@0.4.0': resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} - '@es-joy/jsdoccomment@0.41.0': - resolution: {integrity: sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==} + '@es-joy/jsdoccomment@0.46.0': + resolution: {integrity: sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==} engines: {node: '>=16'} '@esbuild/aix-ppc64@0.21.5': @@ -6256,8 +6259,8 @@ packages: resolution: {integrity: sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==} engines: {node: '>=6.0.0'} - '@mdn/browser-compat-data@5.5.33': - resolution: {integrity: sha512-uO4uIBFn9D4UNyUmaueIWnE/IJhBlSJ7W1rANvDdaawhTX8CSgqUX8tj9/6a+1WjpL9Bgirf67d//S2VwDsfig==} + '@mdn/browser-compat-data@5.5.47': + resolution: {integrity: sha512-M/lmqoDgbKz0LP9K5mjqzNWpbTDmgBeGsh5A+o9KcJuI3KbJ/PCiXFs7XKR1nabQxwYtcHpl9Bn0OGUnijcXiw==} '@mdx-js/react@3.0.1': resolution: {integrity: sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==} @@ -7324,12 +7327,6 @@ packages: '@types/escodegen@0.0.6': resolution: {integrity: sha512-AjwI4MvWx3HAOaZqYsjKWyEObT9lcVV0Y0V8nXo6cXzN8ZiMxVhf6F3d/UNvXVGKrEzL/Dluc5p+y9GkzlTWig==} - '@types/eslint-scope@3.7.7': - resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} - - '@types/eslint@9.6.0': - resolution: {integrity: sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==} - '@types/estree@0.0.39': resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} @@ -7637,50 +7634,50 @@ packages: resolution: {integrity: sha512-S4cL7Taa9yb5qbv+6wLgiKVZ03Qfkc4jGRuiUQMQ8HGBD5pcNRnHeYM33zBvJE4/zJGjJJ8GScB+WmTsn9mORw==} hasBin: true - '@webassemblyjs/ast@1.11.1': - resolution: {integrity: sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==} + '@webassemblyjs/ast@1.12.1': + resolution: {integrity: sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==} - '@webassemblyjs/floating-point-hex-parser@1.11.1': - resolution: {integrity: sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==} + '@webassemblyjs/floating-point-hex-parser@1.11.6': + resolution: {integrity: sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==} - '@webassemblyjs/helper-api-error@1.11.1': - resolution: {integrity: sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==} + '@webassemblyjs/helper-api-error@1.11.6': + resolution: {integrity: sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==} - '@webassemblyjs/helper-buffer@1.11.1': - resolution: {integrity: sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==} + '@webassemblyjs/helper-buffer@1.12.1': + resolution: {integrity: sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==} - '@webassemblyjs/helper-numbers@1.11.1': - resolution: {integrity: sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==} + '@webassemblyjs/helper-numbers@1.11.6': + resolution: {integrity: sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==} - '@webassemblyjs/helper-wasm-bytecode@1.11.1': - resolution: {integrity: sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==} + '@webassemblyjs/helper-wasm-bytecode@1.11.6': + resolution: {integrity: sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==} - '@webassemblyjs/helper-wasm-section@1.11.1': - resolution: {integrity: sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==} + '@webassemblyjs/helper-wasm-section@1.12.1': + resolution: {integrity: sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==} - '@webassemblyjs/ieee754@1.11.1': - resolution: {integrity: sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==} + '@webassemblyjs/ieee754@1.11.6': + resolution: {integrity: sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==} - '@webassemblyjs/leb128@1.11.1': - resolution: {integrity: sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==} + '@webassemblyjs/leb128@1.11.6': + resolution: {integrity: sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==} - '@webassemblyjs/utf8@1.11.1': - resolution: {integrity: sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==} + '@webassemblyjs/utf8@1.11.6': + resolution: {integrity: sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==} - '@webassemblyjs/wasm-edit@1.11.1': - resolution: {integrity: sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==} + '@webassemblyjs/wasm-edit@1.12.1': + resolution: {integrity: sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==} - '@webassemblyjs/wasm-gen@1.11.1': - resolution: {integrity: sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==} + '@webassemblyjs/wasm-gen@1.12.1': + resolution: {integrity: sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==} - '@webassemblyjs/wasm-opt@1.11.1': - resolution: {integrity: sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==} + '@webassemblyjs/wasm-opt@1.12.1': + resolution: {integrity: sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==} - '@webassemblyjs/wasm-parser@1.11.1': - resolution: {integrity: sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==} + '@webassemblyjs/wasm-parser@1.12.1': + resolution: {integrity: sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==} - '@webassemblyjs/wast-printer@1.11.1': - resolution: {integrity: sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==} + '@webassemblyjs/wast-printer@1.12.1': + resolution: {integrity: sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==} '@webpack-cli/configtest@1.2.0': resolution: {integrity: sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==} @@ -8115,8 +8112,8 @@ packages: acorn-globals@7.0.1: resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} - acorn-import-assertions@1.9.0: - resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: acorn: ^8 @@ -8317,9 +8314,6 @@ packages: resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} engines: {node: '>= 0.4'} - array.prototype.toreversed@1.1.2: - resolution: {integrity: sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==} - array.prototype.tosorted@1.1.4: resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} engines: {node: '>= 0.4'} @@ -8363,16 +8357,11 @@ packages: resolution: {integrity: sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==} engines: {node: '>=4'} - axe-core@4.7.0: - resolution: {integrity: sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==} - engines: {node: '>=4'} - axios@1.7.4: resolution: {integrity: sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==} - axobject-query@3.2.4: - resolution: {integrity: sha512-aPTElBrbifBU1krmZxGZOlBkslORe7Ll7+BDnI50Wy4LgOt69luMgevkDfTq1O/ZgprooPCtWpjCwKSZw/iZ4A==} - engines: {node: '>= 0.4'} + axobject-query@3.1.1: + resolution: {integrity: sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==} axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} @@ -9481,9 +9470,6 @@ packages: resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} engines: {node: '>= 0.4'} - es-module-lexer@0.9.3: - resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==} - es-module-lexer@1.5.4: resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==} @@ -9595,8 +9581,8 @@ packages: eslint-import-resolver-webpack: optional: true - eslint-plugin-es-x@7.7.0: - resolution: {integrity: sha512-aP3qj8BwiEDPttxQkZdI221DLKq9sI/qHolE2YSQL1/9+xk7dTV+tB1Fz8/IaCA+lnLA1bDEnvaS2LKs0k2Uig==} + eslint-plugin-es-x@7.8.0: + resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '>=8' @@ -9634,14 +9620,14 @@ packages: jest: optional: true - eslint-plugin-jsdoc@46.10.1: - resolution: {integrity: sha512-x8wxIpv00Y50NyweDUpa+58ffgSAI5sqe+zcZh33xphD0AVh+1kqr1ombaTRb7Fhpove1zfUuujlX9DWWBP5ag==} - engines: {node: '>=16'} + eslint-plugin-jsdoc@48.8.3: + resolution: {integrity: sha512-AtIvwwW9D17MRkM0Z0y3/xZYaa9mdAvJrkY6fU/HNUwGbmMtHVvK4qRM9CDixGVtfNrQitb8c6zQtdh6cTOvLg==} + engines: {node: '>=18'} peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - eslint-plugin-jsx-a11y@6.8.0: - resolution: {integrity: sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==} + eslint-plugin-jsx-a11y@6.9.0: + resolution: {integrity: sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==} engines: {node: '>=4.0'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 @@ -9661,8 +9647,8 @@ packages: eslint-plugin-jest: optional: true - eslint-plugin-prettier@5.1.3: - resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} + eslint-plugin-prettier@5.2.1: + resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: '@types/eslint': '>=8.0.0' @@ -9681,24 +9667,24 @@ packages: peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - eslint-plugin-react@7.34.2: - resolution: {integrity: sha512-2HCmrU+/JNigDN6tg55cRDKCQWicYAPB38JGSFDQt95jDm8rrvSUo7YPkOIm5l6ts1j1zCvysNcasvfTMQzUOw==} + eslint-plugin-react@7.35.0: + resolution: {integrity: sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA==} engines: {node: '>=4'} peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - eslint-plugin-svelte@2.41.0: - resolution: {integrity: sha512-gjU9Q/psxbWG1VNwYbEb0Q6U4W5PBGaDpYmO2zlQ+zlAMVS3Qt0luAK0ACi/tMSwRK6JENiySvMyJbO0YWmXSg==} + eslint-plugin-svelte@2.43.0: + resolution: {integrity: sha512-REkxQWvg2pp7QVLxQNa+dJ97xUqRe7Y2JJbSWkHSuszu0VcblZtXkPBPckkivk99y5CdLw4slqfPylL2d/X4jQ==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0-0 || ^9.0.0-0 - svelte: ^3.37.0 || ^4.0.0 || ^5.0.0-next.155 + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0-next.191 peerDependenciesMeta: svelte: optional: true - eslint-plugin-testing-library@6.2.2: - resolution: {integrity: sha512-1E94YOTUDnOjSLyvOwmbVDzQi/WkKm3WVrMXu6SmBr6DN95xTGZmI6HJ/eOkSXh/DlheRsxaPsJvZByDBhWLVQ==} + eslint-plugin-testing-library@6.3.0: + resolution: {integrity: sha512-GYcEErTt6EGwE0bPDY+4aehfEBpB2gDBFKohir8jlATSUvzStEyzCx8QWB/14xeKc/AwyXkzScSzMHnFojkWrA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0, npm: '>=6'} peerDependencies: eslint: ^7.5.0 || ^8.0.0 @@ -11796,10 +11782,6 @@ packages: resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} engines: {node: '>= 0.4'} - object.hasown@1.1.4: - resolution: {integrity: sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==} - engines: {node: '>= 0.4'} - object.values@1.2.0: resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} engines: {node: '>= 0.4'} @@ -11932,6 +11914,10 @@ packages: parse-diff@0.8.1: resolution: {integrity: sha512-0QG0HqwXCC/zMohOlaxkQmV1igZq1LQ6xsv/ziex6TDbY0GFxr3TDJN+/aHjWH3s2WTysSW3Bhs9Yfh6DOelFA==} + parse-imports@2.1.1: + resolution: {integrity: sha512-TDT4HqzUiTMO1wJRwg/t/hYk8Wdp3iF/ToMIlAoVQfL1Xs/sTxq1dKWSMjMbQmIarfWKymOyly40+zmPHXMqCA==} + engines: {node: '>= 18'} + parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -13178,6 +13164,9 @@ packages: resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} engines: {node: '>=14.16'} + slashes@3.0.12: + resolution: {integrity: sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==} + slice-ansi@0.0.4: resolution: {integrity: sha512-up04hB2hR92PgjpyU3y/eg91yIBILyjVY26NvvciY3EVVPjybkMszMpXQ9QAkcS3I5rtJBDLoTxxg+qvW8c7rw==} engines: {node: '>=0.10.0'} @@ -13333,10 +13322,16 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string.prototype.includes@2.0.0: + resolution: {integrity: sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==} + string.prototype.matchall@4.0.11: resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} engines: {node: '>= 0.4'} + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + string.prototype.trim@1.2.9: resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} engines: {node: '>= 0.4'} @@ -13458,6 +13453,15 @@ packages: svelte: optional: true + svelte-eslint-parser@0.41.0: + resolution: {integrity: sha512-L6f4hOL+AbgfBIB52Z310pg1d2QjRqm7wy3kI1W6hhdhX5bvu7+f0R6w4ykp5HoDdzq+vGhIJmsisaiJDGmVfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + svelte: ^3.37.0 || ^4.0.0 || ^5.0.0-next.191 + peerDependenciesMeta: + svelte: + optional: true + svelte-preprocess@6.0.2: resolution: {integrity: sha512-OvDTLfaOkkhjprbDKO0SOCkjNYuHy16dbD4SpqbIi6QiabOMHxRT4km5/dzbFFkmW1L0E2INF3MFltG2pgOyKQ==} engines: {node: '>= 18.0.0'} @@ -13542,8 +13546,8 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - synckit@0.8.8: - resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} + synckit@0.9.1: + resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} engines: {node: ^14.18.0 || >=16.0.0} tabbable@5.3.3: @@ -13584,6 +13588,22 @@ packages: resolution: {integrity: sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==} engines: {node: '>=14.16'} + terser-webpack-plugin@5.3.10: + resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + terser-webpack-plugin@5.3.3: resolution: {integrity: sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ==} engines: {node: '>= 10.13.0'} @@ -14114,8 +14134,8 @@ packages: webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - webpack@5.76.0: - resolution: {integrity: sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==} + webpack@5.94.0: + resolution: {integrity: sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==} engines: {node: '>=10.13.0'} hasBin: true peerDependencies: @@ -14518,10 +14538,10 @@ snapshots: '@automattic/viewport@1.0.0': {} - '@automattic/webpack-rtl-plugin@6.0.0(webpack@5.76.0(webpack-cli@4.9.1))': + '@automattic/webpack-rtl-plugin@6.0.0(webpack@5.94.0(webpack-cli@4.9.1))': dependencies: rtlcss: 3.5.0 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) '@babel/code-frame@7.24.7': dependencies: @@ -15415,13 +15435,13 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} - '@cerner/duplicate-package-checker-webpack-plugin@2.3.0(webpack@5.76.0(webpack-cli@4.9.1))': + '@cerner/duplicate-package-checker-webpack-plugin@2.3.0(webpack@5.94.0(webpack-cli@4.9.1))': dependencies: chalk: 4.1.2 find-root: 1.1.0 lodash.groupby: 4.6.0 semver: 7.5.2 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) '@colors/colors@1.6.0': {} @@ -15557,7 +15577,7 @@ snapshots: '@emotion/weak-memoize@0.4.0': {} - '@es-joy/jsdoccomment@0.41.0': + '@es-joy/jsdoccomment@0.46.0': dependencies: comment-parser: 1.4.1 esquery: 1.6.0 @@ -15999,7 +16019,7 @@ snapshots: '@mapbox/whoots-js@3.1.0': {} - '@mdn/browser-compat-data@5.5.33': {} + '@mdn/browser-compat-data@5.5.47': {} '@mdx-js/react@3.0.1(@types/react@18.3.3)(react@18.3.1)': dependencies: @@ -16849,10 +16869,10 @@ snapshots: memoizerific: 1.11.3 storybook: 8.2.9 - '@storybook/addon-webpack5-compiler-babel@3.0.3(webpack@5.76.0(webpack-cli@4.9.1))': + '@storybook/addon-webpack5-compiler-babel@3.0.3(webpack@5.94.0(webpack-cli@4.9.1))': dependencies: '@babel/core': 7.24.7 - babel-loader: 9.1.3(@babel/core@7.24.7)(webpack@5.76.0(webpack-cli@4.9.1)) + babel-loader: 9.1.3(@babel/core@7.24.7)(webpack@5.94.0(webpack-cli@4.9.1)) transitivePeerDependencies: - supports-color - webpack @@ -16878,7 +16898,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@storybook/builder-webpack5@8.2.9(storybook@8.2.9)(typescript@5.0.4)(webpack-cli@4.9.1(webpack@5.76.0))': + '@storybook/builder-webpack5@8.2.9(storybook@8.2.9)(typescript@5.0.4)(webpack-cli@4.9.1(webpack@5.94.0))': dependencies: '@storybook/core-webpack': 8.2.9(storybook@8.2.9) '@types/node': 18.19.44 @@ -16887,25 +16907,25 @@ snapshots: case-sensitive-paths-webpack-plugin: 2.4.0 cjs-module-lexer: 1.3.1 constants-browserify: 1.0.0 - css-loader: 6.11.0(webpack@5.76.0(webpack-cli@4.9.1)) + css-loader: 6.11.0(webpack@5.94.0(webpack-cli@4.9.1)) es-module-lexer: 1.5.4 express: 4.19.2 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.0.4)(webpack@5.76.0(webpack-cli@4.9.1)) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.0.4)(webpack@5.94.0(webpack-cli@4.9.1)) fs-extra: 11.2.0 - html-webpack-plugin: 5.6.0(webpack@5.76.0(webpack-cli@4.9.1)) + html-webpack-plugin: 5.6.0(webpack@5.94.0(webpack-cli@4.9.1)) magic-string: 0.30.11 path-browserify: 1.0.1 process: 0.11.10 semver: 7.5.2 storybook: 8.2.9 - style-loader: 3.3.4(webpack@5.76.0(webpack-cli@4.9.1)) - terser-webpack-plugin: 5.3.3(webpack@5.76.0(webpack-cli@4.9.1)) + style-loader: 3.3.4(webpack@5.94.0(webpack-cli@4.9.1)) + terser-webpack-plugin: 5.3.3(webpack@5.94.0(webpack-cli@4.9.1)) ts-dedent: 2.2.0 url: 0.11.4 util: 0.12.5 util-deprecate: 1.0.2 - webpack: 5.76.0(webpack-cli@4.9.1) - webpack-dev-middleware: 6.1.3(webpack@5.76.0(webpack-cli@4.9.1)) + webpack: 5.94.0(webpack-cli@4.9.1) + webpack-dev-middleware: 6.1.3(webpack@5.94.0(webpack-cli@4.9.1)) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.6.2 optionalDependencies: @@ -17010,11 +17030,11 @@ snapshots: dependencies: storybook: 8.2.9 - '@storybook/preset-react-webpack@8.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.9)(typescript@5.0.4)(webpack-cli@4.9.1(webpack@5.76.0))': + '@storybook/preset-react-webpack@8.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.9)(typescript@5.0.4)(webpack-cli@4.9.1(webpack@5.94.0))': dependencies: '@storybook/core-webpack': 8.2.9(storybook@8.2.9) '@storybook/react': 8.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.9)(typescript@5.0.4) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.0.4)(webpack@5.76.0(webpack-cli@4.9.1)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.0.4)(webpack@5.94.0(webpack-cli@4.9.1)) '@types/node': 18.19.44 '@types/semver': 7.5.8 find-up: 5.0.0 @@ -17027,7 +17047,7 @@ snapshots: semver: 7.5.2 storybook: 8.2.9 tsconfig-paths: 4.2.0 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) optionalDependencies: typescript: 5.0.4 transitivePeerDependencies: @@ -17045,7 +17065,7 @@ snapshots: dependencies: storybook: 8.2.9 - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.0.4)(webpack@5.76.0(webpack-cli@4.9.1))': + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.0.4)(webpack@5.94.0(webpack-cli@4.9.1))': dependencies: debug: 4.3.4 endent: 2.1.0 @@ -17055,7 +17075,7 @@ snapshots: react-docgen-typescript: 2.2.2(typescript@5.0.4) tslib: 2.5.0 typescript: 5.0.4 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) transitivePeerDependencies: - supports-color @@ -17071,10 +17091,10 @@ snapshots: react-dom: 18.3.1(react@18.3.1) storybook: 8.2.9 - '@storybook/react-webpack5@8.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.9)(typescript@5.0.4)(webpack-cli@4.9.1(webpack@5.76.0))': + '@storybook/react-webpack5@8.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.9)(typescript@5.0.4)(webpack-cli@4.9.1(webpack@5.94.0))': dependencies: - '@storybook/builder-webpack5': 8.2.9(storybook@8.2.9)(typescript@5.0.4)(webpack-cli@4.9.1(webpack@5.76.0)) - '@storybook/preset-react-webpack': 8.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.9)(typescript@5.0.4)(webpack-cli@4.9.1(webpack@5.76.0)) + '@storybook/builder-webpack5': 8.2.9(storybook@8.2.9)(typescript@5.0.4)(webpack-cli@4.9.1(webpack@5.94.0)) + '@storybook/preset-react-webpack': 8.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.9)(typescript@5.0.4)(webpack-cli@4.9.1(webpack@5.94.0)) '@storybook/react': 8.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.2.9)(typescript@5.0.4) '@types/node': 18.19.44 react: 18.3.1 @@ -17523,16 +17543,6 @@ snapshots: '@types/escodegen@0.0.6': {} - '@types/eslint-scope@3.7.7': - dependencies: - '@types/eslint': 9.6.0 - '@types/estree': 1.0.5 - - '@types/eslint@9.6.0': - dependencies: - '@types/estree': 1.0.5 - '@types/json-schema': 7.0.15 - '@types/estree@0.0.39': {} '@types/estree@0.0.51': {} @@ -17946,95 +17956,95 @@ snapshots: '@vercel/ncc@0.36.1': {} - '@webassemblyjs/ast@1.11.1': + '@webassemblyjs/ast@1.12.1': dependencies: - '@webassemblyjs/helper-numbers': 1.11.1 - '@webassemblyjs/helper-wasm-bytecode': 1.11.1 + '@webassemblyjs/helper-numbers': 1.11.6 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 - '@webassemblyjs/floating-point-hex-parser@1.11.1': {} + '@webassemblyjs/floating-point-hex-parser@1.11.6': {} - '@webassemblyjs/helper-api-error@1.11.1': {} + '@webassemblyjs/helper-api-error@1.11.6': {} - '@webassemblyjs/helper-buffer@1.11.1': {} + '@webassemblyjs/helper-buffer@1.12.1': {} - '@webassemblyjs/helper-numbers@1.11.1': + '@webassemblyjs/helper-numbers@1.11.6': dependencies: - '@webassemblyjs/floating-point-hex-parser': 1.11.1 - '@webassemblyjs/helper-api-error': 1.11.1 + '@webassemblyjs/floating-point-hex-parser': 1.11.6 + '@webassemblyjs/helper-api-error': 1.11.6 '@xtuc/long': 4.2.2 - '@webassemblyjs/helper-wasm-bytecode@1.11.1': {} + '@webassemblyjs/helper-wasm-bytecode@1.11.6': {} - '@webassemblyjs/helper-wasm-section@1.11.1': + '@webassemblyjs/helper-wasm-section@1.12.1': dependencies: - '@webassemblyjs/ast': 1.11.1 - '@webassemblyjs/helper-buffer': 1.11.1 - '@webassemblyjs/helper-wasm-bytecode': 1.11.1 - '@webassemblyjs/wasm-gen': 1.11.1 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-buffer': 1.12.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/wasm-gen': 1.12.1 - '@webassemblyjs/ieee754@1.11.1': + '@webassemblyjs/ieee754@1.11.6': dependencies: '@xtuc/ieee754': 1.2.0 - '@webassemblyjs/leb128@1.11.1': + '@webassemblyjs/leb128@1.11.6': dependencies: '@xtuc/long': 4.2.2 - '@webassemblyjs/utf8@1.11.1': {} + '@webassemblyjs/utf8@1.11.6': {} - '@webassemblyjs/wasm-edit@1.11.1': + '@webassemblyjs/wasm-edit@1.12.1': dependencies: - '@webassemblyjs/ast': 1.11.1 - '@webassemblyjs/helper-buffer': 1.11.1 - '@webassemblyjs/helper-wasm-bytecode': 1.11.1 - '@webassemblyjs/helper-wasm-section': 1.11.1 - '@webassemblyjs/wasm-gen': 1.11.1 - '@webassemblyjs/wasm-opt': 1.11.1 - '@webassemblyjs/wasm-parser': 1.11.1 - '@webassemblyjs/wast-printer': 1.11.1 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-buffer': 1.12.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/helper-wasm-section': 1.12.1 + '@webassemblyjs/wasm-gen': 1.12.1 + '@webassemblyjs/wasm-opt': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 + '@webassemblyjs/wast-printer': 1.12.1 - '@webassemblyjs/wasm-gen@1.11.1': + '@webassemblyjs/wasm-gen@1.12.1': dependencies: - '@webassemblyjs/ast': 1.11.1 - '@webassemblyjs/helper-wasm-bytecode': 1.11.1 - '@webassemblyjs/ieee754': 1.11.1 - '@webassemblyjs/leb128': 1.11.1 - '@webassemblyjs/utf8': 1.11.1 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/ieee754': 1.11.6 + '@webassemblyjs/leb128': 1.11.6 + '@webassemblyjs/utf8': 1.11.6 - '@webassemblyjs/wasm-opt@1.11.1': + '@webassemblyjs/wasm-opt@1.12.1': dependencies: - '@webassemblyjs/ast': 1.11.1 - '@webassemblyjs/helper-buffer': 1.11.1 - '@webassemblyjs/wasm-gen': 1.11.1 - '@webassemblyjs/wasm-parser': 1.11.1 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-buffer': 1.12.1 + '@webassemblyjs/wasm-gen': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 - '@webassemblyjs/wasm-parser@1.11.1': + '@webassemblyjs/wasm-parser@1.12.1': dependencies: - '@webassemblyjs/ast': 1.11.1 - '@webassemblyjs/helper-api-error': 1.11.1 - '@webassemblyjs/helper-wasm-bytecode': 1.11.1 - '@webassemblyjs/ieee754': 1.11.1 - '@webassemblyjs/leb128': 1.11.1 - '@webassemblyjs/utf8': 1.11.1 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/helper-api-error': 1.11.6 + '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/ieee754': 1.11.6 + '@webassemblyjs/leb128': 1.11.6 + '@webassemblyjs/utf8': 1.11.6 - '@webassemblyjs/wast-printer@1.11.1': + '@webassemblyjs/wast-printer@1.12.1': dependencies: - '@webassemblyjs/ast': 1.11.1 + '@webassemblyjs/ast': 1.12.1 '@xtuc/long': 4.2.2 - '@webpack-cli/configtest@1.2.0(webpack-cli@4.9.1(webpack@5.76.0))(webpack@5.76.0(webpack-cli@4.9.1))': + '@webpack-cli/configtest@1.2.0(webpack-cli@4.9.1(webpack@5.94.0))(webpack@5.94.0(webpack-cli@4.9.1))': dependencies: - webpack: 5.76.0(webpack-cli@4.9.1) - webpack-cli: 4.9.1(webpack@5.76.0) + webpack: 5.94.0(webpack-cli@4.9.1) + webpack-cli: 4.9.1(webpack@5.94.0) - '@webpack-cli/info@1.5.0(webpack-cli@4.9.1(webpack@5.76.0))': + '@webpack-cli/info@1.5.0(webpack-cli@4.9.1(webpack@5.94.0))': dependencies: envinfo: 7.13.0 - webpack-cli: 4.9.1(webpack@5.76.0) + webpack-cli: 4.9.1(webpack@5.94.0) - '@webpack-cli/serve@1.7.0(webpack-cli@4.9.1(webpack@5.76.0))': + '@webpack-cli/serve@1.7.0(webpack-cli@4.9.1(webpack@5.94.0))': dependencies: - webpack-cli: 4.9.1(webpack@5.76.0) + webpack-cli: 4.9.1(webpack@5.94.0) '@wordpress/a11y@4.5.0': dependencies: @@ -18906,10 +18916,10 @@ snapshots: moment: 2.29.4 moment-timezone: 0.5.45 - '@wordpress/dependency-extraction-webpack-plugin@6.5.0(webpack@5.76.0(webpack-cli@4.9.1))': + '@wordpress/dependency-extraction-webpack-plugin@6.5.0(webpack@5.94.0(webpack-cli@4.9.1))': dependencies: json2php: 0.0.7 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) '@wordpress/deprecated@4.5.0': dependencies: @@ -19202,7 +19212,7 @@ snapshots: dependencies: '@babel/runtime': 7.24.7 - '@wordpress/eslint-plugin@20.2.0(mikchdjuqfweuug63xtkjtmioa)': + '@wordpress/eslint-plugin@20.2.0(2g4wiqq3ubewvaaot6et2pay5m)': dependencies: '@babel/core': 7.24.7 '@babel/eslint-parser': 7.24.7(@babel/core@7.24.7)(eslint@8.57.0) @@ -19215,11 +19225,11 @@ snapshots: eslint-config-prettier: 9.1.0(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.0.4))(eslint@8.57.0) eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.0.4))(eslint@8.57.0)(typescript@5.0.4))(eslint@8.57.0)(jest@29.7.0)(typescript@5.0.4) - eslint-plugin-jsdoc: 46.10.1(eslint@8.57.0) - eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) + eslint-plugin-jsdoc: 48.8.3(eslint@8.57.0) + eslint-plugin-jsx-a11y: 6.9.0(eslint@8.57.0) eslint-plugin-playwright: 0.22.2(eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.0.4))(eslint@8.57.0)(typescript@5.0.4))(eslint@8.57.0)(jest@29.7.0)(typescript@5.0.4))(eslint@8.57.0) - eslint-plugin-prettier: 5.1.3(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(wp-prettier@3.0.3) - eslint-plugin-react: 7.34.2(eslint@8.57.0) + eslint-plugin-prettier: 5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(wp-prettier@3.0.3) + eslint-plugin-react: 7.35.0(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) globals: 13.24.0 requireindex: 1.2.0 @@ -19826,7 +19836,7 @@ snapshots: acorn: 8.12.1 acorn-walk: 8.3.3 - acorn-import-assertions@1.9.0(acorn@8.12.1): + acorn-import-attributes@1.9.5(acorn@8.12.1): dependencies: acorn: 8.12.1 @@ -20021,13 +20031,6 @@ snapshots: es-abstract: 1.23.3 es-shim-unscopables: 1.0.2 - array.prototype.toreversed@1.1.2: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-shim-unscopables: 1.0.2 - array.prototype.tosorted@1.1.4: dependencies: call-bind: 1.0.7 @@ -20079,8 +20082,6 @@ snapshots: axe-core@4.10.0: {} - axe-core@4.7.0: {} - axios@1.7.4: dependencies: follow-redirects: 1.15.6 @@ -20097,7 +20098,9 @@ snapshots: transitivePeerDependencies: - debug - axobject-query@3.2.4: {} + axobject-query@3.1.1: + dependencies: + deep-equal: 2.2.3 axobject-query@4.1.0: {} @@ -20146,19 +20149,19 @@ snapshots: transitivePeerDependencies: - supports-color - babel-loader@9.1.2(@babel/core@7.24.7)(webpack@5.76.0(webpack-cli@4.9.1)): + babel-loader@9.1.2(@babel/core@7.24.7)(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: '@babel/core': 7.24.7 find-cache-dir: 3.3.2 schema-utils: 4.2.0 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) - babel-loader@9.1.3(@babel/core@7.24.7)(webpack@5.76.0(webpack-cli@4.9.1)): + babel-loader@9.1.3(@babel/core@7.24.7)(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: '@babel/core': 7.24.7 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) babel-plugin-inline-json-import@0.3.2: dependencies: @@ -20794,7 +20797,7 @@ snapshots: cookie@0.6.0: {} - copy-webpack-plugin@11.0.0(webpack@5.76.0(webpack-cli@4.9.1)): + copy-webpack-plugin@11.0.0(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: fast-glob: 3.3.2 glob-parent: 6.0.2 @@ -20802,7 +20805,7 @@ snapshots: normalize-path: 3.0.0 schema-utils: 4.2.0 serialize-javascript: 6.0.2 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) core-js-compat@3.38.0: dependencies: @@ -20879,7 +20882,7 @@ snapshots: dependencies: postcss: 8.4.31 - css-loader@6.11.0(webpack@5.76.0(webpack-cli@4.9.1)): + css-loader@6.11.0(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: icss-utils: 5.1.0(postcss@8.4.41) postcss: 8.4.41 @@ -20890,9 +20893,9 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.6.3 optionalDependencies: - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) - css-loader@6.5.1(webpack@5.76.0(webpack-cli@4.9.1)): + css-loader@6.5.1(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: icss-utils: 5.1.0(postcss@8.4.31) postcss: 8.4.31 @@ -20902,9 +20905,9 @@ snapshots: postcss-modules-values: 4.0.0(postcss@8.4.31) postcss-value-parser: 4.2.0 semver: 7.5.2 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) - css-minimizer-webpack-plugin@5.0.1(webpack@5.76.0(webpack-cli@4.9.1)): + css-minimizer-webpack-plugin@5.0.1(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: '@jridgewell/trace-mapping': 0.3.25 cssnano: 6.1.2(postcss@8.4.31) @@ -20912,7 +20915,7 @@ snapshots: postcss: 8.4.31 schema-utils: 4.2.0 serialize-javascript: 6.0.2 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) css-select@4.3.0: dependencies: @@ -21424,8 +21427,6 @@ snapshots: iterator.prototype: 1.1.2 safe-array-concat: 1.1.2 - es-module-lexer@0.9.3: {} - es-module-lexer@1.5.4: {} es-object-atoms@1.0.0: @@ -21450,12 +21451,12 @@ snapshots: es6-error@4.1.1: {} - esbuild-loader@3.0.1(webpack@5.76.0(webpack-cli@4.9.1)): + esbuild-loader@3.0.1(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: esbuild: 0.17.19 get-tsconfig: 4.7.6 loader-utils: 2.0.4 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) webpack-sources: 1.4.3 esbuild-register@3.6.0(esbuild@0.21.5): @@ -21569,7 +21570,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-es-x@7.7.0(eslint@8.57.0): + eslint-plugin-es-x@7.8.0(eslint@8.57.0): dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@eslint-community/regexpp': 4.11.0 @@ -21620,30 +21621,30 @@ snapshots: - supports-color - typescript - eslint-plugin-jsdoc@46.10.1(eslint@8.57.0): + eslint-plugin-jsdoc@48.8.3(eslint@8.57.0): dependencies: - '@es-joy/jsdoccomment': 0.41.0 + '@es-joy/jsdoccomment': 0.46.0 are-docs-informative: 0.0.2 comment-parser: 1.4.1 - debug: 4.3.4 + debug: 4.3.6 escape-string-regexp: 4.0.0 eslint: 8.57.0 esquery: 1.6.0 - is-builtin-module: 3.2.1 + parse-imports: 2.1.1 semver: 7.6.3 spdx-expression-parse: 4.0.0 + synckit: 0.9.1 transitivePeerDependencies: - supports-color - eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0): + eslint-plugin-jsx-a11y@6.9.0(eslint@8.57.0): dependencies: - '@babel/runtime': 7.24.7 - aria-query: 5.3.0 + aria-query: 5.1.3 array-includes: 3.1.8 array.prototype.flatmap: 1.3.2 ast-types-flow: 0.0.8 - axe-core: 4.7.0 - axobject-query: 3.2.4 + axe-core: 4.10.0 + axobject-query: 3.1.1 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 es-iterator-helpers: 1.0.19 @@ -21652,8 +21653,9 @@ snapshots: jsx-ast-utils: 3.3.5 language-tags: 1.0.9 minimatch: 3.1.2 - object.entries: 1.1.8 object.fromentries: 2.0.8 + safe-regex-test: 1.0.3 + string.prototype.includes: 2.0.0 eslint-plugin-lodash@7.4.0(eslint@8.57.0): dependencies: @@ -21667,12 +21669,12 @@ snapshots: optionalDependencies: eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.0.4))(eslint@8.57.0)(typescript@5.0.4))(eslint@8.57.0)(jest@29.7.0)(typescript@5.0.4) - eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(wp-prettier@3.0.3): + eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(wp-prettier@3.0.3): dependencies: eslint: 8.57.0 prettier: wp-prettier@3.0.3 prettier-linter-helpers: 1.0.0 - synckit: 0.8.8 + synckit: 0.9.1 optionalDependencies: eslint-config-prettier: 9.1.0(eslint@8.57.0) @@ -21680,29 +21682,29 @@ snapshots: dependencies: eslint: 8.57.0 - eslint-plugin-react@7.34.2(eslint@8.57.0): + eslint-plugin-react@7.35.0(eslint@8.57.0): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 array.prototype.flatmap: 1.3.2 - array.prototype.toreversed: 1.1.2 array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.0.19 eslint: 8.57.0 estraverse: 5.3.0 + hasown: 2.0.2 jsx-ast-utils: 3.3.5 minimatch: 3.1.2 object.entries: 1.1.8 object.fromentries: 2.0.8 - object.hasown: 1.1.4 object.values: 1.2.0 prop-types: 15.8.1 resolve: 2.0.0-next.5 semver: 6.3.1 string.prototype.matchall: 4.0.11 + string.prototype.repeat: 1.0.0 - eslint-plugin-svelte@2.41.0(eslint@8.57.0)(svelte@4.2.18): + eslint-plugin-svelte@2.43.0(eslint@8.57.0)(svelte@4.2.18): dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@jridgewell/sourcemap-codec': 1.5.0 @@ -21715,13 +21717,13 @@ snapshots: postcss-safe-parser: 6.0.0(postcss@8.4.41) postcss-selector-parser: 6.1.2 semver: 7.6.3 - svelte-eslint-parser: 0.39.2(svelte@4.2.18) + svelte-eslint-parser: 0.41.0(svelte@4.2.18) optionalDependencies: svelte: 4.2.18 transitivePeerDependencies: - ts-node - eslint-plugin-testing-library@6.2.2(eslint@8.57.0)(typescript@5.0.4): + eslint-plugin-testing-library@6.3.0(eslint@8.57.0)(typescript@5.0.4): dependencies: '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.0.4) eslint: 8.57.0 @@ -22117,7 +22119,7 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.0.4)(webpack@5.76.0(webpack-cli@4.9.1)): + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.0.4)(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: '@babel/code-frame': 7.24.7 chalk: 4.1.2 @@ -22132,9 +22134,9 @@ snapshots: semver: 7.5.2 tapable: 2.2.1 typescript: 5.0.4 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) - fork-ts-checker-webpack-plugin@9.0.2(typescript@5.0.4)(webpack@5.76.0(webpack-cli@4.9.1)): + fork-ts-checker-webpack-plugin@9.0.2(typescript@5.0.4)(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: '@babel/code-frame': 7.24.7 chalk: 4.1.2 @@ -22149,7 +22151,7 @@ snapshots: semver: 7.5.2 tapable: 2.2.1 typescript: 5.0.4 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) form-data@4.0.0: dependencies: @@ -22499,7 +22501,7 @@ snapshots: html-tags@3.3.1: {} - html-webpack-plugin@5.6.0(webpack@5.76.0(webpack-cli@4.9.1)): + html-webpack-plugin@5.6.0(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -22507,7 +22509,7 @@ snapshots: pretty-error: 4.0.0 tapable: 2.2.1 optionalDependencies: - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) htmlparser2@3.10.1: dependencies: @@ -24183,10 +24185,10 @@ snapshots: min-indent@1.0.1: {} - mini-css-extract-plugin@2.4.5(webpack@5.76.0(webpack-cli@4.9.1)): + mini-css-extract-plugin@2.4.5(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: schema-utils: 4.2.0 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) minimatch@3.1.2: dependencies: @@ -24395,12 +24397,6 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.23.3 - object.hasown@1.1.4: - dependencies: - define-properties: 1.2.1 - es-abstract: 1.23.3 - es-object-atoms: 1.0.0 - object.values@1.2.0: dependencies: call-bind: 1.0.7 @@ -24552,6 +24548,11 @@ snapshots: parse-diff@0.8.1: {} + parse-imports@2.1.1: + dependencies: + es-module-lexer: 1.5.4 + slashes: 3.0.12 + parse-json@5.2.0: dependencies: '@babel/code-frame': 7.24.7 @@ -24754,13 +24755,13 @@ snapshots: optionalDependencies: postcss: 8.4.41 - postcss-loader@6.2.0(postcss@8.4.31)(webpack@5.76.0(webpack-cli@4.9.1)): + postcss-loader@6.2.0(postcss@8.4.31)(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: cosmiconfig: 7.1.0 klona: 2.0.6 postcss: 8.4.31 semver: 7.5.2 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) postcss-merge-longhand@6.0.5(postcss@8.4.31): dependencies: @@ -25721,11 +25722,11 @@ snapshots: safer-buffer@2.1.2: {} - sass-loader@12.4.0(sass@1.64.1)(webpack@5.76.0(webpack-cli@4.9.1)): + sass-loader@12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: klona: 2.0.6 neo-async: 2.6.2 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) optionalDependencies: sass: 1.64.1 @@ -25900,6 +25901,8 @@ snapshots: slash@5.1.0: {} + slashes@3.0.12: {} + slice-ansi@0.0.4: {} smart-buffer@4.2.0: {} @@ -26153,6 +26156,11 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + string.prototype.includes@2.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.3 + string.prototype.matchall@4.0.11: dependencies: call-bind: 1.0.7 @@ -26168,6 +26176,11 @@ snapshots: set-function-name: 2.0.2 side-channel: 1.0.6 + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.3 + string.prototype.trim@1.2.9: dependencies: call-bind: 1.0.7 @@ -26233,15 +26246,15 @@ snapshots: style-inject@0.3.0: {} - style-loader@2.0.0(webpack@5.76.0(webpack-cli@4.9.1)): + style-loader@2.0.0(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) - style-loader@3.3.4(webpack@5.76.0(webpack-cli@4.9.1)): + style-loader@3.3.4(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) stylehacks@6.1.1(postcss@8.4.31): dependencies: @@ -26281,6 +26294,16 @@ snapshots: optionalDependencies: svelte: 4.2.18 + svelte-eslint-parser@0.41.0(svelte@4.2.18): + dependencies: + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + postcss: 8.4.41 + postcss-scss: 4.0.9(postcss@8.4.41) + optionalDependencies: + svelte: 4.2.18 + svelte-preprocess@6.0.2(@babel/core@7.24.7)(postcss@8.4.31)(sass@1.64.1)(svelte@4.2.18)(typescript@5.0.4): dependencies: svelte: 4.2.18 @@ -26357,7 +26380,7 @@ snapshots: symbol-tree@3.2.4: {} - synckit@0.8.8: + synckit@0.9.1: dependencies: '@pkgr/core': 0.1.1 tslib: 2.6.3 @@ -26418,23 +26441,32 @@ snapshots: type-fest: 2.19.0 unique-string: 3.0.0 - terser-webpack-plugin@5.3.3(webpack@5.76.0(webpack-cli@4.9.1)): + terser-webpack-plugin@5.3.10(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.6 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) - terser-webpack-plugin@5.3.3(webpack@5.76.0): + terser-webpack-plugin@5.3.10(webpack@5.94.0): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.6 - webpack: 5.76.0 + webpack: 5.94.0 + + terser-webpack-plugin@5.3.3(webpack@5.94.0(webpack-cli@4.9.1)): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + jest-worker: 27.5.1 + schema-utils: 3.3.0 + serialize-javascript: 6.0.2 + terser: 5.31.6 + webpack: 5.94.0(webpack-cli@4.9.1) terser@5.31.6: dependencies: @@ -26457,14 +26489,14 @@ snapshots: text-table@0.2.0: {} - thread-loader@3.0.4(webpack@5.76.0(webpack-cli@4.9.1)): + thread-loader@3.0.4(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: json-parse-better-errors: 1.0.2 loader-runner: 4.3.0 loader-utils: 2.0.4 neo-async: 2.6.2 schema-utils: 3.3.0 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) through@2.3.8: {} @@ -26925,12 +26957,12 @@ snapshots: webidl-conversions@7.0.0: {} - webpack-cli@4.9.1(webpack@5.76.0): + webpack-cli@4.9.1(webpack@5.94.0): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 1.2.0(webpack-cli@4.9.1(webpack@5.76.0))(webpack@5.76.0(webpack-cli@4.9.1)) - '@webpack-cli/info': 1.5.0(webpack-cli@4.9.1(webpack@5.76.0)) - '@webpack-cli/serve': 1.7.0(webpack-cli@4.9.1(webpack@5.76.0)) + '@webpack-cli/configtest': 1.2.0(webpack-cli@4.9.1(webpack@5.94.0))(webpack@5.94.0(webpack-cli@4.9.1)) + '@webpack-cli/info': 1.5.0(webpack-cli@4.9.1(webpack@5.94.0)) + '@webpack-cli/serve': 1.7.0(webpack-cli@4.9.1(webpack@5.94.0)) colorette: 2.0.20 commander: 7.2.0 execa: 5.1.1 @@ -26938,19 +26970,19 @@ snapshots: import-local: 3.2.0 interpret: 2.2.0 rechoir: 0.7.1 - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) webpack-merge: 5.10.0 - webpack-dev-middleware@5.3.4(webpack@5.76.0): + webpack-dev-middleware@5.3.4(webpack@5.94.0): dependencies: colorette: 2.0.20 memfs: 3.5.3 mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.2.0 - webpack: 5.76.0 + webpack: 5.94.0 - webpack-dev-middleware@6.1.3(webpack@5.76.0(webpack-cli@4.9.1)): + webpack-dev-middleware@6.1.3(webpack@5.94.0(webpack-cli@4.9.1)): dependencies: colorette: 2.0.20 memfs: 3.5.3 @@ -26958,7 +26990,7 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.2.0 optionalDependencies: - webpack: 5.76.0(webpack-cli@4.9.1) + webpack: 5.94.0(webpack-cli@4.9.1) webpack-hot-middleware@2.26.1: dependencies: @@ -26981,19 +27013,18 @@ snapshots: webpack-virtual-modules@0.6.2: {} - webpack@5.76.0: + webpack@5.94.0: dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 0.0.51 - '@webassemblyjs/ast': 1.11.1 - '@webassemblyjs/wasm-edit': 1.11.1 - '@webassemblyjs/wasm-parser': 1.11.1 + '@types/estree': 1.0.5 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/wasm-edit': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 acorn: 8.12.1 - acorn-import-assertions: 1.9.0(acorn@8.12.1) + acorn-import-attributes: 1.9.5(acorn@8.12.1) browserslist: 4.23.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.17.1 - es-module-lexer: 0.9.3 + es-module-lexer: 1.5.4 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -27004,7 +27035,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.3(webpack@5.76.0) + terser-webpack-plugin: 5.3.10(webpack@5.94.0) watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -27012,19 +27043,18 @@ snapshots: - esbuild - uglify-js - webpack@5.76.0(webpack-cli@4.9.1): + webpack@5.94.0(webpack-cli@4.9.1): dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 0.0.51 - '@webassemblyjs/ast': 1.11.1 - '@webassemblyjs/wasm-edit': 1.11.1 - '@webassemblyjs/wasm-parser': 1.11.1 + '@types/estree': 1.0.5 + '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/wasm-edit': 1.12.1 + '@webassemblyjs/wasm-parser': 1.12.1 acorn: 8.12.1 - acorn-import-assertions: 1.9.0(acorn@8.12.1) + acorn-import-attributes: 1.9.5(acorn@8.12.1) browserslist: 4.23.1 chrome-trace-event: 1.0.4 enhanced-resolve: 5.17.1 - es-module-lexer: 0.9.3 + es-module-lexer: 1.5.4 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 @@ -27035,11 +27065,11 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.3(webpack@5.76.0(webpack-cli@4.9.1)) + terser-webpack-plugin: 5.3.10(webpack@5.94.0(webpack-cli@4.9.1)) watchpack: 2.4.2 webpack-sources: 3.2.3 optionalDependencies: - webpack-cli: 4.9.1(webpack@5.76.0) + webpack-cli: 4.9.1(webpack@5.94.0) transitivePeerDependencies: - '@swc/core' - esbuild diff --git a/projects/github-actions/repo-gardening/changelog/add-enable-more-eslint-rules b/projects/github-actions/repo-gardening/changelog/add-enable-more-eslint-rules new file mode 100644 index 0000000000000..8222673fd2fa6 --- /dev/null +++ b/projects/github-actions/repo-gardening/changelog/add-enable-more-eslint-rules @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Remove ineffectual code paths and update comment. + + diff --git a/projects/github-actions/repo-gardening/changelog/add-eslint-array-callback-return b/projects/github-actions/repo-gardening/changelog/add-eslint-array-callback-return new file mode 100644 index 0000000000000..f91807380615c --- /dev/null +++ b/projects/github-actions/repo-gardening/changelog/add-eslint-array-callback-return @@ -0,0 +1,5 @@ +Significance: patch +Type: fixed +Comment: Fix `array-callback-return` eslint sniff. Should be no change to functionality. + + diff --git a/projects/github-actions/repo-gardening/changelog/add-eslint-array-callback-return#2 b/projects/github-actions/repo-gardening/changelog/add-eslint-array-callback-return#2 new file mode 100644 index 0000000000000..41d5853cb67d1 --- /dev/null +++ b/projects/github-actions/repo-gardening/changelog/add-eslint-array-callback-return#2 @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +WPCOM Commit Reminder rask: Fix detection of existing reminder comment. diff --git a/projects/github-actions/repo-gardening/changelog/add-more-eslint-rules b/projects/github-actions/repo-gardening/changelog/add-more-eslint-rules new file mode 100644 index 0000000000000..2b32cb03e644c --- /dev/null +++ b/projects/github-actions/repo-gardening/changelog/add-more-eslint-rules @@ -0,0 +1,5 @@ +Significance: patch +Type: fixed +Comment: Fix new eslint sniffs. Should be no change in functionality. + + diff --git a/projects/github-actions/repo-gardening/changelog/try-no-version-bumps-in-trunk b/projects/github-actions/repo-gardening/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..91efe85c55e06 --- /dev/null +++ b/projects/github-actions/repo-gardening/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/github-actions/repo-gardening/changelog/update-jsdoc-comments-for-wp-coding-standards b/projects/github-actions/repo-gardening/changelog/update-jsdoc-comments-for-wp-coding-standards new file mode 100644 index 0000000000000..0e655b2b8b7a3 --- /dev/null +++ b/projects/github-actions/repo-gardening/changelog/update-jsdoc-comments-for-wp-coding-standards @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Reformat jsdoc comments. No change to meaning or functionality. + + diff --git a/projects/github-actions/repo-gardening/package.json b/projects/github-actions/repo-gardening/package.json index 5b642d7a584af..37615c57e66b8 100644 --- a/projects/github-actions/repo-gardening/package.json +++ b/projects/github-actions/repo-gardening/package.json @@ -1,6 +1,6 @@ { "name": "repo-gardening", - "version": "5.1.0-alpha", + "version": "5.0.0", "description": "Manage Pull Requests and issues in your Open Source project (automate labelling, milestones, feedback to PR authors, ...)", "author": "Automattic", "license": "GPL-2.0-or-later", diff --git a/projects/github-actions/repo-gardening/src/tasks/add-labels/index.js b/projects/github-actions/repo-gardening/src/tasks/add-labels/index.js index 15b8973901e6d..442b50f19ef25 100644 --- a/projects/github-actions/repo-gardening/src/tasks/add-labels/index.js +++ b/projects/github-actions/repo-gardening/src/tasks/add-labels/index.js @@ -11,7 +11,7 @@ const getFiles = require( '../../utils/get-files' ); * - Capitalize. * * @param {string} name - Feature name. - * @returns {string} Cleaned up feature name. + * @return {string} Cleaned up feature name. */ function cleanName( name ) { const name_exceptions = { @@ -51,13 +51,13 @@ function cleanName( name ) { /** * Build a list of labels to add to the issue, based off our file list. * - * @param {GitHub} octokit - Initialized Octokit REST client. - * @param {string} owner - Repository owner. - * @param {string} repo - Repository name. - * @param {string} number - PR number. + * @param {GitHub} octokit - Initialized Octokit REST client. + * @param {string} owner - Repository owner. + * @param {string} repo - Repository name. + * @param {string} number - PR number. * @param {boolean} isDraft - Whether the pull request is a draft. - * @param {boolean} isRevert - Whether the pull request is a revert. - * @returns {Promise} Promise resolving to an array of keywords we'll search for. + * @param {boolean} isRevert - Whether the pull request is a revert. + * @return {Promise} Promise resolving to an array of keywords we'll search for. */ async function getLabelsToAdd( octokit, owner, repo, number, isDraft, isRevert ) { const keywords = new Set(); @@ -71,7 +71,7 @@ async function getLabelsToAdd( octokit, owner, repo, number, isDraft, isRevert ) debug( 'add-labels: Loop through all files modified in this PR and add matching labels.' ); - files.map( file => { + for ( const file of files ) { // Projects. const project = file.match( /^projects\/(?[^/]*)\/(?[^/]*)\// ); if ( project && project.groups.ptype && project.groups.pname ) { @@ -273,7 +273,7 @@ async function getLabelsToAdd( octokit, owner, repo, number, isDraft, isRevert ) if ( anyTestFile ) { keywords.add( '[Tests] Includes Tests' ); } - } ); + } // The Image CDN was previously named "Photon". // If we're touching that package, let's add the Photon label too diff --git a/projects/github-actions/repo-gardening/src/tasks/check-description/index.js b/projects/github-actions/repo-gardening/src/tasks/check-description/index.js index 5083f92d12ff9..7a5512750d968 100644 --- a/projects/github-actions/repo-gardening/src/tasks/check-description/index.js +++ b/projects/github-actions/repo-gardening/src/tasks/check-description/index.js @@ -19,7 +19,7 @@ const getLabels = require( '../../utils/labels/get-labels' ); * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Promise} Promise resolving to boolean. + * @return {Promise} Promise resolving to boolean. */ async function hasStatusLabels( octokit, owner, repo, number ) { const labels = await getLabels( octokit, owner, repo, number ); @@ -34,7 +34,7 @@ async function hasStatusLabels( octokit, owner, repo, number ) { * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Promise} Promise resolving to boolean. + * @return {Promise} Promise resolving to boolean. */ async function hasNeedsReviewLabel( octokit, owner, repo, number ) { const labels = await getLabels( octokit, owner, repo, number ); @@ -49,7 +49,7 @@ async function hasNeedsReviewLabel( octokit, owner, repo, number ) { * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Promise} Promise resolving to boolean. + * @return {Promise} Promise resolving to boolean. */ async function hasProgressLabel( octokit, owner, repo, number ) { const labels = await getLabels( octokit, owner, repo, number ); @@ -62,12 +62,12 @@ async function hasProgressLabel( octokit, owner, repo, number ) { * * @param {string} plugin - Plugin name. * @param {object} nextMilestone - Information about next milestone as returnde by GitHub. - * @returns {Promise} Promise resolving to info about the release (code freeze, release date). + * @return {Promise} Promise resolving to info about the release (code freeze, release date). */ async function getMilestoneDates( plugin, nextMilestone ) { let releaseDate = 'none scheduled'; let codeFreezeDate; - if ( nextMilestone && nextMilestone.hasOwnProperty( 'due_on' ) && nextMilestone.due_on ) { + if ( nextMilestone && Object.hasOwn( nextMilestone, 'due_on' ) && nextMilestone.due_on ) { releaseDate = moment( nextMilestone.due_on ).format( 'LL' ); // Look for a code freeze date in the milestone description. @@ -119,7 +119,7 @@ If you have any questions about the release process, please ask in the #jetpack- * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Promise} Promise resolving to info about the next release for that plugin. + * @return {Promise} Promise resolving to info about the next release for that plugin. */ async function buildMilestoneInfo( octokit, owner, repo, number ) { const plugins = await getPluginNames( octokit, owner, repo, number ); @@ -149,7 +149,7 @@ async function buildMilestoneInfo( octokit, owner, repo, number ) { * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Promise} Promise resolving to boolean. + * @return {Promise} Promise resolving to boolean. */ async function getCheckComment( octokit, owner, repo, number ) { let commentID = 0; @@ -157,14 +157,14 @@ async function getCheckComment( octokit, owner, repo, number ) { debug( `check-description: Looking for a previous comment from this task in our PR.` ); const comments = await getComments( octokit, owner, repo, number ); - comments.map( comment => { + for ( const comment of comments ) { if ( comment.user.login === 'github-actions[bot]' && comment.body.includes( '**Thank you for your PR!**' ) ) { commentID = comment.id; } - } ); + } return commentID; } @@ -172,10 +172,10 @@ async function getCheckComment( octokit, owner, repo, number ) { /** * Compose a list item with appropriate status check and passed message * - * @param {boolean} isFailure - Boolean condition to determine if check failed. - * @param {string} checkMessage - Sentence describing successful check. - * @param {string} severity - Optional. Check severity. Could be one of `error`, `warning`, `notice` - * @returns {string} - List item with status emoji and a sentence describing check. + * @param {boolean} isFailure - Boolean condition to determine if check failed. + * @param {string} checkMessage - Sentence describing successful check. + * @param {string} severity - Optional. Check severity. Could be one of `error`, `warning`, `notice` + * @return {string} - List item with status emoji and a sentence describing check. */ function statusEntry( isFailure, checkMessage, severity = 'error' ) { const severityMap = { @@ -196,7 +196,7 @@ function statusEntry( isFailure, checkMessage, severity = 'error' ) { * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Array} - list of affected projects without changelog entry + * @return {Array} - list of affected projects without changelog entry */ async function getChangelogEntries( octokit, owner, repo, number ) { const baseDir = getPrWorkspace(); @@ -247,7 +247,7 @@ async function getChangelogEntries( octokit, owner, repo, number ) { * * @param {WebhookPayloadPullRequest} payload - Pull request event payload. * @param {GitHub} octokit - Initialized Octokit REST client. - * @returns {string} List of checks with appropriate status emojis. + * @return {string} List of checks with appropriate status emojis. */ async function getStatusChecks( payload, octokit ) { const { body, number, head, base } = payload.pull_request; @@ -276,7 +276,7 @@ async function getStatusChecks( payload, octokit ) { * Compose a list of checks for the PR * * @param {object} statusChecks - Map of all checks with boolean as a value - * @returns {string} part of the comment with list of checks + * @return {string} part of the comment with list of checks */ function renderStatusChecks( statusChecks ) { // No PR is too small to include a description of why you made a change @@ -321,7 +321,7 @@ function renderStatusChecks( statusChecks ) { * Compose a list of recommendations based on failed checks * * @param {object} statusChecks - Map of all checks with boolean as a value - * @returns {string} part of the comment with recommendations + * @return {string} part of the comment with recommendations */ function renderRecommendations( statusChecks ) { const recommendations = { @@ -366,8 +366,8 @@ Guidelines: [/docs/writing-a-good-changelog-entry.md](https://github.com/Automat * Creates or updates a comment on PR. * * @param {WebhookPayloadPullRequest} payload - Pull request event payload. - * @param {GitHub} octokit - Initialized Octokit REST client. - * @param {string} comment - Comment string + * @param {GitHub} octokit - Initialized Octokit REST client. + * @param {string} comment - Comment string */ async function postComment( payload, octokit, comment ) { const { number } = payload.pull_request; diff --git a/projects/github-actions/repo-gardening/src/tasks/clean-labels/index.js b/projects/github-actions/repo-gardening/src/tasks/clean-labels/index.js index 1b98b5ef961ce..fe669d3c6c96a 100644 --- a/projects/github-actions/repo-gardening/src/tasks/clean-labels/index.js +++ b/projects/github-actions/repo-gardening/src/tasks/clean-labels/index.js @@ -54,7 +54,7 @@ async function cleanLabels( payload, octokit ) { labelsToRemoveFromPr ) }` ); - labelsToRemoveFromPr.map( name => { + for ( const name of labelsToRemoveFromPr ) { debug( `clean-labels: removing the ${ name } label from PR #${ number }` ); octokit.rest.issues.removeLabel( { owner: ownerLogin, @@ -62,7 +62,7 @@ async function cleanLabels( payload, octokit ) { issue_number: number, name, } ); - } ); + } } module.exports = cleanLabels; diff --git a/projects/github-actions/repo-gardening/src/tasks/flag-oss/index.js b/projects/github-actions/repo-gardening/src/tasks/flag-oss/index.js index a924737e61826..051d54b13bf22 100644 --- a/projects/github-actions/repo-gardening/src/tasks/flag-oss/index.js +++ b/projects/github-actions/repo-gardening/src/tasks/flag-oss/index.js @@ -21,16 +21,13 @@ async function flagOss( payload, octokit ) { } // Check if PR author is org member + // Result is communicated by status code, and non-successful status codes throw. // https://docs.github.com/en/rest/orgs/members?apiVersion=2022-11-28#check-organization-membership-for-a-user try { - const orgMembershipRequest = await octokit.rest.orgs.checkMembershipForUser( { + await octokit.rest.orgs.checkMembershipForUser( { org: owner.login, username: head.user.login, } ); - - if ( 204 === orgMembershipRequest.status ) { - return; - } } catch ( error ) { debug( `flag-oss: Adding OSS Citizen label to PR #${ number }` ); await octokit.rest.issues.addLabels( { diff --git a/projects/github-actions/repo-gardening/src/tasks/gather-support-references/index.js b/projects/github-actions/repo-gardening/src/tasks/gather-support-references/index.js index 8575b8b10ffa1..1683a729700f1 100644 --- a/projects/github-actions/repo-gardening/src/tasks/gather-support-references/index.js +++ b/projects/github-actions/repo-gardening/src/tasks/gather-support-references/index.js @@ -10,14 +10,14 @@ const sendSlackMessage = require( '../../utils/slack/send-slack-message' ); * Search for a previous comment from this task in our issue. * * @param {Array} issueComments - Array of all comments on that issue. - * @returns {Promise} Promise resolving to an object of information about our comment. + * @return {Promise} Promise resolving to an object of information about our comment. */ async function getListComment( issueComments ) { let commentInfo = {}; debug( `gather-support-references: Looking for a previous comment from this task in our issue.` ); - issueComments.map( comment => { + for ( const comment of issueComments ) { if ( comment.user.login === 'github-actions[bot]' && comment.body.includes( '**Support References**' ) @@ -27,7 +27,7 @@ async function getListComment( issueComments ) { body: comment.body, }; } - } ); + } return commentInfo; } @@ -45,12 +45,12 @@ async function getListComment( issueComments ) { * - https://wordpress.com/forums/topic/xxx * - https://wordpress.com/xxx/forums/topic/xxx (for non-English forums) * - * @param {GitHub} octokit - Initialized Octokit REST client. - * @param {string} owner - Repository owner. - * @param {string} repo - Repository name. - * @param {string} number - Issue number. - * @param {Array} issueComments - Array of all comments on that issue. - * @returns {Promise} Promise resolving to an array. + * @param {GitHub} octokit - Initialized Octokit REST client. + * @param {string} owner - Repository owner. + * @param {string} repo - Repository name. + * @param {string} number - Issue number. + * @param {Array} issueComments - Array of all comments on that issue. + * @return {Promise} Promise resolving to an array. */ async function getIssueReferences( octokit, owner, repo, number, issueComments ) { const ticketReferences = []; @@ -71,18 +71,18 @@ async function getIssueReferences( octokit, owner, repo, number, issueComments ) } debug( `gather-support-references: Getting references from comments.` ); - issueComments.map( comment => { + for ( const comment of issueComments ) { if ( comment.user.login !== 'github-actions[bot]' || ! comment.body.includes( '**Support References**' ) ) { ticketReferences.push( ...comment.body.matchAll( referencesRegexP ) ); } - } ); + } // Let's build a array with unique and correct support IDs, formatted properly. const correctedSupportIds = new Set(); - ticketReferences.map( reference => { + for ( const reference of ticketReferences ) { let supportId = reference[ 0 ]; // xxx-zen is the preferred format for tickets. @@ -98,7 +98,7 @@ async function getIssueReferences( octokit, owner, repo, number, issueComments ) } correctedSupportIds.add( supportId ); - } ); + } return [ ...correctedSupportIds ]; } @@ -110,7 +110,7 @@ async function getIssueReferences( octokit, owner, repo, number, issueComments ) * @param {Set} checkedRefs - Set of support references already checked. * @param {boolean} needsEscalationNote - Whether the issue needs an escalation note. * @param {string} escalationNote - String that indicates an issue was escalated. - * @returns {string} Comment body. + * @return {string} Comment body. */ function buildCommentBody( issueReferences, @@ -144,7 +144,7 @@ ${ issueReferences * @param {WebhookPayloadIssue} payload - Issue event payload. * @param {string} channel - Slack channel ID. * @param {string} message - Basic message (without the formatting). - * @returns {object} Object containing the slack message and its formatting. + * @return {object} Object containing the slack message and its formatting. */ function formatSlackMessage( payload, channel, message ) { const { issue, repository } = payload; @@ -206,7 +206,7 @@ function formatSlackMessage( payload, channel, message ) { * @param {string} commentBody - Previous comment ID. * @param {string} escalationNote - String that indicates an issue was escalated. * @param {WebhookPayloadIssue} payload - Issue event payload. - * @returns {Promise} Was the issue escalated? + * @return {Promise} Was the issue escalated? */ async function checkForEscalation( issueReferences, commentBody, escalationNote, payload ) { // No Slack tokens, we won't be able to escalate. Bail. @@ -251,12 +251,12 @@ async function checkForEscalation( issueReferences, commentBody, escalationNote, * Add or update a label on the issue to indicate a number range of support references, * once it has gathered more than 10 support references. * - * @param {GitHub} octokit - Initialized Octokit REST client. - * @param {string} repo - Repository name. - * @param {string} ownerLogin - Owner of the repository. - * @param {number} number - Issue number. + * @param {GitHub} octokit - Initialized Octokit REST client. + * @param {string} repo - Repository name. + * @param {string} ownerLogin - Owner of the repository. + * @param {number} number - Issue number. * @param {number} issueReferencesCount - Number of support references gathered in this issue. - * @returns {Promise} + * @return {Promise} */ async function addOrUpdateInteractionCountLabel( octokit, @@ -329,10 +329,10 @@ async function addOrUpdateInteractionCountLabel( /** * Creates or updates a comment on issue. * - * @param {WebhookPayloadIssue} payload - Issue event payload. - * @param {GitHub} octokit - Initialized Octokit REST client. - * @param {Array} issueReferences - Array of support references. - * @param {Array} issueComments - Array of all comments on that issue. + * @param {WebhookPayloadIssue} payload - Issue event payload. + * @param {GitHub} octokit - Initialized Octokit REST client. + * @param {Array} issueReferences - Array of support references. + * @param {Array} issueComments - Array of all comments on that issue. */ async function createOrUpdateComment( payload, octokit, issueReferences, issueComments ) { const { issue, repository } = payload; @@ -409,11 +409,11 @@ async function createOrUpdateComment( payload, octokit, issueReferences, issueCo /** * Add a label to the issue, if it does not exist yet. * - * @param {GitHub} octokit - Initialized Octokit REST client. - * @param {string} ownerLogin - Repository owner login. - * @param {string} repo - Repository name. - * @param {number} number - Issue number. - * @returns {Promise} + * @param {GitHub} octokit - Initialized Octokit REST client. + * @param {string} ownerLogin - Repository owner login. + * @param {string} repo - Repository name. + * @param {number} number - Issue number. + * @return {Promise} */ async function addHappinessLabel( octokit, ownerLogin, repo, number ) { const happinessLabel = 'Customer Report'; diff --git a/projects/github-actions/repo-gardening/src/tasks/notify-design/index.js b/projects/github-actions/repo-gardening/src/tasks/notify-design/index.js index b05ab9bf8793d..4e82adc93877b 100644 --- a/projects/github-actions/repo-gardening/src/tasks/notify-design/index.js +++ b/projects/github-actions/repo-gardening/src/tasks/notify-design/index.js @@ -12,7 +12,7 @@ const sendSlackMessage = require( '../../utils/slack/send-slack-message' ); * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Promise} Promise resolving to boolean. + * @return {Promise} Promise resolving to boolean. */ async function hasNeedsDesignReviewLabel( octokit, owner, repo, number ) { const labels = await getLabels( octokit, owner, repo, number ); @@ -27,7 +27,7 @@ async function hasNeedsDesignReviewLabel( octokit, owner, repo, number ) { * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Promise} Promise resolving to boolean. + * @return {Promise} Promise resolving to boolean. */ async function hasNeedsDesignLabel( octokit, owner, repo, number ) { const labels = await getLabels( octokit, owner, repo, number ); @@ -42,7 +42,7 @@ async function hasNeedsDesignLabel( octokit, owner, repo, number ) { * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Promise} Promise resolving to boolean. + * @return {Promise} Promise resolving to boolean. */ async function hasDesignInputRequestedLabel( octokit, owner, repo, number ) { const labels = await getLabels( octokit, owner, repo, number ); diff --git a/projects/github-actions/repo-gardening/src/tasks/notify-editorial/index.js b/projects/github-actions/repo-gardening/src/tasks/notify-editorial/index.js index a0d1b581fdca4..e94f9478d6447 100644 --- a/projects/github-actions/repo-gardening/src/tasks/notify-editorial/index.js +++ b/projects/github-actions/repo-gardening/src/tasks/notify-editorial/index.js @@ -12,7 +12,7 @@ const sendSlackMessage = require( '../../utils/slack/send-slack-message' ); * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Promise} Promise resolving to boolean. + * @return {Promise} Promise resolving to boolean. */ async function hasNeedsCopyReviewLabel( octokit, owner, repo, number ) { const labels = await getLabels( octokit, owner, repo, number ); @@ -27,7 +27,7 @@ async function hasNeedsCopyReviewLabel( octokit, owner, repo, number ) { * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Promise} Promise resolving to boolean. + * @return {Promise} Promise resolving to boolean. */ async function hasNeedsCopyLabel( octokit, owner, repo, number ) { const labels = await getLabels( octokit, owner, repo, number ); @@ -42,7 +42,7 @@ async function hasNeedsCopyLabel( octokit, owner, repo, number ) { * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Promise} Promise resolving to boolean. + * @return {Promise} Promise resolving to boolean. */ async function hasEditorialInputRequestedLabel( octokit, owner, repo, number ) { const labels = await getLabels( octokit, owner, repo, number ); diff --git a/projects/github-actions/repo-gardening/src/tasks/reply-to-customers-reminder/index.js b/projects/github-actions/repo-gardening/src/tasks/reply-to-customers-reminder/index.js index 92e8fa995314d..235584bb52718 100644 --- a/projects/github-actions/repo-gardening/src/tasks/reply-to-customers-reminder/index.js +++ b/projects/github-actions/repo-gardening/src/tasks/reply-to-customers-reminder/index.js @@ -14,7 +14,7 @@ const sendSlackMessage = require( '../../utils/slack/send-slack-message' ); * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - Issue number. - * @returns {Promise} Promise resolving to boolean. + * @return {Promise} Promise resolving to boolean. */ async function hasHighPriorityLabel( octokit, owner, repo, number ) { const labels = await getLabels( octokit, owner, repo, number ); @@ -28,7 +28,7 @@ async function hasHighPriorityLabel( octokit, owner, repo, number ) { * @param {WebhookPayloadIssue} payload - Issue event payload. * @param {string} channel - Slack channel ID. * @param {string} message - Basic message (without the formatting). - * @returns {object} Object containing the slack message and its formatting. + * @return {object} Object containing the slack message and its formatting. */ function formatSlackMessage( payload, channel, message ) { const { issue, repository } = payload; diff --git a/projects/github-actions/repo-gardening/src/tasks/update-board/index.js b/projects/github-actions/repo-gardening/src/tasks/update-board/index.js index 86a602d3eda63..adaa3f0b85345 100644 --- a/projects/github-actions/repo-gardening/src/tasks/update-board/index.js +++ b/projects/github-actions/repo-gardening/src/tasks/update-board/index.js @@ -20,7 +20,7 @@ const { automatticAssignments } = require( './automattic-label-team-assignments' * @param {string} number - Issue number. * @param {string} action - Action that triggered the event ('opened', 'reopened', 'labeled'). * @param {object} eventLabel - Label that was added to the issue. - * @returns {Promise} Promise resolving to true if the issue has a "Triaged" label. + * @return {Promise} Promise resolving to true if the issue has a "Triaged" label. */ async function hasTriagedLabel( octokit, owner, repo, number, action, eventLabel ) { const labels = await getLabels( octokit, owner, repo, number ); @@ -46,7 +46,7 @@ async function hasTriagedLabel( octokit, owner, repo, number, action, eventLabel * @param {string} number - Issue number. * @param {string} action - Action that triggered the event ('opened', 'reopened', 'labeled'). * @param {object} eventLabel - Label that was added to the issue. - * @returns {Promise} Promise resolving to true if the issue needs a third-party fix. + * @return {Promise} Promise resolving to true if the issue needs a third-party fix. */ async function needsThirdPartyFix( octokit, owner, repo, number, action, eventLabel ) { const labels = await getLabels( octokit, owner, repo, number ); @@ -62,7 +62,7 @@ async function needsThirdPartyFix( octokit, owner, repo, number, action, eventLa * * @param {GitHub} octokit - Initialized Octokit REST client. * @param {string} projectBoardLink - The link to the project board. - * @returns {Promise} - Project board information. + * @return {Promise} - Project board information. */ async function getProjectDetails( octokit, projectBoardLink ) { const projectRegex = @@ -158,7 +158,7 @@ async function getProjectDetails( octokit, projectBoardLink ) { * @param {object} projectInfo - Info about our project board. * @param {string} repoName - The name of the repository. * @param {string} issueId - The ID of the issue. - * @returns {Promise} - The ID of the project item, or an empty string if not found. + * @return {Promise} - The ID of the project item, or an empty string if not found. */ async function getIssueProjectItemId( octokit, projectInfo, repoName, issueId ) { const { ownerName, projectNumber } = projectInfo; @@ -204,7 +204,7 @@ async function getIssueProjectItemId( octokit, projectInfo, repoName, issueId ) * @param {GitHub} octokit - Initialized Octokit REST client. * @param {object} projectInfo - Info about our project board. * @param {string} node_id - The node_id of the Issue. - * @returns {Promise} - Info about the project item id that was created. + * @return {Promise} - Info about the project item id that was created. */ async function addIssueToBoard( octokit, projectInfo, node_id ) { const { projectNodeId } = projectInfo; @@ -244,7 +244,7 @@ async function addIssueToBoard( octokit, projectInfo, node_id ) { * @param {object} projectInfo - Info about our project board. * @param {string} projectItemId - The ID of the project item. * @param {string} priorityText - Priority of our issue (must match an existing column in the project board). - * @returns {Promise} - The new project item id. + * @return {Promise} - The new project item id. */ async function setPriorityField( octokit, projectInfo, projectItemId, priorityText ) { const { @@ -304,7 +304,7 @@ async function setPriorityField( octokit, projectInfo, projectItemId, priorityTe * @param {object} projectInfo - Info about our project board. * @param {string} projectItemId - The ID of the project item. * @param {string} statusText - Status of our issue (must match an existing column in the project board). - * @returns {Promise} - The new project item id. + * @return {Promise} - The new project item id. */ async function setStatusField( octokit, projectInfo, projectItemId, statusText ) { const { @@ -364,7 +364,7 @@ async function setStatusField( octokit, projectInfo, projectItemId, statusText ) * @param {object} projectInfo - Info about our project board. * @param {string} projectItemId - The ID of the project item. * @param {string} team - Team that should be assigned to our issue (must match an existing column in the project board). - * @returns {Promise} - The new project item id. + * @return {Promise} - The new project item id. */ async function setTeamField( octokit, projectInfo, projectItemId, team ) { const { @@ -420,7 +420,7 @@ async function setTeamField( octokit, projectInfo, projectItemId, team ) { * * @param {string} ownerLogin - Repository owner login. * - * @returns {Promise} - Mapping of teams <> labels. + * @return {Promise} - Mapping of teams <> labels. */ async function loadTeamAssignments( ownerLogin ) { // If we're in an Automattic repo, we can use the team assignments file that ships with this action. @@ -460,12 +460,12 @@ async function loadTeamAssignments( ownerLogin ) { * It could be an existing label, * or it could be that it's being added as part of the event that triggers this action. * - * @param {GitHub} octokit - Initialized Octokit REST client. - * @param {object} payload - Issue event payload. - * @param {object} projectInfo - Info about our project board. - * @param {string} projectItemId - The ID of the project item. - * @param {Array} priorityLabels - Array of priority labels. - * @returns {Promise} - The new project item id. + * @param {GitHub} octokit - Initialized Octokit REST client. + * @param {object} payload - Issue event payload. + * @param {object} projectInfo - Info about our project board. + * @param {string} projectItemId - The ID of the project item. + * @param {Array} priorityLabels - Array of priority labels. + * @return {Promise} - The new project item id. */ async function assignTeam( octokit, payload, projectInfo, projectItemId, priorityLabels ) { const { diff --git a/projects/github-actions/repo-gardening/src/tasks/wpcom-commit-reminder/index.js b/projects/github-actions/repo-gardening/src/tasks/wpcom-commit-reminder/index.js index 7a65c4176dc08..308e95828826c 100644 --- a/projects/github-actions/repo-gardening/src/tasks/wpcom-commit-reminder/index.js +++ b/projects/github-actions/repo-gardening/src/tasks/wpcom-commit-reminder/index.js @@ -12,7 +12,7 @@ const getComments = require( '../../utils/get-comments' ); * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Promise} Promise resolving to a string. + * @return {Promise} Promise resolving to a string. */ async function getMatticBotComment( octokit, owner, repo, number ) { let commentBody = ''; @@ -20,14 +20,14 @@ async function getMatticBotComment( octokit, owner, repo, number ) { debug( `wpcom-commit-reminder: Looking for a comment from Matticbot on this PR.` ); const comments = await getComments( octokit, owner.login, repo, number ); - comments.map( comment => { + for ( const comment of comments ) { if ( comment.user.login === 'matticbot' && comment.body.includes( 'This PR has changes that must be merged to WordPress.com' ) ) { commentBody = comment.body; } - } ); + } return commentBody; } @@ -39,20 +39,20 @@ async function getMatticBotComment( octokit, owner, repo, number ) { * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Promise} Promise resolving to boolean. + * @return {Promise} Promise resolving to boolean. */ async function hasReminderComment( octokit, owner, repo, number ) { debug( `wpcom-commit-reminder: Looking for a previous comment from this task in our PR.` ); const comments = await getComments( octokit, owner.login, repo, number ); - comments.map( comment => { + for ( const comment of comments ) { if ( comment.user.login === 'github-actions[bot]' && comment.body.includes( 'Great news! One last step' ) ) { return true; } - } ); + } return false; } diff --git a/projects/github-actions/repo-gardening/src/utils/get-affected-changelogger-projects.js b/projects/github-actions/repo-gardening/src/utils/get-affected-changelogger-projects.js index acc81c33f552a..4a9afeff25735 100644 --- a/projects/github-actions/repo-gardening/src/utils/get-affected-changelogger-projects.js +++ b/projects/github-actions/repo-gardening/src/utils/get-affected-changelogger-projects.js @@ -5,7 +5,7 @@ const getPrWorkspace = require( './get-pr-workspace' ); /** * Returns a list of Projects that use changelogger package * - * @returns {Array} list of changelogger packages + * @return {Array} list of changelogger packages */ function getChangeloggerProjects() { const projects = []; @@ -29,7 +29,7 @@ function getChangeloggerProjects() { * Returns an object with project type and name * * @param {string} file - File path - * @returns {object} Project type and name + * @return {object} Project type and name */ function getProject( file ) { const project = file.match( /projects\/(?[^/]*)\/(?[^/]*)\// ); @@ -47,7 +47,7 @@ function getProject( file ) { * Returns a list of affected projects * * @param {Array} files - List of files - * @returns {Array} List of affected projects + * @return {Array} List of affected projects */ function getAffectedChangeloggerProjects( files ) { const changeloggerProjects = getChangeloggerProjects(); diff --git a/projects/github-actions/repo-gardening/src/utils/get-associated-pull-request.js b/projects/github-actions/repo-gardening/src/utils/get-associated-pull-request.js index 965616f23f52b..7686179d7e646 100644 --- a/projects/github-actions/repo-gardening/src/utils/get-associated-pull-request.js +++ b/projects/github-actions/repo-gardening/src/utils/get-associated-pull-request.js @@ -6,7 +6,7 @@ * cannot be determined. * * @param {WebhookPayloadPushCommit} commit - Commit object. - * @returns {number?} Pull request number, or null if it cannot be determined. + * @return {number?} Pull request number, or null if it cannot be determined. */ function getAssociatedPullRequest( commit ) { const match = commit.message.match( /\(#(\d+)\)$/m ); diff --git a/projects/github-actions/repo-gardening/src/utils/get-comments.js b/projects/github-actions/repo-gardening/src/utils/get-comments.js index 5b263c7c8a1dc..7940dc770e6d7 100644 --- a/projects/github-actions/repo-gardening/src/utils/get-comments.js +++ b/projects/github-actions/repo-gardening/src/utils/get-comments.js @@ -11,7 +11,7 @@ const cache = {}; * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - Issue number. - * @returns {Promise} Promise resolving to an array of all comments on that given issue. + * @return {Promise} Promise resolving to an array of all comments on that given issue. */ async function getComments( octokit, owner, repo, number ) { const issueComments = []; @@ -29,9 +29,9 @@ async function getComments( octokit, owner, repo, number ) { issue_number: +number, per_page: 100, } ) ) { - response.data.map( comment => { + for ( const comment of response.data ) { issueComments.push( comment ); - } ); + } } cache[ cacheKey ] = issueComments; diff --git a/projects/github-actions/repo-gardening/src/utils/get-files.js b/projects/github-actions/repo-gardening/src/utils/get-files.js index ed4c0b1b8aa92..b0fd5f8bbed56 100644 --- a/projects/github-actions/repo-gardening/src/utils/get-files.js +++ b/projects/github-actions/repo-gardening/src/utils/get-files.js @@ -11,7 +11,7 @@ const cache = {}; * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Promise} Promise resolving to an array of all files modified in that PR. + * @return {Promise} Promise resolving to an array of all files modified in that PR. */ async function getFiles( octokit, owner, repo, number ) { const fileList = []; @@ -29,12 +29,12 @@ async function getFiles( octokit, owner, repo, number ) { pull_number: +number, per_page: 100, } ) ) { - response.data.map( file => { + for ( const file of response.data ) { fileList.push( file.filename ); if ( file.previous_filename ) { fileList.push( file.previous_filename ); } - } ); + } } cache[ cacheKey ] = fileList; diff --git a/projects/github-actions/repo-gardening/src/utils/get-next-valid-milestone.js b/projects/github-actions/repo-gardening/src/utils/get-next-valid-milestone.js index fd33c24a238b5..1257cdb0571c3 100644 --- a/projects/github-actions/repo-gardening/src/utils/get-next-valid-milestone.js +++ b/projects/github-actions/repo-gardening/src/utils/get-next-valid-milestone.js @@ -12,7 +12,7 @@ const cache = {}; * @param {GitHub} octokit - Initialized Octokit REST client. * @param {string} owner - Repository owner. * @param {string} repo - Repository name. - * @returns {Promise} Promise resolving to an array of all open milestones. + * @return {Promise} Promise resolving to an array of all open milestones. */ async function getOpenMilestones( octokit, owner, repo ) { const milestones = []; @@ -45,7 +45,7 @@ async function getOpenMilestones( octokit, owner, repo ) { * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} plugin - Plugin slug. - * @returns {Promise} Promise resolving to milestone, if exists. + * @return {Promise} Promise resolving to milestone, if exists. */ async function getNextValidMilestone( octokit, owner, repo, plugin = 'jetpack' ) { // Find all valid milestones for the specified plugin. diff --git a/projects/github-actions/repo-gardening/src/utils/get-plugin-names.js b/projects/github-actions/repo-gardening/src/utils/get-plugin-names.js index ad1f1926cd104..562a27b0ad286 100644 --- a/projects/github-actions/repo-gardening/src/utils/get-plugin-names.js +++ b/projects/github-actions/repo-gardening/src/utils/get-plugin-names.js @@ -9,17 +9,17 @@ const getLabels = require( './labels/get-labels' ); * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR / Issue number. - * @returns {Promise} Promise resolving to an array of all the plugins touched by that PR. + * @return {Promise} Promise resolving to an array of all the plugins touched by that PR. */ async function getPluginNames( octokit, owner, repo, number ) { const plugins = []; const labels = await getLabels( octokit, owner, repo, number ); - labels.map( label => { + for ( const label of labels ) { const plugin = label.match( /^\[Plugin\]\s(?[^/]*)$/ ); if ( plugin && plugin.groups.pluginName ) { plugins.push( plugin.groups.pluginName.replace( /\s+/, '-' ).toLowerCase() ); } - } ); + } return plugins; } diff --git a/projects/github-actions/repo-gardening/src/utils/get-pr-workspace.js b/projects/github-actions/repo-gardening/src/utils/get-pr-workspace.js index 2a02aa0c6359a..33c33d0fbd8bf 100644 --- a/projects/github-actions/repo-gardening/src/utils/get-pr-workspace.js +++ b/projects/github-actions/repo-gardening/src/utils/get-pr-workspace.js @@ -1,7 +1,7 @@ /** * Get the path to the PR workspace. * - * @returns {string} Path. + * @return {string} Path. */ function getPrWorkspace() { if ( 'undefined' !== typeof process.env.PR_WORKSPACE ) { diff --git a/projects/github-actions/repo-gardening/src/utils/if-not-closed.js b/projects/github-actions/repo-gardening/src/utils/if-not-closed.js index 7f14c883a7de6..7d54e60eac2ad 100644 --- a/projects/github-actions/repo-gardening/src/utils/if-not-closed.js +++ b/projects/github-actions/repo-gardening/src/utils/if-not-closed.js @@ -7,7 +7,7 @@ const debug = require( './debug' ); * handler only if the PR is not currently closed. * * @param {WPAutomationTask} handler - Original task. - * @returns {WPAutomationTask} Enhanced task. + * @return {WPAutomationTask} Enhanced task. */ function ifNotClosed( handler ) { const newHandler = ( payload, octokit ) => { diff --git a/projects/github-actions/repo-gardening/src/utils/if-not-fork.js b/projects/github-actions/repo-gardening/src/utils/if-not-fork.js index 7ee43ee25024b..dcc860a6b6f01 100644 --- a/projects/github-actions/repo-gardening/src/utils/if-not-fork.js +++ b/projects/github-actions/repo-gardening/src/utils/if-not-fork.js @@ -8,7 +8,7 @@ const debug = require( './debug' ); * pull request event which did not originate from a forked repository. * * @param {WPAutomationTask} handler - Original task. - * @returns {WPAutomationTask} Enhanced task. + * @return {WPAutomationTask} Enhanced task. */ function ifNotFork( handler ) { const newHandler = ( payload, octokit ) => { diff --git a/projects/github-actions/repo-gardening/src/utils/labels/get-labels.js b/projects/github-actions/repo-gardening/src/utils/labels/get-labels.js index 020e7c662f491..6cbec5236d2b0 100644 --- a/projects/github-actions/repo-gardening/src/utils/labels/get-labels.js +++ b/projects/github-actions/repo-gardening/src/utils/labels/get-labels.js @@ -11,7 +11,7 @@ const cache = {}; * @param {string} owner - Repository owner. * @param {string} repo - Repository name. * @param {string} number - PR number. - * @returns {Promise} Promise resolving to an array of all labels for that PR. + * @return {Promise} Promise resolving to an array of all labels for that PR. */ async function getLabels( octokit, owner, repo, number ) { const labelList = []; @@ -29,9 +29,9 @@ async function getLabels( octokit, owner, repo, number ) { issue_number: +number, per_page: 100, } ) ) { - response.data.map( label => { + for ( const label of response.data ) { labelList.push( label.name ); - } ); + } } cache[ cacheKey ] = labelList; diff --git a/projects/github-actions/repo-gardening/src/utils/labels/has-escalated-label.js b/projects/github-actions/repo-gardening/src/utils/labels/has-escalated-label.js index 1790442144dcd..7f377f2dfa3f6 100644 --- a/projects/github-actions/repo-gardening/src/utils/labels/has-escalated-label.js +++ b/projects/github-actions/repo-gardening/src/utils/labels/has-escalated-label.js @@ -13,7 +13,7 @@ const getLabels = require( './get-labels' ); * @param {string} number - Issue number. * @param {string} action - Action that triggered the event ('opened', 'reopened', 'labeled'). * @param {object} eventLabel - Label that was added to the issue. - * @returns {Promise} Promise resolving to boolean. + * @return {Promise} Promise resolving to boolean. */ async function hasEscalatedLabel( octokit, owner, repo, number, action, eventLabel ) { // Check for an exisiting label first. diff --git a/projects/github-actions/repo-gardening/src/utils/labels/has-priority-labels.js b/projects/github-actions/repo-gardening/src/utils/labels/has-priority-labels.js index bb1d08a3af436..0e4b6d113cbc4 100644 --- a/projects/github-actions/repo-gardening/src/utils/labels/has-priority-labels.js +++ b/projects/github-actions/repo-gardening/src/utils/labels/has-priority-labels.js @@ -13,7 +13,7 @@ const getLabels = require( './get-labels' ); * @param {string} number - Issue number. * @param {string} action - Action that triggered the event ('opened', 'reopened', 'labeled'). * @param {object} eventLabel - Label that was added to the issue. - * @returns {Promise} Promise resolving to an array of Priority labels. + * @return {Promise} Promise resolving to an array of Priority labels. */ async function hasPriorityLabels( octokit, owner, repo, number, action, eventLabel ) { const labels = await getLabels( octokit, owner, repo, number ); diff --git a/projects/github-actions/repo-gardening/src/utils/labels/is-bug.js b/projects/github-actions/repo-gardening/src/utils/labels/is-bug.js index ea92292d9f2e9..35ec1761e2d20 100644 --- a/projects/github-actions/repo-gardening/src/utils/labels/is-bug.js +++ b/projects/github-actions/repo-gardening/src/utils/labels/is-bug.js @@ -13,7 +13,7 @@ const getLabels = require( './get-labels' ); * @param {string} number - Issue number. * @param {string} action - Action that triggered the event ('opened', 'reopened', 'labeled'). * @param {object} eventLabel - Label that was added to the issue. - * @returns {Promise} Promise resolving to boolean. + * @return {Promise} Promise resolving to boolean. */ async function isBug( octokit, owner, repo, number, action, eventLabel ) { // If the issue has a "[Type] Bug" label, it's a bug. diff --git a/projects/github-actions/repo-gardening/src/utils/parse-content/find-platforms.js b/projects/github-actions/repo-gardening/src/utils/parse-content/find-platforms.js index fcfa0062f949a..8900ac5369671 100644 --- a/projects/github-actions/repo-gardening/src/utils/parse-content/find-platforms.js +++ b/projects/github-actions/repo-gardening/src/utils/parse-content/find-platforms.js @@ -3,7 +3,7 @@ const debug = require( '../debug' ); * Find platform info, based off issue contents. * * @param {string} body - The issue content. - * @returns {Array} Platforms impacted by issue. + * @return {Array} Platforms impacted by issue. */ function findPlatforms( body ) { const regex = /###\sPlatform\s\(Simple\sand\/or Atomic\)\n\n([a-zA-Z ,-]*)\n\n/gm; diff --git a/projects/github-actions/repo-gardening/src/utils/parse-content/find-plugins.js b/projects/github-actions/repo-gardening/src/utils/parse-content/find-plugins.js index 202c6bed17eda..9bda2f45b5ec8 100644 --- a/projects/github-actions/repo-gardening/src/utils/parse-content/find-plugins.js +++ b/projects/github-actions/repo-gardening/src/utils/parse-content/find-plugins.js @@ -4,7 +4,7 @@ const debug = require( '../debug' ); * Find list of plugins impacted by issue, based off issue contents. * * @param {string} body - The issue content. - * @returns {Array} Plugins concerned by issue. + * @return {Array} Plugins concerned by issue. */ function findPlugins( body ) { const regex = /###\sImpacted\splugin\n\n([a-zA-Z ,]*)\n\n/gm; diff --git a/projects/github-actions/repo-gardening/src/utils/parse-content/find-priority.js b/projects/github-actions/repo-gardening/src/utils/parse-content/find-priority.js index 799fdee83de80..137effa04b940 100644 --- a/projects/github-actions/repo-gardening/src/utils/parse-content/find-priority.js +++ b/projects/github-actions/repo-gardening/src/utils/parse-content/find-priority.js @@ -5,7 +5,7 @@ const debug = require( '../debug' ); * Logic follows this priority matrix: pciE2j-oG-p2 * * @param {string} body - The issue content. - * @returns {string} Priority of issue. + * @return {string} Priority of issue. */ function findPriority( body ) { // Look for priority indicators in body. diff --git a/projects/github-actions/repo-gardening/src/utils/parse-content/has-many-support-references.js b/projects/github-actions/repo-gardening/src/utils/parse-content/has-many-support-references.js index 7839fa5368ea0..586b8b078a11d 100644 --- a/projects/github-actions/repo-gardening/src/utils/parse-content/has-many-support-references.js +++ b/projects/github-actions/repo-gardening/src/utils/parse-content/has-many-support-references.js @@ -7,13 +7,12 @@ const { getInput } = require( '@actions/core' ); * We only count the number of unanswered support references, since they're the ones we'll need to contact. * * @param {Array} issueComments - Array of all comments on that issue. - * @returns {Promise} Promise resolving to boolean. + * @return {Promise} Promise resolving to boolean. */ async function hasManySupportReferences( issueComments ) { const referencesThreshhold = getInput( 'reply_to_customers_threshold' ); - let isWidelySpreadIssue = false; - issueComments.map( comment => { + for ( const comment of issueComments ) { if ( comment.user.login === 'github-actions[bot]' && comment.body.includes( '**Support References**' ) @@ -21,12 +20,12 @@ async function hasManySupportReferences( issueComments ) { // Count the number of to-do items in the comment. const countReferences = comment.body.split( '- [ ] ' ).length - 1; if ( countReferences >= parseInt( referencesThreshhold ) ) { - isWidelySpreadIssue = true; + return true; } } - } ); + } - return isWidelySpreadIssue; + return false; } module.exports = hasManySupportReferences; diff --git a/projects/github-actions/repo-gardening/src/utils/slack/format-slack-message.js b/projects/github-actions/repo-gardening/src/utils/slack/format-slack-message.js index eceef0c8f57b6..2bb40b7548256 100644 --- a/projects/github-actions/repo-gardening/src/utils/slack/format-slack-message.js +++ b/projects/github-actions/repo-gardening/src/utils/slack/format-slack-message.js @@ -7,7 +7,7 @@ * @param {WebhookPayloadIssue} payload - Issue event payload. * @param {string} channel - Slack channel ID. * @param {string} message - Basic message (without the formatting). - * @returns {object} Object containing the slack message and its formatting. + * @return {object} Object containing the slack message and its formatting. */ function formatSlackMessage( payload, channel, message ) { const { issue } = payload; diff --git a/projects/github-actions/repo-gardening/src/utils/slack/send-slack-message.js b/projects/github-actions/repo-gardening/src/utils/slack/send-slack-message.js index c5e7f14527709..ad4f771a3cade 100644 --- a/projects/github-actions/repo-gardening/src/utils/slack/send-slack-message.js +++ b/projects/github-actions/repo-gardening/src/utils/slack/send-slack-message.js @@ -10,7 +10,7 @@ const fetch = require( 'node-fetch' ); * @param {string} channel - Slack channel ID. * @param {WebhookPayloadPullRequest|WebhookPayloadIssue} payload - Pull request event payload. * @param {object} customMessageFormat - Custom message formatting. If defined, takes over from message completely. - * @returns {Promise} Promise resolving to a boolean, whether message was successfully posted or not. + * @return {Promise} Promise resolving to a boolean, whether message was successfully posted or not. */ async function sendSlackMessage( message, channel, payload, customMessageFormat = {} ) { const token = getInput( 'slack_token' ); diff --git a/projects/github-actions/required-review/changelog/try-no-version-bumps-in-trunk b/projects/github-actions/required-review/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..91efe85c55e06 --- /dev/null +++ b/projects/github-actions/required-review/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/github-actions/required-review/changelog/update-jsdoc-comments-for-wp-coding-standards b/projects/github-actions/required-review/changelog/update-jsdoc-comments-for-wp-coding-standards new file mode 100644 index 0000000000000..0e655b2b8b7a3 --- /dev/null +++ b/projects/github-actions/required-review/changelog/update-jsdoc-comments-for-wp-coding-standards @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Reformat jsdoc comments. No change to meaning or functionality. + + diff --git a/projects/github-actions/required-review/package.json b/projects/github-actions/required-review/package.json index c9979345b3fb2..23f457596be82 100644 --- a/projects/github-actions/required-review/package.json +++ b/projects/github-actions/required-review/package.json @@ -1,6 +1,6 @@ { "name": "required-review", - "version": "4.0.1-alpha", + "version": "4.0.0", "description": "Check that a Pull Request has reviews from required teams.", "main": "index.js", "author": "Automattic", diff --git a/projects/github-actions/required-review/src/main.js b/projects/github-actions/required-review/src/main.js index e9f98dcbcc280..1e730bcbeae04 100644 --- a/projects/github-actions/required-review/src/main.js +++ b/projects/github-actions/required-review/src/main.js @@ -8,7 +8,7 @@ const Requirement = require( './requirement.js' ); /** * Load the requirements yaml file. * - * @returns {Requirement[]} Requirements. + * @return {Requirement[]} Requirements. */ async function getRequirements() { let requirementsString = core.getInput( 'requirements' ); diff --git a/projects/github-actions/required-review/src/paths.js b/projects/github-actions/required-review/src/paths.js index ee81f5dfdc7a4..395b8b791e391 100644 --- a/projects/github-actions/required-review/src/paths.js +++ b/projects/github-actions/required-review/src/paths.js @@ -5,7 +5,7 @@ const { WError } = require( 'error' ); /** * Fetch the paths in the current PR. * - * @returns {string[]} Paths. + * @return {string[]} Paths. */ async function fetchPaths() { const octokit = github.getOctokit( core.getInput( 'token', { required: true } ) ); diff --git a/projects/github-actions/required-review/src/reporter.js b/projects/github-actions/required-review/src/reporter.js index 3554ade44f835..b4f2a932be78d 100644 --- a/projects/github-actions/required-review/src/reporter.js +++ b/projects/github-actions/required-review/src/reporter.js @@ -10,7 +10,7 @@ const STATE_SUCCESS = 'success'; /** * Report a status check to GitHub. * - * @param {string} state - One of the `STATE_*` constants. + * @param {string} state - One of the `STATE_*` constants. * @param {string} description - Description for the status. */ async function status( state, description ) { diff --git a/projects/github-actions/required-review/src/requirement.js b/projects/github-actions/required-review/src/requirement.js index 5d2258fc2caf4..0ed4af3691dc5 100644 --- a/projects/github-actions/required-review/src/requirement.js +++ b/projects/github-actions/required-review/src/requirement.js @@ -9,10 +9,10 @@ class RequirementError extends SError {} /** * Prints a result set, then returns it. * - * @param {string} label - Label for the set. + * @param {string} label - Label for the set. * @param {string[]} teamReviewers - Team members that have reviewed the file. If an empty array, will print `` instead. - * @param {string[]} neededTeams - Teams that have no reviews from it's members. - * @returns {{teamReviewers, neededTeams}} `{teamReviewers, neededTeams}`. + * @param {string[]} neededTeams - Teams that have no reviews from it's members. + * @return {{teamReviewers, neededTeams}} `{teamReviewers, neededTeams}`. */ function printSet( label, teamReviewers, neededTeams ) { core.info( label + ' ' + ( teamReviewers.length ? teamReviewers.join( ', ' ) : '' ) ); @@ -22,10 +22,10 @@ function printSet( label, teamReviewers, neededTeams ) { /** * Build a reviewer team membership filter. * - * @param {object} config - Requirements configuration object being processed. + * @param {object} config - Requirements configuration object being processed. * @param {Array|string|object} teamConfig - Team name, or single-key object with a list of teams/objects, or array of such. - * @param {string} indent - String for indentation. - * @returns {Function} Function to filter an array of reviewers by membership in the team(s). + * @param {string} indent - String for indentation. + * @return {Function} Function to filter an array of reviewers by membership in the team(s). */ function buildReviewerFilter( config, teamConfig, indent ) { if ( typeof teamConfig === 'string' ) { @@ -140,10 +140,10 @@ class Requirement { /** * Constructor. * - * @param {object} config - Object config - * @param {string[]|string} config.paths - Paths this requirement applies to. Either an array of picomatch globs, or the string "unmatched". - * @param {Array} config.teams - Team reviews requirements. - * @param {boolean} config.consume - Whether matched paths should be ignored by later rules. + * @param {object} config - Object config + * @param {string[]|string} config.paths - Paths this requirement applies to. Either an array of picomatch globs, or the string "unmatched". + * @param {Array} config.teams - Team reviews requirements. + * @param {boolean} config.consume - Whether matched paths should be ignored by later rules. */ constructor( config ) { this.name = config.name || 'Unnamed requirement'; @@ -197,12 +197,12 @@ class Requirement { /** * Test whether this requirement applies to the passed paths. * - * @param {string[]} paths - Paths to test against. + * @param {string[]} paths - Paths to test against. * @param {string[]} matchedPaths - Paths that have already been matched. - * @returns {object} _ Results object. - * @returns {boolean} _.applies Whether the requirement applies. - * @returns {string[]} _.matchedPaths New value for `matchedPaths`. - * @returns {string[]} _.paths New value for `paths`. + * @return {object} _ Results object. + * @return {boolean} _.applies Whether the requirement applies. + * @return {string[]} _.matchedPaths New value for `matchedPaths`. + * @return {string[]} _.paths New value for `paths`. */ appliesToPaths( paths, matchedPaths ) { let matches; @@ -239,7 +239,7 @@ class Requirement { * Test whether this requirement is satisfied. * * @param {string[]} reviewers - Reviewers to test against. - * @returns {boolean} Whether the requirement is satisfied. + * @return {boolean} Whether the requirement is satisfied. */ async needsReviewsFrom( reviewers ) { core.info( 'Checking reviewers...' ); diff --git a/projects/github-actions/required-review/src/reviewers.js b/projects/github-actions/required-review/src/reviewers.js index abaf02d2f9359..65c0ed4410d44 100644 --- a/projects/github-actions/required-review/src/reviewers.js +++ b/projects/github-actions/required-review/src/reviewers.js @@ -5,7 +5,7 @@ const { WError } = require( 'error' ); /** * Fetch the reviewers approving the current PR. * - * @returns {string[]} Reviewers. + * @return {string[]} Reviewers. */ async function fetchReviewers() { const octokit = github.getOctokit( core.getInput( 'token', { required: true } ) ); diff --git a/projects/github-actions/required-review/src/team-members.js b/projects/github-actions/required-review/src/team-members.js index 7b9307f2a2e88..d2978a876985a 100644 --- a/projects/github-actions/required-review/src/team-members.js +++ b/projects/github-actions/required-review/src/team-members.js @@ -9,7 +9,7 @@ const cache = {}; * Special case: Names prefixed with @ are considered to be a one-member team with the named GitHub user. * * @param {string} team - GitHub team slug, or @ followed by a GitHub user name. - * @returns {string[]} Team members. + * @return {string[]} Team members. */ async function fetchTeamMembers( team ) { if ( cache[ team ] ) { diff --git a/projects/github-actions/test-results-to-slack/changelog/try-lossless-image-optmization-part-3 b/projects/github-actions/test-results-to-slack/changelog/try-lossless-image-optmization-part-3 new file mode 100644 index 0000000000000..cf77a8b55bb43 --- /dev/null +++ b/projects/github-actions/test-results-to-slack/changelog/try-lossless-image-optmization-part-3 @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Lossless image optimization for images (should improve performance with no visible changes). diff --git a/projects/github-actions/test-results-to-slack/changelog/try-no-version-bumps-in-trunk b/projects/github-actions/test-results-to-slack/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..91efe85c55e06 --- /dev/null +++ b/projects/github-actions/test-results-to-slack/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/github-actions/test-results-to-slack/changelog/update-jsdoc-comments-for-wp-coding-standards b/projects/github-actions/test-results-to-slack/changelog/update-jsdoc-comments-for-wp-coding-standards new file mode 100644 index 0000000000000..0e655b2b8b7a3 --- /dev/null +++ b/projects/github-actions/test-results-to-slack/changelog/update-jsdoc-comments-for-wp-coding-standards @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Reformat jsdoc comments. No change to meaning or functionality. + + diff --git a/projects/github-actions/test-results-to-slack/package.json b/projects/github-actions/test-results-to-slack/package.json index 482ccc99fc211..7ac0f009ff539 100644 --- a/projects/github-actions/test-results-to-slack/package.json +++ b/projects/github-actions/test-results-to-slack/package.json @@ -1,6 +1,6 @@ { "name": "test-results-to-slack", - "version": "0.3.1-alpha", + "version": "0.3.0", "description": "GitHub Action to send Slack notifications with test results", "author": "Automattic", "license": "GPL-2.0-or-later", diff --git a/projects/github-actions/test-results-to-slack/src/github.js b/projects/github-actions/test-results-to-slack/src/github.js index 3ef7e8b76dbbe..23a8d5ae4c7b9 100644 --- a/projects/github-actions/test-results-to-slack/src/github.js +++ b/projects/github-actions/test-results-to-slack/src/github.js @@ -5,7 +5,7 @@ const extras = require( './extra-context' ); * Decides if the current workflow failed * * @param {string} token - GitHub token - * @returns {boolean} Whether it failed. + * @return {boolean} Whether it failed. */ async function isWorkflowFailed( token ) { // eslint-disable-next-line new-cap @@ -37,7 +37,7 @@ async function isWorkflowFailed( token ) { * Creates and returns a run url * * @param {boolean} withAttempt - whether to include the run attempt in the url - * @returns {string} the run url + * @return {string} the run url */ function getRunUrl( withAttempt = true ) { const { serverUrl, runId } = github.context; diff --git a/projects/github-actions/test-results-to-slack/src/message.js b/projects/github-actions/test-results-to-slack/src/message.js index cb15ea9906c1a..171e2179dcef0 100644 --- a/projects/github-actions/test-results-to-slack/src/message.js +++ b/projects/github-actions/test-results-to-slack/src/message.js @@ -17,7 +17,7 @@ const { refType, refName, runAttempt, triggeringActor, repository } = extras; * that can be used later on to find this message and update it or send replies. * * @param {boolean} isFailure - whether the workflow is failed or not - * @returns {object} Notificaton data as described + * @return {object} Notificaton data as described */ async function createMessage( isFailure ) { let target = `for ${ sha }`; @@ -143,7 +143,7 @@ async function createMessage( isFailure ) { * Returns a Slack context block element with a given text. * * @param {string} text - the text of the element - * @returns {object} - the block element + * @return {object} - the block element */ function getTextContextElement( text ) { return { @@ -157,8 +157,8 @@ function getTextContextElement( text ) { * Returns a Slack button element with a given text and url. * * @param {string} text - the text of the button - * @param {string} url - the url of the button - * @returns {object} - the button element + * @param {string} url - the url of the button + * @return {object} - the button element */ function getButton( text, url ) { return { @@ -175,9 +175,9 @@ function getButton( text, url ) { * Creates the message and sends it if the rules are met. * * @param {string} slackToken - the Slack token - * @param {string} ghToken - the GitHub token - * @param {string} channel - the id of the channel to send the message to - * @param {string} username - the username to use when sending the message + * @param {string} ghToken - the GitHub token + * @param {string} channel - the id of the channel to send the message to + * @param {string} username - the username to use when sending the message */ async function sendMessage( slackToken, ghToken, channel, username ) { const client = new WebClient( slackToken ); diff --git a/projects/github-actions/test-results-to-slack/src/playwright.js b/projects/github-actions/test-results-to-slack/src/playwright.js index 084d4eca532e2..75b9a67191ec1 100644 --- a/projects/github-actions/test-results-to-slack/src/playwright.js +++ b/projects/github-actions/test-results-to-slack/src/playwright.js @@ -6,7 +6,7 @@ const { debug } = require( './debug' ); /** * Parses multiple Playwright JSON reports and returns details about the failed tests. * - * @returns {object} an array of Slack blocks with test failure details. + * @return {object} an array of Slack blocks with test failure details. */ function getPlaywrightBlocks() { const blocks = []; @@ -101,7 +101,7 @@ function getPlaywrightBlocks() { /** * Parses multiple Playwright JSON reports and returns their content as an array of objects. * - * @returns {object} an array of Playwright reports. + * @return {object} an array of Playwright reports. */ function getPlaywrightReports() { let parseError = false; @@ -124,7 +124,7 @@ function getPlaywrightReports() { /** * Parses the 'playwright_report_path' input and finds matching files. * - * @returns {Array} an array of matching paths. + * @return {Array} an array of matching paths. */ function getPlaywrightReportsPaths() { const playwrightReportPath = getInput( 'playwright_report_path' ); @@ -146,9 +146,9 @@ function getPlaywrightReportsPaths() { /** * Creates the final path to attachments. * - * @param {string} outputPath - the output root path, as defined in the Playwright report + * @param {string} outputPath - the output root path, as defined in the Playwright report * @param {string} attachmentPath - the original path to the attachment, as defined in the Playwright report - * @returns {string} the final path to the attachment + * @return {string} the final path to the attachment */ function getAttachmentPath( outputPath, attachmentPath ) { const resultsPath = getInput( 'playwright_output_dir' ); @@ -175,7 +175,7 @@ function getAttachmentPath( outputPath, attachmentPath ) { * Flattens the suites in a Playwright report. * * @param {[object]} suites - an array of nested suites from a Playwright test report - * @returns {[object]} an array of flattened suites + * @return {[object]} an array of flattened suites */ function flattenSuites( suites ) { return suites.reduce( ( all, curr ) => { diff --git a/projects/github-actions/test-results-to-slack/src/rules.js b/projects/github-actions/test-results-to-slack/src/rules.js index 6dab25969da8d..7391554db7fe1 100644 --- a/projects/github-actions/test-results-to-slack/src/rules.js +++ b/projects/github-actions/test-results-to-slack/src/rules.js @@ -6,7 +6,7 @@ const extras = require( './extra-context' ); /** * Returns a list o Slack channel ids, based on context and rules configuration. * - * @returns {string[]} an array of channels ids + * @return {string[]} an array of channels ids */ function getChannels() { const channels = []; diff --git a/projects/github-actions/test-results-to-slack/src/slack.js b/projects/github-actions/test-results-to-slack/src/slack.js index 4ec741e4f9924..61e61b51810e5 100644 --- a/projects/github-actions/test-results-to-slack/src/slack.js +++ b/projects/github-actions/test-results-to-slack/src/slack.js @@ -4,10 +4,10 @@ const { debug, error } = require( './debug' ); /** * Sends a Slack message. * - * @param {object} client - Slack client - * @param {boolean} update - if it should update a message. For true, it will update an existing message based on `ts`, false will send a new message. - * @param {object} options - options - * @returns {Promise<*>} the response from the Slack API. In case when multiple messages are sent due to the blocks length the last message response is returned. + * @param {object} client - Slack client + * @param {boolean} update - if it should update a message. For true, it will update an existing message based on `ts`, false will send a new message. + * @param {object} options - options + * @return {Promise<*>} the response from the Slack API. In case when multiple messages are sent due to the blocks length the last message response is returned. */ async function postOrUpdateMessage( client, update, options ) { const { text, blocks = [], channel, username, icon_emoji, ts, thread_ts } = options; @@ -62,9 +62,9 @@ async function postOrUpdateMessage( client, update, options ) { /** * Split an array of blocks into chunks of a given size * - * @param {[object]} blocks - the array to be split - * @param {number} chunkSize - the maximum size of each chunk - * @returns {[object]} the array of chunks + * @param {[object]} blocks - the array to be split + * @param {number} chunkSize - the maximum size of each chunk + * @return {[object]} the array of chunks */ function getBlocksChunksBySize( blocks, chunkSize ) { const chunks = []; @@ -81,8 +81,8 @@ function getBlocksChunksBySize( blocks, chunkSize ) { * the result will be [ [ {type: 'context'}, {type: 'context'} ], [ {type: 'file'} ], [ {type: 'context'} ] ] * * @param {[object]} blocks - the array to be split - * @param {string} type - the type property to use as delimiter - * @returns {[object]} the array of chunks + * @param {string} type - the type property to use as delimiter + * @return {[object]} the array of chunks */ function getBlocksChunksByType( blocks, type ) { const chunks = []; @@ -108,10 +108,10 @@ function getBlocksChunksByType( blocks, type ) { /** * Split an array of blocks into chunks based on a given type property as delimiter and a max size * - * @param {[object]} blocks - the array to be split - * @param {number} maxSize - the maximum size of each chunk - * @param {string} typeDelimiter - the type property to use as delimiter - * @returns {[object]} the array of chunks + * @param {[object]} blocks - the array to be split + * @param {number} maxSize - the maximum size of each chunk + * @param {string} typeDelimiter - the type property to use as delimiter + * @return {[object]} the array of chunks */ function getBlocksChunks( blocks, maxSize, typeDelimiter ) { const chunksByType = getBlocksChunksByType( blocks, typeDelimiter ); @@ -129,10 +129,10 @@ function getBlocksChunks( blocks, maxSize, typeDelimiter ) { /** * Finds and returns a Slack message that contains a given string in its text (not in blocks!) * - * @param {object} client - the Slack client - * @param {string} channelId - the channel id + * @param {object} client - the Slack client + * @param {string} channelId - the channel id * @param {string} identifier - the string to search for in the messages text - * @returns {Promise<*|null>} the message Object + * @return {Promise<*|null>} the message Object */ async function getMessage( client, channelId, identifier ) { debug( `Looking for ${ identifier }` ); diff --git a/projects/github-actions/test-results-to-slack/tests/resources/playwright/suite-1/results/spec-1/test-failed-1.png b/projects/github-actions/test-results-to-slack/tests/resources/playwright/suite-1/results/spec-1/test-failed-1.png index 0251582d6c47e..96aedec7db4f4 100755 Binary files a/projects/github-actions/test-results-to-slack/tests/resources/playwright/suite-1/results/spec-1/test-failed-1.png and b/projects/github-actions/test-results-to-slack/tests/resources/playwright/suite-1/results/spec-1/test-failed-1.png differ diff --git a/projects/github-actions/test-results-to-slack/tests/resources/playwright/suite-2/results/spec-1-retry-1/test-failed-1.png b/projects/github-actions/test-results-to-slack/tests/resources/playwright/suite-2/results/spec-1-retry-1/test-failed-1.png index 57143f55e3447..5be538fd8c868 100755 Binary files a/projects/github-actions/test-results-to-slack/tests/resources/playwright/suite-2/results/spec-1-retry-1/test-failed-1.png and b/projects/github-actions/test-results-to-slack/tests/resources/playwright/suite-2/results/spec-1-retry-1/test-failed-1.png differ diff --git a/projects/github-actions/test-results-to-slack/tests/resources/playwright/suite-2/results/spec-1/test-failed-1.png b/projects/github-actions/test-results-to-slack/tests/resources/playwright/suite-2/results/spec-1/test-failed-1.png index 57143f55e3447..2629503bbe274 100755 Binary files a/projects/github-actions/test-results-to-slack/tests/resources/playwright/suite-2/results/spec-1/test-failed-1.png and b/projects/github-actions/test-results-to-slack/tests/resources/playwright/suite-2/results/spec-1/test-failed-1.png differ diff --git a/projects/github-actions/test-results-to-slack/tests/rules.test.js b/projects/github-actions/test-results-to-slack/tests/rules.test.js index 2e7c6d3fc625a..932737eda70b5 100644 --- a/projects/github-actions/test-results-to-slack/tests/rules.test.js +++ b/projects/github-actions/test-results-to-slack/tests/rules.test.js @@ -43,7 +43,7 @@ describe( 'Notification rules', () => { * Writes the rules object to a temp file and returns the path to that file. * * @param {object} rules - the rules object - * @returns {string|undefined} the path to the temp file + * @return {string|undefined} the path to the temp file */ function writeRules( rules ) { const rulesPath = './tests/ignore'; diff --git a/projects/js-packages/ai-client/CHANGELOG.md b/projects/js-packages/ai-client/CHANGELOG.md index cd80969d1620a..e553ca4c177b1 100644 --- a/projects/js-packages/ai-client/CHANGELOG.md +++ b/projects/js-packages/ai-client/CHANGELOG.md @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.16.4] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + +## [0.16.3] - 2024-08-21 +### Fixed +- Revert recent SVG image optimizations. [#38981] + +## [0.16.2] - 2024-08-19 +### Changed +- Update dependencies. [#38861] [#38662] [#38665] [#38893] + +### Fixed +- Lossless image optimization for images (should improve performance with no visible changes). [#38750] + ## [0.16.1] - 2024-08-05 ### Changed - AI Logo Generator: fix UI issues. [#38590] @@ -377,6 +392,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated package dependencies. [#31659] - Updated package dependencies. [#31785] +[0.16.4]: https://github.com/Automattic/jetpack-ai-client/compare/v0.16.3...v0.16.4 +[0.16.3]: https://github.com/Automattic/jetpack-ai-client/compare/v0.16.2...v0.16.3 +[0.16.2]: https://github.com/Automattic/jetpack-ai-client/compare/v0.16.1...v0.16.2 [0.16.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.16.0...v0.16.1 [0.16.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.15.0...v0.16.0 [0.15.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.14.6...v0.15.0 diff --git a/projects/js-packages/ai-client/changelog/update-jetpack-ai-add-fair-usage-message-on-extension-ai-control b/projects/js-packages/ai-client/changelog/update-jetpack-ai-add-fair-usage-message-on-extension-ai-control new file mode 100644 index 0000000000000..1d373fa53cda5 --- /dev/null +++ b/projects/js-packages/ai-client/changelog/update-jetpack-ai-add-fair-usage-message-on-extension-ai-control @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Jetpack AI: support fair usage messaging on the Extension AI Control component. diff --git a/projects/js-packages/ai-client/composer.json b/projects/js-packages/ai-client/composer.json index 7cc00fdae6009..ee5d3bcdf78df 100644 --- a/projects/js-packages/ai-client/composer.json +++ b/projects/js-packages/ai-client/composer.json @@ -5,7 +5,7 @@ "license": "GPL-2.0-or-later", "require": {}, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "autoload": { diff --git a/projects/js-packages/ai-client/package.json b/projects/js-packages/ai-client/package.json index 488ce5f0ba562..c27839c7497f1 100644 --- a/projects/js-packages/ai-client/package.json +++ b/projects/js-packages/ai-client/package.json @@ -1,7 +1,7 @@ { "private": false, "name": "@automattic/jetpack-ai-client", - "version": "0.16.2-alpha", + "version": "0.16.4", "description": "A JS client for consuming Jetpack AI services", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/ai-client/#readme", "bugs": { diff --git a/projects/js-packages/ai-client/src/ask-question/index.ts b/projects/js-packages/ai-client/src/ask-question/index.ts index 4211b66976bc1..bfc49863efbcb 100644 --- a/projects/js-packages/ai-client/src/ask-question/index.ts +++ b/projects/js-packages/ai-client/src/ask-question/index.ts @@ -46,9 +46,9 @@ const debug = debugFactory( 'jetpack-ai-client:ask-question' ); * An asynchronous function that asks a question * and returns an event source with suggestions. * - * @param {PromptProp} question - The question to ask. It can be a simple string or an array of PromptMessageItemProps objects. - * @param {AskQuestionOptionsArgProps} options - An optional object for additional configuration: - * @returns {Promise} A promise that resolves to an instance of the SuggestionsEventSource + * @param {PromptProp} question - The question to ask. It can be a simple string or an array of PromptMessageItemProps objects. + * @param {AskQuestionOptionsArgProps} options - An optional object for additional configuration: + * @return {Promise} A promise that resolves to an instance of the SuggestionsEventSource * @example * const question = "What is the meaning of life?"; * const options = { diff --git a/projects/js-packages/ai-client/src/ask-question/sync.ts b/projects/js-packages/ai-client/src/ask-question/sync.ts index 4bbbd7f571d6d..b7480c37d8277 100644 --- a/projects/js-packages/ai-client/src/ask-question/sync.ts +++ b/projects/js-packages/ai-client/src/ask-question/sync.ts @@ -19,9 +19,9 @@ const debug = debugFactory( 'jetpack-ai-client:ask-question-sync' ); /** * A function that asks a question without streaming. * - * @param {PromptProp} question - The question to ask. It can be a simple string or an array of PromptMessageItemProps objects. - * @param {AskQuestionOptionsArgProps} options - An optional object for additional configuration: postId, feature, model. - * @returns {Promise} - A promise that resolves to an instance of the ResponseData + * @param {PromptProp} question - The question to ask. It can be a simple string or an array of PromptMessageItemProps objects. + * @param {AskQuestionOptionsArgProps} options - An optional object for additional configuration: postId, feature, model. + * @return {Promise} - A promise that resolves to an instance of the ResponseData * @example * const question = "What is the meaning of life?"; * const options = { diff --git a/projects/js-packages/ai-client/src/audio-transcription/index.ts b/projects/js-packages/ai-client/src/audio-transcription/index.ts index e566bcebaabe0..81bc95c5fb276 100644 --- a/projects/js-packages/ai-client/src/audio-transcription/index.ts +++ b/projects/js-packages/ai-client/src/audio-transcription/index.ts @@ -12,10 +12,10 @@ const debug = debugFactory( 'jetpack-ai-client:audio-transcription' ); /** * A function that takes an audio blob and transcribes it. * - * @param {Blob} audio - The audio to be transcribed, from a recording or from a file. - * @param {string} feature - The feature name that is calling the transcription. + * @param {Blob} audio - The audio to be transcribed, from a recording or from a file. + * @param {string} feature - The feature name that is calling the transcription. * @param {AbortSignal} requestAbortSignal - The signal to abort the request. - * @returns {Promise} - The promise of a string containing the transcribed audio. + * @return {Promise} - The promise of a string containing the transcribed audio. */ export default async function transcribeAudio( audio: Blob, diff --git a/projects/js-packages/ai-client/src/components/ai-control/ai-control.tsx b/projects/js-packages/ai-client/src/components/ai-control/ai-control.tsx index 60f4155245ef7..3fdbcb42da5fa 100644 --- a/projects/js-packages/ai-client/src/components/ai-control/ai-control.tsx +++ b/projects/js-packages/ai-client/src/components/ai-control/ai-control.tsx @@ -35,7 +35,7 @@ type AIControlProps = { * Base AIControl component. Contains the main structure of the control component and slots for banner, error, actions and message. * * @param {AIControlProps} props - Component props - * @returns {ReactElement} Rendered component + * @return {ReactElement} Rendered component */ export default function AIControl( { className, diff --git a/projects/js-packages/ai-client/src/components/ai-control/block-ai-control.tsx b/projects/js-packages/ai-client/src/components/ai-control/block-ai-control.tsx index c6d16298e033d..6d25d309e7115 100644 --- a/projects/js-packages/ai-client/src/components/ai-control/block-ai-control.tsx +++ b/projects/js-packages/ai-client/src/components/ai-control/block-ai-control.tsx @@ -53,9 +53,9 @@ const debug = debugFactory( 'jetpack-ai-client:block-ai-control' ); /** * BlockAIControl component. Used by the AI Assistant block, adding logic and components to the base AIControl component. * - * @param {BlockAIControlProps} props - Component props - * @param {React.MutableRefObject} ref - Ref to the component - * @returns {ReactElement} Rendered component + * @param {BlockAIControlProps} props - Component props + * @param {React.MutableRefObject} ref - Ref to the component + * @return {ReactElement} Rendered component */ export function BlockAIControl( { diff --git a/projects/js-packages/ai-client/src/components/ai-control/extension-ai-control.tsx b/projects/js-packages/ai-client/src/components/ai-control/extension-ai-control.tsx index 493f79d084367..c29fc11b63248 100644 --- a/projects/js-packages/ai-client/src/components/ai-control/extension-ai-control.tsx +++ b/projects/js-packages/ai-client/src/components/ai-control/extension-ai-control.tsx @@ -10,7 +10,12 @@ import React, { forwardRef } from 'react'; /** * Internal dependencies */ -import { GuidelineMessage, ErrorMessage, UpgradeMessage } from '../message/index.js'; +import { + GuidelineMessage, + ErrorMessage, + UpgradeMessage, + FairUsageLimitMessage, +} from '../message/index.js'; import AIControl from './ai-control.js'; import './style.scss'; /** @@ -31,6 +36,7 @@ type ExtensionAIControlProps = { error?: RequestingErrorProps; requestsRemaining?: number; showUpgradeMessage?: boolean; + showFairUsageMessage?: boolean; upgradeUrl?: string; wrapperRef?: React.MutableRefObject< HTMLDivElement | null >; onChange?: ( newValue: string ) => void; @@ -45,9 +51,9 @@ type ExtensionAIControlProps = { /** * ExtensionAIControl component. Used by the AI Assistant inline extensions, adding logic and components to the base AIControl component. * - * @param {ExtensionAIControlProps} props - Component props - * @param {React.MutableRefObject} ref - Ref to the component - * @returns {ReactElement} Rendered component + * @param {ExtensionAIControlProps} props - Component props + * @param {React.MutableRefObject} ref - Ref to the component + * @return {ReactElement} Rendered component */ export function ExtensionAIControl( { @@ -62,6 +68,7 @@ export function ExtensionAIControl( error, requestsRemaining, showUpgradeMessage = false, + showFairUsageMessage = false, upgradeUrl, wrapperRef, onChange, @@ -215,6 +222,8 @@ export function ExtensionAIControl( upgradeUrl={ upgradeUrl } /> ); + } else if ( showFairUsageMessage ) { + message = ; } else if ( showUpgradeMessage ) { message = ( fair usage policy", + 'jetpack-ai-client' + ); + const element = createInterpolateElement( message, { + link: ( + + ), + } ); + + return { element }; +} + /** * React component to render an upgrade message for free tier users * * @param {number} requestsRemaining - Number of requests remaining. - * @returns {React.ReactElement } - Message component. + * @return {React.ReactElement } - Message component. */ export function UpgradeMessage( { requestsRemaining, @@ -157,7 +177,7 @@ export function UpgradeMessage( { * React component to render an error message * * @param {number} requestsRemaining - Number of requests remaining. - * @returns {React.ReactElement } - Message component. + * @return {React.ReactElement } - Message component. */ export function ErrorMessage( { error, diff --git a/projects/js-packages/ai-client/src/data-flow/context.tsx b/projects/js-packages/ai-client/src/data-flow/context.tsx index 427b00cf39f25..500b50532ab37 100644 --- a/projects/js-packages/ai-client/src/data-flow/context.tsx +++ b/projects/js-packages/ai-client/src/data-flow/context.tsx @@ -58,7 +58,7 @@ type AiDataContextProviderProps = { /** * AI Data Context * - * @returns {AiDataContextProps} Context. + * @return {AiDataContextProps} Context. */ export const AiDataContext = createContext< AiDataContextProps | object >( {} ); @@ -66,7 +66,7 @@ export const AiDataContext = createContext< AiDataContextProps | object >( {} ); * AI Data Context Provider * * @param {AiDataContextProviderProps} props - Component props. - * @returns {React.ReactElement} Context provider. + * @return {React.ReactElement} Context provider. * @example * * { children } diff --git a/projects/js-packages/ai-client/src/data-flow/use-ai-context.ts b/projects/js-packages/ai-client/src/data-flow/use-ai-context.ts index 59870c9f3d8d0..dc756272ec8fe 100644 --- a/projects/js-packages/ai-client/src/data-flow/use-ai-context.ts +++ b/projects/js-packages/ai-client/src/data-flow/use-ai-context.ts @@ -41,7 +41,7 @@ export type UseAiContextOptions = { * and to subscribe to the request events (onDone, onSuggestion). * * @param {UseAiContextOptions} options - the hook options. - * @returns {AiDataContextProps} the AI Assistant data context. + * @return {AiDataContextProps} the AI Assistant data context. */ export default function useAiContext( { onDone, diff --git a/projects/js-packages/ai-client/src/data-flow/with-ai-assistant-data.tsx b/projects/js-packages/ai-client/src/data-flow/with-ai-assistant-data.tsx index 7b1065307b179..dfaa105b40b31 100644 --- a/projects/js-packages/ai-client/src/data-flow/with-ai-assistant-data.tsx +++ b/projects/js-packages/ai-client/src/data-flow/with-ai-assistant-data.tsx @@ -15,7 +15,7 @@ import { AiDataContextProvider } from './index.js'; * AI Assistant Data context to the wrapped component. * * @param {React.ReactElement} WrappedComponent - component to wrap. - * @returns {React.ReactElement} Wrapped component, with the AI Assistant Data context. + * @return {React.ReactElement} Wrapped component, with the AI Assistant Data context. */ const withAiDataProvider = createHigherOrderComponent( ( WrappedComponent: React.ComponentType ) => { diff --git a/projects/js-packages/ai-client/src/hooks/use-ai-suggestions/index.ts b/projects/js-packages/ai-client/src/hooks/use-ai-suggestions/index.ts index 8311f22273e9c..febb6252bd110 100644 --- a/projects/js-packages/ai-client/src/hooks/use-ai-suggestions/index.ts +++ b/projects/js-packages/ai-client/src/hooks/use-ai-suggestions/index.ts @@ -134,7 +134,7 @@ type useAiSuggestionsProps = { * Get the error data for a given error code. * * @param {SuggestionErrorCode} errorCode - The error code. - * @returns {RequestingErrorProps} The error data. + * @return {RequestingErrorProps} The error data. */ export function getErrorData( errorCode: SuggestionErrorCode ): RequestingErrorProps { switch ( errorCode ) { @@ -194,7 +194,7 @@ export function getErrorData( errorCode: SuggestionErrorCode ): RequestingErrorP * Remove the llama artifact from a suggestion. * * @param {string} suggestion - The suggestion. - * @returns {string} The suggestion without the llama artifact. + * @return {string} The suggestion without the llama artifact. */ export function removeLlamaArtifact( suggestion: string ): string { return suggestion.replace( /^<\|start_header_id\|>assistant<\|end_header_id\|>[\n]+/, '' ); @@ -205,7 +205,7 @@ export function removeLlamaArtifact( suggestion: string ): string { * by hitting the query endpoint. * * @param {useAiSuggestionsOptions} options - The options for the hook. - * @returns {useAiSuggestionsProps} The props for the hook. + * @return {useAiSuggestionsProps} The props for the hook. */ export default function useAiSuggestions( { prompt, @@ -230,7 +230,7 @@ export default function useAiSuggestions( { * onSuggestion function handler. * * @param {string} suggestion - The suggestion. - * @returns {void} + * @return {void} */ const handleSuggestion = useCallback( ( event: CustomEvent ) => { @@ -250,7 +250,7 @@ export default function useAiSuggestions( { * onDone function handler. * * @param {string} content - The content. - * @returns {void} + * @return {void} */ const handleDone = useCallback( ( event: CustomEvent ) => { @@ -300,9 +300,9 @@ export default function useAiSuggestions( { /** * Request handler. * - * @param {PromptProp} promptArg - The messages array of the prompt. - * @param {AskQuestionOptionsArgProps} options - The options for the askQuestion request. Uses the hook's askQuestionOptions by default. - * @returns {Promise} The promise. + * @param {PromptProp} promptArg - The messages array of the prompt. + * @param {AskQuestionOptionsArgProps} options - The options for the askQuestion request. Uses the hook's askQuestionOptions by default. + * @return {Promise} The promise. */ const request = useCallback( async ( @@ -352,7 +352,7 @@ export default function useAiSuggestions( { /** * Reset the request state. * - * @returns {void} + * @return {void} */ const reset = useCallback( () => { setRequestingState( 'init' ); @@ -363,7 +363,7 @@ export default function useAiSuggestions( { /** * Close the event source connection. * - * @returns {void} + * @return {void} */ const closeEventSource = useCallback( () => { if ( ! eventSourceRef?.current ) { @@ -400,7 +400,7 @@ export default function useAiSuggestions( { /** * Stop suggestion handler. * - * @returns {void} + * @return {void} */ const stopSuggestion = useCallback( () => { closeEventSource(); diff --git a/projects/js-packages/ai-client/src/hooks/use-audio-transcription/index.ts b/projects/js-packages/ai-client/src/hooks/use-audio-transcription/index.ts index 93ca40d5d4f51..e79b2bb8667b5 100644 --- a/projects/js-packages/ai-client/src/hooks/use-audio-transcription/index.ts +++ b/projects/js-packages/ai-client/src/hooks/use-audio-transcription/index.ts @@ -49,7 +49,7 @@ type AudioTranscriptionErrorResponse = { /** * Map error response to a string. * @param {Error | string | AudioTranscriptionErrorResponse} error - The error response from the audio transcription service. - * @returns {string} the translated error message + * @return {string} the translated error message */ const mapErrorResponse = ( error: Error | string | AudioTranscriptionErrorResponse ): string => { if ( typeof error === 'string' ) { @@ -92,7 +92,7 @@ const mapErrorResponse = ( error: Error | string | AudioTranscriptionErrorRespon * A hook to handle audio transcription. * * @param {string} feature - The feature name that is calling the transcription. - * @returns {UseAudioTranscriptionReturn} - Object with properties to get the transcription data. + * @return {UseAudioTranscriptionReturn} - Object with properties to get the transcription data. */ export default function useAudioTranscription( { feature, diff --git a/projects/js-packages/ai-client/src/hooks/use-audio-validation/index.ts b/projects/js-packages/ai-client/src/hooks/use-audio-validation/index.ts index 6c6f6184fe8b8..5fd087143fcfd 100644 --- a/projects/js-packages/ai-client/src/hooks/use-audio-validation/index.ts +++ b/projects/js-packages/ai-client/src/hooks/use-audio-validation/index.ts @@ -45,7 +45,7 @@ export type ValidatedAudioInformation = { /** * Hook to handle the validation of an audio file. * - * @returns {UseAudioValidationReturn} - Object with the audio validation state and the function to validate the audio. + * @return {UseAudioValidationReturn} - Object with the audio validation state and the function to validate the audio. */ export default function useAudioValidation(): UseAudioValidationReturn { const [ isValidatingAudio, setIsValidatingAudio ] = useState< boolean >( false ); diff --git a/projects/js-packages/ai-client/src/hooks/use-image-generator/index.ts b/projects/js-packages/ai-client/src/hooks/use-image-generator/index.ts index b5fee88814e53..adee712228821 100644 --- a/projects/js-packages/ai-client/src/hooks/use-image-generator/index.ts +++ b/projects/js-packages/ai-client/src/hooks/use-image-generator/index.ts @@ -19,9 +19,9 @@ type ImageGenerationResponse = { /** * Cut the post content on a given lenght so the total length of the prompt is not longer than 4000 characters. - * @param {string} content - the content to be truncated + * @param {string} content - the content to be truncated * @param {number} currentPromptLength - the length of the prompt already in use - * @returns {string} a truncated version of the content respecting the prompt length limit + * @return {string} a truncated version of the content respecting the prompt length limit */ const truncateContent = ( content: string, currentPromptLength: number ): string => { const maxLength = 4000; @@ -35,8 +35,8 @@ const truncateContent = ( content: string, currentPromptLength: number ): string /** * Create the prompt string based on the provided context. * @param {string} postContent - the content of the post - * @param {string} userPrompt - the user prompt for the image generation, if provided. Max length is 1000 characters, will be truncated. - * @returns {string} the prompt string + * @param {string} userPrompt - the user prompt for the image generation, if provided. Max length is 1000 characters, will be truncated. + * @return {string} the prompt string */ const getDalleImageGenerationPrompt = ( postContent: string, userPrompt?: string ): string => { /** @@ -89,8 +89,8 @@ This is the post content: /** * Create the Stable Diffusion pre-processing prompt based on the provided context. * @param {string} postContent - the content of the post. - * @param {string} userPrompt - the user prompt for the image generation, if provided. Max length is 1000 characters, will be truncated. - * @returns {string} the prompt string to be fed to the AI Assistant model. + * @param {string} userPrompt - the user prompt for the image generation, if provided. Max length is 1000 characters, will be truncated. + * @return {string} the prompt string to be fed to the AI Assistant model. */ const getStableDiffusionPreProcessingPrompt = ( postContent: string, @@ -134,9 +134,9 @@ Return just the prompt, without comments. The content is: /** * Uses the Jetpack AI query endpoint to produce a prompt for the stable diffusion model. * @param {string} postContent - the content of the post. - * @param {string} userPrompt - the user prompt for the image generation, if provided. Max length is 1000 characters, will be truncated - * @param {string} feature - the feature to be used for the image generation. - * @returns {string} the prompt string to be used on stable diffusion image generation. + * @param {string} userPrompt - the user prompt for the image generation, if provided. Max length is 1000 characters, will be truncated + * @param {string} feature - the feature to be used for the image generation. + * @return {string} the prompt string to be used on stable diffusion image generation. */ const getStableDiffusionImageGenerationPrompt = async ( postContent: string, diff --git a/projects/js-packages/ai-client/src/hooks/use-media-recording/index.ts b/projects/js-packages/ai-client/src/hooks/use-media-recording/index.ts index ca63d35de8707..ae8a688e59ece 100644 --- a/projects/js-packages/ai-client/src/hooks/use-media-recording/index.ts +++ b/projects/js-packages/ai-client/src/hooks/use-media-recording/index.ts @@ -84,7 +84,7 @@ type MediaRecorderEvent = { * react custom hook to handle media recording. * * @param {UseMediaRecordingProps} props - The props - * @returns {UseMediaRecordingReturn} The media recorder instance + * @return {UseMediaRecordingReturn} The media recorder instance */ export default function useMediaRecording( { onDone, @@ -118,7 +118,7 @@ export default function useMediaRecording( { /** * Get the recorded blob. * - * @returns {Blob} The recorded blob + * @return {Blob} The recorded blob */ function getBlob() { if ( MediaRecorder.isTypeSupported( MEDIA_TYPE_MP4_MP4A ) ) { @@ -265,7 +265,7 @@ export default function useMediaRecording( { * `stop` event listener for the media recorder instance. * Happens after the last `dataavailable` event. * - * @returns {void} + * @return {void} */ function onStopListener(): void { const lastBlob = getBlob(); @@ -293,7 +293,7 @@ export default function useMediaRecording( { * `dataavailable` event listener for the media recorder instance. * * @param {MediaRecorderEvent} event - The event object - * @returns {void} + * @return {void} */ function onDataAvailableListener( event: MediaRecorderEvent ): void { const { data } = event; diff --git a/projects/js-packages/ai-client/src/hooks/use-save-to-media-library/index.ts b/projects/js-packages/ai-client/src/hooks/use-save-to-media-library/index.ts index 88abbceeb94f2..24685ff2a8f73 100644 --- a/projects/js-packages/ai-client/src/hooks/use-save-to-media-library/index.ts +++ b/projects/js-packages/ai-client/src/hooks/use-save-to-media-library/index.ts @@ -15,7 +15,7 @@ const debug = debugFactory( 'ai-client:save-to-media-library' ); /** * Hook to save an image to the media library. * - * @returns {object} Object with the loading state and the function to save the image to the media library. + * @return {object} Object with the loading state and the function to save the image to the media library. */ export default function useSaveToMediaLibrary() { const [ isLoading, setIsLoading ] = useState( false ); diff --git a/projects/js-packages/ai-client/src/hooks/use-transcription-post-processing/index.ts b/projects/js-packages/ai-client/src/hooks/use-transcription-post-processing/index.ts index 7aeee850b7e2e..48b47f0a1dfe8 100644 --- a/projects/js-packages/ai-client/src/hooks/use-transcription-post-processing/index.ts +++ b/projects/js-packages/ai-client/src/hooks/use-transcription-post-processing/index.ts @@ -42,7 +42,7 @@ export type UseTranscriptionPostProcessingProps = { * A hook to handle transcription post-processing. * * @param {string} feature - The feature name that is calling the post-processing actions. - * @returns {UseTranscriptionPostProcessingReturn} - Object with properties to get the post-processing results. + * @return {UseTranscriptionPostProcessingReturn} - Object with properties to get the post-processing results. */ export default function useTranscriptionPostProcessing( { feature, diff --git a/projects/js-packages/ai-client/src/icons/stories/index.stories.tsx b/projects/js-packages/ai-client/src/icons/stories/index.stories.tsx index 44e9e998c4d4b..eaf9c4d31feff 100644 --- a/projects/js-packages/ai-client/src/icons/stories/index.stories.tsx +++ b/projects/js-packages/ai-client/src/icons/stories/index.stories.tsx @@ -27,7 +27,7 @@ const meta: AIControlStoryMeta = { /** * Icons story components. * - * @returns {object} - story component + * @return {object} - story component */ function IconsStory() { return ( diff --git a/projects/js-packages/ai-client/src/jwt/index.ts b/projects/js-packages/ai-client/src/jwt/index.ts index 3c55ab247033f..eaa463ca5a281 100644 --- a/projects/js-packages/ai-client/src/jwt/index.ts +++ b/projects/js-packages/ai-client/src/jwt/index.ts @@ -37,7 +37,7 @@ const JWT_TOKEN_EXPIRATION_TIME = 2 * 60 * 1000; // 2 minutes * Request a token from the Jetpack site. * * @param {RequestTokenOptions} options - Options - * @returns {Promise} The token and the blogId + * @return {Promise} The token and the blogId */ export default async function requestJwt( { apiNonce, diff --git a/projects/js-packages/ai-client/src/libs/markdown/html-to-markdown.ts b/projects/js-packages/ai-client/src/libs/markdown/html-to-markdown.ts index c37f19510b07f..b0cd910dd0a17 100644 --- a/projects/js-packages/ai-client/src/libs/markdown/html-to-markdown.ts +++ b/projects/js-packages/ai-client/src/libs/markdown/html-to-markdown.ts @@ -61,7 +61,7 @@ export default class HTMLToMarkdown { * Renders HTML from Markdown content with specified processing rules. * @param {object} options - The options to use when rendering the Markdown content * @param {string} options.content - The HTML content to render - * @returns {string} The rendered Markdown content + * @return {string} The rendered Markdown content */ render( { content }: { content: string } ): string { const rendered = this.turndownService.turndown( content ); diff --git a/projects/js-packages/ai-client/src/libs/markdown/markdown-to-html.ts b/projects/js-packages/ai-client/src/libs/markdown/markdown-to-html.ts index 54924cbce4ff6..cf51a5f006f25 100644 --- a/projects/js-packages/ai-client/src/libs/markdown/markdown-to-html.ts +++ b/projects/js-packages/ai-client/src/libs/markdown/markdown-to-html.ts @@ -96,11 +96,11 @@ export default class MarkdownToHTML { /** * Renders HTML from Markdown content with specified processing rules. - * @param {object} options - The options to use when rendering the HTML content - * @param {string} options.content - The Markdown content to render - * @param {string} options.rules - The rules to apply to the rendered content + * @param {object} options - The options to use when rendering the HTML content + * @param {string} options.content - The Markdown content to render + * @param {string} options.rules - The rules to apply to the rendered content * @param {boolean} options.extension - Whether to apply the extension-specific rules - * @returns {string} The rendered HTML content + * @return {string} The rendered HTML content */ render( { content, diff --git a/projects/js-packages/ai-client/src/logo-generator/lib/logo-storage.ts b/projects/js-packages/ai-client/src/logo-generator/lib/logo-storage.ts index 2607f3597e7d6..1649b99b71424 100644 --- a/projects/js-packages/ai-client/src/logo-generator/lib/logo-storage.ts +++ b/projects/js-packages/ai-client/src/logo-generator/lib/logo-storage.ts @@ -10,13 +10,13 @@ const MAX_LOGOS = 10; /** * Add an entry to the site's logo history. * - * @param {SaveToStorageProps} saveToStorageProps - The properties to save to storage - * @param {SaveToStorageProps.siteId} saveToStorageProps.siteId - The site ID - * @param {SaveToStorageProps.url} saveToStorageProps.url - The URL of the logo + * @param {SaveToStorageProps} saveToStorageProps - The properties to save to storage + * @param {SaveToStorageProps.siteId} saveToStorageProps.siteId - The site ID + * @param {SaveToStorageProps.url} saveToStorageProps.url - The URL of the logo * @param {SaveToStorageProps.description} saveToStorageProps.description - The description of the logo, based on the prompt used to generate it - * @param {SaveToStorageProps.mediaId} saveToStorageProps.mediaId - The media ID of the logo on the backend + * @param {SaveToStorageProps.mediaId} saveToStorageProps.mediaId - The media ID of the logo on the backend * - * @returns {Logo} The logo that was saved + * @return {Logo} The logo that was saved */ export function stashLogo( { siteId, url, description, mediaId }: SaveToStorageProps ) { const storedContent = getSiteLogoHistory( siteId ); @@ -40,12 +40,12 @@ export function stashLogo( { siteId, url, description, mediaId }: SaveToStorageP /** * Update an entry in the site's logo history. * - * @param {UpdateInStorageProps} updateInStorageProps - The properties to update in storage - * @param {UpdateInStorageProps.siteId} updateInStorageProps.siteId - The site ID - * @param {UpdateInStorageProps.url} updateInStorageProps.url - The URL of the logo to update - * @param {UpdateInStorageProps.newUrl} updateInStorageProps.newUrl - The new URL of the logo + * @param {UpdateInStorageProps} updateInStorageProps - The properties to update in storage + * @param {UpdateInStorageProps.siteId} updateInStorageProps.siteId - The site ID + * @param {UpdateInStorageProps.url} updateInStorageProps.url - The URL of the logo to update + * @param {UpdateInStorageProps.newUrl} updateInStorageProps.newUrl - The new URL of the logo * @param {UpdateInStorageProps.mediaId} updateInStorageProps.mediaId - The new media ID of the logo - * @returns {Logo} The logo that was updated + * @return {Logo} The logo that was updated */ export function updateLogo( { siteId, url, newUrl, mediaId }: UpdateInStorageProps ) { const storedContent = getSiteLogoHistory( siteId ); @@ -69,7 +69,7 @@ export function updateLogo( { siteId, url, newUrl, mediaId }: UpdateInStoragePro * Get the logo history for a site. * * @param {string} siteId - The site ID to get the logo history for - * @returns {Logo[]} The logo history for the site + * @return {Logo[]} The logo history for the site */ export function getSiteLogoHistory( siteId: string ) { const storedString = localStorage.getItem( `logo-history-${ siteId }` ); @@ -104,8 +104,8 @@ export function getSiteLogoHistory( siteId: string ) { /** * Check if the logo history for a site is empty. * - * @param {string }siteId - The site ID to check the logo history for - * @returns {boolean} Whether the logo history for the site is empty + * @param {string } siteId - The site ID to check the logo history for + * @return {boolean} Whether the logo history for the site is empty */ export function isLogoHistoryEmpty( siteId: string ) { const storedContent = getSiteLogoHistory( siteId ); @@ -116,10 +116,10 @@ export function isLogoHistoryEmpty( siteId: string ) { /** * Remove an entry from the site's logo history. * - * @param {RemoveFromStorageProps} removeFromStorageProps - The properties to remove from storage - * @param {RemoveFromStorageProps.siteId} removeFromStorageProps.siteId - The site ID + * @param {RemoveFromStorageProps} removeFromStorageProps - The properties to remove from storage + * @param {RemoveFromStorageProps.siteId} removeFromStorageProps.siteId - The site ID * @param {RemoveFromStorageProps.mediaId} removeFromStorageProps.mediaId - The media ID of the logo to remove - * @returns {void} + * @return {void} */ export function removeLogo( { siteId, mediaId }: RemoveFromStorageProps ) { const storedContent = getSiteLogoHistory( siteId ); @@ -137,7 +137,7 @@ export function removeLogo( { siteId, mediaId }: RemoveFromStorageProps ) { * Clear deleted media from the site's logo history, checking if the media still exists on the backend. * * @param {string} siteId - The site ID to clear deleted media for - * @returns {Promise} + * @return {Promise} */ export async function clearDeletedMedia( siteId: string ) { const storedContent = getSiteLogoHistory( siteId ); diff --git a/projects/js-packages/ai-client/src/logo-generator/lib/media-exists.ts b/projects/js-packages/ai-client/src/logo-generator/lib/media-exists.ts index 9df5950e1f6a2..483025cac8368 100644 --- a/projects/js-packages/ai-client/src/logo-generator/lib/media-exists.ts +++ b/projects/js-packages/ai-client/src/logo-generator/lib/media-exists.ts @@ -10,9 +10,9 @@ import type { CheckMediaProps } from '../types.js'; /** * Uses the media information to confirm it exists or not on the server. * - * @param {CheckMediaProps} checkMediaProps - the media details to check + * @param {CheckMediaProps} checkMediaProps - the media details to check * @param {CheckMediaProps.mediaId} checkMediaProps.mediaId - the id of the media to check - * @returns {Promise} - true if the media exists, false otherwise + * @return {Promise} - true if the media exists, false otherwise */ export async function mediaExists( { mediaId }: CheckMediaProps ): Promise< boolean > { const id = Number( mediaId ); diff --git a/projects/js-packages/ai-client/src/logo-generator/lib/set-site-logo.ts b/projects/js-packages/ai-client/src/logo-generator/lib/set-site-logo.ts index a677c74137c70..d95cbd89c20a6 100644 --- a/projects/js-packages/ai-client/src/logo-generator/lib/set-site-logo.ts +++ b/projects/js-packages/ai-client/src/logo-generator/lib/set-site-logo.ts @@ -10,10 +10,10 @@ import type { SetSiteLogoProps, SetSiteLogoResponseProps } from '../types.js'; /** * Set the site logo using a backend request. * - * @param {SetSiteLogoProps} setSiteLogoProps - The properties to set the site logo - * @param {SetSiteLogoProps.siteId} setSiteLogoProps.siteId - The site ID + * @param {SetSiteLogoProps} setSiteLogoProps - The properties to set the site logo + * @param {SetSiteLogoProps.siteId} setSiteLogoProps.siteId - The site ID * @param {SetSiteLogoProps.imageId} setSiteLogoProps.imageId - The image ID to set as the site logo - * @returns {Promise} The response from the request + * @return {Promise} The response from the request */ export async function setSiteLogo( { siteId, imageId }: SetSiteLogoProps ) { const body = { diff --git a/projects/js-packages/ai-client/src/logo-generator/lib/wpcom-limited-request.ts b/projects/js-packages/ai-client/src/logo-generator/lib/wpcom-limited-request.ts index fbfc67c167e36..9ed6d13bbb3fd 100644 --- a/projects/js-packages/ai-client/src/logo-generator/lib/wpcom-limited-request.ts +++ b/projects/js-packages/ai-client/src/logo-generator/lib/wpcom-limited-request.ts @@ -13,7 +13,7 @@ let concurrentCounter = 0; /** * Concurrency-limited request to wpcom-proxy-request. * @param { object } params - The request params, as expected by apiFetch. - * @returns { Promise } The response. + * @return { Promise } The response. * @throws { Error } If there are too many concurrent requests. */ export default async function wpcomLimitedRequest< T >( params: object ): Promise< T > { diff --git a/projects/js-packages/ai-client/src/logo-generator/store/actions.ts b/projects/js-packages/ai-client/src/logo-generator/store/actions.ts index a166edf0b3939..40d0f91e9577b 100644 --- a/projects/js-packages/ai-client/src/logo-generator/store/actions.ts +++ b/projects/js-packages/ai-client/src/logo-generator/store/actions.ts @@ -41,7 +41,7 @@ import type { SiteDetails } from '../types.js'; * Map the response from the `sites/$site/ai-assistant-feature` * endpoint to the AI Assistant feature props. * @param { AiAssistantFeatureEndpointResponseProps } response - The response from the endpoint. - * @returns { AiFeatureProps } The AI Assistant feature props. + * @return { AiFeatureProps } The AI Assistant feature props. */ export function mapAiFeatureResponseToAiFeatureProps( response: AiAssistantFeatureEndpointResponseProps @@ -77,7 +77,7 @@ const actions = { /** * Thunk action to fetch the AI Assistant feature from the API. - * @returns {Function} The thunk action. + * @return {Function} The thunk action. */ fetchAiAssistantFeature() { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -106,7 +106,7 @@ const actions = { * This thunk action is used to increase * the requests count for the current usage period. * @param {number} count - The number of requests to increase. Default is 1. - * @returns {Function} The thunk action. + * @return {Function} The thunk action. */ increaseAiAssistantRequestsCount( count: number = 1 ) { // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/projects/js-packages/ai-client/src/logo-generator/store/reducer.ts b/projects/js-packages/ai-client/src/logo-generator/store/reducer.ts index 50db694226385..2b073c252cde2 100644 --- a/projects/js-packages/ai-client/src/logo-generator/store/reducer.ts +++ b/projects/js-packages/ai-client/src/logo-generator/store/reducer.ts @@ -40,28 +40,28 @@ import type { SiteDetails } from '../types.js'; /** * Reducer for the Logo Generator store. * - * @param {LogoGeneratorStateProp} state - The current state - * @param {object} action - The action to apply, as described by the properties below - * @param {string} action.type - The action type - * @param {AiFeatureStateProps} action.feature - The AI Assistant feature state - * @param {number} action.count - The number of requests to increase the counter by - * @param {boolean} action.requireUpgrade - Whether an upgrade is required - * @param {boolean} action.tierPlansEnabled - Whether tier plans are enabled - * @param {SiteDetails} action.siteDetails - The site details - * @param {number} action.selectedLogoIndex - The selected logo index - * @param {boolean} action.isSavingLogoToLibrary - Whether a logo is being saved to the library - * @param {boolean} action.isApplyingLogo - Whether a logo is being applied - * @param {object} action.logo - The logo to save, as described by the properties below - * @param {string} action.logo.url - The logo URL - * @param {string} action.logo.description - The logo description - * @param {number} action.mediaId - The media ID from backend - * @param {string} action.url - The URL to save - * @param {boolean} action.isRequestingImage - Whether an image is being requested - * @param {boolean} action.isEnhancingPrompt - Whether a prompt enhancement is being requested - * @param {Array< { url: string; description: string; mediaId?: number } >} action.history - The logo history - * @param {RequestError} action.error - The error to set - * @param {string} action.context - The context where the tool is being used - * @returns {LogoGeneratorStateProp} The new state + * @param {LogoGeneratorStateProp} state - The current state + * @param {object} action - The action to apply, as described by the properties below + * @param {string} action.type - The action type + * @param {AiFeatureStateProps} action.feature - The AI Assistant feature state + * @param {number} action.count - The number of requests to increase the counter by + * @param {boolean} action.requireUpgrade - Whether an upgrade is required + * @param {boolean} action.tierPlansEnabled - Whether tier plans are enabled + * @param {SiteDetails} action.siteDetails - The site details + * @param {number} action.selectedLogoIndex - The selected logo index + * @param {boolean} action.isSavingLogoToLibrary - Whether a logo is being saved to the library + * @param {boolean} action.isApplyingLogo - Whether a logo is being applied + * @param {object} action.logo - The logo to save, as described by the properties below + * @param {string} action.logo.url - The logo URL + * @param {string} action.logo.description - The logo description + * @param {number} action.mediaId - The media ID from backend + * @param {string} action.url - The URL to save + * @param {boolean} action.isRequestingImage - Whether an image is being requested + * @param {boolean} action.isEnhancingPrompt - Whether a prompt enhancement is being requested + * @param {Array< { url: string; description: string; mediaId?: number } >} action.history - The logo history + * @param {RequestError} action.error - The error to set + * @param {string} action.context - The context where the tool is being used + * @return {LogoGeneratorStateProp} The new state */ export default function reducer( state = INITIAL_STATE, diff --git a/projects/js-packages/ai-client/src/logo-generator/store/selectors.ts b/projects/js-packages/ai-client/src/logo-generator/store/selectors.ts index c9445b73ab635..a642d636e95dd 100644 --- a/projects/js-packages/ai-client/src/logo-generator/store/selectors.ts +++ b/projects/js-packages/ai-client/src/logo-generator/store/selectors.ts @@ -9,7 +9,7 @@ const selectors = { /** * Return the AI Assistant feature. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {Partial} The AI Assistant feature data. + * @return {Partial} The AI Assistant feature data. */ getAiAssistantFeature( state: LogoGeneratorStateProp ): Partial< AiFeatureProps > { // Clean up the _meta property. @@ -21,8 +21,8 @@ const selectors = { /** * Return the site details. - * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {Partial | undefined} The site details. + * @param {LogoGeneratorStateProp} state - The app state tree. + * @return {Partial | undefined} The site details. */ getSiteDetails( state: LogoGeneratorStateProp ): Partial< SiteDetails > | undefined { return state.siteDetails; @@ -31,7 +31,7 @@ const selectors = { /** * Get the isRequesting flag for the AI Assistant feature. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {boolean} The isRequesting flag. + * @return {boolean} The isRequesting flag. */ getIsRequestingAiAssistantFeature( state: LogoGeneratorStateProp ): boolean { return state.features.aiAssistantFeature?._meta?.isRequesting ?? false; @@ -40,7 +40,7 @@ const selectors = { /** * Get the logos history. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {Array} The logos history array. + * @return {Array} The logos history array. */ getLogos( state: LogoGeneratorStateProp ): Array< Logo > { return state.history ?? []; @@ -49,7 +49,7 @@ const selectors = { /** * Get the selected logo index. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {number | null} The selected logo index. + * @return {number | null} The selected logo index. */ getSelectedLogoIndex( state: LogoGeneratorStateProp ): number | null { return state.selectedLogoIndex ?? null; @@ -58,7 +58,7 @@ const selectors = { /** * Get the selected logo. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {Logo} The selected logo. + * @return {Logo} The selected logo. */ getSelectedLogo( state: LogoGeneratorStateProp ): Logo { return state.history?.[ state.selectedLogoIndex ] ?? null; @@ -67,7 +67,7 @@ const selectors = { /** * Get the isSavingToLibrary flag. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {boolean} The isSavingToLibrary flag. + * @return {boolean} The isSavingToLibrary flag. */ getIsSavingLogoToLibrary( state: LogoGeneratorStateProp ): boolean { return state._meta?.isSavingLogoToLibrary ?? false; @@ -76,7 +76,7 @@ const selectors = { /** * Get the isApplyingLogo flag. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {boolean} The isApplyingLogo flag. + * @return {boolean} The isApplyingLogo flag. */ getIsApplyingLogo( state: LogoGeneratorStateProp ): boolean { return state._meta?.isApplyingLogo ?? false; @@ -85,7 +85,7 @@ const selectors = { /** * Get the isEnhancingPrompt flag. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {boolean} The isEnhancingPrompt flag. + * @return {boolean} The isEnhancingPrompt flag. */ getIsEnhancingPrompt( state: LogoGeneratorStateProp ): boolean { return state._meta?.isEnhancingPrompt ?? false; @@ -94,7 +94,7 @@ const selectors = { /** * Get the isRequestingImage flag. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {boolean} The isRequestingImage flag. + * @return {boolean} The isRequestingImage flag. */ getIsRequestingImage( state: LogoGeneratorStateProp ): boolean { return state._meta?.isRequestingImage ?? false; @@ -103,7 +103,7 @@ const selectors = { /** * Get an aggregated isBusy flag, based on the loading states of the app. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {boolean} The isBusy flag. + * @return {boolean} The isBusy flag. */ getIsBusy( state: LogoGeneratorStateProp ): boolean { return ( @@ -117,7 +117,7 @@ const selectors = { /** * Get the requireUpgrade value from aiAssistantFeature * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {boolean} The requireUpgrade flag. + * @return {boolean} The requireUpgrade flag. */ getRequireUpgrade( state: LogoGeneratorStateProp ): boolean { const feature = state.features.aiAssistantFeature; @@ -137,7 +137,7 @@ const selectors = { /** * Get the featureFetchError value. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {RequestError} The featureFetchError value. + * @return {RequestError} The featureFetchError value. */ getFeatureFetchError( state: LogoGeneratorStateProp ): RequestError { return state._meta?.featureFetchError ?? null; @@ -146,7 +146,7 @@ const selectors = { /** * Get the firstLogoPromptFetchError value. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {RequestError} The firstLogoPromptFetchError value. + * @return {RequestError} The firstLogoPromptFetchError value. */ getFirstLogoPromptFetchError( state: LogoGeneratorStateProp ): RequestError { return state._meta?.firstLogoPromptFetchError ?? null; @@ -155,7 +155,7 @@ const selectors = { /** * Get the enhancePromptFetchError value. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {RequestError} The enhancePromptFetchError value. + * @return {RequestError} The enhancePromptFetchError value. */ getEnhancePromptFetchError( state: LogoGeneratorStateProp ): RequestError { return state._meta?.enhancePromptFetchError ?? null; @@ -164,7 +164,7 @@ const selectors = { /** * Get the logoFetchError value. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {RequestError} The logoFetchError value. + * @return {RequestError} The logoFetchError value. */ getLogoFetchError( state: LogoGeneratorStateProp ): RequestError { return state._meta?.logoFetchError ?? null; @@ -173,7 +173,7 @@ const selectors = { /** * Get the saveToLibraryError value. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {RequestError} The saveToLibraryError value. + * @return {RequestError} The saveToLibraryError value. */ getSaveToLibraryError( state: LogoGeneratorStateProp ): RequestError { return state._meta?.saveToLibraryError ?? null; @@ -182,7 +182,7 @@ const selectors = { /** * Get the logoUpdateError value. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {RequestError} The logoUpdateError value. + * @return {RequestError} The logoUpdateError value. */ getLogoUpdateError( state: LogoGeneratorStateProp ): RequestError { return state._meta?.logoUpdateError ?? null; @@ -191,7 +191,7 @@ const selectors = { /** * Get the context value. * @param {LogoGeneratorStateProp} state - The app state tree. - * @returns {string} The context value. + * @return {string} The context value. */ getContext( state: LogoGeneratorStateProp ): string { return state._meta?.context ?? ''; diff --git a/projects/js-packages/ai-client/src/suggestions-event-source/index.ts b/projects/js-packages/ai-client/src/suggestions-event-source/index.ts index 30b31d7877a00..f923ef3cf4b9e 100644 --- a/projects/js-packages/ai-client/src/suggestions-event-source/index.ts +++ b/projects/js-packages/ai-client/src/suggestions-event-source/index.ts @@ -53,7 +53,7 @@ const debug = debugFactory( 'jetpack-ai-client:suggestions-event-source' ); * when the stream is closed. * It also emits a 'suggestion' event with the full suggestion received so far * - * @returns {EventSource} The event source + * @return {EventSource} The event source * @fires SuggestionsEventSource#suggestion - The full suggestion has been received so far * @fires SuggestionsEventSource#message - A message has been received * @fires SuggestionsEventSource#chunk - A chunk of data has been received diff --git a/projects/js-packages/analytics/CHANGELOG.md b/projects/js-packages/analytics/CHANGELOG.md index b34c09d6153b5..dd8e5af87208a 100644 --- a/projects/js-packages/analytics/CHANGELOG.md +++ b/projects/js-packages/analytics/CHANGELOG.md @@ -2,6 +2,14 @@ ### This is a list detailing changes for the Jetpack RNA Analytics package releases. +## [0.1.31] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + +## [0.1.30] - 2024-08-21 +### Changed +- Internal updates. + ## [0.1.29] - 2023-12-03 ### Changed - Updated package dependencies. [#34427] @@ -116,6 +124,8 @@ ### Added - Initial release of jetpack-api package. +[0.1.31]: https://github.com/Automattic/jetpack-analytics/compare/v0.1.30...v0.1.31 +[0.1.30]: https://github.com/Automattic/jetpack-analytics/compare/v0.1.29...v0.1.30 [0.1.29]: https://github.com/Automattic/jetpack-analytics/compare/v0.1.28...v0.1.29 [0.1.28]: https://github.com/Automattic/jetpack-analytics/compare/v0.1.27...v0.1.28 [0.1.27]: https://github.com/Automattic/jetpack-analytics/compare/v0.1.26...v0.1.27 diff --git a/projects/js-packages/analytics/composer.json b/projects/js-packages/analytics/composer.json index 84f596820bdf6..cf505e001e644 100644 --- a/projects/js-packages/analytics/composer.json +++ b/projects/js-packages/analytics/composer.json @@ -5,7 +5,7 @@ "license": "GPL-2.0-or-later", "require": {}, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "scripts": { diff --git a/projects/js-packages/analytics/index.jsx b/projects/js-packages/analytics/index.jsx index 2bc8048be4be3..df28a7aec6b08 100644 --- a/projects/js-packages/analytics/index.jsx +++ b/projects/js-packages/analytics/index.jsx @@ -19,8 +19,8 @@ window.ga.l = +new Date(); * Build a query string * * @param {string} group - the group - * @param {string} name - the name - * @returns {string} - the uricomponent + * @param {string} name - the name + * @return {string} - the uricomponent */ function buildQuerystring( group, name ) { let uriComponent = ''; @@ -42,8 +42,8 @@ function buildQuerystring( group, name ) { * Build a query string with no prefix * * @param {string} group - the group - * @param {string} name - the name - * @returns {string} - the uricomponent + * @param {string} name - the name + * @return {string} - the uricomponent */ function buildQuerystringNoPrefix( group, name ) { let uriComponent = ''; diff --git a/projects/js-packages/analytics/package.json b/projects/js-packages/analytics/package.json index 0ff3d743a8ccb..2231680663e5a 100644 --- a/projects/js-packages/analytics/package.json +++ b/projects/js-packages/analytics/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/jetpack-analytics", - "version": "0.1.29", + "version": "0.1.31", "description": "Jetpack Analytics Package", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/analytics/#readme", "bugs": { diff --git a/projects/js-packages/api/CHANGELOG.md b/projects/js-packages/api/CHANGELOG.md index 05698a784e20d..5224c4c6b3442 100644 --- a/projects/js-packages/api/CHANGELOG.md +++ b/projects/js-packages/api/CHANGELOG.md @@ -2,6 +2,10 @@ ### This is a list detailing changes for the Jetpack RNA Components package releases. +## [0.17.11] - 2024-08-21 +### Changed +- Internal updates. + ## [0.17.10] - 2024-08-15 ### Changed - Updated package dependencies. [#38662] @@ -342,6 +346,7 @@ - Add the API methods left behind by the previous PR. - Initial release of jetpack-api package +[0.17.11]: https://github.com/Automattic/jetpack-api/compare/v0.17.10...v0.17.11 [0.17.10]: https://github.com/Automattic/jetpack-api/compare/v0.17.9...v0.17.10 [0.17.9]: https://github.com/Automattic/jetpack-api/compare/v0.17.8...v0.17.9 [0.17.8]: https://github.com/Automattic/jetpack-api/compare/v0.17.7...v0.17.8 diff --git a/projects/js-packages/api/index.jsx b/projects/js-packages/api/index.jsx index af426f0f0f36d..8233d0ba8a616 100644 --- a/projects/js-packages/api/index.jsx +++ b/projects/js-packages/api/index.jsx @@ -5,7 +5,7 @@ import { addQueryArgs } from '@wordpress/url'; * Helps create new custom error classes to better notify upper layers. * * @param {string} name - the Error name that will be availble in Error.name - * @returns {Error} a new custom error class. + * @return {Error} a new custom error class. */ function createCustomError( name ) { class CustomError extends Error { @@ -26,7 +26,7 @@ export const FetchNetworkError = createCustomError( 'FetchNetworkError' ); /** * Create a Jetpack Rest Api Client * - * @param {string} root - The API root + * @param {string} root - The API root * @param {string} nonce - The API Nonce */ function JetpackRestApiClient( root, nonce ) { @@ -550,7 +550,7 @@ function JetpackRestApiClient( root, nonce ) { * The default callback to add a cachebuster parameter to route * * @param {string} route - the route - * @returns {string} - the route with the cachebuster appended + * @return {string} - the route with the cachebuster appended */ function addCacheBuster( route ) { const parts = route.split( '?' ), @@ -565,9 +565,9 @@ function JetpackRestApiClient( root, nonce ) { /** * Generate a request promise for the route and params. Automatically adds a cachebuster. * - * @param {string} route - the route + * @param {string} route - the route * @param {object} params - the params - * @returns {Promise} - the http request promise + * @return {Promise} - the http request promise */ function getRequest( route, params ) { return fetch( cacheBusterCallback( route ), params ); @@ -576,10 +576,10 @@ function JetpackRestApiClient( root, nonce ) { /** * Generate a POST request promise for the route and params. Automatically adds a cachebuster. * - * @param {string} route - the route + * @param {string} route - the route * @param {object} params - the params - * @param {string} body - the body - * @returns {Promise} - the http response promise + * @param {string} body - the body + * @return {Promise} - the http response promise */ function postRequest( route, params, body ) { return fetch( route, Object.assign( {}, params, body ) ).catch( catchNetworkErrors ); @@ -589,7 +589,7 @@ function JetpackRestApiClient( root, nonce ) { * Returns the stats data URL for the given date range * * @param {string} range - the range - * @returns {string} - the stats URL + * @return {string} - the stats URL */ function statsDataUrl( range ) { let url = `${ apiRoot }jetpack/v4/module/stats/data`; @@ -605,7 +605,7 @@ function JetpackRestApiClient( root, nonce ) { * Returns stats data if possible, otherwise an empty object * * @param {object} statsData - the stats data or error - * @returns {object} - the handled stats data + * @return {object} - the handled stats data */ function handleStatsResponseError( statsData ) { // If we get a .response property, it means that .com's response is errory. @@ -628,7 +628,7 @@ export default restApi; * Check the status of the response. Throw an error if it was not OK * * @param {Response} response - the API response - * @returns {Promise} - a promise to return the parsed JSON body as an object + * @return {Promise} - a promise to return the parsed JSON body as an object */ function checkStatus( response ) { // Regular success responses @@ -660,7 +660,7 @@ function checkStatus( response ) { * Parse the JSON response * * @param {Response} response - the response object - * @returns {Promise} - promise to return the parsed json object + * @return {Promise} - promise to return the parsed json object */ function parseJsonResponse( response ) { return response.json().catch( e => catchJsonParseError( e, response.redirected, response.url ) ); @@ -669,9 +669,9 @@ function parseJsonResponse( response ) { /** * Throw appropriate exception given an API error * - * @param {Error} e - the error + * @param {Error} e - the error * @param {boolean} redirected - are we being redirected? - * @param {string} url - the URL that returned the error + * @param {string} url - the URL that returned the error */ function catchJsonParseError( e, redirected, url ) { const err = redirected ? new JsonParseAfterRedirectError( url ) : new JsonParseError(); diff --git a/projects/js-packages/api/package.json b/projects/js-packages/api/package.json index ccf9f545b98e9..3870c37fb8c56 100644 --- a/projects/js-packages/api/package.json +++ b/projects/js-packages/api/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/jetpack-api", - "version": "0.17.10", + "version": "0.17.11", "description": "Jetpack Api Package", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/api/#readme", "bugs": { diff --git a/projects/js-packages/babel-plugin-replace-textdomain/CHANGELOG.md b/projects/js-packages/babel-plugin-replace-textdomain/CHANGELOG.md index d578cc5b2b5cc..4505c316a8040 100644 --- a/projects/js-packages/babel-plugin-replace-textdomain/CHANGELOG.md +++ b/projects/js-packages/babel-plugin-replace-textdomain/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.36] - 2024-08-29 +### Changed +- Internal updates. + ## [1.0.35] - 2024-06-12 ### Changed - Updated package dependencies. [#37796] @@ -161,6 +165,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Initial release. - Replace missing domains too. +[1.0.36]: https://github.com/Automattic/babel-plugin-replace-textdomain/compare/v1.0.35...v1.0.36 [1.0.35]: https://github.com/Automattic/babel-plugin-replace-textdomain/compare/v1.0.34...v1.0.35 [1.0.34]: https://github.com/Automattic/babel-plugin-replace-textdomain/compare/v1.0.33...v1.0.34 [1.0.33]: https://github.com/Automattic/babel-plugin-replace-textdomain/compare/v1.0.32...v1.0.33 diff --git a/projects/js-packages/babel-plugin-replace-textdomain/package.json b/projects/js-packages/babel-plugin-replace-textdomain/package.json index d4bf9ca63bcf9..13ceb793c3fa9 100644 --- a/projects/js-packages/babel-plugin-replace-textdomain/package.json +++ b/projects/js-packages/babel-plugin-replace-textdomain/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/babel-plugin-replace-textdomain", - "version": "1.0.35", + "version": "1.0.36", "description": "A Babel plugin to replace the textdomain in gettext-style function calls.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/babel-plugin-replace-textdomain/#readme", "bugs": { diff --git a/projects/js-packages/babel-plugin-replace-textdomain/src/index.js b/projects/js-packages/babel-plugin-replace-textdomain/src/index.js index 02a26a2d71398..86241269e7486 100644 --- a/projects/js-packages/babel-plugin-replace-textdomain/src/index.js +++ b/projects/js-packages/babel-plugin-replace-textdomain/src/index.js @@ -50,7 +50,7 @@ module.exports = ( babel, opts ) => { callee = callee.expressions[ callee.expressions.length - 1 ]; } const funcName = t.isMemberExpression( callee ) ? callee.property.name : callee.name; - if ( ! functions.hasOwnProperty( funcName ) ) { + if ( ! Object.hasOwn( functions, funcName ) ) { return; } const idx = functions[ funcName ]; diff --git a/projects/js-packages/base-styles/CHANGELOG.md b/projects/js-packages/base-styles/CHANGELOG.md index 7ec6267b58ef5..f7c11b10b7e94 100644 --- a/projects/js-packages/base-styles/CHANGELOG.md +++ b/projects/js-packages/base-styles/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.6.30] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## [0.6.29] - 2024-08-15 ### Changed - Updated package dependencies. [#38662] @@ -301,6 +305,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated package dependencies. - Use Node 16.7.0 in tooling. This shouldn't change the behavior of the code itself. +[0.6.30]: https://github.com/Automattic/jetpack-base-styles/compare/0.6.29...0.6.30 [0.6.29]: https://github.com/Automattic/jetpack-base-styles/compare/0.6.28...0.6.29 [0.6.28]: https://github.com/Automattic/jetpack-base-styles/compare/0.6.27...0.6.28 [0.6.27]: https://github.com/Automattic/jetpack-base-styles/compare/0.6.26...0.6.27 diff --git a/projects/js-packages/base-styles/composer.json b/projects/js-packages/base-styles/composer.json index 2fdf2ba1fd15b..22d7559a60ad3 100644 --- a/projects/js-packages/base-styles/composer.json +++ b/projects/js-packages/base-styles/composer.json @@ -5,7 +5,7 @@ "license": "GPL-2.0-or-later", "require": {}, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "autoload": { diff --git a/projects/js-packages/base-styles/package.json b/projects/js-packages/base-styles/package.json index 8121c62c1303e..7f7834a696a33 100644 --- a/projects/js-packages/base-styles/package.json +++ b/projects/js-packages/base-styles/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/jetpack-base-styles", - "version": "0.6.29", + "version": "0.6.30", "description": "Jetpack components base styles", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/base-styles/#readme", "bugs": { diff --git a/projects/js-packages/boost-score-api/CHANGELOG.md b/projects/js-packages/boost-score-api/CHANGELOG.md index d1dc9e34fe8d7..eec17d7c86020 100644 --- a/projects/js-packages/boost-score-api/CHANGELOG.md +++ b/projects/js-packages/boost-score-api/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.37] - 2024-08-29 +### Changed +- Updated package dependencies. [#39111] + +## [0.1.36] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + +## [0.1.35] - 2024-08-21 +### Changed +- Internal updates. + ## [0.1.34] - 2024-08-15 ### Changed - Updated package dependencies. [#38662] @@ -151,6 +163,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Create package for the boost score bar API [#30781] +[0.1.37]: https://github.com/Automattic/jetpack-boost-score-api/compare/v0.1.36...v0.1.37 +[0.1.36]: https://github.com/Automattic/jetpack-boost-score-api/compare/v0.1.35...v0.1.36 +[0.1.35]: https://github.com/Automattic/jetpack-boost-score-api/compare/v0.1.34...v0.1.35 [0.1.34]: https://github.com/Automattic/jetpack-boost-score-api/compare/v0.1.33...v0.1.34 [0.1.33]: https://github.com/Automattic/jetpack-boost-score-api/compare/v0.1.32...v0.1.33 [0.1.32]: https://github.com/Automattic/jetpack-boost-score-api/compare/v0.1.31...v0.1.32 diff --git a/projects/js-packages/boost-score-api/composer.json b/projects/js-packages/boost-score-api/composer.json index b312f8fcdcfa3..b42e4121420e4 100644 --- a/projects/js-packages/boost-score-api/composer.json +++ b/projects/js-packages/boost-score-api/composer.json @@ -5,7 +5,7 @@ "license": "GPL-2.0-or-later", "require": {}, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "scripts": { diff --git a/projects/js-packages/boost-score-api/package.json b/projects/js-packages/boost-score-api/package.json index 61e7b51d5f606..a918d7ada1852 100644 --- a/projects/js-packages/boost-score-api/package.json +++ b/projects/js-packages/boost-score-api/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/jetpack-boost-score-api", - "version": "0.1.34", + "version": "0.1.37", "description": "A package to get the Jetpack Boost score of a site", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/boost-score-api/#readme", "bugs": { @@ -30,7 +30,7 @@ "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "typescript": "5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "exports": { diff --git a/projects/js-packages/boost-score-api/src/api.ts b/projects/js-packages/boost-score-api/src/api.ts index 9244aca3ee9ed..8b8c2bd80c974 100644 --- a/projects/js-packages/boost-score-api/src/api.ts +++ b/projects/js-packages/boost-score-api/src/api.ts @@ -8,7 +8,7 @@ import type { JSONObject } from './utils/json-object-type'; * * @param {string} path - The path to the endpoint. * @param {string} root - The root URL to use. - * @returns {string} - The full URL. + * @return {string} - The full URL. */ function getEndpointUrl( path: string, root: string ): string { return root + JETPACK_BOOST_REST_NAMESPACE + JETPACK_BOOST_REST_PREFIX + path; @@ -17,12 +17,12 @@ function getEndpointUrl( path: string, root: string ): string { /** * Send a request to the Boost REST API. * - * @param {string} method - The HTTP method to use. - * @param {string} root - The root URL to use. - * @param {string} path - The path to the endpoint. - * @param {null | JSONObject} body - The body of the request. - * @param {string} nonce - The nonce to use. - * @returns {Promise} - The response. + * @param {string} method - The HTTP method to use. + * @param {string} root - The root URL to use. + * @param {string} path - The path to the endpoint. + * @param {null | JSONObject} body - The body of the request. + * @param {string} nonce - The nonce to use. + * @return {Promise} - The response. */ async function sendRequest( method: string, @@ -79,12 +79,12 @@ async function sendRequest( /** * Make a request to the Boost REST API. * - * @param {string} method - The HTTP method to use. - * @param {string} root - The root URL to use. - * @param {string} path - The path to the endpoint. - * @param {null | JSONObject} body - The body of the request. - * @param {string} nonce - The nonce to use. - * @returns {Promise} - The response. + * @param {string} method - The HTTP method to use. + * @param {string} root - The root URL to use. + * @param {string} path - The path to the endpoint. + * @param {null | JSONObject} body - The body of the request. + * @param {string} nonce - The nonce to use. + * @return {Promise} - The response. */ async function makeRequest< T = JSONObject >( method: string, @@ -123,10 +123,10 @@ async function makeRequest< T = JSONObject >( /** * Make a GET request to the Boost REST API. * - * @param {string} root - The root URL to use. - * @param {string} path - The path to the endpoint. + * @param {string} root - The root URL to use. + * @param {string} path - The path to the endpoint. * @param {string} nonce - The nonce to use. - * @returns {Promise} - The response. + * @return {Promise} - The response. */ function get< T = JSONObject >( root: string, path: string, nonce: string ): Promise< T > { return makeRequest< T >( 'get', root, path, null, nonce ); @@ -135,11 +135,11 @@ function get< T = JSONObject >( root: string, path: string, nonce: string ): Pro /** * Make a POST request to the Boost REST API. * - * @param {string} root - The root URL to use. - * @param {string} path - The path to the endpoint. - * @param {null | JSONObject} body - The body of the request. - * @param {string} nonce - The nonce to use. - * @returns {Promise} - The response. + * @param {string} root - The root URL to use. + * @param {string} path - The path to the endpoint. + * @param {null | JSONObject} body - The body of the request. + * @param {string} nonce - The nonce to use. + * @return {Promise} - The response. */ function post< T = JSONObject >( root: string, diff --git a/projects/js-packages/boost-score-api/src/index.ts b/projects/js-packages/boost-score-api/src/index.ts index 0ee22a6c02e98..3643140838ee4 100644 --- a/projects/js-packages/boost-score-api/src/index.ts +++ b/projects/js-packages/boost-score-api/src/index.ts @@ -66,11 +66,11 @@ type ParsedApiResponse = { * Kick off a request to generate speed scores for this site. Will automatically * poll for a response until the task is done, returning a SpeedScores object. * - * @param {boolean} force - Force regenerate speed scores. - * @param {string} rootUrl - Root URL for the HTTP request. - * @param {string} siteUrl - URL of the site. - * @param {string} nonce - Nonce to use for authentication. - * @returns {SpeedScoresSet} Speed scores returned by the server. + * @param {boolean} force - Force regenerate speed scores. + * @param {string} rootUrl - Root URL for the HTTP request. + * @param {string} siteUrl - URL of the site. + * @param {string} nonce - Nonce to use for authentication. + * @return {SpeedScoresSet} Speed scores returned by the server. */ export async function requestSpeedScores( force = false, @@ -103,8 +103,8 @@ export async function requestSpeedScores( * * @param {string} rootUrl - Root URL for the HTTP request. * @param {string} siteUrl - URL of the site. - * @param {string} nonce - Nonce to use for authentication. - * @returns {SpeedHistoryResponse} Speed score history returned by the server. + * @param {string} nonce - Nonce to use for authentication. + * @return {SpeedHistoryResponse} Speed score history returned by the server. */ export async function requestSpeedScoresHistory( rootUrl: string, @@ -128,7 +128,7 @@ export async function requestSpeedScoresHistory( * scores (if ready), and a status (success|pending|error). * * @param {JSONObject} response - API response to parse - * @returns {ParsedApiResponse} API response, processed. + * @return {ParsedApiResponse} API response, processed. */ function parseResponse( response: JSONObject ): ParsedApiResponse { // Handle an explicit error @@ -181,8 +181,8 @@ function parseResponse( response: JSONObject ): ParsedApiResponse { * * @param {string} rootUrl - Root URL of the site to request metrics for * @param {string} siteUrl - Site URL to request metrics for - * @param {string} nonce - Nonce to use for authentication - * @returns {SpeedScoresSet} Speed scores returned by the server. + * @param {string} nonce - Nonce to use for authentication + * @return {SpeedScoresSet} Speed scores returned by the server. */ async function pollRequest( rootUrl: string, @@ -211,7 +211,7 @@ async function pollRequest( * * @param {number} mobile - Mobile speed score * @param {number} desktop - Desktop speed score - * @returns {string} letter score + * @return {string} letter score */ export function getScoreLetter( mobile: number, desktop: number ): string { const sum = mobile + desktop; @@ -240,7 +240,7 @@ export function getScoreLetter( mobile: number, desktop: number ): string { * The message varies depending on the results of the speed scores so lets modify this * * @param {SpeedScoresSet} scores - Speed scores returned by the server. - * @returns {boolean} true if scores changed. + * @return {boolean} true if scores changed. */ export function didScoresChange( scores: SpeedScoresSet ): boolean { const current = scores.current; @@ -265,7 +265,7 @@ export function didScoresChange( scores: SpeedScoresSet ): boolean { * Determine the change in scores to pass through to other functions. * * @param {SpeedScoresSet} scores - Speed scores returned by the server. - * @returns {number} - The change in scores in percentage. + * @return {number} - The change in scores in percentage. */ export function getScoreMovementPercentage( scores: SpeedScoresSet ): number { const current = scores.current; @@ -286,7 +286,7 @@ export function getScoreMovementPercentage( scores: SpeedScoresSet ): number { * Determine the number of days since the last timestamp. * * @param {number} timestamp - the timestamp returned by the server. - * @returns {number} - The number of days. + * @return {number} - The number of days. */ export function calculateDaysSince( timestamp: number ): number { // Create Date objects for the provided timestamp and the current date diff --git a/projects/js-packages/boost-score-api/src/utils/cast-to-number.ts b/projects/js-packages/boost-score-api/src/utils/cast-to-number.ts index f2875e148b002..c8149f60715ef 100644 --- a/projects/js-packages/boost-score-api/src/utils/cast-to-number.ts +++ b/projects/js-packages/boost-score-api/src/utils/cast-to-number.ts @@ -6,7 +6,7 @@ * @template DefaultType * @param {*} value - External value to process as a number * @param {DefaultType} defaultValue - Default value to return if not a number. - * @returns {number | DefaultType} value as a number, of defaultValue. + * @return {number | DefaultType} value as a number, of defaultValue. */ export function castToNumber< DefaultType = number >( value: unknown, diff --git a/projects/js-packages/boost-score-api/src/utils/cast-to-string.ts b/projects/js-packages/boost-score-api/src/utils/cast-to-string.ts index d9b1dec4afe67..0ecc4c417741d 100644 --- a/projects/js-packages/boost-score-api/src/utils/cast-to-string.ts +++ b/projects/js-packages/boost-score-api/src/utils/cast-to-string.ts @@ -6,7 +6,7 @@ * @template DefaultType * @param {*} value - External value to process as a string * @param {DefaultType} defaultValue - Default value to return if not a string - * @returns {string | DefaultType} value as a string, of defaultValue. + * @return {string | DefaultType} value as a string, of defaultValue. */ export function castToString< DefaultType = undefined >( value: unknown, diff --git a/projects/js-packages/boost-score-api/src/utils/json-types.ts b/projects/js-packages/boost-score-api/src/utils/json-types.ts index 030378a9ec417..78356a0bdc884 100644 --- a/projects/js-packages/boost-score-api/src/utils/json-types.ts +++ b/projects/js-packages/boost-score-api/src/utils/json-types.ts @@ -14,7 +14,7 @@ export type JSONValue = string | number | boolean | JSONObject | JSONArray | nul * Returns true if the given JSONValue is a JSONObject. * * @param {JSONValue} value - Value to check. - * @returns {boolean} True if the given value is a JSONObject. + * @return {boolean} True if the given value is a JSONObject. */ export function isJsonObject( value: JSONValue ): value is JSONObject { return !! value && value instanceof Object && ! ( value instanceof Array ); @@ -25,7 +25,7 @@ export function isJsonObject( value: JSONValue ): value is JSONObject { * Sure, you could use x instanceof Array but this is shorter and more consistent. * * @param {JSONValue} value - Value to check. - * @returns {boolean} True if the given value is a JSONArray. + * @return {boolean} True if the given value is a JSONArray. */ export function isJsonArray( value: JSONValue ): value is JSONArray { return value instanceof Array; diff --git a/projects/js-packages/boost-score-api/src/utils/poll-promise.ts b/projects/js-packages/boost-score-api/src/utils/poll-promise.ts index efe56bfe451e9..8c75352efe45e 100644 --- a/projects/js-packages/boost-score-api/src/utils/poll-promise.ts +++ b/projects/js-packages/boost-score-api/src/utils/poll-promise.ts @@ -22,7 +22,7 @@ type PollPromiseArgs< RetType = void > = { * @param {number} obj.timeout - Milliseconds before rejecting w/ a timeout * @param {Function} obj.callback - Callback to call every ms. * @param {string} obj.timeoutError - Message to throw on timeout. - * @returns {Promise< RetType >} - A promise which resolves to the value resolved() inside callback. + * @return {Promise< RetType >} - A promise which resolves to the value resolved() inside callback. */ export default async function pollPromise< RetType = void >( { interval, diff --git a/projects/js-packages/boost-score-api/src/utils/standardize-error.ts b/projects/js-packages/boost-score-api/src/utils/standardize-error.ts index f075723d0ba20..d1a9aa9ff0215 100644 --- a/projects/js-packages/boost-score-api/src/utils/standardize-error.ts +++ b/projects/js-packages/boost-score-api/src/utils/standardize-error.ts @@ -6,7 +6,7 @@ import type { JSONValue } from './json-types'; * * @param {*} data - Any thrown error data to interpret as an Error (or subclass) * @param {JSONValue|Error} defaultMessage - A default message to throw if no sensible error can be found. - * @returns {Error} the data guaranteed to be an Error or subclass thereof. + * @return {Error} the data guaranteed to be an Error or subclass thereof. */ export function standardizeError( data: JSONValue | Error, defaultMessage?: string ): Error { if ( data instanceof Error ) { diff --git a/projects/js-packages/boost-score-api/tests/index.test.js b/projects/js-packages/boost-score-api/tests/index.test.js index 16f3ad24ccf98..3453f99e98bd2 100644 --- a/projects/js-packages/boost-score-api/tests/index.test.js +++ b/projects/js-packages/boost-score-api/tests/index.test.js @@ -82,7 +82,8 @@ describe( 'getScoreMovementPercentage', () => { expect( getScoreMovementPercentage( changedMockData.scores ) ).toBe( 0 ); - ( changedMockData.scores.noBoost.desktop = 80 ), ( changedMockData.scores.noBoost.mobile = 70 ); + changedMockData.scores.noBoost.desktop = 80; + changedMockData.scores.noBoost.mobile = 70; expect( getScoreMovementPercentage( changedMockData.scores ) ).toBe( 13 ); } ); diff --git a/projects/js-packages/components/CHANGELOG.md b/projects/js-packages/components/CHANGELOG.md index 0bb4c1392b727..826ff78f6e3c5 100644 --- a/projects/js-packages/components/CHANGELOG.md +++ b/projects/js-packages/components/CHANGELOG.md @@ -2,6 +2,25 @@ ### This is a list detailing changes for the Jetpack RNA Components package releases. +## [0.55.11] - 2024-08-29 +### Changed +- Updated package dependencies. [#39111] + +## [0.55.10] - 2024-08-23 +### Changed +- Internal updates. + +## [0.55.9] - 2024-08-21 +### Fixed +- Revert recent SVG image optimizations. [#38981] + +## [0.55.8] - 2024-08-19 +### Changed +- Updated package dependencies. [#38893] + +### Fixed +- Lossless image optimization for images (should improve performance with no visible changes). [#38750] + ## [0.55.7] - 2024-08-15 ### Changed - Updated package dependencies. [#38665] @@ -1122,6 +1141,10 @@ ### Changed - Update node version requirement to 14.16.1 +[0.55.11]: https://github.com/Automattic/jetpack-components/compare/0.55.10...0.55.11 +[0.55.10]: https://github.com/Automattic/jetpack-components/compare/0.55.9...0.55.10 +[0.55.9]: https://github.com/Automattic/jetpack-components/compare/0.55.8...0.55.9 +[0.55.8]: https://github.com/Automattic/jetpack-components/compare/0.55.7...0.55.8 [0.55.7]: https://github.com/Automattic/jetpack-components/compare/0.55.6...0.55.7 [0.55.6]: https://github.com/Automattic/jetpack-components/compare/0.55.5...0.55.6 [0.55.5]: https://github.com/Automattic/jetpack-components/compare/0.55.4...0.55.5 diff --git a/projects/js-packages/components/components/action-button/index.jsx b/projects/js-packages/components/components/action-button/index.jsx index f7f37245760ee..42d366eaf2fa0 100644 --- a/projects/js-packages/components/components/action-button/index.jsx +++ b/projects/js-packages/components/components/action-button/index.jsx @@ -20,7 +20,7 @@ import styles from './style.module.scss'; * It is useful to async actions when the user has to wait the result of a request or process. * * @param {object} props - The properties. - * @returns {React.Component} The `ActionButton` component. + * @return {React.Component} The `ActionButton` component. */ const ActionButton = props => { const { diff --git a/projects/js-packages/components/components/admin-page/index.tsx b/projects/js-packages/components/components/admin-page/index.tsx index 480070cd31ace..8ce477b8d9d21 100644 --- a/projects/js-packages/components/components/admin-page/index.tsx +++ b/projects/js-packages/components/components/admin-page/index.tsx @@ -14,7 +14,7 @@ import type React from 'react'; * All content must be passed as children wrapped in as many elements as needed. * * @param {AdminPageProps} props - Component properties. - * @returns {React.ReactNode} AdminPage component. + * @return {React.ReactNode} AdminPage component. */ const AdminPage: React.FC< AdminPageProps > = ( { children, diff --git a/projects/js-packages/components/components/admin-section/basic/index.tsx b/projects/js-packages/components/components/admin-section/basic/index.tsx index 4e721e209858c..73789f8f7dadc 100644 --- a/projects/js-packages/components/components/admin-section/basic/index.tsx +++ b/projects/js-packages/components/components/admin-section/basic/index.tsx @@ -6,7 +6,7 @@ import type { AdminSectionBaseProps } from '../types'; * This is the wrapper component to build sections within your admin page. * * @param {AdminSectionBaseProps} props - Component properties. - * @returns {React.ReactNode} AdminSection component. + * @return {React.ReactNode} AdminSection component. */ const AdminSection: React.FC< AdminSectionBaseProps > = ( { children } ) => { return
{ children }
; diff --git a/projects/js-packages/components/components/admin-section/hero/index.tsx b/projects/js-packages/components/components/admin-section/hero/index.tsx index a794068fd1440..201e4a28bb17f 100644 --- a/projects/js-packages/components/components/admin-section/hero/index.tsx +++ b/projects/js-packages/components/components/admin-section/hero/index.tsx @@ -6,7 +6,7 @@ import type { AdminSectionBaseProps } from '../types'; * The wrapper component for a Hero Section to be used in admin pages. * * @param {AdminSectionBaseProps} props - Component properties. - * @returns {React.Component} AdminSectionHero component. + * @return {React.Component} AdminSectionHero component. */ const AdminSectionHero: React.FC< AdminSectionBaseProps > = ( { children } ) => { return
{ children }
; diff --git a/projects/js-packages/components/components/alert/index.tsx b/projects/js-packages/components/components/alert/index.tsx index 1a98b7c5014e2..527d5937fcbce 100644 --- a/projects/js-packages/components/components/alert/index.tsx +++ b/projects/js-packages/components/components/alert/index.tsx @@ -35,12 +35,12 @@ const getIconByLevel = ( level: AlertProps[ 'level' ] ) => { /** * Alert component * - * @param {object} props - The component properties. - * @param {string} props.level - The alert level: error, warning, info, success. - * @param {boolean} props.showIcon - Whether to show the alert icon. - * @param {string} props.className - The wrapper class name. - * @param {React.Component} props.children - The alert content. - * @returns {React.ReactElement} The `Alert` component. + * @param {object} props - The component properties. + * @param {string} props.level - The alert level: error, warning, info, success. + * @param {boolean} props.showIcon - Whether to show the alert icon. + * @param {string} props.className - The wrapper class name. + * @param {React.Component} props.children - The alert content. + * @return {React.ReactElement} The `Alert` component. */ const Alert: React.FC< AlertProps > = ( { level = 'warning', diff --git a/projects/js-packages/components/components/automattic-byline-logo/index.tsx b/projects/js-packages/components/components/automattic-byline-logo/index.tsx index 797f732ae8265..caff7fa9ef853 100644 --- a/projects/js-packages/components/components/automattic-byline-logo/index.tsx +++ b/projects/js-packages/components/components/automattic-byline-logo/index.tsx @@ -7,7 +7,7 @@ import { AutomatticBylineLogoProps } from './types'; * Automattic "By line" Logo component. * * @param {AutomatticBylineLogoProps} props - Component properties. - * @returns {React.ReactNode} AutomatticBylineLogo component. + * @return {React.ReactNode} AutomatticBylineLogo component. */ const AutomatticBylineLogo: React.FC< AutomatticBylineLogoProps > = ( { title = __( 'An Automattic Airline', 'jetpack' ), diff --git a/projects/js-packages/components/components/automattic-for-agencies-logo/index.tsx b/projects/js-packages/components/components/automattic-for-agencies-logo/index.tsx index 949ef24c7a5f2..549681a341994 100644 --- a/projects/js-packages/components/components/automattic-for-agencies-logo/index.tsx +++ b/projects/js-packages/components/components/automattic-for-agencies-logo/index.tsx @@ -4,9 +4,9 @@ import React from 'react'; /** * Automattic for Agencies Logo component * - * @param {object} props - Component props - * @param {string} props.color - Color code for the logo text - * @returns {React.ReactElement} Component template + * @param {object} props - Component props + * @param {string} props.color - Color code for the logo text + * @return {React.ReactElement} Component template */ export default function AutomatticForAgenciesLogo( { color = '#FFFFFF', diff --git a/projects/js-packages/components/components/automattic-icon-logo/index.tsx b/projects/js-packages/components/components/automattic-icon-logo/index.tsx index 5f1b63ffdcbce..9ea7bf77080fd 100644 --- a/projects/js-packages/components/components/automattic-icon-logo/index.tsx +++ b/projects/js-packages/components/components/automattic-icon-logo/index.tsx @@ -4,10 +4,10 @@ import React from 'react'; /** * Automattic Icon Logo component * - * @param {object} props - Component props - * @param {string} props.innerColor - Color code for the line in the middle of the logo. - * @param {string} props.outerColor - Color code for the logo's outer - * @returns {React.ReactElement} Component template + * @param {object} props - Component props + * @param {string} props.innerColor - Color code for the line in the middle of the logo. + * @param {string} props.outerColor - Color code for the logo's outer + * @return {React.ReactElement} Component template */ export default function AutomatticIconLogo( { innerColor = '#00A3E0', diff --git a/projects/js-packages/components/components/boost-score-graph/day-highlight-plugin.ts b/projects/js-packages/components/components/boost-score-graph/day-highlight-plugin.ts index 3a879cd71b99e..50b0f6317ce58 100644 --- a/projects/js-packages/components/components/boost-score-graph/day-highlight-plugin.ts +++ b/projects/js-packages/components/components/boost-score-graph/day-highlight-plugin.ts @@ -3,7 +3,7 @@ import uPlot from 'uplot'; /** * Definition of the column highlight plugin. * - * @returns {object} The uPlot plugin object with hooks. + * @return {object} The uPlot plugin object with hooks. */ export function dayHighlightPlugin() { let overEl, highlightEl; diff --git a/projects/js-packages/components/components/boost-score-graph/get-date-format.ts b/projects/js-packages/components/components/boost-score-graph/get-date-format.ts index 6970cc544c60d..2af4a2ff823a2 100644 --- a/projects/js-packages/components/components/boost-score-graph/get-date-format.ts +++ b/projects/js-packages/components/components/boost-score-graph/get-date-format.ts @@ -4,10 +4,10 @@ const MONTH_FORMAT = 'short'; /** * Returns a formatted date based on the provided template and locale. * - * @param {string} template - The template used to format the date. - * @param {Date} date - The date object to be formatted. + * @param {string} template - The template used to format the date. + * @param {Date} date - The date object to be formatted. * @param {string} [locale='en'] - The locale code specifying the language and region to be used for formatting. Default 'en'. - * @returns {string} The formatted date as a string. + * @return {string} The formatted date as a string. */ export default function getDateFormat( template: string, date: Date, locale = 'en' ): string { let newDayMonthFormat; diff --git a/projects/js-packages/components/components/boost-score-graph/index.tsx b/projects/js-packages/components/components/boost-score-graph/index.tsx index ecb580e983a88..be5e81cc8b8b6 100644 --- a/projects/js-packages/components/components/boost-score-graph/index.tsx +++ b/projects/js-packages/components/components/boost-score-graph/index.tsx @@ -40,11 +40,11 @@ export type ScoreGraphAlignedData = [ /** * BoostScoreGraph component composed by the chart and the legend. * - * @param {BoostScoreGraphProps} props - The props object for the BoostScoreGraph component. - * @param {string} props.title - Title for the chart. - * @param {Period[]} props.periods - The periods to display in the chart. - * @param {boolean} [props.isLoading=false] - Whether the component is in a loading state. - * @returns {React.ReactElement} The JSX element representing the BoostScoreGraph component, or null if loading. + * @param {BoostScoreGraphProps} props - The props object for the BoostScoreGraph component. + * @param {string} props.title - Title for the chart. + * @param {Period[]} props.periods - The periods to display in the chart. + * @param {boolean} [props.isLoading=false] - Whether the component is in a loading state. + * @return {React.ReactElement} The JSX element representing the BoostScoreGraph component, or null if loading. */ export const BoostScoreGraph: FunctionComponent< BoostScoreGraphProps > = ( { periods = [], diff --git a/projects/js-packages/components/components/boost-score-graph/tooltips-plugin.ts b/projects/js-packages/components/components/boost-score-graph/tooltips-plugin.ts index 5d0dbfe45fa88..c6dfb97d2e7e6 100644 --- a/projects/js-packages/components/components/boost-score-graph/tooltips-plugin.ts +++ b/projects/js-packages/components/components/boost-score-graph/tooltips-plugin.ts @@ -7,7 +7,7 @@ import { Period } from '.'; * Custom tooltips plugin for uPlot. * * @param {Period[]} periods - The periods to display in the tooltip. - * @returns {object} The uPlot plugin object with hooks. + * @return {object} The uPlot plugin object with hooks. */ export function tooltipsPlugin( periods ) { const reactRoot = document.createElement( 'div' ); @@ -17,7 +17,7 @@ export function tooltipsPlugin( periods ) { /** * Initializes the tooltips plugin. * - * @param {uPlot} u - The uPlot instance. + * @param {uPlot} u - The uPlot instance. * @param {object} _opts - Options for the uPlot instance. */ function init( u: uPlot, _opts: object ) { diff --git a/projects/js-packages/components/components/boost-score-graph/uplot-line-chart.tsx b/projects/js-packages/components/components/boost-score-graph/uplot-line-chart.tsx index ce451ade39ad8..86908cb4137b5 100644 --- a/projects/js-packages/components/components/boost-score-graph/uplot-line-chart.tsx +++ b/projects/js-packages/components/components/boost-score-graph/uplot-line-chart.tsx @@ -33,7 +33,7 @@ interface UplotChartProps { * * @param {string} label - The label for the series. * @param {number} score - The last score for the series. - * @returns {object} The series information object. + * @return {object} The series information object. */ function createSerieInfo( label: string, score ) { const { spline } = uPlot.paths; @@ -67,9 +67,9 @@ function createSerieInfo( label: string, score ) { /** * Get the color value based on the score. * - * @param {number} score - The score to get the color for. + * @param {number} score - The score to get the color for. * @param {string} opacity - Whether to return a transparent color. - * @returns {string} The color value. + * @return {string} The color value. */ function getColor( score: number, opacity = 'FF' ) { let color = '#D63638'; // bad @@ -86,11 +86,11 @@ function getColor( score: number, opacity = 'FF' ) { /** * UplotLineChart component. * - * @param {object} props - The props object for the UplotLineChart component. - * @param {{ startDate: number, endDate: number }} props.range - The date range of the chart. - * @param {Period[]} props.periods - The periods to display in the chart. - * @param {Annotation[]} props.annotations - The annotations to display in the chart. - * @returns {React.Element} The JSX element representing the UplotLineChart component. + * @param {object} props - The props object for the UplotLineChart component. + * @param {{ startDate: number, endDate: number }} props.range - The date range of the chart. + * @param {Period[]} props.periods - The periods to display in the chart. + * @param {Annotation[]} props.annotations - The annotations to display in the chart. + * @return {React.Element} The JSX element representing the UplotLineChart component. */ export default function UplotLineChart( { range, periods, annotations = [] }: UplotChartProps ) { const uplot = useRef< uPlot | null >( null ); diff --git a/projects/js-packages/components/components/boost-score-graph/use-boost-score-transform.ts b/projects/js-packages/components/components/boost-score-graph/use-boost-score-transform.ts index 2a04490bcf9d4..e75383aa6d81a 100644 --- a/projects/js-packages/components/components/boost-score-graph/use-boost-score-transform.ts +++ b/projects/js-packages/components/components/boost-score-graph/use-boost-score-transform.ts @@ -18,7 +18,7 @@ const getPeriodDimension = function ( key: string, periods: Period[] ) { * Transforms an array of periods into an array of arrays, where the first array is the timestamps, and the rest are the values for each key * * @param {Period[]} periods - Array of periods to transform - * @returns {ScoreGraphAlignedData | []} - Array of arrays, where the first array is the timestamps, and the rest are the values for each key + * @return {ScoreGraphAlignedData | []} - Array of arrays, where the first array is the timestamps, and the rest are the values for each key */ export function useBoostScoreTransform( periods: Period[] ): ScoreGraphAlignedData | [] { return useMemo( () => { diff --git a/projects/js-packages/components/components/boost-score-graph/use-resize.ts b/projects/js-packages/components/components/boost-score-graph/use-resize.ts index d94e6e019fe50..c491ebfe1a996 100644 --- a/projects/js-packages/components/components/boost-score-graph/use-resize.ts +++ b/projects/js-packages/components/components/boost-score-graph/use-resize.ts @@ -7,7 +7,7 @@ const THROTTLE_DURATION = 400; // in ms /** * Custom hook to handle resizing of uPlot charts. * - * @param {React.RefObject} uplotRef - The ref object for the uPlot instance. + * @param {React.RefObject} uplotRef - The ref object for the uPlot instance. * @param {React.RefObject} containerRef - The ref object for the container div. */ export default function useResize( diff --git a/projects/js-packages/components/components/button/index.tsx b/projects/js-packages/components/components/button/index.tsx index 101c600900512..d7f0e608c5a81 100644 --- a/projects/js-packages/components/components/button/index.tsx +++ b/projects/js-packages/components/components/button/index.tsx @@ -16,7 +16,7 @@ import type { ButtonProps } from './types'; * Button component * * @param {ButtonProps} props - Component Props - * @returns {React.ReactNode} Rendered button + * @return {React.ReactNode} Rendered button */ const Button = forwardRef< HTMLInputElement, ButtonProps >( ( props, ref ) => { const { diff --git a/projects/js-packages/components/components/chip/index.tsx b/projects/js-packages/components/components/chip/index.tsx index d122347e44a7f..6684927495182 100644 --- a/projects/js-packages/components/components/chip/index.tsx +++ b/projects/js-packages/components/components/chip/index.tsx @@ -10,10 +10,10 @@ type ChipProps = { /** * Chip component * - * @param {object} props - The component properties. - * @param {string} props.type - The type new or info - * @param {string} props.text - Chip text - * @returns {React.ReactElement} The `Chip` component. + * @param {object} props - The component properties. + * @param {string} props.type - The type new or info + * @param {string} props.text - Chip text + * @return {React.ReactElement} The `Chip` component. */ const Chip: React.FC< ChipProps > = ( { type = 'info', text } ) => { const classes = clsx( styles.chip, styles[ `is-${ type }` ] ); diff --git a/projects/js-packages/components/components/decorative-card/index.tsx b/projects/js-packages/components/components/decorative-card/index.tsx index b1ddf205d8c05..921364592b7d8 100644 --- a/projects/js-packages/components/components/decorative-card/index.tsx +++ b/projects/js-packages/components/components/decorative-card/index.tsx @@ -6,7 +6,7 @@ import './style.scss'; * A decorative card used in the disconnection flow. * * @param {DecorativeCardProps} props - The properties. - * @returns {React.ReactNode} - The DecorativeCard component. + * @return {React.ReactNode} - The DecorativeCard component. */ const DecorativeCard: React.FC< DecorativeCardProps > = ( { diff --git a/projects/js-packages/components/components/dialog/index.tsx b/projects/js-packages/components/components/dialog/index.tsx index 847f3677c9bb5..521266875ea3e 100644 --- a/projects/js-packages/components/components/dialog/index.tsx +++ b/projects/js-packages/components/components/dialog/index.tsx @@ -16,12 +16,12 @@ type DialogProps = { /** * Dialog component. * - * @param {object} props - React component props. - * @param {React.ReactNode} props.primary - Primary-section content. - * @param {React.ReactNode} props.secondary - Secondary-section content. - * @param {boolean} props.isTwoSections - Handle two sections layout when true. - * @param {object} props.containerProps - Props to pass to the container component. - * @returns {React.ReactNode} Rendered dialog + * @param {object} props - React component props. + * @param {React.ReactNode} props.primary - Primary-section content. + * @param {React.ReactNode} props.secondary - Secondary-section content. + * @param {boolean} props.isTwoSections - Handle two sections layout when true. + * @param {object} props.containerProps - Props to pass to the container component. + * @return {React.ReactNode} Rendered dialog */ const Dialog: React.FC< DialogProps > = ( { primary, diff --git a/projects/js-packages/components/components/dialog/stories/boost.png b/projects/js-packages/components/components/dialog/stories/boost.png index dd818e4664052..4e7cb0cec7511 100644 Binary files a/projects/js-packages/components/components/dialog/stories/boost.png and b/projects/js-packages/components/components/dialog/stories/boost.png differ diff --git a/projects/js-packages/components/components/donut-meter/index.tsx b/projects/js-packages/components/components/donut-meter/index.tsx index 4eaf0a309037b..7911bce0d58a8 100644 --- a/projects/js-packages/components/components/donut-meter/index.tsx +++ b/projects/js-packages/components/components/donut-meter/index.tsx @@ -72,7 +72,7 @@ const getAdaptiveType = ( percentage: number ) => { * Generate record meter donut bar * * @param {DonutMeterProps} props - Props - * @returns {React.ReactElement} - JSX element + * @return {React.ReactElement} - JSX element */ const DonutMeter: React.FC< DonutMeterProps > = ( { className = '', diff --git a/projects/js-packages/components/components/global-notices/global-notices.tsx b/projects/js-packages/components/components/global-notices/global-notices.tsx index b3c694858e3df..0125aeb4ac7e8 100644 --- a/projects/js-packages/components/components/global-notices/global-notices.tsx +++ b/projects/js-packages/components/components/global-notices/global-notices.tsx @@ -11,7 +11,7 @@ export type GlobalNoticesProps = { * * @param {GlobalNoticesProps} props - Component props. * - * @returns {import('react').ReactNode} The rendered notices list. + * @return {import('react').ReactNode} The rendered notices list. */ export function GlobalNotices( { maxVisibleNotices = 3 }: GlobalNoticesProps ) { const { getNotices, removeNotice } = useGlobalNotices(); diff --git a/projects/js-packages/components/components/global-notices/use-global-notices.ts b/projects/js-packages/components/components/global-notices/use-global-notices.ts index 333ef0a5fcce6..4f924117bec0d 100644 --- a/projects/js-packages/components/components/global-notices/use-global-notices.ts +++ b/projects/js-packages/components/components/global-notices/use-global-notices.ts @@ -9,7 +9,7 @@ export type TGlobalNotices = ReturnType< NoticesStore[ 'getActions' ] > & /** * The global notices hook. * - * @returns {TGlobalNotices} The global notices selectors and actions. + * @return {TGlobalNotices} The global notices selectors and actions. */ export function useGlobalNotices(): TGlobalNotices { const actionCreators = useDispatch( noticesStore ); diff --git a/projects/js-packages/components/components/icon-tooltip/index.tsx b/projects/js-packages/components/components/icon-tooltip/index.tsx index 584da8b429490..c64b6e74309dd 100644 --- a/projects/js-packages/components/components/icon-tooltip/index.tsx +++ b/projects/js-packages/components/components/icon-tooltip/index.tsx @@ -24,7 +24,7 @@ const placementsToPositions = ( placement: Placement ): Position => { * Generate Icon Tooltip * * @param {IconTooltipProps} props - Props - * @returns {React.ReactElement} - JSX element + * @return {React.ReactElement} - JSX element */ const IconTooltip: React.FC< IconTooltipProps > = ( { className = '', diff --git a/projects/js-packages/components/components/icons/index.tsx b/projects/js-packages/components/components/icons/index.tsx index 1e77dd87e8808..a390b8a3a3f6f 100644 --- a/projects/js-packages/components/components/icons/index.tsx +++ b/projects/js-packages/components/components/icons/index.tsx @@ -9,7 +9,7 @@ import type React from 'react'; * Icon Wrapper component. * * @param {BaseIconProps} props - Component props. - * @returns {React.ReactNode} Icon Wrapper component. + * @return {React.ReactNode} Icon Wrapper component. */ const IconWrapper: React.FC< BaseIconProps > = ( { className, @@ -264,8 +264,8 @@ export type IconSlug = keyof IconsMap; /** * Return icon component by slug. * - * @param {string} slug - Icon slug. - * @returns {React.ComponentType} Icon component. + * @param {string} slug - Icon slug. + * @return {React.ComponentType} Icon component. */ export function getIconBySlug< Slug extends IconSlug >( slug: Slug ): IconsMap[ Slug ] { if ( ! iconsMap[ slug ] ) { diff --git a/projects/js-packages/components/components/icons/stories/index.stories.tsx b/projects/js-packages/components/components/icons/stories/index.stories.tsx index 4a7f3047bd5cb..c772ad86def3d 100644 --- a/projects/js-packages/components/components/icons/stories/index.stories.tsx +++ b/projects/js-packages/components/components/icons/stories/index.stories.tsx @@ -26,7 +26,7 @@ const sizes = [ /** * Icons story components. * - * @returns {object} - story component + * @return {object} - story component */ function IconsStory() { return ( diff --git a/projects/js-packages/components/components/indeterminate-progress-bar/index.tsx b/projects/js-packages/components/components/indeterminate-progress-bar/index.tsx index ea3a182cee505..2ac01bbba8f3b 100644 --- a/projects/js-packages/components/components/indeterminate-progress-bar/index.tsx +++ b/projects/js-packages/components/components/indeterminate-progress-bar/index.tsx @@ -14,7 +14,7 @@ import type React from 'react'; * Indeterminate Progress Bar component * * @param {IndeterminateProgressBarProps} props - Component props. - * @returns {React.ReactNode} - IndeterminateProgressBar react component. + * @return {React.ReactNode} - IndeterminateProgressBar react component. */ const IndeterminateProgressBar: React.FC< IndeterminateProgressBarProps > = ( { className } ) => { return ( diff --git a/projects/js-packages/components/components/jetpack-footer/index.tsx b/projects/js-packages/components/components/jetpack-footer/index.tsx index 3a4c2572fefc9..41b41ad0ae251 100644 --- a/projects/js-packages/components/components/jetpack-footer/index.tsx +++ b/projects/js-packages/components/components/jetpack-footer/index.tsx @@ -32,7 +32,7 @@ const ExternalIcon: React.FC = () => ( * JetpackFooter component displays a tiny Jetpack logo with the product name on the left and the Automattic Airline "by line" on the right. * * @param {JetpackFooterProps} props - Component properties. - * @returns {React.ReactNode} JetpackFooter component. + * @return {React.ReactNode} JetpackFooter component. */ const JetpackFooter: React.FC< JetpackFooterProps > = ( { moduleName = __( 'Jetpack', 'jetpack' ), diff --git a/projects/js-packages/components/components/layout/col/index.tsx b/projects/js-packages/components/components/layout/col/index.tsx index ecaf0e725e3e6..3dce2c691678c 100644 --- a/projects/js-packages/components/components/layout/col/index.tsx +++ b/projects/js-packages/components/components/layout/col/index.tsx @@ -11,8 +11,8 @@ const lgCols = Number( styles.lgCols ); /** * The basic Col component. * - * @param {ColProps} props - Component properties. - * @returns {React.ReactElement} Col component. + * @param {ColProps} props - Component properties. + * @return {React.ReactElement} Col component. */ const Col: React.FC< ColProps > = props => { const { children, tagName = 'div', className } = props; diff --git a/projects/js-packages/components/components/layout/container/index.tsx b/projects/js-packages/components/components/layout/container/index.tsx index 00c22cef79005..630df333a9656 100644 --- a/projects/js-packages/components/components/layout/container/index.tsx +++ b/projects/js-packages/components/components/layout/container/index.tsx @@ -8,7 +8,7 @@ import type React from 'react'; * JP Container * * @param {ContainerProps} props - Component properties. - * @returns {React.ReactElement} Container component. + * @return {React.ReactElement} Container component. */ const Container: React.FC< ContainerProps > = ( { children, diff --git a/projects/js-packages/components/components/layout/use-breakpoint-match/index.ts b/projects/js-packages/components/components/layout/use-breakpoint-match/index.ts index 48a33160066b3..a2733eb075034 100644 --- a/projects/js-packages/components/components/layout/use-breakpoint-match/index.ts +++ b/projects/js-packages/components/components/layout/use-breakpoint-match/index.ts @@ -39,9 +39,9 @@ const getMediaByOperator = ( /** * Hook to match if current viewport is equal, greater or less than expected breakpoint * - * @param {(Breakpoints | Array< Breakpoints >)} breakpointToMatch - An single breakpoint or list of breakpoints to match. - * @param {(Operators | Array< Operators >)} operatorToMatch - An single operator or list of them. It should follow the same sequence than breakpoints. - * @returns {Array} - List of matches, following breakpoints sequence. + * @param {(Breakpoints | Array< Breakpoints >)} breakpointToMatch - An single breakpoint or list of breakpoints to match. + * @param {(Operators | Array< Operators >)} operatorToMatch - An single operator or list of them. It should follow the same sequence than breakpoints. + * @return {Array} - List of matches, following breakpoints sequence. * @example * * ```es6 diff --git a/projects/js-packages/components/components/notice/index.tsx b/projects/js-packages/components/components/notice/index.tsx index b0406544b7022..5e0786d541c77 100644 --- a/projects/js-packages/components/components/notice/index.tsx +++ b/projects/js-packages/components/components/notice/index.tsx @@ -41,14 +41,14 @@ const getIconByLevel = ( level: NoticeProps[ 'level' ] ) => { /** * Notice component * - * @param {object} props - The component properties. - * @param {string} props.level - The notice level: error, warning, info, success. - * @param {boolean} props.hideCloseButton - Whether to hide the close button. - * @param {Function} props.onClose - The function to call when the close button is clicked. - * @param {string} props.title - The title of the notice. - * @param {React.ReactNode[]} props.actions - Actions to show across the bottom of the bar. - * @param {React.Component} props.children - The notice content. - * @returns {React.ReactElement} The `Notice` component. + * @param {object} props - The component properties. + * @param {string} props.level - The notice level: error, warning, info, success. + * @param {boolean} props.hideCloseButton - Whether to hide the close button. + * @param {Function} props.onClose - The function to call when the close button is clicked. + * @param {string} props.title - The title of the notice. + * @param {React.ReactNode[]} props.actions - Actions to show across the bottom of the bar. + * @param {React.Component} props.children - The notice content. + * @return {React.ReactElement} The `Notice` component. */ const Notice: React.FC< NoticeProps > = ( { level = 'info', diff --git a/projects/js-packages/components/components/notice/stories/index.stories.jsx b/projects/js-packages/components/components/notice/stories/index.stories.jsx index 00460aaf6bd22..c60d9a0b3ab28 100644 --- a/projects/js-packages/components/components/notice/stories/index.stories.jsx +++ b/projects/js-packages/components/components/notice/stories/index.stories.jsx @@ -1,3 +1,4 @@ +/* eslint-disable no-alert -- ok for demo */ import { ExternalLink } from '@wordpress/components'; import Button from '../../button'; import Notice from '../index'; diff --git a/projects/js-packages/components/components/number-format/index.ts b/projects/js-packages/components/components/number-format/index.ts index 076fb6a30ae48..aee89d2f666b3 100644 --- a/projects/js-packages/components/components/number-format/index.ts +++ b/projects/js-packages/components/components/number-format/index.ts @@ -3,9 +3,9 @@ import { getUserLocale } from '../../lib/locale'; /** * Format a number using the locale in use by the user viewing the page. * - * @param {number} number - The number to format. + * @param {number} number - The number to format. * @param {Intl.NumberFormatOptions} options - The format options - * @returns {string} Formatted number. + * @return {string} Formatted number. */ const numberFormat = ( number: number, options: Intl.NumberFormatOptions = {} ): string => { const locale = getUserLocale(); diff --git a/projects/js-packages/components/components/number-slider/index.tsx b/projects/js-packages/components/components/number-slider/index.tsx index d391851b454f7..47e854b8bfcdd 100644 --- a/projects/js-packages/components/components/number-slider/index.tsx +++ b/projects/js-packages/components/components/number-slider/index.tsx @@ -9,7 +9,7 @@ import './style.scss'; * More support from the original ReactSlider component: https://zillow.github.io/react-slider/ * * @param {NumberSliderProps} props - Props - * @returns {React.ReactElement} - JSX element + * @return {React.ReactElement} - JSX element */ const NumberSlider: React.FC< NumberSliderProps > = ( { className, diff --git a/projects/js-packages/components/components/pricing-card/index.tsx b/projects/js-packages/components/components/pricing-card/index.tsx index 781e4d8370857..b7a64766a50ec 100644 --- a/projects/js-packages/components/components/pricing-card/index.tsx +++ b/projects/js-packages/components/components/pricing-card/index.tsx @@ -15,7 +15,7 @@ import './style.scss'; * doesn't exist. * * @param {CurrencyObject} currencyObject -- A currency object returned from `getCurrencyObject`. - * @returns {boolean} Whether or not to display the price decimal part. + * @return {boolean} Whether or not to display the price decimal part. */ const showPriceDecimals = ( currencyObject: CurrencyObject ): boolean => { return currencyObject.fraction.indexOf( '00' ) === -1; @@ -25,7 +25,7 @@ const showPriceDecimals = ( currencyObject: CurrencyObject ): boolean => { * The Pricing card component. * * @param {PricingCardProps} props -- The component props. - * @returns {React.ReactNode} The rendered component. + * @return {React.ReactNode} The rendered component. */ const PricingCard: React.FC< PricingCardProps > = ( { currencyCode = 'USD', diff --git a/projects/js-packages/components/components/product-offer/icons-card.tsx b/projects/js-packages/components/components/product-offer/icons-card.tsx index b997b03e2e002..a2e26a824f6ad 100644 --- a/projects/js-packages/components/components/product-offer/icons-card.tsx +++ b/projects/js-packages/components/components/product-offer/icons-card.tsx @@ -8,8 +8,8 @@ import { IconsCardProps } from './types'; * Icons composition for a bundle product, * based on the list of supported products. * - * @param {IconsCardProps} props - Component props. - * @returns {React.ReactNode} Bundle product icons react component. + * @param {IconsCardProps} props - Component props. + * @return {React.ReactNode} Bundle product icons react component. */ export const IconsCard: React.FC< IconsCardProps > = ( { products, icon, size = 24 } ) => { if ( icon ) { diff --git a/projects/js-packages/components/components/product-offer/index.tsx b/projects/js-packages/components/components/product-offer/index.tsx index 8875381796d27..86744cd0ea22d 100644 --- a/projects/js-packages/components/components/product-offer/index.tsx +++ b/projects/js-packages/components/components/product-offer/index.tsx @@ -16,7 +16,7 @@ import type React from 'react'; * Product Detail component. * * @param {ProductOfferProps} props - Component props. - * @returns {React.ReactNode} - ProductOffer react component. + * @return {React.ReactNode} - ProductOffer react component. */ const ProductOffer: React.FC< ProductOfferProps > = ( { addProductUrl, diff --git a/projects/js-packages/components/components/product-offer/product-offer-header.tsx b/projects/js-packages/components/components/product-offer/product-offer-header.tsx index fd8873b2bb454..141e315578de2 100644 --- a/projects/js-packages/components/components/product-offer/product-offer-header.tsx +++ b/projects/js-packages/components/components/product-offer/product-offer-header.tsx @@ -9,7 +9,7 @@ import type React from 'react'; * Product Detail Card Header component. * * @param {ProductOfferHeaderProps} props - Component props. - * @returns {React.ReactNode} ProductOfferHeader react component. + * @return {React.ReactNode} ProductOfferHeader react component. */ export const ProductOfferHeader: React.FC< ProductOfferHeaderProps > = ( { title = __( 'Popular upgrade', 'jetpack' ), diff --git a/projects/js-packages/components/components/product-price/index.tsx b/projects/js-packages/components/components/product-price/index.tsx index 211cc06709a1b..edfbf6a6fa0ff 100644 --- a/projects/js-packages/components/components/product-price/index.tsx +++ b/projects/js-packages/components/components/product-price/index.tsx @@ -16,7 +16,7 @@ import type React from 'react'; * React component to render the price. * * @param {ProductPriceProps} props - Component props. - * @returns {React.ReactNode} Price react component. + * @return {React.ReactNode} Price react component. */ const ProductPrice: React.FC< ProductPriceProps > = ( { price, diff --git a/projects/js-packages/components/components/product-price/price.tsx b/projects/js-packages/components/components/product-price/price.tsx index fcfae78050707..1e70ac8666417 100644 --- a/projects/js-packages/components/components/product-price/price.tsx +++ b/projects/js-packages/components/components/product-price/price.tsx @@ -8,8 +8,8 @@ import type React from 'react'; /** * React component to render a Price composition. * - * @param {PriceProps} props - Component props. - * @returns {React.ReactNode} -Price react component. + * @param {PriceProps} props - Component props. + * @return {React.ReactNode} -Price react component. */ export const Price: React.FC< PriceProps > = ( { value, currency, isOff, hidePriceFraction } ) => { const classNames = clsx( styles.price, 'product-price_price', { diff --git a/projects/js-packages/components/components/progress-bar/index.tsx b/projects/js-packages/components/components/progress-bar/index.tsx index fa530c4103128..879d1c6175de8 100644 --- a/projects/js-packages/components/components/progress-bar/index.tsx +++ b/projects/js-packages/components/components/progress-bar/index.tsx @@ -13,7 +13,7 @@ import type React from 'react'; * Progress Bar component * * @param {ProgressBarProps} props - Component props. - * @returns {React.ReactNode} - ProgressBar react component. + * @return {React.ReactNode} - ProgressBar react component. */ const ProgressBar: React.FC< ProgressBarProps > = ( { className, diff --git a/projects/js-packages/components/components/qr-code/index.tsx b/projects/js-packages/components/components/qr-code/index.tsx index 24f27a78466c2..08ac1263a01eb 100644 --- a/projects/js-packages/components/components/qr-code/index.tsx +++ b/projects/js-packages/components/components/qr-code/index.tsx @@ -49,7 +49,7 @@ export type QRCodeProps = { * Renders a QR Code. * * @param {QRCodeProps} props - Component props - * @returns {React.ReactNode} - React component. + * @return {React.ReactNode} - React component. */ const QRCode: React.FC< QRCodeProps > = ( { value = 'https://jetpack.com', diff --git a/projects/js-packages/components/components/record-meter-bar/index.tsx b/projects/js-packages/components/components/record-meter-bar/index.tsx index 1eb1d8b5771f0..8bf072645a6af 100644 --- a/projects/js-packages/components/components/record-meter-bar/index.tsx +++ b/projects/js-packages/components/components/record-meter-bar/index.tsx @@ -63,7 +63,7 @@ export type RecordMeterBarProps = { * Generate Record Meter bar * * @param {RecordMeterBarProps} props - Props - * @returns {React.ReactElement} - JSX element + * @return {React.ReactElement} - JSX element */ const RecordMeterBar: React.FC< RecordMeterBarProps > = ( { totalCount, diff --git a/projects/js-packages/components/components/stat-card/index.tsx b/projects/js-packages/components/components/stat-card/index.tsx index 93db43246d695..b6854dc02f37e 100644 --- a/projects/js-packages/components/components/stat-card/index.tsx +++ b/projects/js-packages/components/components/stat-card/index.tsx @@ -16,7 +16,7 @@ import type React from 'react'; * StatCard component * * @param {StatCardProps} props - Component props. - * @returns {React.ReactNode} - StatCard react component. + * @return {React.ReactNode} - StatCard react component. */ const StatCard = ( { className, icon, label, value, variant = 'square' }: StatCardProps ) => { const formattedValue = numberFormat( value ); diff --git a/projects/js-packages/components/components/text/index.tsx b/projects/js-packages/components/components/text/index.tsx index 0ff935397873b..139bc422f5a9f 100644 --- a/projects/js-packages/components/components/text/index.tsx +++ b/projects/js-packages/components/components/text/index.tsx @@ -8,7 +8,7 @@ import type { H3Props, TextProps, TitleProps } from './types'; * Text component. * * @param {TextProps} props - Component props. - * @returns {React.ReactElement} - JSX.Element + * @return {React.ReactElement} - JSX.Element */ const Text = forwardRef< HTMLElement, TextProps >( ( { variant = 'body', children, component, className, ...componentProps }, ref ) => { @@ -45,8 +45,8 @@ export default Text; /** * Heading component - Medium size. * - * @param {TextProps} props - Component props. - * @returns {React.ReactElement} - JSX.Element + * @param {TextProps} props - Component props. + * @return {React.ReactElement} - JSX.Element */ export const H2: React.FC< TextProps > = ( { children, ...componentProps } ) => ( @@ -57,8 +57,8 @@ export const H2: React.FC< TextProps > = ( { children, ...componentProps } ) => /** * Heading component - Small size, * - * @param {H3Props} props - Component props. - * @returns {React.ReactElement} - JSX.Element + * @param {H3Props} props - Component props. + * @return {React.ReactElement} - JSX.Element */ export const H3: React.FC< H3Props > = ( { children, weight = 'bold', ...componentProps } ) => { const variant = `headline-small${ @@ -75,8 +75,8 @@ export const H3: React.FC< H3Props > = ( { children, weight = 'bold', ...compone /** * Title component, based on Text component. * - * @param {TitleProps} props - Component props. - * @returns {React.ReactElement} - JSX.Element + * @param {TitleProps} props - Component props. + * @return {React.ReactElement} - JSX.Element */ export const Title: React.FC< TitleProps > = ( { children, diff --git a/projects/js-packages/components/components/text/stories/headings.index.stories.tsx b/projects/js-packages/components/components/text/stories/headings.index.stories.tsx index ad1998f24958e..362c6a6afdeaf 100644 --- a/projects/js-packages/components/components/text/stories/headings.index.stories.tsx +++ b/projects/js-packages/components/components/text/stories/headings.index.stories.tsx @@ -22,9 +22,9 @@ export default { /** * Helper component to create a the story. * - * @param {object} props - Component props. + * @param {object} props - Component props. * @param {React.Component} props.children - Icon component children. - * @returns {React.Component} Text component instance. + * @return {React.Component} Text component instance. */ function Instance( { children } ) { return ( diff --git a/projects/js-packages/components/components/theme-provider/index.tsx b/projects/js-packages/components/components/theme-provider/index.tsx index 8da3e546b4603..109c74b597423 100644 --- a/projects/js-packages/components/components/theme-provider/index.tsx +++ b/projects/js-packages/components/components/theme-provider/index.tsx @@ -111,8 +111,8 @@ const setup = ( root: HTMLElement, id: string, withGlobalStyles?: boolean ) => { /** * ThemeProvider React component. * - * @param {ThemeProviderProps} props - Component properties. - * @returns {React.ReactNode} ThemeProvider component. + * @param {ThemeProviderProps} props - Component properties. + * @return {React.ReactNode} ThemeProvider component. */ const ThemeProvider: React.FC< ThemeProviderProps > = ( { children = null, diff --git a/projects/js-packages/components/components/theme-provider/stories/index.stories.tsx b/projects/js-packages/components/components/theme-provider/stories/index.stories.tsx index 42c37f49bb076..c64d593de0f5d 100644 --- a/projects/js-packages/components/components/theme-provider/stories/index.stories.tsx +++ b/projects/js-packages/components/components/theme-provider/stories/index.stories.tsx @@ -11,8 +11,8 @@ import type { StoryFn, Meta } from '@storybook/react'; * (c) 2019 Chris Ferdinandi, MIT License, https://gomakethings.com * Derived from work by Brian Suda, https://24ways.org/2010/calculating-color-contrast/ * - * @param {string} hexcolor - hexcolor value - * @returns {string} The contrasting color (black or white) + * @param {string} hexcolor - hexcolor value + * @return {string} The contrasting color (black or white) */ function getContrast( hexcolor ) { // If a leading # is provided, remove it @@ -115,7 +115,7 @@ export const Typographies = args => ( ); Typographies.args = { - [ 'Text Instance' ]: '', + 'Text Instance': '', }; Typographies.parameters = { docs: { source: { code: null } }, diff --git a/projects/js-packages/components/components/upsell-banner/index.tsx b/projects/js-packages/components/components/upsell-banner/index.tsx index d81f095a27a64..ed57683e62d51 100644 --- a/projects/js-packages/components/components/upsell-banner/index.tsx +++ b/projects/js-packages/components/components/upsell-banner/index.tsx @@ -13,7 +13,7 @@ import './style.scss'; * - The secondary CTA is the first button, at the left position. * * @param {UpsellBannerProps} props - Component props. - * @returns {React.ReactNode} - UpsellBanner component. + * @return {React.ReactNode} - UpsellBanner component. */ const UpsellBanner: React.FC< UpsellBannerProps > = props => { const { diff --git a/projects/js-packages/components/lib/locale/index.ts b/projects/js-packages/components/lib/locale/index.ts index 5aa4252885817..7afd53da19bd8 100644 --- a/projects/js-packages/components/lib/locale/index.ts +++ b/projects/js-packages/components/lib/locale/index.ts @@ -4,7 +4,7 @@ import { getSettings } from '@wordpress/date'; * Clean up WP locale so it matches the format expected by browsers. * * @param {string} locale - Locale given by WordPress. - * @returns {string} Browser-formatted locale. + * @return {string} Browser-formatted locale. */ export const cleanLocale = ( locale: string ) => { const regex = /^([a-z]{2,3})(_[a-z]{2}|_[a-z][a-z0-9]{4,7})?(?:_.*)?$/i; @@ -30,7 +30,7 @@ declare const global: typeof globalThis; /** * Current user locale, or browser locale as fallback. * - * @returns {string} Formatted user locale (e.g. `en-US` or `fr-FR`). + * @return {string} Formatted user locale (e.g. `en-US` or `fr-FR`). */ export const getUserLocale = () => { const { diff --git a/projects/js-packages/components/package.json b/projects/js-packages/components/package.json index 78b7ea6249b80..c5b00d1f3d21b 100644 --- a/projects/js-packages/components/package.json +++ b/projects/js-packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/jetpack-components", - "version": "0.55.8-alpha", + "version": "0.55.11", "description": "Jetpack Components Package", "author": "Automattic", "license": "GPL-2.0-or-later", @@ -60,7 +60,7 @@ "storybook": "8.2.9", "ts-dedent": "2.2.0", "typescript": "5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "peerDependencies": { diff --git a/projects/js-packages/components/tools/get-product-checkout-url/index.ts b/projects/js-packages/components/tools/get-product-checkout-url/index.ts index bb124fcd4c6ae..b6ae1e6f0c645 100644 --- a/projects/js-packages/components/tools/get-product-checkout-url/index.ts +++ b/projects/js-packages/components/tools/get-product-checkout-url/index.ts @@ -1,11 +1,11 @@ /** * Return the checkout URL for the given product. * - * @param {string} productSlug - wpcom product slug. - * @param {string} siteSuffix - Site suffix - * @param {string} redirectUrl - Redirect URL used to define redirect_to + * @param {string} productSlug - wpcom product slug. + * @param {string} siteSuffix - Site suffix + * @param {string} redirectUrl - Redirect URL used to define redirect_to * @param {boolean} isUserConnected - True when the user is connected Jetpack - * @returns {string} The Calypso checkout URL + * @return {string} The Calypso checkout URL */ export default function getProductCheckoutUrl( productSlug: string, diff --git a/projects/js-packages/components/tools/get-site-admin-url/index.ts b/projects/js-packages/components/tools/get-site-admin-url/index.ts index 9a7079805ecfe..5c64a95d84f51 100644 --- a/projects/js-packages/components/tools/get-site-admin-url/index.ts +++ b/projects/js-packages/components/tools/get-site-admin-url/index.ts @@ -1,7 +1,7 @@ /** * Returns the site admin URL. * - * @returns {?string} The site admin URL or null if not available. + * @return {?string} The site admin URL or null if not available. */ export default function getSiteAdminUrl() { return ( diff --git a/projects/js-packages/components/tools/jp-redirect/index.ts b/projects/js-packages/components/tools/jp-redirect/index.ts index 3f13f524d776b..0058c14d218b2 100644 --- a/projects/js-packages/components/tools/jp-redirect/index.ts +++ b/projects/js-packages/components/tools/jp-redirect/index.ts @@ -12,13 +12,13 @@ import { GetRedirectUrlArgs, QueryVars } from './types'; * Note: if using full URL, query parameters and anchor must be passed in args. Any querystring of url fragment in the URL will be discarded. * * @since 0.2.0 - * @param {string} source - The URL handler registered in the server or the full destination URL (starting with https://). - * @param {GetRedirectUrlArgs} args - Additional arguments to build the url. - * This is not a complete list as any argument passed here - * will be sent to as a query parameter to the Redirect server. - * These parameters will not necessarily be passed over to the final destination URL. - * If you want to add a parameter to the final destination URL, use the `query` argument. - * @returns {string} The redirect URL + * @param {string} source - The URL handler registered in the server or the full destination URL (starting with https://). + * @param {GetRedirectUrlArgs} args - Additional arguments to build the url. + * This is not a complete list as any argument passed here + * will be sent to as a query parameter to the Redirect server. + * These parameters will not necessarily be passed over to the final destination URL. + * If you want to add a parameter to the final destination URL, use the `query` argument. + * @return {string} The redirect URL */ export default function getRedirectUrl( source: string, args: GetRedirectUrlArgs = {} ) { const queryVars: QueryVars = {}; @@ -45,7 +45,7 @@ export default function getRedirectUrl( source: string, args: GetRedirectUrlArgs if ( ! Object.keys( queryVars ).includes( 'site' ) && typeof jetpack_redirects !== 'undefined' && - jetpack_redirects.hasOwnProperty( 'currentSiteRawUrl' ) + Object.hasOwn( jetpack_redirects, 'currentSiteRawUrl' ) ) { queryVars.site = jetpack_redirects.currentBlogID ?? jetpack_redirects.currentSiteRawUrl; } diff --git a/projects/js-packages/components/tools/pricing-utils/index.ts b/projects/js-packages/components/tools/pricing-utils/index.ts index e5424468d872e..7802a679686d1 100644 --- a/projects/js-packages/components/tools/pricing-utils/index.ts +++ b/projects/js-packages/components/tools/pricing-utils/index.ts @@ -4,7 +4,7 @@ import { IntroOffer } from './types'; * Returns whether an Introductory Offer is a first month trial * * @param {IntroOffer} introOffer - an intro offer object - * @returns {boolean} Whether it's a first month trial or not + * @return {boolean} Whether it's a first month trial or not */ export function isFirstMonthTrial( introOffer: IntroOffer ): boolean { return introOffer?.interval_count === 1 && introOffer?.interval_unit === 'month'; diff --git a/projects/js-packages/config/CHANGELOG.md b/projects/js-packages/config/CHANGELOG.md index 375e8665338e5..7b9294c9fc851 100644 --- a/projects/js-packages/config/CHANGELOG.md +++ b/projects/js-packages/config/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.25] - 2024-08-29 +### Changed +- Internal updates. + ## [0.1.24] - 2023-12-03 ### Changed - Updated package dependencies. [#34427] @@ -100,6 +104,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - fixed and improved README +[0.1.25]: https://github.com/Automattic/jetpack-config-js/compare/v0.1.24...v0.1.25 [0.1.24]: https://github.com/Automattic/jetpack-config-js/compare/v0.1.23...v0.1.24 [0.1.23]: https://github.com/Automattic/jetpack-config-js/compare/v0.1.22...v0.1.23 [0.1.22]: https://github.com/Automattic/jetpack-config-js/compare/v0.1.21...v0.1.22 diff --git a/projects/js-packages/config/package.json b/projects/js-packages/config/package.json index 8df5bee780985..2f89385ef4536 100644 --- a/projects/js-packages/config/package.json +++ b/projects/js-packages/config/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/jetpack-config", - "version": "0.1.24", + "version": "0.1.25", "description": "Handles Jetpack global configuration shared across all packages", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/config/#readme", "bugs": { diff --git a/projects/js-packages/config/src/index.js b/projects/js-packages/config/src/index.js index 44a326a2edcc6..e7fd2d8b03b61 100644 --- a/projects/js-packages/config/src/index.js +++ b/projects/js-packages/config/src/index.js @@ -12,7 +12,7 @@ try { } const jetpackConfigHas = key => { - return jetpackConfig.hasOwnProperty( key ); + return Object.hasOwn( jetpackConfig, key ); }; const jetpackConfigGet = key => { diff --git a/projects/js-packages/connection/CHANGELOG.md b/projects/js-packages/connection/CHANGELOG.md index 5085ee8ac70f7..2a2f2c0f73401 100644 --- a/projects/js-packages/connection/CHANGELOG.md +++ b/projects/js-packages/connection/CHANGELOG.md @@ -2,6 +2,17 @@ ### This is a list detailing changes for the Jetpack RNA Connection Component releases. +## [0.35.3] - 2024-08-21 +### Changed +- Internal updates. + +## [0.35.2] - 2024-08-19 +### Changed +- Updated package dependencies. [#38893] + +### Fixed +- Lossless image optimization for images (should improve performance with no visible changes). [#38750] + ## [0.35.1] - 2024-08-15 ### Changed - Updated package dependencies. [#38665] @@ -820,6 +831,8 @@ - `Main` and `ConnectUser` components added. - `JetpackRestApiClient` API client added. +[0.35.3]: https://github.com/Automattic/jetpack-connection-js/compare/v0.35.2...v0.35.3 +[0.35.2]: https://github.com/Automattic/jetpack-connection-js/compare/v0.35.1...v0.35.2 [0.35.1]: https://github.com/Automattic/jetpack-connection-js/compare/v0.35.0...v0.35.1 [0.35.0]: https://github.com/Automattic/jetpack-connection-js/compare/v0.34.2...v0.35.0 [0.34.2]: https://github.com/Automattic/jetpack-connection-js/compare/v0.34.1...v0.34.2 diff --git a/projects/js-packages/connection/components/connect-button/index.jsx b/projects/js-packages/connection/components/connect-button/index.jsx index d9744f72abdec..0529e4ae1e189 100644 --- a/projects/js-packages/connection/components/connect-button/index.jsx +++ b/projects/js-packages/connection/components/connect-button/index.jsx @@ -8,7 +8,7 @@ import useConnection from '../use-connection'; * The RNA connection component. * * @param {object} props -- The properties. - * @returns {React.Component} The RNA connection component. + * @return {React.Component} The RNA connection component. */ const ConnectButton = props => { const { diff --git a/projects/js-packages/connection/components/connect-screen/required-plan/index.jsx b/projects/js-packages/connection/components/connect-screen/required-plan/index.jsx index d25f8c46c45d3..f6a20a8cb7baa 100644 --- a/projects/js-packages/connection/components/connect-screen/required-plan/index.jsx +++ b/projects/js-packages/connection/components/connect-screen/required-plan/index.jsx @@ -9,7 +9,7 @@ import ConnectScreenRequiredPlanVisual from './visual'; * The Connection Screen Visual component for consumers that require a Plan. * * @param {object} props -- The properties. - * @returns {React.Component} The `ConnectScreenForRequiredPlan` component. + * @return {React.Component} The `ConnectScreenForRequiredPlan` component. */ const ConnectScreenRequiredPlan = props => { const { diff --git a/projects/js-packages/connection/components/connect-screen/required-plan/visual.jsx b/projects/js-packages/connection/components/connect-screen/required-plan/visual.jsx index 571014204f6c6..5d300d879612d 100644 --- a/projects/js-packages/connection/components/connect-screen/required-plan/visual.jsx +++ b/projects/js-packages/connection/components/connect-screen/required-plan/visual.jsx @@ -19,7 +19,7 @@ const debug = debugFactory( 'jetpack:connection:ConnectScreenRequiredPlanVisual' * The Connection Screen Visual component for consumers that require a Plan. * * @param {object} props -- The properties. - * @returns {React.Component} The `ConnectScreenRequiredPlanVisual` component. + * @return {React.Component} The `ConnectScreenRequiredPlanVisual` component. */ const ConnectScreenRequiredPlanVisual = props => { const { diff --git a/projects/js-packages/connection/components/connect-user/index.jsx b/projects/js-packages/connection/components/connect-user/index.jsx index 72062b0ac465a..f1c84d3d5558a 100644 --- a/projects/js-packages/connection/components/connect-user/index.jsx +++ b/projects/js-packages/connection/components/connect-user/index.jsx @@ -5,12 +5,12 @@ import { useState, useEffect } from 'react'; /** * The user connection component. * - * @param {object} props -- The properties. + * @param {object} props -- The properties. * @param {Function} props.redirectFunc -- The redirect function (`window.location.assign()` by default). - * @param {string} props.connectUrl -- The authorization URL (no-iframe). - * @param {string} props.redirectUri -- The redirect admin URI. - * @param {string} props.from -- Where the connection request is coming from. - * @returns {null} -- Nothing to return. + * @param {string} props.connectUrl -- The authorization URL (no-iframe). + * @param {string} props.redirectUri -- The redirect admin URI. + * @param {string} props.from -- Where the connection request is coming from. + * @return {null} -- Nothing to return. */ const ConnectUser = props => { const { diff --git a/projects/js-packages/connection/components/connected-plugins/index.jsx b/projects/js-packages/connection/components/connected-plugins/index.jsx index 043f1910387ca..cee45bf838644 100644 --- a/projects/js-packages/connection/components/connected-plugins/index.jsx +++ b/projects/js-packages/connection/components/connected-plugins/index.jsx @@ -7,7 +7,7 @@ import DisconnectCard from '../disconnect-card'; * Render a list of connected plugins. * * @param {object} props - The properties - * @returns {React.Component} - The ConnectedPlugins React component + * @return {React.Component} - The ConnectedPlugins React component */ const ConnectedPlugins = props => { diff --git a/projects/js-packages/connection/components/connection-error-notice/index.jsx b/projects/js-packages/connection/components/connection-error-notice/index.jsx index 5e3acc883d1d8..5ad05369eb6cf 100644 --- a/projects/js-packages/connection/components/connection-error-notice/index.jsx +++ b/projects/js-packages/connection/components/connection-error-notice/index.jsx @@ -9,7 +9,7 @@ import styles from './styles.module.scss'; * The RNA Connection Error Notice component. * * @param {object} props -- The properties. - * @returns {React.Component} The `ConnectionErrorNotice` component. + * @return {React.Component} The `ConnectionErrorNotice` component. */ const ConnectionErrorNotice = props => { const { message, isRestoringConnection, restoreConnectionCallback, restoreConnectionError } = diff --git a/projects/js-packages/connection/components/disconnect-card/index.jsx b/projects/js-packages/connection/components/disconnect-card/index.jsx index 8ceedd6f1dcf8..580462b3f937e 100644 --- a/projects/js-packages/connection/components/disconnect-card/index.jsx +++ b/projects/js-packages/connection/components/disconnect-card/index.jsx @@ -8,7 +8,7 @@ import './style.scss'; * Used in the disconnection flow. * * @param {object} props - The Properties. - * @returns {React.Component} DisconnectCard - The disconnect card component. + * @return {React.Component} DisconnectCard - The disconnect card component. */ const DisconnectCard = props => { const { title, value, description } = props; diff --git a/projects/js-packages/connection/components/disconnect-dialog/index.jsx b/projects/js-packages/connection/components/disconnect-dialog/index.jsx index 61e2f4901a122..80f7656ef4f38 100644 --- a/projects/js-packages/connection/components/disconnect-dialog/index.jsx +++ b/projects/js-packages/connection/components/disconnect-dialog/index.jsx @@ -15,7 +15,7 @@ import StepThankYou from './steps/step-thank-you'; * The RNA Disconnect Dialog component. * * @param {object} props -- The properties. - * @returns {React.Component} The `DisconnectDialog` component. + * @return {React.Component} The `DisconnectDialog` component. */ const DisconnectDialog = props => { const [ isDisconnecting, setIsDisconnecting ] = useState( false ); @@ -302,7 +302,7 @@ const DisconnectDialog = props => { /** * Determine what step to show based on the current state * - * @returns { React.Component|undefined } - component for current step + * @return { React.Component|undefined } - component for current step */ const getCurrentStep = () => { if ( ! isDisconnected ) { diff --git a/projects/js-packages/connection/components/disconnect-dialog/steps/step-disconnect-confirm.jsx b/projects/js-packages/connection/components/disconnect-dialog/steps/step-disconnect-confirm.jsx index 1e89a88185f3b..6acda014f9fb1 100644 --- a/projects/js-packages/connection/components/disconnect-dialog/steps/step-disconnect-confirm.jsx +++ b/projects/js-packages/connection/components/disconnect-dialog/steps/step-disconnect-confirm.jsx @@ -11,7 +11,7 @@ import disconnectImage from '../images/disconnect-confirm.jpg'; * Will only show option to provide feedback if the canProvideFeedback prop is true. * * @param {object} props - The properties. - * @returns {React.Component} - StepDisconnectConfirm Component + * @return {React.Component} - StepDisconnectConfirm Component */ const StepDisconnectConfirm = props => { const { onExit, canProvideFeedback, onProvideFeedback } = props; diff --git a/projects/js-packages/connection/components/disconnect-dialog/steps/step-disconnect.jsx b/projects/js-packages/connection/components/disconnect-dialog/steps/step-disconnect.jsx index 4bbbe95017b65..03f91f659a808 100644 --- a/projects/js-packages/connection/components/disconnect-dialog/steps/step-disconnect.jsx +++ b/projects/js-packages/connection/components/disconnect-dialog/steps/step-disconnect.jsx @@ -10,7 +10,7 @@ import ConnectedPlugins from '../../connected-plugins'; * Disconnect step in disconnection flow. * * @param {object} props - The properties. - * @returns {React.Component} - The StepDisconnect component + * @return {React.Component} - The StepDisconnect component */ const StepDisconnect = props => { const { @@ -66,7 +66,7 @@ const StepDisconnect = props => { /** * Render the disconnect button, allows for some variance based on context. * - * @returns {React.Component} - Button used for disconnect. + * @return {React.Component} - Button used for disconnect. */ const renderDisconnectButton = () => { let buttonText = __( 'Disconnect', 'jetpack' ); @@ -93,7 +93,7 @@ const StepDisconnect = props => { * Show some fallback output if there are no connected plugins to show and no passed disconnect component. * This is a more generic message about disconnecting Jetpack. * - * @returns {React.ElementType|undefined} - Fallback message for when there are no connected plugins or passed components to show. + * @return {React.ElementType|undefined} - Fallback message for when there are no connected plugins or passed components to show. */ const renderFallbackOutput = () => { const hasOtherConnectedPlugins = diff --git a/projects/js-packages/connection/components/disconnect-dialog/steps/step-survey.jsx b/projects/js-packages/connection/components/disconnect-dialog/steps/step-survey.jsx index 4c88f86e600a0..61a7f26342c3e 100644 --- a/projects/js-packages/connection/components/disconnect-dialog/steps/step-survey.jsx +++ b/projects/js-packages/connection/components/disconnect-dialog/steps/step-survey.jsx @@ -10,7 +10,7 @@ import DisconnectSurvey from '../../disconnect-survey'; * Show the survey step and allow the user to select a response. * * @param {object} props - The properties. - * @returns {React.Component} The StepSurvey Component + * @return {React.Component} The StepSurvey Component */ const StepSurvey = props => { const { onExit, onFeedBackProvided, isSubmittingFeedback } = props; diff --git a/projects/js-packages/connection/components/disconnect-dialog/steps/step-thank-you.jsx b/projects/js-packages/connection/components/disconnect-dialog/steps/step-thank-you.jsx index 229342c9d1b21..33a90c58067e3 100644 --- a/projects/js-packages/connection/components/disconnect-dialog/steps/step-thank-you.jsx +++ b/projects/js-packages/connection/components/disconnect-dialog/steps/step-thank-you.jsx @@ -10,7 +10,7 @@ import disconnectImage from '../images/disconnect-thanks.jpg'; * Show the "thank you" step following survey submission * * @param {object} props - The properties. - * @returns {React.Component} - The StepThankYou Component + * @return {React.Component} - The StepThankYou Component */ const StepThankYou = props => { const { onExit } = props; diff --git a/projects/js-packages/connection/components/disconnect-survey/index.jsx b/projects/js-packages/connection/components/disconnect-survey/index.jsx index 413bf117555d0..be1f25faea11e 100644 --- a/projects/js-packages/connection/components/disconnect-survey/index.jsx +++ b/projects/js-packages/connection/components/disconnect-survey/index.jsx @@ -8,7 +8,7 @@ import SurveyChoice from './survey-choice'; * Handles showing the disconnect survey. * * @param {object} props - The component props. - * @returns {React.Component} - DisconnectSurvey component. + * @return {React.Component} - DisconnectSurvey component. */ const DisconnectSurvey = props => { const { onSubmit, isSubmittingFeedback } = props; @@ -68,8 +68,8 @@ const DisconnectSurvey = props => { /** * Checks to see if an option is the currently selected option, returns a css class name if it matches. * - * @param {string} optionId - ID of the option to check for. - * @returns {string} - The "selected" class if this option is currently selected. + * @param {string} optionId - ID of the option to check for. + * @return {string} - The "selected" class if this option is currently selected. */ const selectedClass = optionId => { if ( optionId === selectedAnswer ) { @@ -83,7 +83,7 @@ const DisconnectSurvey = props => { * Event handler for keyboard events on the answer blocks. * * @param {string} answerId - The slug of the answer that has been selected. - * @param {object} e - Keydown event. + * @param {object} e - Keydown event. */ const handleAnswerKeyDown = useCallback( ( answerId, e ) => { @@ -102,7 +102,7 @@ const DisconnectSurvey = props => { /** * Show all the survey options from the options array. * - * @returns {React.ElementType []} - Mapped array of rendered survey options. + * @return {React.ElementType []} - Mapped array of rendered survey options. */ const renderOptions = () => { return options.map( option => { @@ -123,7 +123,7 @@ const DisconnectSurvey = props => { * Show the custom input survey option. * Contains an input field for a custom response. * - * @returns {React.ElementType} - The custom survey option with an input field. + * @return {React.ElementType} - The custom survey option with an input field. */ const renderCustomOption = () => { return ( diff --git a/projects/js-packages/connection/components/disconnect-survey/survey-choice.jsx b/projects/js-packages/connection/components/disconnect-survey/survey-choice.jsx index 21ed1430d7ec4..1a4d3cf801074 100644 --- a/projects/js-packages/connection/components/disconnect-survey/survey-choice.jsx +++ b/projects/js-packages/connection/components/disconnect-survey/survey-choice.jsx @@ -5,12 +5,12 @@ import './_jp-connect_disconnect-survey-card.scss'; /** * SurveyChoice - Present one choice in the survey. * - * @param {string} props.id - The ID/slug string of the survey option - * @param {Function} props.onClick - Event handler for clicking on the survey option. - * @param {Function} props.onKeydown - Event handler for pressing a key on the survey option. - * @param {React.ElementType} props.children - Any passed elements as children to this component. - * @param {string} props.className - A class name to apply to the survey choice. - * @returns {React.Component} SurveyChoice - The SurveyChoice component. + * @param {string} props.id - The ID/slug string of the survey option + * @param {Function} props.onClick - Event handler for clicking on the survey option. + * @param {Function} props.onKeydown - Event handler for pressing a key on the survey option. + * @param {React.ElementType} props.children - Any passed elements as children to this component. + * @param {string} props.className - A class name to apply to the survey choice. + * @return {React.Component} SurveyChoice - The SurveyChoice component. */ const SurveyChoice = props => { diff --git a/projects/js-packages/connection/components/in-place-connection/index.jsx b/projects/js-packages/connection/components/in-place-connection/index.jsx index 158ce822f0758..b57ae6cfa778c 100644 --- a/projects/js-packages/connection/components/in-place-connection/index.jsx +++ b/projects/js-packages/connection/components/in-place-connection/index.jsx @@ -7,18 +7,18 @@ import './style.scss'; /** * The in-place connection component. * - * @param {object} props -- The properties. - * @param {string} props.title -- Element title. - * @param {boolean} props.isLoading -- Whether the element is still loading. - * @param {string|number} props.width -- Iframe width. - * @param {string|number} props.height -- Iframe height. - * @param {boolean} props.displayTOS -- Whether the site has connection owner connected. - * @param {boolean} props.scrollToIframe -- Whether we need to auto-scroll the window upon element rendering. - * @param {string} props.connectUrl -- The connection URL. - * @param {Function} props.onComplete -- The callback to be called upon complete of the connection process. - * @param {Function} props.onThirdPartyCookiesBlocked -- The callback to be called if third-party cookies are disabled. - * @param {string} props.location -- Component location identifier passed to WP.com. - * @returns {React.Component} The in-place connection component. + * @param {object} props -- The properties. + * @param {string} props.title -- Element title. + * @param {boolean} props.isLoading -- Whether the element is still loading. + * @param {string|number} props.width -- Iframe width. + * @param {string|number} props.height -- Iframe height. + * @param {boolean} props.displayTOS -- Whether the site has connection owner connected. + * @param {boolean} props.scrollToIframe -- Whether we need to auto-scroll the window upon element rendering. + * @param {string} props.connectUrl -- The connection URL. + * @param {Function} props.onComplete -- The callback to be called upon complete of the connection process. + * @param {Function} props.onThirdPartyCookiesBlocked -- The callback to be called if third-party cookies are disabled. + * @param {string} props.location -- Component location identifier passed to WP.com. + * @return {React.Component} The in-place connection component. */ const InPlaceConnection = props => { const { diff --git a/projects/js-packages/connection/components/manage-connection-dialog/index.jsx b/projects/js-packages/connection/components/manage-connection-dialog/index.jsx index 87470fc22961f..a24771d625017 100644 --- a/projects/js-packages/connection/components/manage-connection-dialog/index.jsx +++ b/projects/js-packages/connection/components/manage-connection-dialog/index.jsx @@ -19,7 +19,7 @@ import './style.scss'; * The RNA Manage Connection Dialog component. * * @param {object} props -- The properties. - * @returns {React.JSX} The `ManageConnectionDialog` component. + * @return {React.JSX} The `ManageConnectionDialog` component. */ const ManageConnectionDialog = props => { const { diff --git a/projects/js-packages/connection/components/use-connection/index.jsx b/projects/js-packages/connection/components/use-connection/index.jsx index e18e713db1452..d77757bb3c057 100644 --- a/projects/js-packages/connection/components/use-connection/index.jsx +++ b/projects/js-packages/connection/components/use-connection/index.jsx @@ -41,7 +41,7 @@ export default ( { /** * User register process handler. * - * @returns {Promise} - Promise which resolves when the product status is activated. + * @return {Promise} - Promise which resolves when the product status is activated. */ const handleConnectUser = () => { if ( ! skipUserConnection ) { @@ -64,7 +64,7 @@ export default ( { * the site was successfully registered. * * @param {Event} [e] - Event that dispatched handleRegisterSite - * @returns {Promise} Promise when running the registration process. Otherwise, nothing. + * @return {Promise} Promise when running the registration process. Otherwise, nothing. */ const handleRegisterSite = e => { e && e.preventDefault(); diff --git a/projects/js-packages/connection/helpers/get-calypso-origin.ts b/projects/js-packages/connection/helpers/get-calypso-origin.ts index 84171a1c0ed1a..3946bc4c3f509 100644 --- a/projects/js-packages/connection/helpers/get-calypso-origin.ts +++ b/projects/js-packages/connection/helpers/get-calypso-origin.ts @@ -3,7 +3,7 @@ import { getScriptData } from '@automattic/jetpack-script-data'; /** * Get the Calypso origin based on the development environment. * - * @returns {string} The Calypso url origin. + * @return {string} The Calypso url origin. */ export default function getCalypsoOrigin() { const calypsoEnv = ( diff --git a/projects/js-packages/connection/hooks/use-connection-error-notice/index.jsx b/projects/js-packages/connection/hooks/use-connection-error-notice/index.jsx index 5f85997cef8fd..82b78fe298926 100644 --- a/projects/js-packages/connection/hooks/use-connection-error-notice/index.jsx +++ b/projects/js-packages/connection/hooks/use-connection-error-notice/index.jsx @@ -7,7 +7,7 @@ import useRestoreConnection from '../../hooks/use-restore-connection/index.jsx'; * Returns a ConnectionErrorNotice component and the conditional flag on whether * to render the component or not. * - * @returns {object} - The hook data. + * @return {object} - The hook data. */ export default function useConnectionErrorNotice() { const { connectionErrors } = useConnection( {} ); diff --git a/projects/js-packages/connection/hooks/use-product-checkout-workflow/index.jsx b/projects/js-packages/connection/hooks/use-product-checkout-workflow/index.jsx index 87bb103c68c88..1462a9d9584d2 100644 --- a/projects/js-packages/connection/hooks/use-product-checkout-workflow/index.jsx +++ b/projects/js-packages/connection/hooks/use-product-checkout-workflow/index.jsx @@ -22,17 +22,17 @@ const defaultAdminUrl = * Custom hook that performs the needed steps * to concrete the checkout workflow. * - * @param {object} props - The props passed to the hook. - * @param {string} props.productSlug - The WordPress product slug. - * @param {string} props.redirectUrl - The URI to redirect to after checkout. - * @param {string} [props.siteSuffix] - The site suffix. - * @param {string} [props.adminUrl] - The site wp-admin url. - * @param {boolean} props.connectAfterCheckout - Whether or not to conect after checkout if not connected (default false - connect before). + * @param {object} props - The props passed to the hook. + * @param {string} props.productSlug - The WordPress product slug. + * @param {string} props.redirectUrl - The URI to redirect to after checkout. + * @param {string} [props.siteSuffix] - The site suffix. + * @param {string} [props.adminUrl] - The site wp-admin url. + * @param {boolean} props.connectAfterCheckout - Whether or not to conect after checkout if not connected (default false - connect before). * @param {Function} props.siteProductAvailabilityHandler - The function used to check whether the site already has the requested product. This will be checked after registration and the checkout page will be skipped if the promise returned resloves true. * @param {Function} props.from - The plugin slug initiated the flow. - * @param {number} [props.quantity] - The quantity of the product to purchase. - * @param {boolean} [props.useBlogIdSuffix] - Use blog ID instead of site suffix in the checkout URL. - * @returns {Function} The useEffect hook. + * @param {number} [props.quantity] - The quantity of the product to purchase. + * @param {boolean} [props.useBlogIdSuffix] - Use blog ID instead of site suffix in the checkout URL. + * @return {Function} The useEffect hook. */ export default function useProductCheckoutWorkflow( { productSlug, @@ -152,9 +152,9 @@ export default function useProductCheckoutWorkflow( { /** * Handler to run the checkout workflow. * - * @param {Event} [event] - Event that dispatched run + * @param {Event} [event] - Event that dispatched run * @param {string} redirect - A possible redirect URL to go to after the checkout - * @returns {void} Nothing. + * @return {void} Nothing. */ const run = ( event, redirect = null ) => { event && event.preventDefault(); diff --git a/projects/js-packages/connection/hooks/use-restore-connection/index.jsx b/projects/js-packages/connection/hooks/use-restore-connection/index.jsx index f43048a5bdd58..dac3fd2be2920 100644 --- a/projects/js-packages/connection/hooks/use-restore-connection/index.jsx +++ b/projects/js-packages/connection/hooks/use-restore-connection/index.jsx @@ -11,7 +11,7 @@ const { apiRoot, apiNonce } = * Restore connection hook. * It will initiate an API request attempting to restore the connection, or reconnect if it cannot be restored. * - * @returns {object} - The hook data. + * @return {object} - The hook data. */ export default function useRestoreConnection() { const [ isRestoringConnection, setIsRestoringConnection ] = useState( false ); @@ -25,7 +25,7 @@ export default function useRestoreConnection() { * Initiate connection restore. * * @param {boolean} autoReconnectUser - If user connection needs to be reestablished, automatically initiate the flow. - * @returns {Promise} - The API request promise. + * @return {Promise} - The API request promise. */ const restoreConnection = ( autoReconnectUser = true ) => { setIsRestoringConnection( true ); diff --git a/projects/js-packages/connection/package.json b/projects/js-packages/connection/package.json index 37db15ad77281..199057e0bef15 100644 --- a/projects/js-packages/connection/package.json +++ b/projects/js-packages/connection/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/jetpack-connection", - "version": "0.35.2-alpha", + "version": "0.35.3", "description": "Jetpack Connection Component", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/connection/#readme", "bugs": { diff --git a/projects/js-packages/connection/state/actions.jsx b/projects/js-packages/connection/state/actions.jsx index 40f0c7a87d093..4286a4b7642b9 100644 --- a/projects/js-packages/connection/state/actions.jsx +++ b/projects/js-packages/connection/state/actions.jsx @@ -72,11 +72,11 @@ const setIsOfflineMode = isOfflineMode => { /** * Connect site with wp.com user * - * @param {object} Object - contains from and redirectFunc - * @param {string} Object.from - Value that represents the redirect origin - * @param {Function} Object.redirectFunc - A function to handle the redirect, defaults to location.assign - * @param {string} [Object.redirectUri] - A URI that the user will be redirected to - * @yields {object} Action object that will be yielded + * @param {object} Object - contains from and redirectFunc + * @param {string} Object.from - Value that represents the redirect origin + * @param {Function} Object.redirectFunc - A function to handle the redirect, defaults to location.assign + * @param {string} [Object.redirectUri] - A URI that the user will be redirected to + * @yield {object} Action object that will be yielded */ function* connectUser( { from, redirectFunc, redirectUri } = {} ) { yield setUserIsConnecting( true ); @@ -87,12 +87,12 @@ function* connectUser( { from, redirectFunc, redirectUri } = {} ) { * * Register an site into jetpack * - * @param {object} Object - contains registrationNonce and redirectUri + * @param {object} Object - contains registrationNonce and redirectUri * @param {string} Object.registrationNonce - Registration nonce - * @param {string} Object.redirectUri - URI that user will be redirected - * @param {string} [Object.from] - Value that represents the origin of the request (optional) - * @yields {object} Action object that will be yielded - * @returns {Promise} Resolved or rejected value of registerSite + * @param {string} Object.redirectUri - URI that user will be redirected + * @param {string} [Object.from] - Value that represents the origin of the request (optional) + * @yield {object} Action object that will be yielded + * @return {Promise} Resolved or rejected value of registerSite */ function* registerSite( { registrationNonce, redirectUri, from = '' } ) { yield clearRegistrationError(); @@ -114,7 +114,7 @@ function* registerSite( { registrationNonce, redirectUri, from = '' } ) { /** * Side effect action which will fetch a new list of connectedPlugins from the server * - * @returns {Promise} - Promise which resolves when the product status is activated. + * @return {Promise} - Promise which resolves when the product status is activated. */ const refreshConnectedPlugins = () => diff --git a/projects/js-packages/connection/state/selectors.jsx b/projects/js-packages/connection/state/selectors.jsx index cee4a8bada01c..40948292abc62 100644 --- a/projects/js-packages/connection/state/selectors.jsx +++ b/projects/js-packages/connection/state/selectors.jsx @@ -12,7 +12,7 @@ const connectionSelectors = { * Checks whether the store is fetching the connection status from the server * * @deprecated since 0.14.0 - * @returns {boolean} Is the store is fetching the connection status from the server? + * @return {boolean} Is the store is fetching the connection status from the server? */ getConnectionStatusIsFetching: () => false, getSiteIsRegistering: state => state.siteIsRegistering || false, diff --git a/projects/js-packages/ai-client/changelog/renovate-definitelytyped b/projects/js-packages/critical-css-gen/changelog/renovate-npm-webpack-vulnerability similarity index 100% rename from projects/js-packages/ai-client/changelog/renovate-definitelytyped rename to projects/js-packages/critical-css-gen/changelog/renovate-npm-webpack-vulnerability diff --git a/projects/js-packages/critical-css-gen/changelog/update-jsdoc-comments-for-wp-coding-standards b/projects/js-packages/critical-css-gen/changelog/update-jsdoc-comments-for-wp-coding-standards new file mode 100644 index 0000000000000..0e655b2b8b7a3 --- /dev/null +++ b/projects/js-packages/critical-css-gen/changelog/update-jsdoc-comments-for-wp-coding-standards @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Reformat jsdoc comments. No change to meaning or functionality. + + diff --git a/projects/js-packages/critical-css-gen/package.json b/projects/js-packages/critical-css-gen/package.json index ad3cdef23e65c..3f0e3fb816e7f 100644 --- a/projects/js-packages/critical-css-gen/package.json +++ b/projects/js-packages/critical-css-gen/package.json @@ -47,7 +47,7 @@ "source-map-js": "1.2.0", "tslib": "2.5.0", "typescript": "5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-dev-middleware": "5.3.4" }, "exports": { diff --git a/projects/js-packages/critical-css-gen/src/browser-interface-playwright.ts b/projects/js-packages/critical-css-gen/src/browser-interface-playwright.ts index 8355608d7945e..f0da79687a6a7 100644 --- a/projects/js-packages/critical-css-gen/src/browser-interface-playwright.ts +++ b/projects/js-packages/critical-css-gen/src/browser-interface-playwright.ts @@ -16,7 +16,7 @@ export class BrowserInterfacePlaywright extends BrowserInterface { * Creates a new BrowserInterfacePlaywright instance. * * @param {BrowserContext} context - The playwright browser context to work with. - * @param {string[]} urls - Array of urls to evaluate. The reason we are taking this as an argument is because we want to load all of them in parallel. + * @param {string[]} urls - Array of urls to evaluate. The reason we are taking this as an argument is because we want to load all of them in parallel. */ constructor( private context: BrowserContext, @@ -40,7 +40,7 @@ export class BrowserInterfacePlaywright extends BrowserInterface { * * @param {BrowserContext} context - Browser context to use. * @param {string[]} urls - Array of urls to open. - * @returns {Promise< TabsByUrl >} Promise resolving to the browser context. + * @return {Promise< TabsByUrl >} Promise resolving to the browser context. */ private async openUrls( context: BrowserContext, urls: string[] ): Promise< void > { this.tabs = await objectPromiseAll< Tab >( @@ -56,7 +56,7 @@ export class BrowserInterfacePlaywright extends BrowserInterface { * * @param {BrowserContext} browserContext - Browser context to use. * @param {string} url - Url to open. - * @returns {Promise} Promise resolving to the page instance. + * @return {Promise} Promise resolving to the page instance. */ private async newTab( browserContext: BrowserContext, url: string ): Promise< Tab > { const tab = { @@ -111,7 +111,7 @@ export class BrowserInterfacePlaywright extends BrowserInterface { * @param {string} url - URL to fetch. * @param {object} options - Fetch options. * @param {string} _role - 'css' or 'html' indicating what kind of thing is being fetched. - * @returns {Promise} A promise that resolves to the fetch response. + * @return {Promise} A promise that resolves to the fetch response. */ async fetch( url: string, options: FetchOptions, _role: 'css' | 'html' ) { return fetch( url, options ); diff --git a/projects/js-packages/critical-css-gen/src/browser-interface.ts b/projects/js-packages/critical-css-gen/src/browser-interface.ts index a8393827258b2..4633b4c37d44b 100644 --- a/projects/js-packages/critical-css-gen/src/browser-interface.ts +++ b/projects/js-packages/critical-css-gen/src/browser-interface.ts @@ -40,9 +40,9 @@ export class BrowserInterface { * Context-specific wrapper for fetch; uses window.fetch in browsers, or a * node library when using Puppeteer. * - * @param {string} _url - The URL to fetch - * @param {FetchOptions} _options - Fetch options - * @param {'css' | 'html'} _role - Role of the fetch operation + * @param {string} _url - The URL to fetch + * @param {FetchOptions} _options - Fetch options + * @param {'css' | 'html'} _role - Role of the fetch operation */ async fetch( _url: string, @@ -80,9 +80,9 @@ export class BrowserInterface { /** * Get all internal styles as a combined string from the window. * - * @param {object} wrappedArgs - Object containing the inner window. + * @param {object} wrappedArgs - Object containing the inner window. * @param {Window} wrappedArgs.innerWindow - Window inside the browser interface. - * @returns {string} Combined internal styles as a string. + * @return {string} Combined internal styles as a string. */ static innerGetInternalStyles( { innerWindow } ): string { innerWindow = null === innerWindow ? window : innerWindow; @@ -99,11 +99,11 @@ export class BrowserInterface { * for easy querySelector calling (values), return an array of selectors which match * _any_ element on the page. * - * @param {object} wrappedArgs - Object containing the inner window and arguments. + * @param {object} wrappedArgs - Object containing the inner window and arguments. * @param {Window} wrappedArgs.innerWindow - Window inside the browser interface. * @param {Object[]} wrappedArgs.args - Array of arguments. - * {Object} wrappedArgs.args[selectors] - Map containing selectors (object keys), and simplified versions for easy matching (values). - * @returns {string[]} Array of selectors matching above-the-fold elements. + * {Object} wrappedArgs.args[selectors] - Map containing selectors (object keys), and simplified versions for easy matching (values). + * @return {string[]} Array of selectors matching above-the-fold elements. */ public static innerFindMatchingSelectors( { innerWindow, args: [ selectors ] } ) { innerWindow = null === innerWindow ? window : innerWindow; @@ -122,12 +122,12 @@ export class BrowserInterface { * for easy querySelector calling (values), return an array of selectors which match * any above-the-fold element on the page. * - * @param {object} wrappedArgs - Object containing the inner window and arguments. + * @param {object} wrappedArgs - Object containing the inner window and arguments. * @param {Window} wrappedArgs.innerWindow - Window inside the browser interface. * @param {Object[]} wrappedArgs.args - Array of arguments. - * {Object} wrappedArgs.args[selectors] - Map containing selectors (object keys), and simplified versions for easy matching (values). - * {string[]} wrappedArgs.args[pageSelectors] - String array containing selectors that appear anywhere on this page (as returned by innerFindMatchingSelectors) - should be a subset of keys in selectors. - * @returns {string[]} Array of selectors matching above-the-fold elements. + * {Object} wrappedArgs.args[selectors] - Map containing selectors (object keys), and simplified versions for easy matching (values). + * {string[]} wrappedArgs.args[pageSelectors] - String array containing selectors that appear anywhere on this page (as returned by innerFindMatchingSelectors) - should be a subset of keys in selectors. + * @return {string[]} Array of selectors matching above-the-fold elements. */ public static innerFindAboveFoldSelectors( { innerWindow, diff --git a/projects/js-packages/critical-css-gen/src/css-file-set.ts b/projects/js-packages/critical-css-gen/src/css-file-set.ts index 924a32ef70600..6a18e2eb37b18 100644 --- a/projects/js-packages/critical-css-gen/src/css-file-set.ts +++ b/projects/js-packages/critical-css-gen/src/css-file-set.ts @@ -103,7 +103,7 @@ export class CSSFileSet { * Collates an object describing the selectors found in the CSS files in this set, and which * HTML page URLs include them (via CSS files) * - * @returns {object} - An object with selector text keys, each containing a Set of page URLs (strings) + * @return {object} - An object with selector text keys, each containing a Set of page URLs (strings) */ collateSelectorPages(): { [ selector: string ]: Set< string > } { const selectors = {}; @@ -138,7 +138,7 @@ export class CSSFileSet { * set of selectors that are worth keeping. (i.e.: appear above the fold). * * @param {Set} usefulSelectors - Set of selectors to keep. - * @returns {StyleAST[]} Array of pruned StyleAST objects. + * @return {StyleAST[]} Array of pruned StyleAST objects. */ prunedAsts( usefulSelectors: Set< string > ): StyleAST[] { // Perform basic pruning. @@ -256,7 +256,7 @@ export class CSSFileSet { /** * Returns a list of errors that occurred while fetching or parsing these CSS files. * - * @returns {Error[]} - List of errors that occurred. + * @return {Error[]} - List of errors that occurred. */ getErrors() { return this.errors; diff --git a/projects/js-packages/critical-css-gen/src/generate-critical-css.ts b/projects/js-packages/critical-css-gen/src/generate-critical-css.ts index d11436f015f47..432172192a14a 100644 --- a/projects/js-packages/critical-css-gen/src/generate-critical-css.ts +++ b/projects/js-packages/critical-css-gen/src/generate-critical-css.ts @@ -18,7 +18,7 @@ const noop = () => { * @param {BrowserInterface} browserInterface - interface to access pages * @param {string[]} urls - list of URLs to scan for CSS files * @param {number} maxPages - number of pages to process at most - * @returns {Array} - Two member array; CSSFileSet, and an object containing errors that occurred at each URL. + * @return {Array} - Two member array; CSSFileSet, and an object containing errors that occurred at each URL. */ async function collateCssFiles( browserInterface: BrowserInterface, @@ -80,7 +80,7 @@ async function collateCssFiles( * @param {number} param.maxPages - Maximum number of pages to process * @param {Function} param.updateProgress - Update progress callback function * - * @returns {Set} - List of above the fold selectors. + * @return {Set} - List of above the fold selectors. */ async function getAboveFoldSelectors( { browserInterface, @@ -142,15 +142,15 @@ async function getAboveFoldSelectors( { /** * Generates critical CSS for the given URLs and viewports. * - * @param {object} root0 - The options object + * @param {object} root0 - The options object * @param {BrowserInterface} root0.browserInterface - Interface to interact with the browser - * @param {Function} root0.progressCallback - Optional callback function to report progress - * @param {string[]} root0.urls - Array of URLs to generate critical CSS for - * @param {Viewport[]} root0.viewports - Array of viewport sizes to consider - * @param {FilterSpec} root0.filters - Optional filters to apply to the CSS - * @param {number} root0.successRatio - Ratio of successful URLs required (default: 1) - * @param {number} root0.maxPages - Maximum number of pages to process (default: 10) - * @returns {Promise<[string, Error[]]>} A promise that resolves to an array containing the critical CSS string and an array of errors. + * @param {Function} root0.progressCallback - Optional callback function to report progress + * @param {string[]} root0.urls - Array of URLs to generate critical CSS for + * @param {Viewport[]} root0.viewports - Array of viewport sizes to consider + * @param {FilterSpec} root0.filters - Optional filters to apply to the CSS + * @param {number} root0.successRatio - Ratio of successful URLs required (default: 1) + * @param {number} root0.maxPages - Maximum number of pages to process (default: 10) + * @return {Promise<[string, Error[]]>} A promise that resolves to an array containing the critical CSS string and an array of errors. */ export async function generateCriticalCSS( { browserInterface, diff --git a/projects/js-packages/critical-css-gen/src/ignored-pseudo-elements.ts b/projects/js-packages/critical-css-gen/src/ignored-pseudo-elements.ts index c68947883212f..082eebe86cc25 100644 --- a/projects/js-packages/critical-css-gen/src/ignored-pseudo-elements.ts +++ b/projects/js-packages/critical-css-gen/src/ignored-pseudo-elements.ts @@ -14,7 +14,7 @@ let removePseudoElementRegex: RegExp; * Builds a RegExp for finding pseudo elements that should be ignored while matching * elements that are above the fold. * - * @returns {RegExp} A RegExp to use when removing unwanted pseudo elements. + * @return {RegExp} A RegExp to use when removing unwanted pseudo elements. */ function getRemovePseudoElementRegex(): RegExp { if ( removePseudoElementRegex ) { @@ -32,7 +32,7 @@ function getRemovePseudoElementRegex(): RegExp { * * @param {string} selector - selector to filter. * - * @returns {string} selector with ignored pseudo elements removed. + * @return {string} selector with ignored pseudo elements removed. */ export function removeIgnoredPseudoElements( selector: string ): string { return selector.replace( getRemovePseudoElementRegex(), '' ).trim(); diff --git a/projects/js-packages/critical-css-gen/src/minify-css.ts b/projects/js-packages/critical-css-gen/src/minify-css.ts index ed6032121ac0c..eebce4b9cc86f 100644 --- a/projects/js-packages/critical-css-gen/src/minify-css.ts +++ b/projects/js-packages/critical-css-gen/src/minify-css.ts @@ -8,7 +8,7 @@ import CleanCSS from 'clean-css'; * * @param {string} css - CSS to minify. * - * @returns {[ string, string[] ]} - Minified CSS and a list of errors returned. + * @return {[ string, string[] ]} - Minified CSS and a list of errors returned. */ export function minifyCss( css: string ): [ string, string[] ] { const result = new CleanCSS().minify( css ); diff --git a/projects/js-packages/critical-css-gen/src/object-promise-all.ts b/projects/js-packages/critical-css-gen/src/object-promise-all.ts index 016cc07f3a49c..78da9541de643 100644 --- a/projects/js-packages/critical-css-gen/src/object-promise-all.ts +++ b/projects/js-packages/critical-css-gen/src/object-promise-all.ts @@ -3,7 +3,7 @@ * Roughly equivalent of Promise.all, but applies to an object. * * @param {object} object - containing promises to resolve - * @returns {object} - Promise which resolves to an object containing resultant values + * @return {object} - Promise which resolves to an object containing resultant values */ export async function objectPromiseAll< ValueType >( object: { [ key: string ]: Promise< ValueType >; diff --git a/projects/js-packages/critical-css-gen/src/style-ast.ts b/projects/js-packages/critical-css-gen/src/style-ast.ts index bde637e0dc4e0..191ca798b2d03 100644 --- a/projects/js-packages/critical-css-gen/src/style-ast.ts +++ b/projects/js-packages/critical-css-gen/src/style-ast.ts @@ -18,7 +18,7 @@ const excludedProperties = [ /** * Checks if the given node is a CSS declaration. * @param {csstree.CssNode} node - The CSS node to check. - * @returns {boolean} True if the node is a CSS declaration, false otherwise. + * @return {boolean} True if the node is a CSS declaration, false otherwise. */ function isDeclaration( node: csstree.CssNode ): node is csstree.Declaration { return node.type === 'Declaration'; @@ -27,7 +27,7 @@ function isDeclaration( node: csstree.CssNode ): node is csstree.Declaration { /** * Checks if the given node has an empty child list. * @param {csstree.CssNode} node - The CSS node to check. - * @returns {boolean} True if the node has an empty child list, false otherwise. + * @return {boolean} True if the node has an empty child list, false otherwise. */ function hasEmptyChildList( node: csstree.CssNode ): boolean { if ( 'children' in node && node.children instanceof csstree.List ) { @@ -84,7 +84,7 @@ export class StyleAST { * * @param {Set< string >} criticalSelectors - Set of selectors to keep in the new AST. * - * @returns {StyleAST} - New AST with pruned contents. + * @return {StyleAST} - New AST with pruned contents. */ pruned( criticalSelectors: Set< string > ): StyleAST { const clone = new StyleAST( this.css, csstree.clone( this.ast ), this.errors ); @@ -103,7 +103,7 @@ export class StyleAST { * Given an AST node, returns the original text it was compiled from in the source CSS. * * @param {object} node - Node from the AST. - * @returns {string} original text the node was compiled from. + * @return {string} original text the node was compiled from. */ originalText( node: csstree.CssNode ): string { if ( node.loc && node.loc.start && node.loc.end ) { @@ -168,7 +168,7 @@ export class StyleAST { * that were removed. * * @param {Set< string >} usedVariables - Set of used variables to keep. - * @returns {number} variables pruned. + * @return {number} variables pruned. */ pruneUnusedVariables( usedVariables: Set< string > ): number { let pruned = 0; @@ -197,7 +197,7 @@ export class StyleAST { /** * Find all variables that are used and return them as a Set. - * @returns {Set< string >} Set of used variables. + * @return {Set< string >} Set of used variables. */ getUsedVariables(): Set< string > { const usedVariables = new Set< string >(); @@ -291,7 +291,7 @@ export class StyleAST { * Returns true if the given CSS rule object relates to animation keyframes. * * @param {csstree.WalkContext} rule - CSS rule. - * @returns {boolean} True if the rule is a keyframe rule, false otherwise. + * @return {boolean} True if the rule is a keyframe rule, false otherwise. */ static isKeyframeRule( rule: csstree.WalkContext ): boolean { return ( rule.atrule && csstree.keyword( rule.atrule.name ).basename === 'keyframes' ) || false; @@ -473,7 +473,7 @@ export class StyleAST { /** * Returns a count of the rules in this Style AST. * - * @returns {number} rules in this AST. + * @return {number} rules in this AST. */ ruleCount(): number { let rules = 0; @@ -491,7 +491,7 @@ export class StyleAST { /** * Returns a list of font families that are used by any rule in this AST. * - * @returns {Set} Set of used fonts. + * @return {Set} Set of used fonts. */ getUsedFontFamilies(): Set< string > { const fontFamilies = new Set< string >(); @@ -525,7 +525,7 @@ export class StyleAST { * string types if present. * * @param {csstree.CssNode} node - AST node. - * @returns {string} The value of the node as a string. + * @return {string} The value of the node as a string. */ static readValue( node: csstree.CssNode ): string { if ( node.type === 'String' && stringPattern.test( node.value ) ) { @@ -544,7 +544,7 @@ export class StyleAST { * * @param {object} mediaQueryNode - Media Query AST node to examine. * - * @returns {boolean} true if the media query is relevant to screens. + * @return {boolean} true if the media query is relevant to screens. */ static isUsefulMediaQuery( mediaQueryNode: csstree.MediaQuery ): boolean { // Find media types. @@ -587,7 +587,7 @@ export class StyleAST { /** * Returns this AST converted to CSS. * - * @returns {string} this AST represented in CSS. + * @return {string} this AST represented in CSS. */ toCSS(): string { return csstree.generate( this.ast ); @@ -598,7 +598,7 @@ export class StyleAST { * * @param {string} css - CSS to parse. * - * @returns {StyleAST} new parse AST based on the CSS. + * @return {StyleAST} new parse AST based on the CSS. */ static parse( css: string ): StyleAST { const errors: Error[] = []; diff --git a/projects/js-packages/critical-css-gen/tests/lib/mock-fetch.js b/projects/js-packages/critical-css-gen/tests/lib/mock-fetch.js index d09fc397d0316..50f55a82d53f8 100644 --- a/projects/js-packages/critical-css-gen/tests/lib/mock-fetch.js +++ b/projects/js-packages/critical-css-gen/tests/lib/mock-fetch.js @@ -5,7 +5,7 @@ const { dataDirectory } = require( './data-directory.js' ); * Mocked out version of node-fetch; allows fetching local resources from the data directory. * * @param {string} url - to fetch. - * @returns {Promise} - A Promise that resolves to an object with 'ok' and 'text' properties. + * @return {Promise} - A Promise that resolves to an object with 'ok' and 'text' properties. */ const mockFetch = async url => { return new Promise( ( resolve, reject ) => { diff --git a/projects/js-packages/eslint-changed/changelog/add-enable-more-eslint-rules b/projects/js-packages/eslint-changed/changelog/add-enable-more-eslint-rules new file mode 100644 index 0000000000000..db4cc1e54899d --- /dev/null +++ b/projects/js-packages/eslint-changed/changelog/add-enable-more-eslint-rules @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Resolve new eslint sniffs. Should be no changes to functionality. + + diff --git a/projects/js-packages/eslint-changed/changelog/try-no-version-bumps-in-trunk b/projects/js-packages/eslint-changed/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..91efe85c55e06 --- /dev/null +++ b/projects/js-packages/eslint-changed/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/js-packages/eslint-changed/changelog/update-jsdoc-comments-for-wp-coding-standards b/projects/js-packages/eslint-changed/changelog/update-jsdoc-comments-for-wp-coding-standards new file mode 100644 index 0000000000000..0e655b2b8b7a3 --- /dev/null +++ b/projects/js-packages/eslint-changed/changelog/update-jsdoc-comments-for-wp-coding-standards @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Reformat jsdoc comments. No change to meaning or functionality. + + diff --git a/projects/js-packages/eslint-changed/package.json b/projects/js-packages/eslint-changed/package.json index ae64558d9b528..1cc6ebabdf16e 100644 --- a/projects/js-packages/eslint-changed/package.json +++ b/projects/js-packages/eslint-changed/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/eslint-changed", - "version": "2.0.9-alpha", + "version": "2.0.8", "description": "Run eslint on files, but only report warnings and errors from lines that were changed.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/eslint-changed/#readme", "type": "module", diff --git a/projects/js-packages/eslint-changed/src/cli.js b/projects/js-packages/eslint-changed/src/cli.js index 1ab88f0fd489f..5790f0a5b9f77 100755 --- a/projects/js-packages/eslint-changed/src/cli.js +++ b/projects/js-packages/eslint-changed/src/cli.js @@ -6,7 +6,7 @@ import { Command } from 'commander'; import { ESLint } from 'eslint'; import parseDiff from 'parse-diff'; -const APP_VERSION = '2.0.9-alpha'; +const APP_VERSION = '2.0.8'; /** * Create a Commander instance. @@ -14,7 +14,7 @@ const APP_VERSION = '2.0.9-alpha'; * Call `.parseAsync()` to run. * * @param {object} [process] - Process object. Needs at least a `cwd()` method and an `env` property. - * @returns {Command} Commander instance. + * @return {Command} Commander instance. */ export function createProgram( process = global.process ) { const program = new Command(); @@ -72,8 +72,8 @@ export function createProgram( process = global.process ) { /** * Main method. * - * @param {object} process - Process object. - * @param {object} argv - Command line options. + * @param {object} process - Process object. + * @param {object} argv - Command line options. * @param {Command} program - Commander instance. */ async function main( process, argv, program ) { @@ -108,7 +108,7 @@ async function main( process, argv, program ) { * Get files from a diff. * * @param {Array} diff - Diff array from `parse-diff`. - * @returns {string[]} File name strings. + * @return {string[]} File name strings. */ function getFilesFromDiff( diff ) { let files = diff.map( x => x.to ); @@ -128,9 +128,9 @@ async function main( process, argv, program ) { /** * Spawn a command, exiting if it fails. * - * @param {string} cmd - Command to execute. + * @param {string} cmd - Command to execute. * @param {string[]} cmdArgs - Arguments to the command. - * @returns {string} Command output. + * @return {string} Command output. */ function doCmd( cmd, cmdArgs ) { const res = spawnSync( cmd, cmdArgs, spawnOpt ); diff --git a/projects/js-packages/eslint-changed/tests/cli.test.js b/projects/js-packages/eslint-changed/tests/cli.test.js index 2ef4d711ff41c..449ae0b2d7198 100644 --- a/projects/js-packages/eslint-changed/tests/cli.test.js +++ b/projects/js-packages/eslint-changed/tests/cli.test.js @@ -16,9 +16,9 @@ describe( 'bin/eslint-changed.js', () => { /** * Run eslint-changed. * - * @param {string[]} args - Arguments to pass. - * @param {object} [options] - Process options. - * @returns {object} data - Process data. + * @param {string[]} args - Arguments to pass. + * @param {object} [options] - Process options. + * @return {object} data - Process data. */ async function runEslintChanged( args, options = {} ) { const proc = { @@ -278,10 +278,12 @@ describe( 'bin/eslint-changed.js', () => { [ '--eslint-orig', path.join( dirname, 'fixtures/no-new-errors.orig.json' ) ], [ '--eslint-new', path.join( dirname, 'fixtures/no-new-errors.new.json' ) ], ]; + // eslint-disable-next-line no-bitwise for ( let i = ( 1 << argsets.length ) - 2; i > 0; i-- ) { const args = []; const missing = []; for ( let j = 0; j < argsets.length; j++ ) { + // eslint-disable-next-line no-bitwise if ( i & ( 1 << j ) ) { args.push( ...argsets[ j ] ); } else { @@ -330,12 +332,12 @@ describe( 'bin/eslint-changed.js', () => { * * The path is stored in `tmpdir`. * - * @param {object[]} branches - An array of branches to create. - * @param {string} [branches.name] - Name of the branch. - * @param {string} [branches.parent] - Name of the parent branch. If omitted, the parent is the previous entry in the array. Must be omitted in the first entry. - * @param {Object} branches.files - Files to modify, and their contents (or null to delete the file). - * @param {Object} [staged] - Files to modify and stage. - * @param {Object} [unstaged] - Files to modify and leave unstaged. + * @param {object[]} branches - An array of branches to create. + * @param {string} [branches.name] - Name of the branch. + * @param {string} [branches.parent] - Name of the parent branch. If omitted, the parent is the previous entry in the array. Must be omitted in the first entry. + * @param {Object} branches.files - Files to modify, and their contents (or null to delete the file). + * @param {Object} [staged] - Files to modify and stage. + * @param {Object} [unstaged] - Files to modify and leave unstaged. */ async function mktmpdirgit( branches, staged, unstaged ) { await mktmpdir(); @@ -355,7 +357,7 @@ describe( 'bin/eslint-changed.js', () => { * Modify files. * * @param {Object} files - Files to modify, and their contents (or null to delete the file). - * @param {boolean} git - Whether to do git manipulations. + * @param {boolean} git - Whether to do git manipulations. */ async function doFiles( files, git ) { const modified = []; diff --git a/projects/js-packages/eslint-config-target-es/changelog/renovate-eslint-packages#3 b/projects/js-packages/eslint-config-target-es/changelog/renovate-eslint-packages#3 new file mode 100644 index 0000000000000..0dafb1cfd30ee --- /dev/null +++ b/projects/js-packages/eslint-config-target-es/changelog/renovate-eslint-packages#3 @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Add mapping for `es-x/no-regexp-duplicate-named-capturing-groups`. diff --git a/projects/js-packages/ai-client/changelog/renovate-storybook-monorepo b/projects/js-packages/eslint-config-target-es/changelog/renovate-mdn-browser-compat-data-5.x#2 similarity index 100% rename from projects/js-packages/ai-client/changelog/renovate-storybook-monorepo rename to projects/js-packages/eslint-config-target-es/changelog/renovate-mdn-browser-compat-data-5.x#2 diff --git a/projects/js-packages/eslint-config-target-es/changelog/try-no-version-bumps-in-trunk b/projects/js-packages/eslint-config-target-es/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..91efe85c55e06 --- /dev/null +++ b/projects/js-packages/eslint-config-target-es/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/js-packages/eslint-config-target-es/changelog/update-jsdoc-comments-for-wp-coding-standards b/projects/js-packages/eslint-config-target-es/changelog/update-jsdoc-comments-for-wp-coding-standards new file mode 100644 index 0000000000000..0e655b2b8b7a3 --- /dev/null +++ b/projects/js-packages/eslint-config-target-es/changelog/update-jsdoc-comments-for-wp-coding-standards @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Reformat jsdoc comments. No change to meaning or functionality. + + diff --git a/projects/js-packages/eslint-config-target-es/package.json b/projects/js-packages/eslint-config-target-es/package.json index ee0e4f8c0f938..4f1ebdebfee67 100644 --- a/projects/js-packages/eslint-config-target-es/package.json +++ b/projects/js-packages/eslint-config-target-es/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/eslint-config-target-es", - "version": "2.2.0-alpha", + "version": "2.1.0", "description": "ESLint sharable config to activate eslint-plugin-es checks based on browserslist targets.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/eslint-config-target-es/README.md#readme", "bugs": { @@ -17,7 +17,7 @@ "test": "jest tests" }, "dependencies": { - "@mdn/browser-compat-data": "5.5.33", + "@mdn/browser-compat-data": "5.5.47", "browserslist": "^4.17.6", "debug": "^4.3.2", "semver": "^7.3.5" @@ -25,7 +25,7 @@ "devDependencies": { "@wordpress/browserslist-config": "6.5.0", "eslint": "8.57.0", - "eslint-plugin-es-x": "7.7.0", + "eslint-plugin-es-x": "7.8.0", "globals": "15.4.0", "jest": "29.7.0" }, diff --git a/projects/js-packages/eslint-config-target-es/src/funcs.js b/projects/js-packages/eslint-config-target-es/src/funcs.js index 53a9920c678f7..3d2ae46f8d926 100644 --- a/projects/js-packages/eslint-config-target-es/src/funcs.js +++ b/projects/js-packages/eslint-config-target-es/src/funcs.js @@ -10,9 +10,9 @@ const warn = debug( '@automattic/eslint-config-target-es:warn' ); /** * Get the list of supported browsers. * - * @param {object} options - Options. + * @param {object} options - Options. * @param {string} options.query - Browserslist query. - * @returns {object} Browsers mapped to arrays of versions. + * @return {object} Browsers mapped to arrays of versions. */ function getAllBrowsers( options = {} ) { const browsers = {}; @@ -42,9 +42,9 @@ function getAllBrowsers( options = {} ) { * Get the list of supported browsers. * * @deprecated since 2.1.0. Use getAllBrowsers instead. - * @param {object} options - Options. + * @param {object} options - Options. * @param {string} options.query - Browserslist query. - * @returns {object} Browsers mapped to minimum versions. + * @return {object} Browsers mapped to minimum versions. */ function getBrowsers( options = {} ) { warn( 'getBrowsers is deprecated. Use getAllBrowsers instead.' ); @@ -59,10 +59,10 @@ function getBrowsers( options = {} ) { /** * Get the es-x rule configurations. * - * @param {object} options - Options. + * @param {object} options - Options. * @param {boolean|null} options.builtins - If true, only rules with "javascript.builtins" paths are checked. If false, such rules are not checked. If null/undefined, all may be checked. - * @param {string} options.query - Browserslist query. - * @returns {object} Rules configuration. + * @param {string} options.query - Browserslist query. + * @return {object} Rules configuration. */ function getRules( options = {} ) { const browsers = getAllBrowsers( options ); diff --git a/projects/js-packages/eslint-config-target-es/src/needsCheck.js b/projects/js-packages/eslint-config-target-es/src/needsCheck.js index b34d37f023a99..859a49bfe2095 100644 --- a/projects/js-packages/eslint-config-target-es/src/needsCheck.js +++ b/projects/js-packages/eslint-config-target-es/src/needsCheck.js @@ -9,11 +9,11 @@ const debuglog = debug( '@automattic/eslint-config-target-es:debug' ); /** * Test if a rule needs to be checked. * - * @param {string} rule - Rule. - * @param {object} browsers - Browsers targeted. - * @param {object} options - Options. + * @param {string} rule - Rule. + * @param {object} browsers - Browsers targeted. + * @param {object} options - Options. * @param {boolean|null} options.builtins - If true, only rules with "javascript.builtins" paths are checked. If false, such rules are not checked. If null/undefined, all may be checked. - * @returns {boolean} Whether the rule needs to be checked. + * @return {boolean} Whether the rule needs to be checked. */ function needsCheck( rule, browsers, options = {} ) { let paths = rulesMap[ rule ]; diff --git a/projects/js-packages/eslint-config-target-es/src/rulesMap.js b/projects/js-packages/eslint-config-target-es/src/rulesMap.js index 244a43c61a654..83d84bfc443be 100644 --- a/projects/js-packages/eslint-config-target-es/src/rulesMap.js +++ b/projects/js-packages/eslint-config-target-es/src/rulesMap.js @@ -1,6 +1,10 @@ // Map of eslint-plugin-es-x rules to MDN compat-data paths. // Values are either a path, an array of paths, true to always enable the rule, or false to always disable it. module.exports = { + // ES2025 + 'no-regexp-duplicate-named-capturing-groups': + 'javascript.regular_expressions.named_capturing_group.duplicate_named_capturing_groups', + // ES2024 'no-arraybuffer-prototype-transfer': 'javascript.builtins.ArrayBuffer.transfer', 'no-atomics-waitasync': 'javascript.builtins.Atomics.waitAsync', diff --git a/projects/js-packages/eslint-config-target-es/tests/configs-eslintrc.test.js b/projects/js-packages/eslint-config-target-es/tests/configs-eslintrc.test.js index 28408c4c5edec..0ea9f50cd8ece 100644 --- a/projects/js-packages/eslint-config-target-es/tests/configs-eslintrc.test.js +++ b/projects/js-packages/eslint-config-target-es/tests/configs-eslintrc.test.js @@ -24,7 +24,7 @@ afterEach( () => { * Load the config, bypassing normal module caching. * * @param {string} name - Config name. - * @returns {object} Config. + * @return {object} Config. */ function loadConfig( name ) { let config; diff --git a/projects/js-packages/eslint-config-target-es/tests/configs-flat.test.js b/projects/js-packages/eslint-config-target-es/tests/configs-flat.test.js index 79a33be71c1a1..a1ba3f652b1fa 100644 --- a/projects/js-packages/eslint-config-target-es/tests/configs-flat.test.js +++ b/projects/js-packages/eslint-config-target-es/tests/configs-flat.test.js @@ -33,7 +33,7 @@ afterEach( () => { * Load the config, bypassing normal module caching. * * @param {string} name - Config name. - * @returns {object} Config. + * @return {object} Config. */ function loadConfig( name ) { let config; diff --git a/projects/js-packages/i18n-check-webpack-plugin/CHANGELOG.md b/projects/js-packages/i18n-check-webpack-plugin/CHANGELOG.md index 77ca9c5ac19da..574f5639dbc3b 100644 --- a/projects/js-packages/i18n-check-webpack-plugin/CHANGELOG.md +++ b/projects/js-packages/i18n-check-webpack-plugin/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.1.11] - 2024-08-29 +### Changed +- Updated package dependencies. [#39111] + +## [1.1.10] - 2024-08-21 +### Changed +- Internal updates. + ## [1.1.9] - 2024-06-12 ### Changed - Updated package dependencies. [#37796] @@ -210,6 +218,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Initial release. +[1.1.11]: https://github.com/Automattic/i18n-check-webpack-plugin/compare/v1.1.10...v1.1.11 +[1.1.10]: https://github.com/Automattic/i18n-check-webpack-plugin/compare/v1.1.9...v1.1.10 [1.1.9]: https://github.com/Automattic/i18n-check-webpack-plugin/compare/v1.1.8...v1.1.9 [1.1.8]: https://github.com/Automattic/i18n-check-webpack-plugin/compare/v1.1.7...v1.1.8 [1.1.7]: https://github.com/Automattic/i18n-check-webpack-plugin/compare/v1.1.6...v1.1.7 diff --git a/projects/js-packages/i18n-check-webpack-plugin/package.json b/projects/js-packages/i18n-check-webpack-plugin/package.json index afc3d9a806fac..05b891c900632 100644 --- a/projects/js-packages/i18n-check-webpack-plugin/package.json +++ b/projects/js-packages/i18n-check-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/i18n-check-webpack-plugin", - "version": "1.1.9", + "version": "1.1.11", "description": "A Webpack plugin to check that WordPress i18n hasn't been mangled by Webpack optimizations.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/i18n-check-webpack-plugin/#readme", "bugs": { @@ -23,12 +23,12 @@ "@automattic/jetpack-webpack-config": "workspace:*", "@babel/core": "7.24.7", "jest": "29.7.0", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "peerDependencies": { "@babel/core": "^7.0.0", - "webpack": "^5.0.0" + "webpack": "^5.94.0" }, "exports": { ".": "./src/I18nCheckPlugin.js", diff --git a/projects/js-packages/i18n-check-webpack-plugin/src/GettextEntry.js b/projects/js-packages/i18n-check-webpack-plugin/src/GettextEntry.js index 154edb00e37be..819deb546a807 100644 --- a/projects/js-packages/i18n-check-webpack-plugin/src/GettextEntry.js +++ b/projects/js-packages/i18n-check-webpack-plugin/src/GettextEntry.js @@ -22,12 +22,12 @@ class GettextEntry { /** * Constructor. * - * @param {object} data - Entry data. - * @param {string} data.msgid - Message string. - * @param {string} data.plural - Plural string. - * @param {string} data.context - Context. - * @param {string} data.domain - Text domain. - * @param {Iterable} data.comments - Comments. + * @param {object} data - Entry data. + * @param {string} data.msgid - Message string. + * @param {string} data.plural - Plural string. + * @param {string} data.context - Context. + * @param {string} data.domain - Text domain. + * @param {Iterable} data.comments - Comments. * @param {Iterable} data.locations - Locations. */ constructor( data ) { diff --git a/projects/js-packages/i18n-check-webpack-plugin/src/GettextExtractor.js b/projects/js-packages/i18n-check-webpack-plugin/src/GettextExtractor.js index 814061fbf214a..fb8f6e06c5533 100644 --- a/projects/js-packages/i18n-check-webpack-plugin/src/GettextExtractor.js +++ b/projects/js-packages/i18n-check-webpack-plugin/src/GettextExtractor.js @@ -38,10 +38,10 @@ class GettextExtractor { /** * Constructor. * - * @param {object} options - Configuration options. - * @param {object} options.babelOptions - Options for Babel. - * @param {Object} options.functions - Functions to extract. Defaults are available as a static property `defaultFunctions`. - * @param {Function} options.lintLogger - Lint logging callback. See `this.setLintLogger()`. + * @param {object} options - Configuration options. + * @param {object} options.babelOptions - Options for Babel. + * @param {Object} options.functions - Functions to extract. Defaults are available as a static property `defaultFunctions`. + * @param {Function} options.lintLogger - Lint logging callback. See `this.setLintLogger()`. */ constructor( options = {} ) { this.#babelOptions = options.babelOptions || {}; @@ -54,7 +54,7 @@ class GettextExtractor { * * @param {string} file - File name. * @param {object} opts - Babel options. - * @returns {GettextEntries} Set of entries. + * @return {GettextEntries} Set of entries. */ async extractFromFile( file, opts = {} ) { const contents = await fs.readFile( file, { encoding: 'utf8' } ); @@ -65,8 +65,8 @@ class GettextExtractor { * Parse source. * * @param {string} source - JavaScript source. - * @param {object} opts - Babel options. - * @returns {babel.File} Babel File object. + * @param {object} opts - Babel options. + * @return {babel.File} Babel File object. */ async parse( source, opts = {} ) { const options = { ...this.#babelOptions, ...opts }; @@ -79,8 +79,8 @@ class GettextExtractor { * Extract gettext strings from source. * * @param {string} source - JavaScript source. - * @param {object} opts - Babel options. - * @returns {GettextEntries} Set of entries. + * @param {object} opts - Babel options. + * @return {GettextEntries} Set of entries. */ async extract( source, opts ) { return this.extractFromAst( await this.parse( source, opts ), opts ); @@ -90,8 +90,8 @@ class GettextExtractor { * Extract gettext strings from a Babel File object. * * @param {babel.File} file - Babel File object, e.g. from `this.parse()`. - * @param {object} opts - Babel options. - * @returns {GettextEntries} Set of entries. + * @param {object} opts - Babel options. + * @return {GettextEntries} Set of entries. */ extractFromAst( file, opts = {} ) { const entries = new GettextEntries(); @@ -101,11 +101,11 @@ class GettextExtractor { /** * Extract gettext strings from a Babel File object. * - * @param {babel.File} file - Babel File object, e.g. from `this.parse()`. - * @param {GettextEntries} entries - Entries object to fill in. - * @param {number|false} evalline - If this is a recursive call from an `eval()`, the line of the eval. - * @param {object} opts - Babel options. - * @returns {GettextEntries} `entries`. + * @param {babel.File} file - Babel File object, e.g. from `this.parse()`. + * @param {GettextEntries} entries - Entries object to fill in. + * @param {number|false} evalline - If this is a recursive call from an `eval()`, the line of the eval. + * @param {object} opts - Babel options. + * @return {GettextEntries} `entries`. */ #extractFromAst( file, entries, evalline, opts ) { const options = { ...this.#babelOptions, ...opts }; @@ -156,7 +156,7 @@ class GettextExtractor { return; } - if ( ! this.#functions.hasOwnProperty( callee.name ) ) { + if ( ! Object.hasOwn( this.#functions, callee.name ) ) { return; } @@ -311,7 +311,7 @@ class GettextExtractor { * * @see https://github.com/wp-cli/i18n-command/blob/e9eef8aab4b5e43c3aa09bf60e1e7a9d6d30d302/src/JsFunctionsScanner.php#L254 * @param {babel.CallExpression} node - CallExpression node. - * @returns {{ name: string, comments: string[] }|undefined} Callee name and comments, or undefined. + * @return {{ name: string, comments: string[] }|undefined} Callee name and comments, or undefined. */ #resolveExpressionCallee( node ) { const callee = node.callee; @@ -422,8 +422,8 @@ class GettextExtractor { * * @see https://github.com/wp-cli/i18n-command/blob/e9eef8aab4b5e43c3aa09bf60e1e7a9d6d30d302/src/JsFunctionsScanner.php#L364 * @param {babel.Comment} comment - Comment. - * @param {babel.Node} node - Node. - * @returns {boolean} Whether the comment comes before the node. + * @param {babel.Node} node - Node. + * @return {boolean} Whether the comment comes before the node. */ #commentPrecedesNode( comment, node ) { // Comments should be on the same or an earlier line than the translation. diff --git a/projects/js-packages/i18n-check-webpack-plugin/src/I18nCheckPlugin.js b/projects/js-packages/i18n-check-webpack-plugin/src/I18nCheckPlugin.js index 0d90fdabe4a8c..1309260725c9d 100644 --- a/projects/js-packages/i18n-check-webpack-plugin/src/I18nCheckPlugin.js +++ b/projects/js-packages/i18n-check-webpack-plugin/src/I18nCheckPlugin.js @@ -127,8 +127,8 @@ class I18nCheckPlugin { * Record the resources for an asset. * * @param {webpack.Compilation} compilation - Compilation. - * @param {string} filename - Asset filename. - * @param {webpack.Module[]} modules - Modules in the asset. + * @param {string} filename - Asset filename. + * @param {webpack.Module[]} modules - Modules in the asset. */ #recordResourcesForAsset( compilation, filename, modules ) { const resources = new Set(); @@ -159,7 +159,7 @@ class I18nCheckPlugin { * Stringify an entry to msgid + context. * * @param {GettextEntry} entry - Entry. - * @returns {string} String. + * @return {string} String. */ #strentry( entry ) { let ret = '"' + entry.msgid.replace( /[\\"]/g, '\\$&' ).replaceAll( '\n', '\\n' ) + '"'; @@ -210,8 +210,8 @@ class I18nCheckPlugin { * Process an asset. * * @param {webpack.Compilation} compilation - Compilation. - * @param {string} filename - Asset filename. - * @param {Map} moduleCache - Cache for processed modules. + * @param {string} filename - Asset filename. + * @param {Map} moduleCache - Cache for processed modules. */ async #processAsset( compilation, filename, moduleCache ) { const t0 = Date.now(); diff --git a/projects/js-packages/i18n-check-webpack-plugin/src/I18nSafeMangleExportsPlugin.js b/projects/js-packages/i18n-check-webpack-plugin/src/I18nSafeMangleExportsPlugin.js index 5ba6b32dd8bf2..da868376a0580 100644 --- a/projects/js-packages/i18n-check-webpack-plugin/src/I18nSafeMangleExportsPlugin.js +++ b/projects/js-packages/i18n-check-webpack-plugin/src/I18nSafeMangleExportsPlugin.js @@ -26,7 +26,7 @@ const { assignDeterministicIds } = require( 'webpack/lib/ids/IdHelpers' ); /** * Determine if we can mangle. * @param {ExportsInfo} exportsInfo - exports info - * @returns {boolean} mangle is possible + * @return {boolean} mangle is possible */ const canMangle = exportsInfo => { if ( exportsInfo.otherExportsInfo.getUsed( undefined ) !== UsageState.Unused ) { @@ -45,10 +45,10 @@ const canMangle = exportsInfo => { const comparator = compareSelect( e => e.name, compareStringsNumeric ); /** * Mangle exports. - * @param {boolean} deterministic - use deterministic names - * @param {ExportsInfo} exportsInfo - exports info - * @param {boolean | undefined} isNamespace - is namespace object - * @returns {void} + * @param {boolean} deterministic - use deterministic names + * @param {ExportsInfo} exportsInfo - exports info + * @param {boolean | undefined} isNamespace - is namespace object + * @return {void} */ const mangleExportsInfo = ( deterministic, exportsInfo, isNamespace ) => { if ( ! canMangle( exportsInfo ) ) { @@ -153,7 +153,7 @@ class MangleExportsPlugin { /** * Apply the plugin * @param {Compiler} compiler - the compiler instance - * @returns {void} + * @return {void} */ apply( compiler ) { const { _deterministic: deterministic } = this; diff --git a/projects/js-packages/i18n-check-webpack-plugin/tests/__snapshots__/build.test.js.snap b/projects/js-packages/i18n-check-webpack-plugin/tests/__snapshots__/build.test.js.snap index 8b8d785c2dc7f..c01f8541166ad 100644 --- a/projects/js-packages/i18n-check-webpack-plugin/tests/__snapshots__/build.test.js.snap +++ b/projects/js-packages/i18n-check-webpack-plugin/tests/__snapshots__/build.test.js.snap @@ -167,16 +167,16 @@ exports[`Webpack \`options-filter\`: Webpack build stats 1`] = ` { "errors": [ { - "message": "string/main.js:1:77: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", + "message": "string/main.js:1:76: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", }, { - "message": "string/main.js:1:187: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", + "message": "string/main.js:1:186: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", }, { - "message": "string/main.js:1:376: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", + "message": "string/main.js:1:374: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", }, { - "message": "string/main.js:1:490: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", + "message": "string/main.js:1:488: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", }, { "message": "string/main.js: Optimization seems to have broken the following translation strings: @@ -190,16 +190,16 @@ exports[`Webpack \`options-filter\`: Webpack build stats 1`] = ` { "errors": [ { - "message": "regex/main.js:1:77: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", + "message": "regex/main.js:1:76: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", }, { - "message": "regex/main.js:1:187: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", + "message": "regex/main.js:1:186: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", }, { - "message": "regex/main.js:1:376: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", + "message": "regex/main.js:1:374: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", }, { - "message": "regex/main.js:1:490: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", + "message": "regex/main.js:1:488: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", }, { "message": "regex/main.js: Optimization seems to have broken the following translation strings: @@ -213,16 +213,16 @@ exports[`Webpack \`options-filter\`: Webpack build stats 1`] = ` { "errors": [ { - "message": "function/main.js:1:77: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", + "message": "function/main.js:1:76: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", }, { - "message": "function/main.js:1:187: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", + "message": "function/main.js:1:186: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", }, { - "message": "function/main.js:1:376: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", + "message": "function/main.js:1:374: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", }, { - "message": "function/main.js:1:490: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", + "message": "function/main.js:1:488: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", }, { "message": "function/main.js: Optimization seems to have broken the following translation strings: @@ -236,16 +236,16 @@ exports[`Webpack \`options-filter\`: Webpack build stats 1`] = ` { "errors": [ { - "message": "array/main.js:1:77: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", + "message": "array/main.js:1:76: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", }, { - "message": "array/main.js:1:187: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", + "message": "array/main.js:1:186: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", }, { - "message": "array/main.js:1:376: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", + "message": "array/main.js:1:374: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", }, { - "message": "array/main.js:1:490: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", + "message": "array/main.js:1:488: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", }, { "message": "array/main.js: Optimization seems to have broken the following translation strings: @@ -259,16 +259,16 @@ exports[`Webpack \`options-filter\`: Webpack build stats 1`] = ` { "errors": [ { - "message": "undefined/main.js:1:77: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", + "message": "undefined/main.js:1:76: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", }, { - "message": "undefined/main.js:1:187: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", + "message": "undefined/main.js:1:186: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", }, { - "message": "undefined/main.js:1:376: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", + "message": "undefined/main.js:1:374: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", }, { - "message": "undefined/main.js:1:490: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", + "message": "undefined/main.js:1:488: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", }, { "message": "undefined/main.js: Optimization seems to have broken the following translation strings: @@ -289,19 +289,19 @@ exports[`Webpack \`options-filter\`: Webpack build stats 1`] = ` "errors": [ { "compilerPath": "string", - "message": "string/main.js:1:77: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", + "message": "string/main.js:1:76: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", }, { "compilerPath": "string", - "message": "string/main.js:1:187: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", + "message": "string/main.js:1:186: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", }, { "compilerPath": "string", - "message": "string/main.js:1:376: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", + "message": "string/main.js:1:374: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", }, { "compilerPath": "string", - "message": "string/main.js:1:490: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", + "message": "string/main.js:1:488: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", }, { "compilerPath": "string", @@ -311,19 +311,19 @@ exports[`Webpack \`options-filter\`: Webpack build stats 1`] = ` }, { "compilerPath": "regex", - "message": "regex/main.js:1:77: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", + "message": "regex/main.js:1:76: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", }, { "compilerPath": "regex", - "message": "regex/main.js:1:187: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", + "message": "regex/main.js:1:186: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", }, { "compilerPath": "regex", - "message": "regex/main.js:1:376: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", + "message": "regex/main.js:1:374: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", }, { "compilerPath": "regex", - "message": "regex/main.js:1:490: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", + "message": "regex/main.js:1:488: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", }, { "compilerPath": "regex", @@ -333,19 +333,19 @@ exports[`Webpack \`options-filter\`: Webpack build stats 1`] = ` }, { "compilerPath": "function", - "message": "function/main.js:1:77: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", + "message": "function/main.js:1:76: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", }, { "compilerPath": "function", - "message": "function/main.js:1:187: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", + "message": "function/main.js:1:186: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", }, { "compilerPath": "function", - "message": "function/main.js:1:376: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", + "message": "function/main.js:1:374: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", }, { "compilerPath": "function", - "message": "function/main.js:1:490: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", + "message": "function/main.js:1:488: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", }, { "compilerPath": "function", @@ -355,19 +355,19 @@ exports[`Webpack \`options-filter\`: Webpack build stats 1`] = ` }, { "compilerPath": "array", - "message": "array/main.js:1:77: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", + "message": "array/main.js:1:76: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", }, { "compilerPath": "array", - "message": "array/main.js:1:187: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", + "message": "array/main.js:1:186: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", }, { "compilerPath": "array", - "message": "array/main.js:1:376: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", + "message": "array/main.js:1:374: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", }, { "compilerPath": "array", - "message": "array/main.js:1:490: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", + "message": "array/main.js:1:488: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", }, { "compilerPath": "array", @@ -377,19 +377,19 @@ exports[`Webpack \`options-filter\`: Webpack build stats 1`] = ` }, { "compilerPath": "undefined", - "message": "undefined/main.js:1:77: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", + "message": "undefined/main.js:1:76: msgid argument is not a string literal: __(t?"arr is set":"arr is not set","domain")", }, { "compilerPath": "undefined", - "message": "undefined/main.js:1:187: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", + "message": "undefined/main.js:1:186: msgid argument is not a string literal: __(t?"func is set":"func is not set","domain")", }, { "compilerPath": "undefined", - "message": "undefined/main.js:1:376: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", + "message": "undefined/main.js:1:374: msgid argument is not a string literal: __(t?"regex is set":"regex is not set","domain")", }, { "compilerPath": "undefined", - "message": "undefined/main.js:1:490: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", + "message": "undefined/main.js:1:488: msgid argument is not a string literal: __(t?"string is set":"string is not set","domain")", }, { "compilerPath": "undefined", diff --git a/projects/js-packages/i18n-check-webpack-plugin/tests/build.test.js b/projects/js-packages/i18n-check-webpack-plugin/tests/build.test.js index ae95ae46015fd..2665ce69ab5e5 100644 --- a/projects/js-packages/i18n-check-webpack-plugin/tests/build.test.js +++ b/projects/js-packages/i18n-check-webpack-plugin/tests/build.test.js @@ -9,7 +9,7 @@ const configFixtures = fs.readdirSync( fixturesPath ).sort(); * Find all files in a path. * * @param {string} dir - Path. - * @returns {string[]} Promise resolving to a list of files. + * @return {string[]} Promise resolving to a list of files. */ function lsFiles( dir ) { const ret = []; diff --git a/projects/js-packages/i18n-loader-webpack-plugin/CHANGELOG.md b/projects/js-packages/i18n-loader-webpack-plugin/CHANGELOG.md index 8d72aaddcce4b..218908cefe6b5 100644 --- a/projects/js-packages/i18n-loader-webpack-plugin/CHANGELOG.md +++ b/projects/js-packages/i18n-loader-webpack-plugin/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.56] - 2024-08-29 +### Changed +- Updated package dependencies. [#39111] + +## [2.0.55] - 2024-08-21 +### Changed +- Internal updates. + ## [2.0.54] - 2024-08-15 ### Changed - Updated package dependencies. [#38662] @@ -245,6 +253,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Initial release. +[2.0.56]: https://github.com/Automattic/i18n-loader-webpack-plugin/compare/v2.0.55...v2.0.56 +[2.0.55]: https://github.com/Automattic/i18n-loader-webpack-plugin/compare/v2.0.54...v2.0.55 [2.0.54]: https://github.com/Automattic/i18n-loader-webpack-plugin/compare/v2.0.53...v2.0.54 [2.0.53]: https://github.com/Automattic/i18n-loader-webpack-plugin/compare/v2.0.52...v2.0.53 [2.0.52]: https://github.com/Automattic/i18n-loader-webpack-plugin/compare/v2.0.51...v2.0.52 diff --git a/projects/js-packages/i18n-loader-webpack-plugin/package.json b/projects/js-packages/i18n-loader-webpack-plugin/package.json index 12965e26eee2c..2b757aee168a3 100644 --- a/projects/js-packages/i18n-loader-webpack-plugin/package.json +++ b/projects/js-packages/i18n-loader-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/i18n-loader-webpack-plugin", - "version": "2.0.54", + "version": "2.0.56", "description": "A Webpack plugin to load WordPress i18n when Webpack lazy-loads a bundle.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/i18n-loader-webpack-plugin/#readme", "bugs": { @@ -23,11 +23,11 @@ "@wordpress/dependency-extraction-webpack-plugin": "6.5.0", "@wordpress/i18n": "5.5.0", "jest": "29.7.0", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "peerDependencies": { - "webpack": "^5.29.0" + "webpack": "^5.94.0" }, "exports": { ".": "./src/I18nLoaderPlugin.js" diff --git a/projects/js-packages/i18n-loader-webpack-plugin/src/I18nLoaderPlugin.js b/projects/js-packages/i18n-loader-webpack-plugin/src/I18nLoaderPlugin.js index 2417c76c2e82a..4eb3974b915d4 100644 --- a/projects/js-packages/i18n-loader-webpack-plugin/src/I18nLoaderPlugin.js +++ b/projects/js-packages/i18n-loader-webpack-plugin/src/I18nLoaderPlugin.js @@ -148,7 +148,7 @@ class I18nLoaderPlugin { /** * Fetch stuff we need for the various callbacks. * - * @returns {object} Stuff. + * @return {object} Stuff. */ function getStuff() { const loaderModule = compilation.moduleGraph.getModule( loaderModuleDep ); diff --git a/projects/js-packages/i18n-loader-webpack-plugin/src/I18nLoaderRuntimeModule.js b/projects/js-packages/i18n-loader-webpack-plugin/src/I18nLoaderRuntimeModule.js index 413a9ea1887e2..d6dfc7d77ebbb 100644 --- a/projects/js-packages/i18n-loader-webpack-plugin/src/I18nLoaderRuntimeModule.js +++ b/projects/js-packages/i18n-loader-webpack-plugin/src/I18nLoaderRuntimeModule.js @@ -21,7 +21,7 @@ class I18nLoaderRuntimeModule extends webpack.RuntimeModule { * Get the path for a chunk. * * @param {webpack.Chunk} chunk - Chunk. - * @returns {string} Chunk path + * @return {string} Chunk path */ getChunkPath( chunk ) { const compilation = this.compilation; @@ -44,7 +44,7 @@ class I18nLoaderRuntimeModule extends webpack.RuntimeModule { /** * Get set of chunks we need to care about. * - * @returns {Set} Chunk IDs. + * @return {Set} Chunk IDs. */ getChunks() { const ret = new Set(); diff --git a/projects/js-packages/i18n-loader-webpack-plugin/tests/build.test.js b/projects/js-packages/i18n-loader-webpack-plugin/tests/build.test.js index 73011112c665d..54cf024e78d62 100644 --- a/projects/js-packages/i18n-loader-webpack-plugin/tests/build.test.js +++ b/projects/js-packages/i18n-loader-webpack-plugin/tests/build.test.js @@ -8,9 +8,9 @@ require( './globals' ); * Extract a section from a string. * * @param {string} content - String to extract from. - * @param {string} start - Starting line. - * @param {string} end - Line to end before. - * @returns {string|null} Section. + * @param {string} start - Starting line. + * @param {string} end - Line to end before. + * @return {string|null} Section. */ function extractSection( content, start, end ) { const s = content.indexOf( '\n' + start ); @@ -25,7 +25,7 @@ function extractSection( content, start, end ) { * Find all files in a path. * * @param {string} dir - Path. - * @returns {string[]} Promise resolving to a list of files. + * @return {string[]} Promise resolving to a list of files. */ function lsFiles( dir ) { const ret = []; diff --git a/projects/js-packages/i18n-loader-webpack-plugin/tests/globals.js b/projects/js-packages/i18n-loader-webpack-plugin/tests/globals.js index 70e2d97c0bb58..df1fb398b49dc 100644 --- a/projects/js-packages/i18n-loader-webpack-plugin/tests/globals.js +++ b/projects/js-packages/i18n-loader-webpack-plugin/tests/globals.js @@ -11,9 +11,9 @@ class I18nLoader { * Actually just returns a promise from `this.expect`, if any, * or throws an error. * - * @param {string} path - Path being "downloaded". + * @param {string} path - Path being "downloaded". * @param {string} domain - Text domain. - * @returns {Promise} Promise. + * @return {Promise} Promise. */ downloadI18n( path, domain ) { const ret = this.expect[ path ]; @@ -46,7 +46,7 @@ class I18nLoader { * Mock an error. * * @param {string} path - Path. - * @param {Error} err - Error. + * @param {Error} err - Error. */ expectError = ( path, err ) => { this.expect[ path ] = () => { diff --git a/projects/js-packages/idc/CHANGELOG.md b/projects/js-packages/idc/CHANGELOG.md index 8d6696c72a03f..72a6081ee7e1d 100644 --- a/projects/js-packages/idc/CHANGELOG.md +++ b/projects/js-packages/idc/CHANGELOG.md @@ -2,6 +2,14 @@ ### This is a list detailing changes for the Jetpack RNA IDC package releases. +## 0.11.9 - 2024-08-29 +### Changed +- Internal updates. + +## 0.11.8 - 2024-08-21 +### Changed +- Internal updates. + ## 0.11.7 - 2024-08-15 ### Changed - Updated package dependencies. [#38662] diff --git a/projects/js-packages/idc/components/card-fresh/index.jsx b/projects/js-packages/idc/components/card-fresh/index.jsx index 90cfb8f48a70c..055b019f6924d 100644 --- a/projects/js-packages/idc/components/card-fresh/index.jsx +++ b/projects/js-packages/idc/components/card-fresh/index.jsx @@ -14,7 +14,7 @@ import ErrorMessage from '../error-message'; * Render the error message. * * @param {string} supportURL - The support page URL. - * @returns {React.Component} The error message. + * @return {React.Component} The error message. */ const renderError = supportURL => { return ( @@ -49,7 +49,7 @@ const renderComparisonUrls = ( wpcomHostName, currentHostName ) => { * The "start fresh" card. * * @param {object} props - The properties. - * @returns {React.Component} The `ConnectScreen` component. + * @return {React.Component} The `ConnectScreen` component. */ const CardFresh = props => { const { diff --git a/projects/js-packages/idc/components/card-migrate/index.jsx b/projects/js-packages/idc/components/card-migrate/index.jsx index 9c719764dbf61..57f1e55e0710b 100644 --- a/projects/js-packages/idc/components/card-migrate/index.jsx +++ b/projects/js-packages/idc/components/card-migrate/index.jsx @@ -14,7 +14,7 @@ import ErrorMessage from '../error-message'; * Render the error message. * * @param {string} supportURL - The support page URL. - * @returns {React.Component} The error message. + * @return {React.Component} The error message. */ const renderError = supportURL => { return ( @@ -39,7 +39,7 @@ const renderError = supportURL => { * The "migrate" card. * * @param {object} props - The properties. - * @returns {React.Component} The `ConnectScreen` component. + * @return {React.Component} The `ConnectScreen` component. */ const CardMigrate = props => { const wpcomHostName = extractHostname( props.wpcomHomeUrl ); diff --git a/projects/js-packages/idc/components/idc-screen/index.jsx b/projects/js-packages/idc/components/idc-screen/index.jsx index 2ba3594bda4ac..0336fc13345e1 100644 --- a/projects/js-packages/idc/components/idc-screen/index.jsx +++ b/projects/js-packages/idc/components/idc-screen/index.jsx @@ -14,7 +14,7 @@ import IDCScreenVisual from './visual'; * The IDC screen component. * * @param {object} props - The properties. - * @returns {React.Component} The `ConnectScreen` component. + * @return {React.Component} The `ConnectScreen` component. */ const IDCScreen = props => { const { @@ -55,11 +55,11 @@ const IDCScreen = props => { initializeAnalytics( tracksEventData, tracksUserData ); if ( tracksEventData ) { - if ( tracksEventData.hasOwnProperty( 'isAdmin' ) && tracksEventData.isAdmin ) { + if ( Object.hasOwn( tracksEventData, 'isAdmin' ) && tracksEventData.isAdmin ) { trackAndBumpMCStats( 'notice_view' ); } else { trackAndBumpMCStats( 'non_admin_notice_view', { - page: tracksEventData.hasOwnProperty( 'currentScreen' ) + page: Object.hasOwn( tracksEventData, 'currentScreen' ) ? tracksEventData.currentScreen : false, } ); diff --git a/projects/js-packages/idc/components/idc-screen/screen-main.jsx b/projects/js-packages/idc/components/idc-screen/screen-main.jsx index 098a11c8d3f28..8203832de09c8 100644 --- a/projects/js-packages/idc/components/idc-screen/screen-main.jsx +++ b/projects/js-packages/idc/components/idc-screen/screen-main.jsx @@ -13,7 +13,7 @@ import SafeMode from '../safe-mode'; * Retrieve the main screen body. * * @param {object} props - The properties. - * @returns {React.Component} The ScreenMain component. + * @return {React.Component} The ScreenMain component. */ const ScreenMain = props => { const { diff --git a/projects/js-packages/idc/components/idc-screen/screen-migrated.jsx b/projects/js-packages/idc/components/idc-screen/screen-migrated.jsx index abcc5dd7094e5..3237deee40526 100644 --- a/projects/js-packages/idc/components/idc-screen/screen-migrated.jsx +++ b/projects/js-packages/idc/components/idc-screen/screen-migrated.jsx @@ -11,7 +11,7 @@ import extractHostname from '../../tools/extract-hostname'; * Retrieve the migrated screen body. * * @param {object} props - The properties. - * @returns {React.Component} The ScreenMigrated component. + * @return {React.Component} The ScreenMigrated component. */ const ScreenMigrated = props => { const { finishCallback = () => {}, isFinishing = false, customContent = {} } = props; diff --git a/projects/js-packages/idc/components/idc-screen/screen-non-admin.jsx b/projects/js-packages/idc/components/idc-screen/screen-non-admin.jsx index 9784f244dd574..c78c3d4dc1f67 100644 --- a/projects/js-packages/idc/components/idc-screen/screen-non-admin.jsx +++ b/projects/js-packages/idc/components/idc-screen/screen-non-admin.jsx @@ -9,7 +9,7 @@ import customContentShape from '../../tools/custom-content-shape'; * Retrieve the main screen body. * * @param {object} props - The properties. - * @returns {React.Component} The ScreenMain component. + * @return {React.Component} The ScreenMain component. */ const ScreenNonAdmin = props => { const { customContent = {} } = props; diff --git a/projects/js-packages/idc/components/safe-mode/index.jsx b/projects/js-packages/idc/components/safe-mode/index.jsx index d021f44c5c8bd..db15094424d8d 100644 --- a/projects/js-packages/idc/components/safe-mode/index.jsx +++ b/projects/js-packages/idc/components/safe-mode/index.jsx @@ -17,9 +17,9 @@ import './style.scss'; /** * Render the "Stay safe" button. * - * @param {Function} callback - Button click callback. - * @param {boolean} isDisabled - Whether the button should be disabled. - * @returns {React.Component} - The rendered output. + * @param {Function} callback - Button click callback. + * @param {boolean} isDisabled - Whether the button should be disabled. + * @return {React.Component} - The rendered output. */ const renderStaySafeButton = ( callback, isDisabled ) => { @@ -41,7 +41,7 @@ const renderStaySafeButton = ( callback, isDisabled ) => { /** * Render the "staying safe" line. * - * @returns {React.Component} - The rendered output. + * @return {React.Component} - The rendered output. */ const renderStayingSafe = () => { return ( @@ -56,7 +56,7 @@ const renderStayingSafe = () => { * Render the error message. * * @param {string} supportURL - The support page URL. - * @returns {React.Component} The error message. + * @return {React.Component} The error message. */ const renderError = supportURL => { return ( diff --git a/projects/js-packages/idc/hooks/use-migration-finished.jsx b/projects/js-packages/idc/hooks/use-migration-finished.jsx index 4b4582833474d..b76afa51f4b7f 100644 --- a/projects/js-packages/idc/hooks/use-migration-finished.jsx +++ b/projects/js-packages/idc/hooks/use-migration-finished.jsx @@ -3,7 +3,7 @@ import { useCallback, useState } from 'react'; /** * Custom hook to handle finishing migration action. * - * @returns {{isFinishingMigration: boolean, finishMigrationCallback: ((function(): void)|*)}} Hook values. + * @return {{isFinishingMigration: boolean, finishMigrationCallback: ((function(): void)|*)}} Hook values. */ export default () => { const [ isFinishingMigration, setIsFinishingMigration ] = useState( false ); diff --git a/projects/js-packages/idc/hooks/use-migration.jsx b/projects/js-packages/idc/hooks/use-migration.jsx index c1b0dcfeb649d..15c2e3420bc33 100644 --- a/projects/js-packages/idc/hooks/use-migration.jsx +++ b/projects/js-packages/idc/hooks/use-migration.jsx @@ -8,7 +8,7 @@ import trackAndBumpMCStats from '../tools/tracking'; * Custom hook to handle the migration action. * * @param {Function} onMigrated - The callback to be called when migration has completed. - * @returns {{isMigrating: boolean, migrateCallback: ((function(): void)|*)}} Hook values. + * @return {{isMigrating: boolean, migrateCallback: ((function(): void)|*)}} Hook values. */ export default onMigrated => { const [ isMigrating, setIsMigrating ] = useState( false ); diff --git a/projects/js-packages/idc/hooks/use-start-fresh.jsx b/projects/js-packages/idc/hooks/use-start-fresh.jsx index 34a03e14d9561..7016511c7a305 100644 --- a/projects/js-packages/idc/hooks/use-start-fresh.jsx +++ b/projects/js-packages/idc/hooks/use-start-fresh.jsx @@ -8,7 +8,7 @@ import trackAndBumpMCStats from '../tools/tracking'; * Custom hook to handle the migration action. * * @param {string} redirectUri - WP-admin URI to redirect user to after reconnecting. - * @returns {{isStartingFresh: boolean, startFreshCallback: ((function(): void)|*)}} Hook values. + * @return {{isStartingFresh: boolean, startFreshCallback: ((function(): void)|*)}} Hook values. */ export default redirectUri => { const [ isStartingFresh, setIsStartingFresh ] = useState( false ); diff --git a/projects/js-packages/idc/package.json b/projects/js-packages/idc/package.json index 0da320891618e..6b9b7b6bece08 100644 --- a/projects/js-packages/idc/package.json +++ b/projects/js-packages/idc/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/jetpack-idc", - "version": "0.11.7", + "version": "0.11.9", "description": "Jetpack Connection Component", "author": "Automattic", "license": "GPL-2.0-or-later", diff --git a/projects/js-packages/idc/tools/extract-hostname.jsx b/projects/js-packages/idc/tools/extract-hostname.jsx index 8563f11abe37b..5b99fd4132dea 100644 --- a/projects/js-packages/idc/tools/extract-hostname.jsx +++ b/projects/js-packages/idc/tools/extract-hostname.jsx @@ -2,7 +2,7 @@ * Extract hostname from an URL if needed. * * @param {string} url - The URL to extract hostname from. - * @returns {string} The hostname extracted from the URL. + * @return {string} The hostname extracted from the URL. */ const extractHostname = url => /^https?:\/\//.test( url ) ? new URL( url ).hostname : url.replace( /\/$/, '' ); diff --git a/projects/js-packages/idc/tools/tracking.jsx b/projects/js-packages/idc/tools/tracking.jsx index 8f405fe4d725a..315f919dd834b 100644 --- a/projects/js-packages/idc/tools/tracking.jsx +++ b/projects/js-packages/idc/tools/tracking.jsx @@ -4,23 +4,23 @@ import analytics from '@automattic/jetpack-analytics'; * Initialize the analytics object. * * @param {object} tracksEventData - Tracks data. - * @param {object} tracksUserData - User data. + * @param {object} tracksUserData - User data. */ export function initializeAnalytics( tracksEventData, tracksUserData ) { if ( tracksUserData && - tracksUserData.hasOwnProperty( 'userid' ) && - tracksUserData.hasOwnProperty( 'username' ) + Object.hasOwn( tracksUserData, 'userid' ) && + Object.hasOwn( tracksUserData, 'username' ) ) { analytics.initialize( tracksUserData.userid, tracksUserData.username ); } if ( tracksEventData ) { - if ( tracksEventData.hasOwnProperty( 'blogID' ) ) { + if ( Object.hasOwn( tracksEventData, 'blogID' ) ) { analytics.assignSuperProps( { blog_id: tracksEventData.blogID } ); } - if ( tracksEventData.hasOwnProperty( 'platform' ) ) { + if ( Object.hasOwn( tracksEventData, 'platform' ) ) { analytics.assignSuperProps( { platform: tracksEventData.platform } ); } } @@ -35,7 +35,7 @@ export function initializeAnalytics( tracksEventData, tracksUserData ) { * Tracks Will be prefixed by 'jetpack_idc_' and use underscores. * MC Will not be prefixed, and will use dashes. * - * @param {string} eventName - name. + * @param {string} eventName - name. * @param {object} extraProps - extra props. */ export default function trackAndBumpMCStats( eventName, extraProps = {} ) { diff --git a/projects/js-packages/image-guide/CHANGELOG.md b/projects/js-packages/image-guide/CHANGELOG.md index e773c91e2dbfb..51f3534157e22 100644 --- a/projects/js-packages/image-guide/CHANGELOG.md +++ b/projects/js-packages/image-guide/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.5.11] - 2024-08-29 +### Changed +- Updated package dependencies. [#38287] + +### Fixed +- Fix: Handle uncaught exception for images with empty or no src attributes. [#39024] +- Fixed a bug where image guide would show up for svg images. [#38329] + ## [0.5.10] - 2024-07-10 ### Changed - Updated package dependencies. [#38092] @@ -113,6 +121,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed - Minor package.json change - removing private entry. +[0.5.11]: https://github.com/Automattic/jetpack-image-guide/compare/v0.5.10...v0.5.11 [0.5.10]: https://github.com/Automattic/jetpack-image-guide/compare/v0.5.9...v0.5.10 [0.5.9]: https://github.com/Automattic/jetpack-image-guide/compare/v0.5.8...v0.5.9 [0.5.8]: https://github.com/Automattic/jetpack-image-guide/compare/v0.5.7...v0.5.8 diff --git a/projects/js-packages/image-guide/changelog/update-fix-image-guide-svgs b/projects/js-packages/image-guide/changelog/update-fix-image-guide-svgs deleted file mode 100644 index 694da4b8779ef..0000000000000 --- a/projects/js-packages/image-guide/changelog/update-fix-image-guide-svgs +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fixed - -Fixed a bug where image guide would show up for svg images. diff --git a/projects/js-packages/image-guide/composer.json b/projects/js-packages/image-guide/composer.json index e902e85e94aae..a8736b1eaa47d 100644 --- a/projects/js-packages/image-guide/composer.json +++ b/projects/js-packages/image-guide/composer.json @@ -5,7 +5,7 @@ "license": "GPL-2.0-or-later", "require": {}, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "autoload": { diff --git a/projects/js-packages/image-guide/package.json b/projects/js-packages/image-guide/package.json index 3c2bfa39a1d18..f88b9d1c663ed 100644 --- a/projects/js-packages/image-guide/package.json +++ b/projects/js-packages/image-guide/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/jetpack-image-guide", - "version": "0.5.11-alpha", + "version": "0.5.11", "description": "Go through the dom to analyze image size on screen vs actual file size.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/image-guide/#readme", "type": "module", @@ -56,7 +56,7 @@ "svelte-preprocess": "6.0.2", "tslib": "2.5.0", "typescript": "5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "exports": { diff --git a/projects/js-packages/image-guide/src/find-image-elements.ts b/projects/js-packages/image-guide/src/find-image-elements.ts index 802082c7a8020..0e7a0af0508ec 100644 --- a/projects/js-packages/image-guide/src/find-image-elements.ts +++ b/projects/js-packages/image-guide/src/find-image-elements.ts @@ -9,7 +9,16 @@ import { MeasurableImage, type FetchFn } from './MeasurableImage.js'; export function findMeasurableElements( nodes: Element[] ): HTMLElement[] | HTMLImageElement[] { return nodes.filter( ( el ): el is HTMLElement | HTMLImageElement => { if ( el instanceof HTMLImageElement ) { - if ( isSvgUrl( el.src ) ) { + // Handle img tags with empty or no src attributes. + if ( ! el.src.trim() ) { + return false; + } + + try { + if ( isSvgUrl( el.src ) ) { + return false; + } + } catch ( e ) { return false; } return true; @@ -58,6 +67,13 @@ export function backgroundImageSource( node: HTMLElement ) { return null; } +/** + * Check if a URL is an SVG. + * + * @param {string} srcUrl - The URL to check + * @throws {Error} - If the URL is not valid. + * @return {boolean} - true if the URL is an SVG + */ function isSvgUrl( srcUrl: string ): boolean { const url = new URL( srcUrl ); return url.pathname.toLowerCase().endsWith( '.svg' ); diff --git a/projects/js-packages/licensing/CHANGELOG.md b/projects/js-packages/licensing/CHANGELOG.md index 13d02df02ff84..6480d9800ec9d 100644 --- a/projects/js-packages/licensing/CHANGELOG.md +++ b/projects/js-packages/licensing/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.12.26 - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + +## 0.12.25 - 2024-08-21 +### Changed +- Internal updates. + +## 0.12.24 - 2024-08-19 +### Fixed +- Lossless image optimization for images (should improve performance with no visible changes). [#38750] + ## 0.12.23 - 2024-08-15 ### Changed - Updated package dependencies. [#38662] diff --git a/projects/js-packages/licensing/components/activation-screen-controls/index.jsx b/projects/js-packages/licensing/components/activation-screen-controls/index.jsx index 37f455e0ef6c0..fa5cb83509285 100644 --- a/projects/js-packages/licensing/components/activation-screen-controls/index.jsx +++ b/projects/js-packages/licensing/components/activation-screen-controls/index.jsx @@ -12,12 +12,12 @@ import './style.scss'; /** * The Activation Screen Controls component. * - * @param {object} props -- The properties. + * @param {object} props -- The properties. * @param {Function} props.className -- class name of the input control. - * @param {boolean} props.disabled -- determines if input control is disabled. - * @param {string} props.value -- the license code to edit or submit - * @param {Function} props.onChange -- function to handle changes to the value. - * @returns {React.Component} The `ManualLicenseKeyInput` component. + * @param {boolean} props.disabled -- determines if input control is disabled. + * @param {string} props.value -- the license code to edit or submit + * @param {Function} props.onChange -- function to handle changes to the value. + * @return {React.Component} The `ManualLicenseKeyInput` component. */ const ManualLicenseKeyInput = props => { const { className, disabled, onChange, value } = props; @@ -36,13 +36,13 @@ const ManualLicenseKeyInput = props => { /** * The Activation Screen Controls component. * - * @param {object} props -- The properties. - * @param {Function} props.className -- class name of the input control. - * @param {Array} props.availableLicenses -- list of available license keys for activation. - * @param {boolean} props.disabled -- determines if input control is disabled. - * @param {string} props.value -- the license code to edit or submit - * @param {Function} props.onChange -- function to handle changes to the value. - * @returns {React.Component} The `SelectableLicenseKeyInput` component. + * @param {object} props -- The properties. + * @param {Function} props.className -- class name of the input control. + * @param {Array} props.availableLicenses -- list of available license keys for activation. + * @param {boolean} props.disabled -- determines if input control is disabled. + * @param {string} props.value -- the license code to edit or submit + * @param {Function} props.onChange -- function to handle changes to the value. + * @return {React.Component} The `SelectableLicenseKeyInput` component. */ const SelectableLicenseKeyInput = props => { const { className, availableLicenses, disabled, onChange, value } = props; @@ -121,16 +121,16 @@ const SelectableLicenseKeyInput = props => { /** * The Activation Screen Controls component. * - * @param {object} props -- The properties. - * @param {Function} props.activateLicense -- function to handle submitting a license - * @param {Array} props.availableLicenses -- list of available license keys for activation. - * @param {boolean} props.fetchingAvailableLicenses -- status to determine if the screen is fetching available license keys. - * @param {boolean} props.isActivating -- should the controls be disabled - * @param {string} props.license -- the license code to edit or submit - * @param {?string} props.licenseError -- any error that occurred while activating a license - * @param {Function} props.onLicenseChange -- function to handle changes to license - * @param {string} props.siteUrl -- the url of the site - * @returns {React.Component} The `ActivationScreenControls` component. + * @param {object} props -- The properties. + * @param {Function} props.activateLicense -- function to handle submitting a license + * @param {Array} props.availableLicenses -- list of available license keys for activation. + * @param {boolean} props.fetchingAvailableLicenses -- status to determine if the screen is fetching available license keys. + * @param {boolean} props.isActivating -- should the controls be disabled + * @param {string} props.license -- the license code to edit or submit + * @param {?string} props.licenseError -- any error that occurred while activating a license + * @param {Function} props.onLicenseChange -- function to handle changes to license + * @param {string} props.siteUrl -- the url of the site + * @return {React.Component} The `ActivationScreenControls` component. */ const ActivationScreenControls = props => { const { diff --git a/projects/js-packages/licensing/components/activation-screen-illustration/index.jsx b/projects/js-packages/licensing/components/activation-screen-illustration/index.jsx index 83114ef53fc51..c2451f53efe51 100644 --- a/projects/js-packages/licensing/components/activation-screen-illustration/index.jsx +++ b/projects/js-packages/licensing/components/activation-screen-illustration/index.jsx @@ -9,10 +9,10 @@ import './style.scss'; /** * The Activation Screen Illustration component. * - * @param {object} props -- The properties. - * @param {string} props.imageUrl -- The assets base URL. + * @param {object} props -- The properties. + * @param {string} props.imageUrl -- The assets base URL. * @param {boolean} props.showSupportLink -- The assets base URL. - * @returns {React.Component} The `ActivationScreenIllustration` component. + * @return {React.Component} The `ActivationScreenIllustration` component. */ const ActivationScreenIllustration = props => { const { imageUrl, showSupportLink = false } = props; diff --git a/projects/js-packages/licensing/components/activation-screen-success-info/index.jsx b/projects/js-packages/licensing/components/activation-screen-success-info/index.jsx index 7f73bb4c9b24f..5a5e6c81910ca 100644 --- a/projects/js-packages/licensing/components/activation-screen-success-info/index.jsx +++ b/projects/js-packages/licensing/components/activation-screen-success-info/index.jsx @@ -10,12 +10,12 @@ import './style.scss'; /** * The Activation Screen Illustration component. * - * @param {object} props -- The properties. - * @param {number} props.productId -- The id of the product activated - * @param {string} props.siteRawUrl -- The url of the site - * @param {string} props.siteAdminUrl -- URL of the Jetpack Site Admin + * @param {object} props -- The properties. + * @param {number} props.productId -- The id of the product activated + * @param {string} props.siteRawUrl -- The url of the site + * @param {string} props.siteAdminUrl -- URL of the Jetpack Site Admin * @param {string} props.currentRecommendationsStep -- The current recommendation step - * @returns {React.Component} The `ActivationSuccessInfo` component. + * @return {React.Component} The `ActivationSuccessInfo` component. */ const ActivationSuccessInfo = props => { const { productId, siteRawUrl, siteAdminUrl, currentRecommendationsStep } = props; diff --git a/projects/js-packages/licensing/components/activation-screen-success-info/product-details/index.js b/projects/js-packages/licensing/components/activation-screen-success-info/product-details/index.js index e0c6107537bfb..7bbecf07e52b8 100644 --- a/projects/js-packages/licensing/components/activation-screen-success-info/product-details/index.js +++ b/projects/js-packages/licensing/components/activation-screen-success-info/product-details/index.js @@ -10,10 +10,10 @@ import './style.scss'; /** * The Jetpack Product Details component. * - * @param {object} props -- The properties. - * @param {number} props.productId -- The id of the product + * @param {object} props -- The properties. + * @param {number} props.productId -- The id of the product * @param {string} props.siteRawUrl -- The url of the site - * @returns {React.Component} The `JetpackProductDetails` component. + * @return {React.Component} The `JetpackProductDetails` component. */ const JetpackProductDetails = props => { const { productId, siteRawUrl } = props; diff --git a/projects/js-packages/licensing/components/activation-screen/index.jsx b/projects/js-packages/licensing/components/activation-screen/index.jsx index 970cecec545a0..760850f332fae 100644 --- a/projects/js-packages/licensing/components/activation-screen/index.jsx +++ b/projects/js-packages/licensing/components/activation-screen/index.jsx @@ -17,7 +17,7 @@ import './style.scss'; * attachLicenses has a particular result, which we reduce to the parts we care about here * * @param {(object|Array)} result -- the result from the attachLicenses request - * @returns {number} The activatedProductId from the result + * @return {number} The activatedProductId from the result * @throws Errors either from the API response or from any issues parsing the response */ const parseAttachLicensesResult = result => { @@ -45,14 +45,14 @@ const parseAttachLicensesResult = result => { /** * The Activation Screen component. * - * @param {object} props -- The properties. - * @param {Function?} props.onActivationSuccess -- A function to call on success. - * @param {string} props.siteRawUrl -- url of the Jetpack Site - * @param {string?} props.startingLicense -- pre-fill the license value - * @param {string} props.siteAdminUrl -- URL of the Jetpack Site Admin - * @param {string} props.currentRecommendationsStep -- The current recommendation step. - * @param {string} props.currentUser -- Current wpcom user info. - * @returns {React.Component} The `ActivationScreen` component. + * @param {object} props -- The properties. + * @param {Function?} props.onActivationSuccess -- A function to call on success. + * @param {string} props.siteRawUrl -- url of the Jetpack Site + * @param {string?} props.startingLicense -- pre-fill the license value + * @param {string} props.siteAdminUrl -- URL of the Jetpack Site Admin + * @param {string} props.currentRecommendationsStep -- The current recommendation step. + * @param {string} props.currentUser -- Current wpcom user info. + * @return {React.Component} The `ActivationScreen` component. */ const ActivationScreen = props => { const { diff --git a/projects/js-packages/licensing/components/activation-screen/utils.js b/projects/js-packages/licensing/components/activation-screen/utils.js index 46428a18dfc43..f11d7b04117f5 100644 --- a/projects/js-packages/licensing/components/activation-screen/utils.js +++ b/projects/js-packages/licensing/components/activation-screen/utils.js @@ -55,7 +55,7 @@ const PRODUCT_GROUPS = { * Get the group of a product given a product Id. * * @param {number} productId -- The id of the product - * @returns {string} The group of the product. + * @return {string} The group of the product. */ export function getProductGroup( productId ) { return ( diff --git a/projects/js-packages/licensing/components/golden-token-modal/index.jsx b/projects/js-packages/licensing/components/golden-token-modal/index.jsx index 6b5bae9fd2838..5cc4c01896c03 100644 --- a/projects/js-packages/licensing/components/golden-token-modal/index.jsx +++ b/projects/js-packages/licensing/components/golden-token-modal/index.jsx @@ -21,12 +21,12 @@ const onModalCloseDefault = event => { /** * Component that displays a golden token experience. * - * @param {object} props - Component props. - * @param {Function} props.redeemClick - Callback function to handle redeem click. - * @param {object} props.displayName - Connected user data. - * @param {Function} props.onModalClose - Callback function to handle module closure. + * @param {object} props - Component props. + * @param {Function} props.redeemClick - Callback function to handle redeem click. + * @param {object} props.displayName - Connected user data. + * @param {Function} props.onModalClose - Callback function to handle module closure. * @param {Function} props.tokenRedeemed - If their token is already redeemed. - * @returns {React.Component} - GoldenToken component. + * @return {React.Component} - GoldenToken component. */ function GoldenTokenModal( { redeemClick, diff --git a/projects/js-packages/licensing/components/jetpack-license-activation-with-lock.png b/projects/js-packages/licensing/components/jetpack-license-activation-with-lock.png index ea421dc01db46..bc30500273cdb 100644 Binary files a/projects/js-packages/licensing/components/jetpack-license-activation-with-lock.png and b/projects/js-packages/licensing/components/jetpack-license-activation-with-lock.png differ diff --git a/projects/js-packages/licensing/components/jetpack-license-activation-with-success.png b/projects/js-packages/licensing/components/jetpack-license-activation-with-success.png index a2562d9b7e30f..3a84fe15f0670 100644 Binary files a/projects/js-packages/licensing/components/jetpack-license-activation-with-success.png and b/projects/js-packages/licensing/components/jetpack-license-activation-with-success.png differ diff --git a/projects/js-packages/licensing/composer.json b/projects/js-packages/licensing/composer.json index e94268c0e4b60..7c4dee7366c82 100644 --- a/projects/js-packages/licensing/composer.json +++ b/projects/js-packages/licensing/composer.json @@ -5,7 +5,7 @@ "license": "GPL-2.0-or-later", "require": {}, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "scripts": { diff --git a/projects/js-packages/licensing/hooks/use-active-plugins/index.js b/projects/js-packages/licensing/hooks/use-active-plugins/index.js index 2e9ec2c28a751..5b6cecc669e35 100644 --- a/projects/js-packages/licensing/hooks/use-active-plugins/index.js +++ b/projects/js-packages/licensing/hooks/use-active-plugins/index.js @@ -9,7 +9,7 @@ const fetchActivePlugins = async () => { /** * Hook to handle retrieving dismissed notices and dismissing a notice. * - * @returns {Array} An array of active plugins. + * @return {Array} An array of active plugins. */ export default function useActivePlugins() { const [ activePlugins, setActivePlugins ] = useState( [] ); diff --git a/projects/js-packages/licensing/package.json b/projects/js-packages/licensing/package.json index 0b2c91a127ff0..cf9cf23554365 100644 --- a/projects/js-packages/licensing/package.json +++ b/projects/js-packages/licensing/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-licensing", - "version": "0.12.23", + "version": "0.12.26", "description": "Jetpack licensing flow", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/licensing/#readme", "bugs": { diff --git a/projects/js-packages/partner-coupon/CHANGELOG.md b/projects/js-packages/partner-coupon/CHANGELOG.md index 8f3c02494e366..78508747a982b 100644 --- a/projects/js-packages/partner-coupon/CHANGELOG.md +++ b/projects/js-packages/partner-coupon/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.2.86 - 2024-08-21 +### Changed +- Internal updates. + +## 0.2.85 - 2024-08-19 +### Changed +- Update dependencies. [#38861] +- Updated package dependencies. [#38662] + ## 0.2.84 - 2024-08-12 ### Removed - Tests: Removed react-test-renderer. [#38755] diff --git a/projects/js-packages/partner-coupon/components/redeem-partner-coupon-post-connection/index.jsx b/projects/js-packages/partner-coupon/components/redeem-partner-coupon-post-connection/index.jsx index 3af8837d37225..bbf63d5bd88de 100644 --- a/projects/js-packages/partner-coupon/components/redeem-partner-coupon-post-connection/index.jsx +++ b/projects/js-packages/partner-coupon/components/redeem-partner-coupon-post-connection/index.jsx @@ -15,7 +15,7 @@ export const DISMISS_LS_ITEM_MAX_AGE = 3 * 24 * 60 * 60; // 3 days /** * Is partner coupon redeem CTA dismissed? * - * @returns {boolean} Is the redeem CTA dismissed? + * @return {boolean} Is the redeem CTA dismissed? */ function isDismissed() { const dismissedAt = localStorage.getItem( DISMISS_LS_ITEM_NAME ); @@ -33,7 +33,7 @@ function isDismissed() { /** * Dismiss partner coupon redeem CTA. * - * @returns {void} + * @return {void} */ function dismiss() { localStorage.setItem( DISMISS_LS_ITEM_NAME, new Date().getTime() ); diff --git a/projects/js-packages/partner-coupon/hooks.js b/projects/js-packages/partner-coupon/hooks.js index 9f8b5fcdcfd8c..da6edcfd21459 100644 --- a/projects/js-packages/partner-coupon/hooks.js +++ b/projects/js-packages/partner-coupon/hooks.js @@ -4,12 +4,12 @@ import { useCallback, useEffect } from 'react'; /** * Handle partner coupon redeem analytics and clicks. * - * @param {object} partnerCoupon - Partner coupon details. - * @param {string} siteRawUrl - Site's raw URL. - * @param {object} connectionStatus - Connection status. - * @param {boolean} tracksUserData - Should we track user data. - * @param {object} analytics - Analytics. - * @returns {Function} Click handler for coupon redemption. + * @param {object} partnerCoupon - Partner coupon details. + * @param {string} siteRawUrl - Site's raw URL. + * @param {object} connectionStatus - Connection status. + * @param {boolean} tracksUserData - Should we track user data. + * @param {object} analytics - Analytics. + * @return {Function} Click handler for coupon redemption. */ export function usePartnerCouponRedemption( partnerCoupon, diff --git a/projects/js-packages/partner-coupon/package.json b/projects/js-packages/partner-coupon/package.json index ed5f38855c2eb..812a0af4cefb1 100644 --- a/projects/js-packages/partner-coupon/package.json +++ b/projects/js-packages/partner-coupon/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-partner-coupon", - "version": "0.2.85-alpha", + "version": "0.2.86", "description": "This package aims to add components to make it easier to redeem partner coupons", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/partner-coupon/#readme", "bugs": { diff --git a/projects/js-packages/publicize-components/CHANGELOG.md b/projects/js-packages/publicize-components/CHANGELOG.md index 17d426280223d..a40b949dce544 100644 --- a/projects/js-packages/publicize-components/CHANGELOG.md +++ b/projects/js-packages/publicize-components/CHANGELOG.md @@ -5,6 +5,48 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.64.0] - 2024-08-29 +### Added +- Added share status info to Jetpack sidebar [#39073] +- Added usePostPrePublishValue hook [#39119] + +### Changed +- Social: Default to the current post ID for share status selector [#39112] +- Social: Updated the share status modal to render it globally [#39116] + +### Fixed +- Fixed a deadlock with media validation and media picker [#38933] + +## [0.63.0] - 2024-08-26 +### Added +- Added the new feature flag for the social share status [#39015] + +### Changed +- Moved PostPublishPanels component to publicize-components package [#39049] +- Social: Migrated shares data to the new script data [#38988] +- Updated package dependencies. [#39004] + +## [0.62.0] - 2024-08-21 +### Changed +- Social: Migrated the API paths from initial state to the new script data. [#38962] + +### Removed +- Social: Removed share limits UI and data logic. [#38904] + +## [0.61.0] - 2024-08-19 +### Added +- Added a description for the social modal. [#38927] + +### Changed +- Social: Migrated services list to the initial state. [#38924] [#38861] [#38662] [#38665] + +### Removed +- Remove the unused Advanced plan nudge. [#38926] + +### Fixed +- Fixed a ui issue with the toggle naming. [#38925] +- Lossless image optimization for images (should improve performance with no visible changes). [#38750] + ## [0.60.0] - 2024-08-12 ### Changed - Hid most of the actions and notices when sharing is off [#38801] @@ -831,6 +873,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Updated package dependencies. [#24470] +[0.64.0]: https://github.com/Automattic/jetpack-publicize-components/compare/v0.63.0...v0.64.0 +[0.63.0]: https://github.com/Automattic/jetpack-publicize-components/compare/v0.62.0...v0.63.0 +[0.62.0]: https://github.com/Automattic/jetpack-publicize-components/compare/v0.61.0...v0.62.0 +[0.61.0]: https://github.com/Automattic/jetpack-publicize-components/compare/v0.60.0...v0.61.0 [0.60.0]: https://github.com/Automattic/jetpack-publicize-components/compare/v0.59.0...v0.60.0 [0.59.0]: https://github.com/Automattic/jetpack-publicize-components/compare/v0.58.0...v0.59.0 [0.58.0]: https://github.com/Automattic/jetpack-publicize-components/compare/v0.57.0...v0.58.0 diff --git a/projects/js-packages/publicize-components/changelog/add-social-share-status-shares-modal b/projects/js-packages/publicize-components/changelog/add-social-share-status-shares-modal new file mode 100644 index 0000000000000..bf7d182e6814d --- /dev/null +++ b/projects/js-packages/publicize-components/changelog/add-social-share-status-shares-modal @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Add share status log modal to published posts diff --git a/projects/js-packages/publicize-components/changelog/fix-social-hide-share-status-when-no-connection-is-on b/projects/js-packages/publicize-components/changelog/fix-social-hide-share-status-when-no-connection-is-on new file mode 100644 index 0000000000000..4bc68b5f4acd1 --- /dev/null +++ b/projects/js-packages/publicize-components/changelog/fix-social-hide-share-status-when-no-connection-is-on @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Fixed share status being shown even if no connection is enabled diff --git a/projects/js-packages/publicize-components/changelog/fix-social-modal-dynamic-toggle b/projects/js-packages/publicize-components/changelog/fix-social-modal-dynamic-toggle deleted file mode 100644 index b2fa4f2dc7326..0000000000000 --- a/projects/js-packages/publicize-components/changelog/fix-social-modal-dynamic-toggle +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fixed - -Fixed a ui issue with the toggle naming diff --git a/projects/js-packages/publicize-components/changelog/renovate-wordpress-monorepo#2 b/projects/js-packages/publicize-components/changelog/renovate-wordpress-monorepo#2 deleted file mode 100644 index e9ddd505ace9a..0000000000000 --- a/projects/js-packages/publicize-components/changelog/renovate-wordpress-monorepo#2 +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: fixed -Comment: Fix apiFetch handler in unit test to handle `parse` option. - - diff --git a/projects/js-packages/publicize-components/composer.json b/projects/js-packages/publicize-components/composer.json index 02a3ba11be85b..3e31ce5907f6e 100644 --- a/projects/js-packages/publicize-components/composer.json +++ b/projects/js-packages/publicize-components/composer.json @@ -5,7 +5,7 @@ "license": "GPL-2.0-or-later", "require": {}, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "autoload": { diff --git a/projects/js-packages/publicize-components/index.ts b/projects/js-packages/publicize-components/index.ts index c24bfa53c11b8..16b6a042ff927 100644 --- a/projects/js-packages/publicize-components/index.ts +++ b/projects/js-packages/publicize-components/index.ts @@ -16,8 +16,7 @@ export { default as SocialImageGeneratorToggle } from './src/components/social-i export { default as TemplatePickerButton } from './src/components/social-image-generator/template-picker/button'; export { default as PublicizePanel } from './src/components/panel'; export { default as ReviewPrompt } from './src/components/review-prompt'; -export { default as PostPublishReviewPrompt } from './src/components/post-publish-review-prompt'; -export { default as PostPublishManualSharing } from './src/components/post-publish-manual-sharing'; +export { default as PostPublishPanels } from './src/components/post-publish-panels'; export { default as RefreshJetpackSocialSettingsWrapper } from './src/components/refresh-jetpack-social-settings'; export { default as ConnectionManagement } from './src/components/connection-management'; @@ -31,9 +30,9 @@ export * from './src/social-store'; export * from './src/utils'; export * from './src/components/share-post'; export * from './src/hooks/use-sync-post-data-to-store'; -export * from './src/components/share-limits-bar'; export * from './src/hooks/use-saving-post'; -export * from './src/hooks/use-share-limits'; export * from './src/hooks/use-post-meta'; export * from './src/components/share-buttons'; export * from './src/components/manage-connections-modal'; +export * from './src/utils/shares-data'; +export * from './src/components/global-modals'; diff --git a/projects/js-packages/publicize-components/package.json b/projects/js-packages/publicize-components/package.json index 62c109704e207..4235dbb072f2c 100644 --- a/projects/js-packages/publicize-components/package.json +++ b/projects/js-packages/publicize-components/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-publicize-components", - "version": "0.60.1-alpha", + "version": "0.64.0", "description": "A library of JS components required by the Publicize editor plugin", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/publicize-components/#readme", "bugs": { @@ -32,6 +32,7 @@ "@wordpress/components": "28.5.0", "@wordpress/compose": "7.5.0", "@wordpress/data": "10.5.0", + "@wordpress/date": "5.5.0", "@wordpress/edit-post": "8.5.0", "@wordpress/editor": "14.5.0", "@wordpress/element": "6.5.0", diff --git a/projects/js-packages/publicize-components/src/assets/connections-facebook.png b/projects/js-packages/publicize-components/src/assets/connections-facebook.png index de2e00744782d..88702bb1a10dd 100644 Binary files a/projects/js-packages/publicize-components/src/assets/connections-facebook.png and b/projects/js-packages/publicize-components/src/assets/connections-facebook.png differ diff --git a/projects/js-packages/publicize-components/src/assets/connections-instagram-business.png b/projects/js-packages/publicize-components/src/assets/connections-instagram-business.png index f4dedd427391a..8a9d029751212 100644 Binary files a/projects/js-packages/publicize-components/src/assets/connections-instagram-business.png and b/projects/js-packages/publicize-components/src/assets/connections-instagram-business.png differ diff --git a/projects/js-packages/publicize-components/src/assets/connections-linkedin.png b/projects/js-packages/publicize-components/src/assets/connections-linkedin.png index b7be697d0c9cb..58e58983b1811 100644 Binary files a/projects/js-packages/publicize-components/src/assets/connections-linkedin.png and b/projects/js-packages/publicize-components/src/assets/connections-linkedin.png differ diff --git a/projects/js-packages/publicize-components/src/assets/connections-nextdoor.png b/projects/js-packages/publicize-components/src/assets/connections-nextdoor.png index 28e2903d40718..48fc9877e610d 100644 Binary files a/projects/js-packages/publicize-components/src/assets/connections-nextdoor.png and b/projects/js-packages/publicize-components/src/assets/connections-nextdoor.png differ diff --git a/projects/js-packages/publicize-components/src/assets/connections-threads.png b/projects/js-packages/publicize-components/src/assets/connections-threads.png index 08af213096819..d000e12025b6d 100644 Binary files a/projects/js-packages/publicize-components/src/assets/connections-threads.png and b/projects/js-packages/publicize-components/src/assets/connections-threads.png differ diff --git a/projects/js-packages/publicize-components/src/assets/connections-tumblr.png b/projects/js-packages/publicize-components/src/assets/connections-tumblr.png index eb40c6a10cf5e..78324ad3977b6 100644 Binary files a/projects/js-packages/publicize-components/src/assets/connections-tumblr.png and b/projects/js-packages/publicize-components/src/assets/connections-tumblr.png differ diff --git a/projects/js-packages/publicize-components/src/components/connection-management/connection-info.tsx b/projects/js-packages/publicize-components/src/components/connection-management/connection-info.tsx index 1b64fab0a5727..eb86600155cd4 100644 --- a/projects/js-packages/publicize-components/src/components/connection-management/connection-info.tsx +++ b/projects/js-packages/publicize-components/src/components/connection-management/connection-info.tsx @@ -17,7 +17,7 @@ type ConnectionInfoProps = ConnectionStatusProps; * * @param {ConnectionInfoProps} props - component props * - * @returns {import('react').ReactNode} - React element + * @return {import('react').ReactNode} - React element */ export function ConnectionInfo( { connection, service }: ConnectionInfoProps ) { const [ isPanelOpen, togglePanel ] = useReducer( state => ! state, false ); diff --git a/projects/js-packages/publicize-components/src/components/connection-management/connection-name.tsx b/projects/js-packages/publicize-components/src/components/connection-management/connection-name.tsx index c77ab0ee8baf8..5259df0d9ea5b 100644 --- a/projects/js-packages/publicize-components/src/components/connection-management/connection-name.tsx +++ b/projects/js-packages/publicize-components/src/components/connection-management/connection-name.tsx @@ -14,7 +14,7 @@ type ConnectionNameProps = { * * @param {ConnectionNameProps} props - component props * - * @returns {import('react').ReactNode} - React element + * @return {import('react').ReactNode} - React element */ export function ConnectionName( { connection }: ConnectionNameProps ) { const isUpdating = useSelect( diff --git a/projects/js-packages/publicize-components/src/components/connection-management/connection-status.tsx b/projects/js-packages/publicize-components/src/components/connection-management/connection-status.tsx index 03177f511a97b..b8a3f254ae643 100644 --- a/projects/js-packages/publicize-components/src/components/connection-management/connection-status.tsx +++ b/projects/js-packages/publicize-components/src/components/connection-management/connection-status.tsx @@ -17,7 +17,7 @@ export type ConnectionStatusProps = { * * @param {ConnectionStatusProps} props - component props * - * @returns {import('react').ReactNode} - React element + * @return {import('react').ReactNode} - React element */ export function ConnectionStatus( { connection, service }: ConnectionStatusProps ) { if ( connection.status !== 'broken' ) { diff --git a/projects/js-packages/publicize-components/src/components/connection-management/disconnect.tsx b/projects/js-packages/publicize-components/src/components/connection-management/disconnect.tsx index c41a1ba2ec2c3..c4629fcd89912 100644 --- a/projects/js-packages/publicize-components/src/components/connection-management/disconnect.tsx +++ b/projects/js-packages/publicize-components/src/components/connection-management/disconnect.tsx @@ -18,7 +18,7 @@ export type DisconnectProps = { * * @param {DisconnectProps} props - component props * - * @returns {import('react').ReactNode} - React element + * @return {import('react').ReactNode} - React element */ export function Disconnect( { connection, diff --git a/projects/js-packages/publicize-components/src/components/connection-management/mark-as-shared.tsx b/projects/js-packages/publicize-components/src/components/connection-management/mark-as-shared.tsx index 2c959957e33f1..913a1c9b2016f 100644 --- a/projects/js-packages/publicize-components/src/components/connection-management/mark-as-shared.tsx +++ b/projects/js-packages/publicize-components/src/components/connection-management/mark-as-shared.tsx @@ -14,7 +14,7 @@ type MarkAsSharedProps = { * * @param {MarkAsSharedProps} props - component props * - * @returns {import('react').ReactNode} - React element + * @return {import('react').ReactNode} - React element */ export function MarkAsShared( { connection }: MarkAsSharedProps ) { const { updateConnectionById } = useDispatch( socialStore ); diff --git a/projects/js-packages/publicize-components/src/components/connection-management/reconnect.tsx b/projects/js-packages/publicize-components/src/components/connection-management/reconnect.tsx index 7dedd9865b39d..107fdc5240c10 100644 --- a/projects/js-packages/publicize-components/src/components/connection-management/reconnect.tsx +++ b/projects/js-packages/publicize-components/src/components/connection-management/reconnect.tsx @@ -18,7 +18,7 @@ export type ReconnectProps = { * * @param {ReconnectProps} props - component props * - * @returns {import('react').ReactNode} - React element + * @return {import('react').ReactNode} - React element */ export function Reconnect( { connection, service, variant = 'link' }: ReconnectProps ) { const { deleteConnectionById, setKeyringResult, openConnectionsModal, setReconnectingAccount } = diff --git a/projects/js-packages/publicize-components/src/components/connection/index.js b/projects/js-packages/publicize-components/src/components/connection/index.js index fbc3878fb5d45..9e5f895645f0d 100644 --- a/projects/js-packages/publicize-components/src/components/connection/index.js +++ b/projects/js-packages/publicize-components/src/components/connection/index.js @@ -20,7 +20,7 @@ class PublicizeConnection extends Component { * Displays a message when a connection requires reauthentication. We used this when migrating LinkedIn API usage from v1 to v2, * since the prevous OAuth1 tokens were incompatible with OAuth2. * - * @returns {object|?null} Notice about reauthentication + * @return {object|?null} Notice about reauthentication */ maybeDisplayLinkedInNotice = () => this.connectionNeedsReauth() && ( @@ -44,7 +44,7 @@ class PublicizeConnection extends Component { /** * Check whether the connection needs to be reauthenticated. * - * @returns {boolean} True if connection must be reauthenticated. + * @return {boolean} True if connection must be reauthenticated. */ connectionNeedsReauth = () => this.props.mustReauthConnections.includes( this.props.name ); diff --git a/projects/js-packages/publicize-components/src/components/form/advanced-plan-nudge.tsx b/projects/js-packages/publicize-components/src/components/form/advanced-plan-nudge.tsx deleted file mode 100644 index 5ae37b9e72f30..0000000000000 --- a/projects/js-packages/publicize-components/src/components/form/advanced-plan-nudge.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { getRedirectUrl } from '@automattic/jetpack-components'; -import { getSiteFragment } from '@automattic/jetpack-shared-extension-utils'; -import { ExternalLink } from '@wordpress/components'; -import { createInterpolateElement, useCallback } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import { usePublicizeConfig } from '../../..'; -import useDismissNotice from '../../hooks/use-dismiss-notice'; -import Notice from '../notice'; - -const MONTH_IN_SECONDS = 30 * 24 * 60 * 60; - -export const AdvancedPlanNudge: React.FC = () => { - const { shouldShowAdvancedPlanNudge } = usePublicizeConfig(); - - const { dismissNotice, shouldShowNotice, NOTICES } = useDismissNotice(); - const onAdvancedNudgeDismiss = useCallback( - () => dismissNotice( NOTICES.advancedUpgradeEditor, 3 * MONTH_IN_SECONDS ), - [ dismissNotice, NOTICES ] - ); - - return ( - shouldShowAdvancedPlanNudge && - shouldShowNotice( NOTICES.advancedUpgradeEditor ) && ( - - { createInterpolateElement( - __( - 'Need more reach? Unlock custom media sharing with the Advanced Plan', - 'jetpack' - ), - { - upgradeLink: ( - { + const hasPaidFeatures = useSelect( select => select( socialStore ).hasPaidFeatures(), [] ); + + const autosaveAndRedirect = useAutoSaveAndRedirect(); + + const isWpcom = isSimpleSite() || isAtomicSite(); + + if ( isWpcom || hasPaidFeatures ) { + return null; + } + + return ( + + + ); + + if ( withWrapper ) { + return
{ trigger }
; + } + + return trigger; + } +); diff --git a/projects/js-packages/publicize-components/src/components/share-status/modal.tsx b/projects/js-packages/publicize-components/src/components/share-status/modal.tsx new file mode 100644 index 0000000000000..cffdb48fcb257 --- /dev/null +++ b/projects/js-packages/publicize-components/src/components/share-status/modal.tsx @@ -0,0 +1,48 @@ +import { ThemeProvider } from '@automattic/jetpack-components'; +import { Modal } from '@wordpress/components'; +import { useDispatch, useSelect } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; +import { store as socialStore } from '../../social-store'; +import { ShareList } from './share-list'; +import styles from './styles.module.scss'; + +/** + * Share status modal component. + * + * @return {import('react').ReactNode} - Share status modal component. + */ +export function ShareStatusModal() { + const { closeShareStatusModal } = useDispatch( socialStore ); + + return ( +
+ + + +
+ ); +} + +/** + * Themed share status modal component. + * + * This component can be used to avoid dealing with modal state management. + * + * @return {import('react').ReactNode} - React element + */ +export function ThemedShareStatusModal() { + const shouldModalBeOpen = useSelect( + select => select( socialStore ).isShareStatusModalOpen(), + [] + ); + + return ( + + { shouldModalBeOpen ? : null } + + ); +} diff --git a/projects/js-packages/publicize-components/src/components/share-status/share-info.tsx b/projects/js-packages/publicize-components/src/components/share-status/share-info.tsx new file mode 100644 index 0000000000000..9427778bf92b5 --- /dev/null +++ b/projects/js-packages/publicize-components/src/components/share-status/share-info.tsx @@ -0,0 +1,38 @@ +import { getDate, humanTimeDiff } from '@wordpress/date'; +import ConnectionIcon from '../connection-icon'; +import { ShareStatusAction } from './share-status-action'; +import { ShareStatusLabel } from './share-status-label'; +import styles from './styles.module.scss'; + +/** + * + * ShareInfo component + * + * @param {object} props - component props + * @param {object} props.share - share object + * @return {import('react').ReactNode} - React element + */ +export function ShareInfo( { share } ) { + const { service, external_name, profile_picture, timestamp, status, message } = share; + + return ( +
+ +
+
{ external_name }
+
+
+ { + // @ts-expect-error - humanTimeDiff is incorrectly typed, first argument can be a timestamp + humanTimeDiff( timestamp * 1000, getDate() ) + } +
+ + +
+ ); +} diff --git a/projects/js-packages/publicize-components/src/components/share-status/share-list.tsx b/projects/js-packages/publicize-components/src/components/share-status/share-list.tsx new file mode 100644 index 0000000000000..90714ab167389 --- /dev/null +++ b/projects/js-packages/publicize-components/src/components/share-status/share-list.tsx @@ -0,0 +1,46 @@ +import { Spinner } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; +import { __ } from '@wordpress/i18n'; +import { store as socialStore } from '../../social-store'; +import { ShareInfo } from './share-info'; +import styles from './styles.module.scss'; + +/** + * ShareList component + * + * @return {import('react').ReactNode} - Share status modal component. + */ +export function ShareList() { + const { shareStatus } = useSelect( select => { + const store = select( socialStore ); + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- `@wordpress/editor` is a nightmare to work with TypeScript + const _editorStore = select( editorStore ) as any; + + return { + shareStatus: store.getPostShareStatus( _editorStore.getCurrentPostId() ), + }; + }, [] ); + + return ( +
+ { shareStatus.loading && ( +
+ { __( 'Loading…', 'jetpack' ) } +
+ ) } + { shareStatus.shares.length > 0 && ( +
    + { shareStatus.shares.map( ( share, idx ) => ( +
  • + +
  • + ) ) } +
+ ) } +
+ ); +} diff --git a/projects/js-packages/publicize-components/src/components/share-status/share-status-action.tsx b/projects/js-packages/publicize-components/src/components/share-status/share-status-action.tsx new file mode 100644 index 0000000000000..e81cae6506c55 --- /dev/null +++ b/projects/js-packages/publicize-components/src/components/share-status/share-status-action.tsx @@ -0,0 +1,26 @@ +import { ExternalLink } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import styles from './styles.module.scss'; + +/** + * + * Share status action component. + * + * @param {object} props - component props + * @param {boolean} props.status - status of the share + * @param {string} props.shareLink - link to the share + * @return {import('react').ReactNode} - React element + */ +export function ShareStatusAction( { status, shareLink } ) { + return ( +
+ { 'success' !== status ? ( + Retry + ) : ( + + { __( 'View', 'jetpack' ) } + + ) } +
+ ); +} diff --git a/projects/js-packages/publicize-components/src/components/share-status/share-status-label.tsx b/projects/js-packages/publicize-components/src/components/share-status/share-status-label.tsx new file mode 100644 index 0000000000000..c01703bad43c6 --- /dev/null +++ b/projects/js-packages/publicize-components/src/components/share-status/share-status-label.tsx @@ -0,0 +1,46 @@ +import { IconTooltip, Text } from '@automattic/jetpack-components'; +import { __, _x } from '@wordpress/i18n'; +import { Icon, check } from '@wordpress/icons'; +import clsx from 'clsx'; +import React from 'react'; +import styles from './styles.module.scss'; + +/** + * + * Share status label component. + * + * @param {object} props - component props + * @param {boolean} props.status - status of the share + * @param {string} props.message - link to the share, or error message if failed + * @return {import('react').ReactNode} - React element + */ +export function ShareStatusLabel( { status, message } ) { + const isSuccessful = 'success' === status; + + const icon = isSuccessful ? ( + + ) : ( + + { message } + + ); + + return ( +
+
{ icon }
+
+ { isSuccessful + ? _x( 'Shared', 'The sharing is successful', 'jetpack' ) + : __( 'Failed', 'jetpack' ) } +
+
+ ); +} diff --git a/projects/js-packages/publicize-components/src/components/share-status/styles.module.scss b/projects/js-packages/publicize-components/src/components/share-status/styles.module.scss new file mode 100644 index 0000000000000..2018e13947793 --- /dev/null +++ b/projects/js-packages/publicize-components/src/components/share-status/styles.module.scss @@ -0,0 +1,89 @@ +.trigger-wrapper { + margin-top: 1rem; + padding-block: 1rem; +} + +.wrapper { + margin-top: 1rem; + padding-block: 1rem; +} + +.spinner{ + margin: 0 1rem 1rem 1rem; +} + +.modal { + width: 60rem; +} + +.share-log-list { + outline: 1px solid var(--jp-gray-5); + border-radius: 4px; + margin: 0; + width: 100%; + + .share-log-list-item { + margin-bottom: 0px; + padding: 0.8rem 1rem; + + &:not(:last-child) { + border-bottom: 1px solid var(--jp-gray-5); + } + } + + .share-item { + display: flex; + gap: 1rem; + align-items: center; + } +} + +.share-item-name-wrapper { + display: flex; + flex-direction: column; + gap: 0.5rem; + flex: 1; + overflow: auto; +} + +.share-item-name { + display: flex; + align-items: center; +} + +.share-status-wrapper { + display: flex; + align-items: center; + width: 5rem; + + &.share-status-success { + color: var(--jp-green-50); + } + + &.share-status-failure { + color: var(--jp-red-50); + height: 29px; + } +} + +.share-status-label { + flex: 1; +} + +.share-status-icon-tooltip { + width: 24px; + top: 2px; + margin-inline-start: 2px; + + > button { + color: var(--jp-red-50) !important; + } +} + +.share-status-icon { + fill: var(--jp-green-50); +} + +.share-status-action-wrapper { + width: 3rem; +} diff --git a/projects/js-packages/publicize-components/src/components/social-image-generator/template-picker/modal/index.js b/projects/js-packages/publicize-components/src/components/social-image-generator/template-picker/modal/index.js index f635c86926389..0f97415416ca2 100644 --- a/projects/js-packages/publicize-components/src/components/social-image-generator/template-picker/modal/index.js +++ b/projects/js-packages/publicize-components/src/components/social-image-generator/template-picker/modal/index.js @@ -10,11 +10,11 @@ import styles from './styles.module.scss'; /** * Wraps the template picker component in a modal, and saves the selected template on modal save. * - * @param {object} props - The component props. - * @param {Function} props.onSelect - A function that will be called when a template is selected. Receives the name of the selected template as an argument. - * @param {Function} props.render - A function that will be called with an object containing an "open" function, which can be called to open the template picker. + * @param {object} props - The component props. + * @param {Function} props.onSelect - A function that will be called when a template is selected. Receives the name of the selected template as an argument. + * @param {Function} props.render - A function that will be called with an object containing an "open" function, which can be called to open the template picker. * @param {string|null} [props.value=null] - The name of the currently selected template. - * @returns {JSXElement} - The component's rendered output. + * @return {JSXElement} - The component's rendered output. */ const TemplatePickerModal = ( { onSelect, render, value = null } ) => { const [ isOpen, setIsOpen ] = useState( false ); diff --git a/projects/js-packages/publicize-components/src/components/social-image-generator/template-picker/modal/test/index.test.js b/projects/js-packages/publicize-components/src/components/social-image-generator/template-picker/modal/test/index.test.js index b70899946566b..fcc684722df0b 100644 --- a/projects/js-packages/publicize-components/src/components/social-image-generator/template-picker/modal/test/index.test.js +++ b/projects/js-packages/publicize-components/src/components/social-image-generator/template-picker/modal/test/index.test.js @@ -7,7 +7,7 @@ import TemplatePickerModal from '..'; * Helper method to set up the user event. * * @param {ReactElement} jsx - The element to render. - * @returns {object} An object with the user method and everything from the render method. + * @return {object} An object with the user method and everything from the render method. */ const setup = async jsx => ( { user: await userEvent.setup(), diff --git a/projects/js-packages/publicize-components/src/components/social-image-generator/template-picker/picker/index.js b/projects/js-packages/publicize-components/src/components/social-image-generator/template-picker/picker/index.js index d8383dedc9013..a2a91b14f2fb9 100644 --- a/projects/js-packages/publicize-components/src/components/social-image-generator/template-picker/picker/index.js +++ b/projects/js-packages/publicize-components/src/components/social-image-generator/template-picker/picker/index.js @@ -12,9 +12,9 @@ import TEMPLATES_DATA from './templates.js'; * with the onTemplateSelected callback. * * @param {{value: string|null, onTemplateSelected: Function}} props - The component props: - * Value is the name of the currently selected template, onTemplateSelected is a function that - * will be called when a template is selected. Receives the name of the selected template as an argument. - * @returns {ReactNode} - The component's rendered output. + * Value is the name of the currently selected template, onTemplateSelected is a function that + * will be called when a template is selected. Receives the name of the selected template as an argument. + * @return {ReactNode} - The component's rendered output. */ const TemplatePicker = ( { value = null, onTemplateSelected = null } ) => { const onTemplateClicked = useCallback( diff --git a/projects/js-packages/publicize-components/src/components/social-image-generator/toggle/index.tsx b/projects/js-packages/publicize-components/src/components/social-image-generator/toggle/index.tsx index 154b38b034f8d..7a7ceee6f7f50 100644 --- a/projects/js-packages/publicize-components/src/components/social-image-generator/toggle/index.tsx +++ b/projects/js-packages/publicize-components/src/components/social-image-generator/toggle/index.tsx @@ -21,7 +21,7 @@ type SocialImageGeneratorToggleProps = { * A button toggle wrapper for enabling/disabling the Social Image Generator feature. * * @param {SocialImageGeneratorToggleProps} props - Component props. - * @returns {React.ReactElement} - JSX.Element + * @return {React.ReactElement} - JSX.Element */ const SocialImageGeneratorToggle: React.FC< SocialImageGeneratorToggleProps > = ( { toggleClass, diff --git a/projects/js-packages/publicize-components/src/components/social-post-modal/modal.tsx b/projects/js-packages/publicize-components/src/components/social-post-modal/modal.tsx index deb4e2103e548..8cf54e4d21ca2 100644 --- a/projects/js-packages/publicize-components/src/components/social-post-modal/modal.tsx +++ b/projects/js-packages/publicize-components/src/components/social-post-modal/modal.tsx @@ -10,7 +10,7 @@ import styles from './styles.module.scss'; /** * The Social Post Modal component. * - * @returns {import('react').ReactNode} - Social Post Modal component. + * @return {import('react').ReactNode} - Social Post Modal component. */ export function SocialPostModal() { const [ isModalOpen, toggleModal ] = useReducer( state => ! state, false ); diff --git a/projects/js-packages/publicize-components/src/components/social-post-modal/post-preview.tsx b/projects/js-packages/publicize-components/src/components/social-post-modal/post-preview.tsx index f8d15a3f4fff9..66c90805181c6 100644 --- a/projects/js-packages/publicize-components/src/components/social-post-modal/post-preview.tsx +++ b/projects/js-packages/publicize-components/src/components/social-post-modal/post-preview.tsx @@ -27,7 +27,7 @@ export type PostPreviewProps = { * * @param {PostPreviewProps} props - PostPreview component props. * - * @returns {import('react').ReactNode} - Post preview component. + * @return {import('react').ReactNode} - Post preview component. */ export function PostPreview( { connection }: PostPreviewProps ) { const user = useMemo( diff --git a/projects/js-packages/publicize-components/src/components/social-post-modal/preview-section.tsx b/projects/js-packages/publicize-components/src/components/social-post-modal/preview-section.tsx index 92cd970ff221e..ab96029e8e502 100644 --- a/projects/js-packages/publicize-components/src/components/social-post-modal/preview-section.tsx +++ b/projects/js-packages/publicize-components/src/components/social-post-modal/preview-section.tsx @@ -14,7 +14,7 @@ import styles from './styles.module.scss'; /** * Preview section of the social post modal. * - * @returns {import('react').ReactNode} - Preview section of the social post modal. + * @return {import('react').ReactNode} - Preview section of the social post modal. */ export function PreviewSection() { const { recordEvent } = useAnalytics(); diff --git a/projects/js-packages/publicize-components/src/components/social-post-modal/settings-section.tsx b/projects/js-packages/publicize-components/src/components/social-post-modal/settings-section.tsx index b27fcbdcc0adf..061ff8312d92b 100644 --- a/projects/js-packages/publicize-components/src/components/social-post-modal/settings-section.tsx +++ b/projects/js-packages/publicize-components/src/components/social-post-modal/settings-section.tsx @@ -5,7 +5,7 @@ import styles from './styles.module.scss'; /** * Settings section of the social post modal. * - * @returns {import('react').ReactNode} - Settings section of the social post modal. + * @return {import('react').ReactNode} - Settings section of the social post modal. */ export function SettingsSection() { return ( @@ -14,6 +14,9 @@ export function SettingsSection() {

{ __( 'Social Preview', 'jetpack' ) }

+

+ { __( 'Edit and preview your social post before sharing.', 'jetpack' ) } +

diff --git a/projects/js-packages/publicize-components/src/components/social-post-modal/styles.module.scss b/projects/js-packages/publicize-components/src/components/social-post-modal/styles.module.scss index b1fe31fee28ab..663a5cf3b0131 100644 --- a/projects/js-packages/publicize-components/src/components/social-post-modal/styles.module.scss +++ b/projects/js-packages/publicize-components/src/components/social-post-modal/styles.module.scss @@ -62,7 +62,7 @@ } .settings-content { - padding: 2rem; + padding: 1rem 2rem; @include break-medium { border-inline-end: 1px solid var(--studio-gray-5); @@ -97,3 +97,8 @@ .disabled-tab { opacity: 0.5; } + +.modal-description { + color: var(--jp-gray-40); + margin-top: 0; +} diff --git a/projects/js-packages/publicize-components/src/components/social-previews/google-search.js b/projects/js-packages/publicize-components/src/components/social-previews/google-search.js index 7839815791a68..f8a048eb9e60e 100644 --- a/projects/js-packages/publicize-components/src/components/social-previews/google-search.js +++ b/projects/js-packages/publicize-components/src/components/social-previews/google-search.js @@ -6,10 +6,10 @@ import React from 'react'; /** * The Google Search tab component. * - * @param {object} props - The props. + * @param {object} props - The props. * @param {object[]} props.tweets - The tweets. - * @param {object} props.media - The media. - * @returns {React.ReactNode} The Google Search tab component. + * @param {object} props.media - The media. + * @return {React.ReactNode} The Google Search tab component. */ export function GoogleSearch( props ) { const siteTitle = useSelect( select => { diff --git a/projects/js-packages/publicize-components/src/components/social-previews/instagram.js b/projects/js-packages/publicize-components/src/components/social-previews/instagram.js index a8a450fdfa523..cfed68ba5b5c2 100644 --- a/projects/js-packages/publicize-components/src/components/social-previews/instagram.js +++ b/projects/js-packages/publicize-components/src/components/social-previews/instagram.js @@ -12,7 +12,7 @@ import { SOCIAL_STORE_ID, CONNECTION_SERVICE_INSTAGRAM_BUSINESS } from '../../so * The Instagram tab component. * * @param {object} props - The props. - * @returns {React.ReactNode} The Instagram tab component. + * @return {React.ReactNode} The Instagram tab component. */ export function Instagram( props ) { const { title, image, media, description } = props; diff --git a/projects/js-packages/publicize-components/src/components/social-previews/linkedin.js b/projects/js-packages/publicize-components/src/components/social-previews/linkedin.js index 8cbc7bc6747c3..f609ba2c18803 100644 --- a/projects/js-packages/publicize-components/src/components/social-previews/linkedin.js +++ b/projects/js-packages/publicize-components/src/components/social-previews/linkedin.js @@ -9,7 +9,7 @@ import { SOCIAL_STORE_ID, CONNECTION_SERVICE_LINKEDIN } from '../../social-store * The linkedin tab component. * * @param {object} props - The props. - * @returns {React.ReactNode} The linkedin tab component. + * @return {React.ReactNode} The linkedin tab component. */ export function LinkedIn( props ) { const { title, url, image, media, description: postDescription } = props; diff --git a/projects/js-packages/publicize-components/src/components/social-previews/nextdoor.js b/projects/js-packages/publicize-components/src/components/social-previews/nextdoor.js index 892e0a1f83d91..5688fb89edd5b 100644 --- a/projects/js-packages/publicize-components/src/components/social-previews/nextdoor.js +++ b/projects/js-packages/publicize-components/src/components/social-previews/nextdoor.js @@ -8,7 +8,7 @@ import { SOCIAL_STORE_ID, CONNECTION_SERVICE_NEXTDOOR } from '../../social-store * The linkedin tab component. * * @param {object} props - The props. - * @returns {React.ReactNode} The linkedin tab component. + * @return {React.ReactNode} The linkedin tab component. */ export function Nextdoor( props ) { const { title, url, image, media, description: postDescription } = props; diff --git a/projects/js-packages/publicize-components/src/components/social-previews/threads.js b/projects/js-packages/publicize-components/src/components/social-previews/threads.js index 76ac408f9cf3f..e6bf11750eaca 100644 --- a/projects/js-packages/publicize-components/src/components/social-previews/threads.js +++ b/projects/js-packages/publicize-components/src/components/social-previews/threads.js @@ -8,14 +8,14 @@ import { CONNECTION_SERVICE_THREADS, store } from '../../social-store'; /** * The threads tab component. * - * @param {object} props - The props. - * @param {string} props.excerpt - The post excerpt - * @param {string} props.title - The post title - * @param {string} props.description - The post description/excerpt - * @param {object} props.image - The post featured image - * @param {string} props.url - The URL of the post - * @param {object[]} props.media - Array of attached media - * @returns {React.ReactNode} The threads tab component. + * @param {object} props - The props. + * @param {string} props.excerpt - The post excerpt + * @param {string} props.title - The post title + * @param {string} props.description - The post description/excerpt + * @param {object} props.image - The post featured image + * @param {string} props.url - The URL of the post + * @param {object[]} props.media - Array of attached media + * @return {React.ReactNode} The threads tab component. */ export function Threads( { excerpt, title, description, image, url, media } ) { const { shareMessage } = usePostMeta(); diff --git a/projects/js-packages/publicize-components/src/components/social-previews/twitter.js b/projects/js-packages/publicize-components/src/components/social-previews/twitter.js index 901eaa6e08ff0..8927cd4706ce3 100644 --- a/projects/js-packages/publicize-components/src/components/social-previews/twitter.js +++ b/projects/js-packages/publicize-components/src/components/social-previews/twitter.js @@ -7,13 +7,13 @@ import { SOCIAL_STORE_ID, CONNECTION_SERVICE_TWITTER } from '../../social-store' /** * The twitter tab component. * - * @param {object} props - The props. - * @param {string} props.title - The post title - * @param {string} props.description - The post description/excerpt - * @param {object} props.image - The post featured image - * @param {string} props.url - The URL of the post - * @param {object[]} props.media - Array of attached media - * @returns {React.ReactNode} The twitter tab component. + * @param {object} props - The props. + * @param {string} props.title - The post title + * @param {string} props.description - The post description/excerpt + * @param {object} props.image - The post featured image + * @param {string} props.url - The URL of the post + * @param {object[]} props.media - Array of attached media + * @return {React.ReactNode} The twitter tab component. */ function Twitter( { title, description, image, url, media } ) { const { shareMessage } = usePostMeta(); diff --git a/projects/js-packages/publicize-components/src/components/social-previews/use-available-services.js b/projects/js-packages/publicize-components/src/components/social-previews/use-available-services.js index e479b1994d510..a3f575f8c884a 100644 --- a/projects/js-packages/publicize-components/src/components/social-previews/use-available-services.js +++ b/projects/js-packages/publicize-components/src/components/social-previews/use-available-services.js @@ -16,7 +16,7 @@ import Twitter from './twitter'; /** * Returns the list of available services. * - * @returns {Array<{title: string, icon: React.Component, name: string, preview: React.Component}>} The list of available services. + * @return {Array<{title: string, icon: React.Component, name: string, preview: React.Component}>} The list of available services. */ export function useAvailableSerivces() { const additionalConnections = getSupportedAdditionalConnections(); diff --git a/projects/js-packages/publicize-components/src/components/social-previews/use-post-data.js b/projects/js-packages/publicize-components/src/components/social-previews/use-post-data.js index 25711edcf0504..3f7b318b5a393 100644 --- a/projects/js-packages/publicize-components/src/components/social-previews/use-post-data.js +++ b/projects/js-packages/publicize-components/src/components/social-previews/use-post-data.js @@ -7,7 +7,7 @@ import { getMediaSourceUrl, getPostImageUrl } from './utils'; /** * Returns the post data. * - * @returns {object} The post data. + * @return {object} The post data. */ export function usePostData() { const { attachedMedia, imageGeneratorSettings } = usePostMeta(); diff --git a/projects/js-packages/publicize-components/src/components/social-previews/utils.js b/projects/js-packages/publicize-components/src/components/social-previews/utils.js index 9ec506bf2a842..81a241f0da879 100644 --- a/projects/js-packages/publicize-components/src/components/social-previews/utils.js +++ b/projects/js-packages/publicize-components/src/components/social-previews/utils.js @@ -2,7 +2,7 @@ * Gets the URL of the media. Tries loading a smaller size (1024px width) if available and falls back to the full size. * * @param {object} media - Media object - * @returns {?string} URL address + * @return {?string} URL address */ export function getMediaSourceUrl( media ) { if ( ! media ) { @@ -17,7 +17,7 @@ export function getMediaSourceUrl( media ) { * Gets the URL of an image from the post body * * @param {string} editedPostContent - The post content coming from core/editor - * @returns {?string} URL address + * @return {?string} URL address */ export function getPostImageUrl( editedPostContent ) { const parser = new DOMParser(); diff --git a/projects/js-packages/publicize-components/src/hooks/use-attached-media/index.js b/projects/js-packages/publicize-components/src/hooks/use-attached-media/index.js index 6db6b44edc973..8f18783567c93 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-attached-media/index.js +++ b/projects/js-packages/publicize-components/src/hooks/use-attached-media/index.js @@ -2,14 +2,14 @@ import { usePostMeta } from '../use-post-meta'; /** * @typedef {object} AttachedMediaHook - * @property {Array} attachedMedia - List of media with ID, URL, and metadata. + * @property {Array} attachedMedia - List of media with ID, URL, and metadata. * @property {Function} updateAttachedMedia - Callback used to update the attached media. */ /** * Hook to handle storing the attached media, choosing whether it is a social post. * - * @returns {AttachedMediaHook} - An object with the attached media hook properties set. + * @return {AttachedMediaHook} - An object with the attached media hook properties set. */ export default function useAttachedMedia() { const { attachedMedia, updateJetpackSocialOptions } = usePostMeta(); diff --git a/projects/js-packages/publicize-components/src/hooks/use-dismiss-notice/index.js b/projects/js-packages/publicize-components/src/hooks/use-dismiss-notice/index.js index 8b4dd00a405a8..ebe127baa0ba7 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-dismiss-notice/index.js +++ b/projects/js-packages/publicize-components/src/hooks/use-dismiss-notice/index.js @@ -4,9 +4,9 @@ import { useCallback, useMemo, useState } from '@wordpress/element'; /** * @typedef {object} NoticeTypes - * @property {string} instagram - The name of the Instagram notice. + * @property {string} instagram - The name of the Instagram notice. * @property {string} advancedUpgradeEditor - The name of the advanced upgrade nudge in the editor. - * @property {string} advancedUpgradeAdmin - The name of the advanced upgrade nudge in the admin page. + * @property {string} advancedUpgradeAdmin - The name of the advanced upgrade nudge in the admin page. */ const NOTICES = { @@ -23,16 +23,16 @@ const calculateReappearanceTime = seconds => { /** * @typedef {object} DismissNoticeHook - * @property {Array} dismissedNotices - Array of names of dismissed notices. - * @property {Function} dismissNotice - Callback used to dismiss a notice. - * @property {Function} shouldShowNotice - Callback used to check if a notice should be shown. - * @property {NoticeTypes} NOTICES - Object containing the names of the supported notices. + * @property {Array} dismissedNotices - Array of names of dismissed notices. + * @property {Function} dismissNotice - Callback used to dismiss a notice. + * @property {Function} shouldShowNotice - Callback used to check if a notice should be shown. + * @property {NoticeTypes} NOTICES - Object containing the names of the supported notices. */ /** * Hook to handle retrieving dismissed notices and dismissing a notice. * - * @returns {DismissNoticeHook} - An object with the dismissed notice hook properties set. + * @return {DismissNoticeHook} - An object with the dismissed notice hook properties set. */ export default function useDismissNotice() { const [ dismissedNotices, setDismissedNotices ] = useState( () => { @@ -46,7 +46,7 @@ export default function useDismissNotice() { /** * Dismiss a notice for a given time. * - * @param {string} notice - The name of the notice to dismiss. + * @param {string} notice - The name of the notice to dismiss. * @param {number} [dismissDuration=-1] - The number of seconds to dismiss the notice for. -1 means forever. */ const dismissNotice = useCallback( ( notice, dismissDuration = -1 ) => { @@ -65,7 +65,7 @@ export default function useDismissNotice() { * Check if a notice should be shown. * * @param {string} notice - The name of the notice to check. - * @returns {boolean} - Whether the notice should be shown. + * @return {boolean} - Whether the notice should be shown. */ const shouldShowNotice = useCallback( notice => { diff --git a/projects/js-packages/publicize-components/src/hooks/use-featured-image/index.js b/projects/js-packages/publicize-components/src/hooks/use-featured-image/index.js index de543485ae2d0..47a36df2a1e6d 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-featured-image/index.js +++ b/projects/js-packages/publicize-components/src/hooks/use-featured-image/index.js @@ -4,7 +4,7 @@ import { store as editorStore } from '@wordpress/editor'; /** * Returns the ID of the current featured image if there is one. * - * @returns {number?} The ID of the featured image. + * @return {number?} The ID of the featured image. */ export default () => useSelect( select => select( editorStore ).getEditedPostAttribute( 'featured_media' ) ); diff --git a/projects/js-packages/publicize-components/src/hooks/use-image-generator-config/index.js b/projects/js-packages/publicize-components/src/hooks/use-image-generator-config/index.js index 9bf8dfcf3287f..a0177f1c73fab 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-image-generator-config/index.js +++ b/projects/js-packages/publicize-components/src/hooks/use-image-generator-config/index.js @@ -14,21 +14,21 @@ const getCurrentSettings = ( sigSettings, isPostPublished ) => ( { /** * @typedef {object} ImageGeneratorConfigHook - * @property {Array} postSettings - Array of post settings (custom text, image type etc). - * @property {boolean} isEnabled - True if the image generator is enabled for this post. - * @property {string} customText - Custom text for the generated image. - * @property {string} imageType - Optional. Type of the image in the generated image. - * @property {number} imageId - Optional. ID of the image in the generated image. - * @property {string} template - Template for the generated image. - * @property {Function} setIsEnabled - Callback to enable or disable the image generator for a post. + * @property {Array} postSettings - Array of post settings (custom text, image type etc). + * @property {boolean} isEnabled - True if the image generator is enabled for this post. + * @property {string} customText - Custom text for the generated image. + * @property {string} imageType - Optional. Type of the image in the generated image. + * @property {number} imageId - Optional. ID of the image in the generated image. + * @property {string} template - Template for the generated image. + * @property {Function} setIsEnabled - Callback to enable or disable the image generator for a post. * @property {Function} updateProperty - Callback to update various SIG settings. - * @property {Function} setToken - Callback to change the token. + * @property {Function} setToken - Callback to change the token. */ /** * Hook to handle storing and retrieving image generator config. * - * @returns {ImageGeneratorConfigHook} - An object with the attached media hook properties set. + * @return {ImageGeneratorConfigHook} - An object with the attached media hook properties set. */ export default function useImageGeneratorConfig() { const { imageGeneratorSettings, jetpackSocialOptions, updateJetpackSocialOptions } = diff --git a/projects/js-packages/publicize-components/src/hooks/use-media-details/index.js b/projects/js-packages/publicize-components/src/hooks/use-media-details/index.js index 134998bc7a02b..b5cb6c93a3256 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-media-details/index.js +++ b/projects/js-packages/publicize-components/src/hooks/use-media-details/index.js @@ -5,7 +5,7 @@ import { useCallback, useEffect, useState } from '@wordpress/element'; * Get meta data from a VideoPress video. * * @param {object} video - VideoPress media object. - * @returns {Promise} A promise containing {mime: string, fileSize: number, length: number}} + * @return {Promise} A promise containing {mime: string, fileSize: number, length: number}} */ const getVideoPressMetadata = async video => { if ( @@ -34,7 +34,7 @@ const getVideoPressMetadata = async video => { * Get relevant details from a WordPress media object. * * @param {object} media - WordPress media object. - * @returns {Promise} An object containing mediaData and metaData. + * @return {Promise} An object containing mediaData and metaData. */ const getMediaDetails = async media => { if ( ! media ) { @@ -87,7 +87,7 @@ const getMediaDetails = async media => { * Hook to handle storing the attached media. * * @param {number} mediaId - ID of the current media in the Media Lib. - * @returns {[ mediaDetails: import('./types').MediaDetails ]} - The media details + * @return {[ mediaDetails: import('./types').MediaDetails ]} - The media details */ export default function useMediaDetails( mediaId = null ) { const [ mediaDetails, setMediaDetails ] = useState( [ {} ] ); diff --git a/projects/js-packages/publicize-components/src/hooks/use-media-restrictions/constants.ts b/projects/js-packages/publicize-components/src/hooks/use-media-restrictions/constants.ts index 5945e8686b500..8aad3e9828ec0 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-media-restrictions/constants.ts +++ b/projects/js-packages/publicize-components/src/hooks/use-media-restrictions/constants.ts @@ -10,7 +10,7 @@ export const DIMENSION_ERROR = 'DIMENSION_ERROR'; /** * Returns the error labels. * - * @returns {Record} The error labels. + * @return {Record} The error labels. */ export function getErrorLabels() { return { @@ -26,7 +26,7 @@ export function getErrorLabels() { * * @param {string} errorType - The error type. * - * @returns {string} The error label. + * @return {string} The error label. */ export function getErrorLabel( errorType: string ) { return getErrorLabels()[ errorType ] || __( 'Invalid media', 'jetpack' ); diff --git a/projects/js-packages/publicize-components/src/hooks/use-media-restrictions/index.ts b/projects/js-packages/publicize-components/src/hooks/use-media-restrictions/index.ts index 48cc3a44d04ad..dccf4f4d48d13 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-media-restrictions/index.ts +++ b/projects/js-packages/publicize-components/src/hooks/use-media-restrictions/index.ts @@ -23,7 +23,7 @@ import { MediaRestrictions } from './types'; * Checks whether a media is a video. * * @param {string} mime - The MIME tye of the media - * @returns {boolean} Whether it is a video. + * @return {boolean} Whether it is a video. */ export function isVideo( mime ) { return mime.split( '/' )[ 0 ] === 'video'; @@ -33,7 +33,7 @@ export function isVideo( mime ) { * Checks whether a media is convertible so we can convert it if needed. * * @param {object} metaData - Media metadata, mime, fileSize and length. - * @returns {boolean} Whether it is convertible. + * @return {boolean} Whether it is convertible. */ const isMediaConvertible = metaData => { if ( ! metaData?.mime || ! metaData?.fileSize ) { @@ -61,11 +61,11 @@ const isMediaConvertible = metaData => { /** * This function is used to check if the provided image is valid based on it's size and type. * - * @param {number} sizeInMb - The fileSize in bytes. - * @param {number} width - Width of the image. - * @param {number} height - Height of the image. + * @param {number} sizeInMb - The fileSize in bytes. + * @param {number} width - Width of the image. + * @param {number} height - Height of the image. * @param {object} imageLimits - Has the properties to check against - * @returns {FILE_SIZE_ERROR} Returns validation error. + * @return {FILE_SIZE_ERROR} Returns validation error. */ const getImageValidationError = ( sizeInMb, width, height, imageLimits ) => { const { @@ -91,12 +91,12 @@ const getImageValidationError = ( sizeInMb, width, height, imageLimits ) => { /** * This function is used to check if the provided video is valid based on it's size and type and length. * - * @param {number} sizeInMb - The fileSize in bytes. - * @param {number} length - Video length in seconds and. - * @param {number} width - Width of the video. - * @param {number} height - Height of the video. + * @param {number} sizeInMb - The fileSize in bytes. + * @param {number} length - Video length in seconds and. + * @param {number} width - Width of the video. + * @param {number} height - Height of the video. * @param {object} videoLimits - Has the properties to check against - * @returns {(FILE_SIZE_ERROR | VIDEO_LENGTH_TOO_LONG_ERROR | VIDEO_LENGTH_TOO_SHORT_ERROR)} Returns validation error. + * @return {(FILE_SIZE_ERROR | VIDEO_LENGTH_TOO_LONG_ERROR | VIDEO_LENGTH_TOO_SHORT_ERROR)} Returns validation error. */ const getVideoValidationError = ( sizeInMb, length, width, height, videoLimits ) => { const { @@ -131,12 +131,12 @@ const getVideoValidationError = ( sizeInMb, length, width, height, videoLimits ) /** * Checks whether the media with the provided metaData is valid. It can validate images or videos. * - * @param {object} metaData - Media metadata, mime, fileSize and length. - * @param {object} mediaData - Data for media, width, height, source_url etc. - * @param {string} serviceName - The name of the social media service we want to validate against. facebook, tumblr etc. - * @param {boolean} hasAttachedMedia - Whether the media is attached. + * @param {object} metaData - Media metadata, mime, fileSize and length. + * @param {object} mediaData - Data for media, width, height, source_url etc. + * @param {string} serviceName - The name of the social media service we want to validate against. facebook, tumblr etc. + * @param {boolean} hasAttachedMedia - Whether the media is attached. * @param {boolean} hasAutoGeneratedImage - Whether there is an auto generated image. - * @returns {(FILE_SIZE_ERROR | FILE_TYPE_ERROR | VIDEO_LENGTH_TOO_SHORT_ERROR | VIDEO_LENGTH_TOO_LONG_ERROR)} Returns validation error. + * @return {(FILE_SIZE_ERROR | FILE_TYPE_ERROR | VIDEO_LENGTH_TOO_SHORT_ERROR | VIDEO_LENGTH_TOO_LONG_ERROR)} Returns validation error. */ const getValidationError = ( metaData, @@ -183,8 +183,8 @@ const getValidationError = ( * Hooks to deal with the media restrictions * * @param {Array< Connection >} connections - Currently enabled connections. - * @param {MediaDetails} media - Currently enabled connections. - * @returns {MediaRestrictions} Social media connection handler. + * @param {MediaDetails} media - Currently enabled connections. + * @return {MediaRestrictions} Social media connection handler. */ const useMediaRestrictions = ( connections: Array< Connection >, diff --git a/projects/js-packages/publicize-components/src/hooks/use-media-restrictions/restrictions.ts b/projects/js-packages/publicize-components/src/hooks/use-media-restrictions/restrictions.ts index 76b87c0e4363a..4fd972fa355b3 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-media-restrictions/restrictions.ts +++ b/projects/js-packages/publicize-components/src/hooks/use-media-restrictions/restrictions.ts @@ -135,7 +135,7 @@ export const RESTRICTIONS = { minLength: 3, }, }, - [ 'instagram-business' ]: { + 'instagram-business': { requiresMedia: true, allowedMediaTypes: [ 'image/jpg', 'image/jpeg', MP4, MOV, VIDEOPRESS ], image: { diff --git a/projects/js-packages/publicize-components/src/hooks/use-post-meta/index.js b/projects/js-packages/publicize-components/src/hooks/use-post-meta/index.js index e6501f34148e8..a230bdb6e37ba 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-post-meta/index.js +++ b/projects/js-packages/publicize-components/src/hooks/use-post-meta/index.js @@ -6,7 +6,7 @@ import { getShareMessageMaxLength } from '../../utils'; /** * Returns the post meta values. * - * @returns {import('./types').UsePostMeta} The post meta values. + * @return {import('../../utils/types').UsePostMeta} The post meta values. */ export function usePostMeta() { const { editPost } = useDispatch( editorStore ); diff --git a/projects/js-packages/publicize-components/src/hooks/use-post-pre-publish-value/index.ts b/projects/js-packages/publicize-components/src/hooks/use-post-pre-publish-value/index.ts new file mode 100644 index 0000000000000..60d80b8b9d97f --- /dev/null +++ b/projects/js-packages/publicize-components/src/hooks/use-post-pre-publish-value/index.ts @@ -0,0 +1,39 @@ +import { useSelect } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; +import { useEffect, useRef, useState } from '@wordpress/element'; + +/** + * Preserve a value from the post pre-publish state. + * + * The value will stop updating after the post is published. + * + * @template V + * @param {V} value - The value to preserve. + * + * @return {V} The preserved value. + */ +export function usePostPrePublishValue< V >( value: V ) { + const isPublishing = useSelect( + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- `@wordpress/editor` is a nightmare to work with TypeScript + select => ( select( editorStore ) as any ).isPublishingPost(), + [] + ); + + const [ currentValue, setCurrentValue ] = useState( value ); + + const valueFrozen = useRef( false ); + + useEffect( () => { + // Freeze the value after publishing starts. + if ( isPublishing ) { + valueFrozen.current = true; + } + + // Since the value is not frozen yet, update the current value. + if ( ! valueFrozen.current ) { + setCurrentValue( value ); + } + }, [ isPublishing, value ] ); + + return currentValue; +} diff --git a/projects/js-packages/publicize-components/src/hooks/use-post-pre-publish-value/test/index.test.js b/projects/js-packages/publicize-components/src/hooks/use-post-pre-publish-value/test/index.test.js new file mode 100644 index 0000000000000..70b59a9ebdc08 --- /dev/null +++ b/projects/js-packages/publicize-components/src/hooks/use-post-pre-publish-value/test/index.test.js @@ -0,0 +1,79 @@ +import { act, renderHook } from '@testing-library/react'; +import { RegistryProvider } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; +import { usePostPrePublishValue } from '../'; +import { + connections as connectionsList, + createRegistryWithStores, +} from '../../../utils/test-utils'; + +const connections = connectionsList.map( connection => ( { ...connection, enabled: true } ) ); + +const post = { + jetpack_publicize_connections: [ connections[ 0 ] ], +}; + +describe( 'usePostPrePublishValue', () => { + it( 'should return the value by default', async () => { + const registry = createRegistryWithStores( post ); + + const { result } = renderHook( () => usePostPrePublishValue( 'test-value' ), { + wrapper: ( { children } ) => ( + { children } + ), + } ); + + expect( result.current ).toBe( 'test-value' ); + } ); + + it( 'should return the updated value when the post is not being published', async () => { + const registry = createRegistryWithStores( post ); + + const { rerender, result } = renderHook( + ( initialValue = 'first-value' ) => usePostPrePublishValue( initialValue ), + { + wrapper: ( { children } ) => ( + { children } + ), + } + ); + + rerender( 'second-value' ); + + await act( async () => { + await registry.dispatch( editorStore ).editPost( { + status: 'draft', + content: 'Some test content', + } ); + } ); + + expect( result.current ).toBe( 'second-value' ); + } ); + + it( 'should preserve the pre-publish value', async () => { + const registry = createRegistryWithStores( post ); + + const { rerender, result } = renderHook( + ( initialValue = 'first-value' ) => usePostPrePublishValue( initialValue ), + { + wrapper: ( { children } ) => ( + { children } + ), + } + ); + + rerender( 'second-value' ); + + await act( async () => { + registry.dispatch( editorStore ).editPost( { + status: 'publish', + content: 'Some test content', + } ); + registry.dispatch( editorStore ).savePost(); + } ); + + rerender( 'third-value' ); + + expect( result.current ).toBe( 'second-value' ); + } ); +} ); diff --git a/projects/js-packages/publicize-components/src/hooks/use-publicize-config/index.js b/projects/js-packages/publicize-components/src/hooks/use-publicize-config/index.js index 271cbd0ba514b..f1b896fcd5aab 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-publicize-config/index.js +++ b/projects/js-packages/publicize-components/src/hooks/use-publicize-config/index.js @@ -17,15 +17,13 @@ const republicizeFeatureName = 'republicize'; * Hook that provides various elements of Publicize configuration, * whether it's enabled, and whether resharing is available. * - * @returns { object } The various flags and togglePublicizeFeature, + * @return { object } The various flags and togglePublicizeFeature, * for toggling support for the current post. */ export default function usePublicizeConfig() { - const sharesData = getJetpackData()?.social?.sharesData ?? {}; const blogID = getJetpackData()?.wpcomBlogId; - const isShareLimitEnabled = sharesData.is_share_limit_enabled; const isRePublicizeFeatureAvailable = - getJetpackExtensionAvailability( republicizeFeatureName )?.available || isShareLimitEnabled; + getJetpackExtensionAvailability( republicizeFeatureName )?.available; const isPostPublished = useSelect( select => select( editorStore ).isCurrentPostPublished(), [] ); const currentPostType = useSelect( select => select( editorStore ).getCurrentPostType(), [] ); const { isUserConnected } = useConnection(); @@ -115,10 +113,7 @@ export default function usePublicizeConfig() { isRePublicizeFeatureAvailable, isRePublicizeUpgradableViaUpsell, hidePublicizeFeature, - isShareLimitEnabled, isPostAlreadyShared, - numberOfSharesRemaining: sharesData.shares_remaining, - shouldShowAdvancedPlanNudge: sharesData.show_advanced_plan_upgrade_nudge, hasPaidPlan, isEnhancedPublishingEnabled, isSocialImageGeneratorAvailable: diff --git a/projects/js-packages/publicize-components/src/hooks/use-refresh-connections/index.js b/projects/js-packages/publicize-components/src/hooks/use-refresh-connections/index.js index 2205988638fce..40b230fea061c 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-refresh-connections/index.js +++ b/projects/js-packages/publicize-components/src/hooks/use-refresh-connections/index.js @@ -6,7 +6,7 @@ import useSelectSocialMediaConnections from '../use-social-media-connections'; /** * Hook that provides a function to refresh the connections. * - * @returns { object } The refreshConnections function. + * @return { object } The refreshConnections function. */ export default function useRefreshConnections() { const shouldAutoRefresh = useRef( false ); diff --git a/projects/js-packages/publicize-components/src/hooks/use-save-image-to-library/index.ts b/projects/js-packages/publicize-components/src/hooks/use-save-image-to-library/index.ts index 58159171e7dc1..042934f8b14a3 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-save-image-to-library/index.ts +++ b/projects/js-packages/publicize-components/src/hooks/use-save-image-to-library/index.ts @@ -17,7 +17,7 @@ export type SaveImageToLibrary = { * * @param {SaveImageToLibraryOptions} options - Options for the hook. * - * @returns {SaveImageToLibrary} The object. + * @return {SaveImageToLibrary} The object. */ export function useSaveImageToLibrary( { onError, onSuccess }: SaveImageToLibraryOptions ) { const [ isSaving, setIsSaving ] = useState( false ); diff --git a/projects/js-packages/publicize-components/src/hooks/use-saving-post/index.js b/projects/js-packages/publicize-components/src/hooks/use-saving-post/index.js index 1fbe99fbce52d..47849e39f6666 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-saving-post/index.js +++ b/projects/js-packages/publicize-components/src/hooks/use-saving-post/index.js @@ -8,8 +8,8 @@ import { useEffect } from '@wordpress/element'; * running the callback when it happens. * Additionally, it accepts a dependency array which is passed to useEffect hook. * - * @param {Function} fn - Callback function to run when the post is just saved. - * @param {Array} deps - Depencency array. + * @param {Function} fn - Callback function to run when the post is just saved. + * @param {Array} deps - Depencency array. */ export function usePostJustSaved( fn, deps ) { const isSaving = useSelect( select => select( editorStore ).isSavingPost(), [] ); @@ -29,8 +29,8 @@ export function usePostJustSaved( fn, deps ) { * running the callback when it happens. * Additionally, it accepts a dependency array which is passed to useEffect hook. * - * @param {Function} fn - Callback function to run when the post is just published. - * @param {Array} [deps] - Depencency array. + * @param {Function} fn - Callback function to run when the post is just published. + * @param {Array} [deps] - Depencency array. */ export function usePostJustPublished( fn, deps ) { const isPublishing = useSelect( select => select( editorStore ).isPublishingPost(), [] ); @@ -50,8 +50,8 @@ export function usePostJustPublished( fn, deps ) { * running the callback when it happens. * Additionally, it accepts a dependency array which is passed to useEffect hook. * - * @param {Function} fn - Callback function to run when the post starts publishing. - * @param {Array} deps - Dependency array. + * @param {Function} fn - Callback function to run when the post starts publishing. + * @param {Array} deps - Dependency array. */ export function usePostStartedPublishing( fn, deps ) { const isPublishing = useSelect( select => select( editorStore ).isPublishingPost(), [] ); diff --git a/projects/js-packages/publicize-components/src/hooks/use-share-limits/index.ts b/projects/js-packages/publicize-components/src/hooks/use-share-limits/index.ts deleted file mode 100644 index afb5496887d59..0000000000000 --- a/projects/js-packages/publicize-components/src/hooks/use-share-limits/index.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { useSelect } from '@wordpress/data'; -import { __, _n, sprintf } from '@wordpress/i18n'; -import { store as socialStore } from '../../social-store'; - -export type ShareLimits = { - status: 'approaching' | 'exceeded' | 'full' | 'none'; - noticeType: 'default' | 'warning' | 'error'; - message: string; - usedCount: number; - scheduledCount: number; - remainingCount: number; -}; - -export type UseShareLimitsArgs = { - scheduledCountAdjustment?: number; - usedCountAdjustment?: number; -}; - -/** - * Returns the messages for the share limits - * - * @param {number} remainingCount - The number of shares left - * @returns {ReturnType} Share limits messages - */ -export function getMessages( remainingCount: number ) { - const remaining = Number.isFinite( remainingCount ) - ? sprintf( - // translators: %d: The number of shares to social media remaining - _n( - 'You have %d auto-share remaining.', - 'You have %d auto-shares remaining.', - remainingCount, - 'jetpack' - ), - remainingCount - ) - : ''; - return { - default: '', - exceeded: __( - 'You have reached your auto-share limit. Scheduled posts will not be shared until shares become available.', - 'jetpack' - ), - full: __( 'You have reached your auto-share limit.', 'jetpack' ), - approaching: remaining, - }; -} - -/** - * Returns the share limits details - * - * @param {UseShareLimitsArgs} args - Arguments - * - * @returns {ShareLimits} Share limits details - */ -export function useShareLimits( { - scheduledCountAdjustment = 0, - usedCountAdjustment = 0, -}: UseShareLimitsArgs = {} ): ShareLimits { - return useSelect( - select => { - const store = select( socialStore ); - - const shareLimit = store.getShareLimit(); - const scheduledShares = store.getScheduledSharesCount() + scheduledCountAdjustment; - const usedSharesCount = store.getSharesUsedCount() + usedCountAdjustment; - const totalSharesCount = usedSharesCount + scheduledShares; - const remainingCount = store.numberOfSharesRemaining(); - const messages = getMessages( remainingCount ); - - let noticeType: ShareLimits[ 'noticeType' ] = 'default'; - let status: ShareLimits[ 'status' ] = 'none'; - let message = messages.default; - - // If they have exceeded their limit - if ( totalSharesCount > shareLimit ) { - noticeType = 'error'; - status = 'exceeded'; - message = messages.exceeded; - } else if ( totalSharesCount === shareLimit ) { - status = 'full'; - noticeType = 'error'; - message = messages.full; - } - // If they have used 90% of their limit, they are almost at the end - else if ( totalSharesCount >= shareLimit * 0.9 ) { - status = 'approaching'; - noticeType = 'error'; - message = messages.approaching; - } - // If they have used 80% of their limit, they are approaching it - else if ( totalSharesCount >= shareLimit * 0.8 ) { - status = 'approaching'; - noticeType = 'warning'; - message = messages.approaching; - } - - return { - status, - noticeType, - message, - usedCount: usedSharesCount, - scheduledCount: scheduledShares, - remainingCount, - }; - }, - [ scheduledCountAdjustment, usedCountAdjustment ] - ); -} diff --git a/projects/js-packages/publicize-components/src/hooks/use-share-limits/test/index.test.tsx b/projects/js-packages/publicize-components/src/hooks/use-share-limits/test/index.test.tsx deleted file mode 100644 index 4bb2db3d72616..0000000000000 --- a/projects/js-packages/publicize-components/src/hooks/use-share-limits/test/index.test.tsx +++ /dev/null @@ -1,211 +0,0 @@ -import { renderHook } from '@testing-library/react'; -import { RegistryProvider, createRegistry, createReduxStore } from '@wordpress/data'; -import { WPDataRegistry } from '@wordpress/data/build-types/registry'; -import { getMessages, useShareLimits } from '../'; -import { SOCIAL_STORE_CONFIG, SOCIAL_STORE_ID } from '../../../social-store'; -import { SocialStoreState } from '../../../social-store/types'; - -type DeepPartial< T > = T extends object - ? { - [ P in keyof T ]?: DeepPartial< T[ P ] >; - } - : T; - -/** - * Create a registry with stores. - * - * @param {Partial< SocialStoreState >} initialState - Initial state for the store. - * - * @returns {WPDataRegistry} Registry. - */ -function createRegistryWithStores( initialState = {} ): WPDataRegistry { - // Create a registry. - const registry = createRegistry(); - - const socialStore = createReduxStore( SOCIAL_STORE_ID, { ...SOCIAL_STORE_CONFIG, initialState } ); - // Register stores. - // @ts-expect-error The registry type is not correct. This comment can be removed when register() exists in the type. - registry.register( socialStore ); - - return registry; -} - -/** - * Returns the initial state for the store. - * - * @param {Partial< SocialStoreState >} data - Data to override the default state - * - * @returns {SocialStoreState} Initial state for the store - */ -function getStoreInitialState( data: DeepPartial< SocialStoreState > ) { - return { - ...data, - sharesData: { - is_share_limit_enabled: true, - to_be_publicized_count: 0, - share_limit: 30, - publicized_count: 0, - show_advanced_plan_upgrade_nudge: false, - shared_posts_count: 0, - ...data.sharesData, - }, - }; -} - -const messages = getMessages( 0 ); - -describe( 'useShareLimits', () => { - it( 'should return the default values', () => { - const { result } = renderHook( () => useShareLimits() ); - - expect( result.current ).toEqual( { - status: 'none', - noticeType: 'default', - message: getMessages( Infinity ).default, - usedCount: 0, - scheduledCount: 0, - remainingCount: Infinity, - } ); - } ); - - const testCases = [ - { - name: 'should return the default values at the beginning', - sharesData: { - publicized_count: 0, - to_be_publicized_count: 0, - }, - expected: { - status: 'none', - noticeType: 'default', - message: getMessages( 30 ).default, - usedCount: 0, - scheduledCount: 0, - remainingCount: 30, - }, - }, - { - name: 'should return "default" with default message when used + scheduled < limit', - sharesData: { - publicized_count: 5, - to_be_publicized_count: 5, - }, - expected: { - status: 'none', - noticeType: 'default', - message: getMessages( 20 ).default, - usedCount: 5, - scheduledCount: 5, - remainingCount: 20, - }, - }, - { - name: 'should return "full" with limit exceeded message when the limit is reached without scheduled posts', - sharesData: { - publicized_count: 30, - to_be_publicized_count: 0, - }, - expected: { - status: 'full', - noticeType: 'error', - message: messages.full, - usedCount: 30, - scheduledCount: 0, - remainingCount: 0, - }, - }, - { - name: 'should return "full" with scheduled shares message when the limit is reached with scheduled posts', - sharesData: { - publicized_count: 15, - to_be_publicized_count: 15, - }, - expected: { - status: 'full', - noticeType: 'error', - message: messages.full, - usedCount: 15, - scheduledCount: 15, - remainingCount: 0, - }, - }, - { - name: 'should return "crossed" with limit exceeded message when the limit is crossed without scheduled posts', - sharesData: { - publicized_count: 35, // impossible to reach this number but just in case - to_be_publicized_count: 0, - }, - expected: { - status: 'exceeded', - noticeType: 'error', - message: messages.exceeded, - usedCount: 35, - scheduledCount: 0, - remainingCount: 0, - }, - }, - { - name: 'should return "crossed" with limit exceeded message when the limit is crossed with scheduled posts', - sharesData: { - publicized_count: 30, - to_be_publicized_count: 5, - }, - expected: { - status: 'exceeded', - noticeType: 'error', - message: messages.exceeded, - usedCount: 30, - scheduledCount: 5, - remainingCount: 0, - }, - }, - { - name: 'should return "approaching" with approaching limit message when the limit is approached without scheduled posts', - sharesData: { - publicized_count: 25, - to_be_publicized_count: 0, - }, - expected: { - status: 'approaching', - noticeType: 'warning', - message: getMessages( 5 ).approaching, - usedCount: 25, - scheduledCount: 0, - remainingCount: 5, - }, - }, - { - name: 'should return "approaching" with approaching limit message when the limit is approached with scheduled posts', - sharesData: { - publicized_count: 20, - to_be_publicized_count: 5, - }, - expected: { - status: 'approaching', - noticeType: 'warning', - message: getMessages( 5 ).approaching, - usedCount: 20, - scheduledCount: 5, - remainingCount: 5, - }, - }, - ]; - - for ( const { name, expected, ...initiaState } of testCases ) { - describe( 'dynamic tests', () => { - it( `${ name }`, () => { - const { result } = renderHook( () => useShareLimits(), { - wrapper: ( { children } ) => ( - - { children } - - ), - } ); - - expect( result.current ).toEqual( expected ); - } ); - } ); - } -} ); diff --git a/projects/js-packages/publicize-components/src/hooks/use-share-post/index.js b/projects/js-packages/publicize-components/src/hooks/use-share-post/index.js index 2dd89900f0626..0b94ee04a8844 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-share-post/index.js +++ b/projects/js-packages/publicize-components/src/hooks/use-share-post/index.js @@ -1,4 +1,3 @@ -import { getJetpackData } from '@automattic/jetpack-shared-extension-utils'; import apiFetch from '@wordpress/api-fetch'; import { useSelect } from '@wordpress/data'; import { store as editorStore } from '@wordpress/editor'; @@ -6,12 +5,13 @@ import { useState, useCallback } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import useSocialMediaConnections from '../../hooks/use-social-media-connections'; import useSocialMediaMessage from '../../hooks/use-social-media-message'; +import { getSocialScriptData } from '../../utils/script-data'; /** * Takes an error object and returns a more meaningful error message. * * @param {object} result - An API error object. - * @returns {{ message: string, result: object }} The error message and passed in error object. + * @return {{ message: string, result: object }} The error message and passed in error object. */ function getHumanReadableError( result ) { // Errors coming from the API. @@ -67,7 +67,7 @@ function getHumanReadableError( result ) { * A hook to get the necessary data and callbacks to reshare a post. * * @param {number} postId - The ID of the post to share. - * @returns { { doPublicize: Function, data: object } } The doPublicize callback to share the post. + * @return { { doPublicize: Function, data: object } } The doPublicize callback to share the post. */ export default function useSharePost( postId ) { // Sharing data. @@ -79,9 +79,7 @@ export default function useSharePost( postId ) { postId = postId || currentPostId; const [ data, setData ] = useState( { data: [], error: {} } ); - const path = ( - getJetpackData()?.social?.resharePath ?? '/wpcom/v2/posts/{postId}/publicize' - ).replace( '{postId}', postId ); + const path = getSocialScriptData().api_paths.resharePost.replace( '{postId}', postId ); const doPublicize = useCallback( function () { diff --git a/projects/js-packages/publicize-components/src/hooks/use-social-media-connections/index.ts b/projects/js-packages/publicize-components/src/hooks/use-social-media-connections/index.ts index f33c4ed00df3a..cc922ef523042 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-social-media-connections/index.ts +++ b/projects/js-packages/publicize-components/src/hooks/use-social-media-connections/index.ts @@ -4,7 +4,7 @@ import { store as socialStore } from '../../social-store'; /** * Hooks to deal with the social media connections. * - * @returns {object} Social media connection handler. + * @return {object} Social media connection handler. */ export default function useSocialMediaConnections() { const { refreshConnectionTestResults, toggleConnectionById } = useDispatch( socialStore ); diff --git a/projects/js-packages/publicize-components/src/hooks/use-social-media-message/index.js b/projects/js-packages/publicize-components/src/hooks/use-social-media-message/index.js index 313e4f0b89887..2783efc96e1ce 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-social-media-message/index.js +++ b/projects/js-packages/publicize-components/src/hooks/use-social-media-message/index.js @@ -3,15 +3,15 @@ import { usePostMeta } from '../use-post-meta'; /** * @typedef {object} MessageHook - * @property {string} message - The text of the message. - * @property {number} maxLength - The maximum length of the message. + * @property {string} message - The text of the message. + * @property {number} maxLength - The maximum length of the message. * @property {Function} updateMessage - Callback used to update the message. */ /** * Hook to handle storing the the current custom message. * - * @returns {MessageHook} - An object with the message hook properties set. + * @return {MessageHook} - An object with the message hook properties set. */ export default function useSocialMediaMessage() { const { updateMeta, shareMessage } = usePostMeta(); diff --git a/projects/js-packages/publicize-components/src/hooks/use-sync-post-data-to-store/test/index.test.js b/projects/js-packages/publicize-components/src/hooks/use-sync-post-data-to-store/test/index.test.js index 2593baa4d1c1d..c74bf768b4b3d 100644 --- a/projects/js-packages/publicize-components/src/hooks/use-sync-post-data-to-store/test/index.test.js +++ b/projects/js-packages/publicize-components/src/hooks/use-sync-post-data-to-store/test/index.test.js @@ -7,7 +7,7 @@ import { store as socialStore } from '../../../social-store'; import { connections as connectionsList, createRegistryWithStores, - testPost, + postPublishFetchHandler, } from '../../../utils/test-utils'; const connections = connectionsList.map( connection => ( { ...connection, enabled: true } ) ); @@ -16,9 +16,6 @@ const post = { jetpack_publicize_connections: [ connections[ 0 ] ], }; -const getMethod = options => - options.headers?.[ 'X-HTTP-Method-Override' ] || options.method || 'GET'; - describe( 'useSyncPostDataToStore', () => { it( 'should do nothing by default', async () => { const registry = createRegistryWithStores( post ); @@ -67,37 +64,7 @@ describe( 'useSyncPostDataToStore', () => { await registry.resolveSelect( socialStore ).getConnections(); // Mock apiFetch response. - apiFetch.setFetchHandler( async options => { - const method = getMethod( options ); - const { path, data, parse = true } = options; - - const wrapReturn = parse - ? v => v - : v => - // Ideally we'd do `new Response( JSON.stringify( v ) )` here, but jsdom deletes that. Sigh. - // See https://github.com/jsdom/jsdom/issues/1724 - ( { - async json() { - return v; - }, - } ); - - if ( method === 'PUT' && path.startsWith( `/wp/v2/posts/${ testPost.id }` ) ) { - return wrapReturn( { ...post, ...data } ); - } else if ( - // This URL is requested by the actions dispatched in this test. - // They are safe to ignore and are only listed here to avoid triggeringan error. - method === 'GET' && - path.startsWith( '/wp/v2/types/post' ) - ) { - return wrapReturn( {} ); - } - - throw { - code: 'unknown_path', - message: `Unknown path: ${ method } ${ path }`, - }; - } ); + apiFetch.setFetchHandler( postPublishFetchHandler( post ) ); const prevConnections = registry.select( socialStore ).getConnections(); diff --git a/projects/js-packages/publicize-components/src/social-store/actions/connection-data.js b/projects/js-packages/publicize-components/src/social-store/actions/connection-data.js index 5e2c7ec0aae9d..8c23c207ad21d 100644 --- a/projects/js-packages/publicize-components/src/social-store/actions/connection-data.js +++ b/projects/js-packages/publicize-components/src/social-store/actions/connection-data.js @@ -3,6 +3,7 @@ import apiFetch from '@wordpress/api-fetch'; import { dispatch as coreDispatch } from '@wordpress/data'; import { store as editorStore } from '@wordpress/editor'; import { __, sprintf } from '@wordpress/i18n'; +import { getSocialScriptData } from '../../utils/script-data'; import { ADD_CONNECTION, DELETE_CONNECTION, @@ -22,7 +23,7 @@ import { /** * Set connections list * @param {Array} connections - list of connections - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setConnections( connections ) { return { @@ -36,7 +37,7 @@ export function setConnections( connections ) { * * @param {import('../types').KeyringResult} [keyringResult] - keyring result * - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setKeyringResult( keyringResult ) { return { @@ -48,7 +49,7 @@ export function setKeyringResult( keyringResult ) { /** * Add connection to the list * @param {import('../types').Connection} connection - connection object - * @returns {object} - an action object. + * @return {object} - an action object. */ export function addConnection( connection ) { return { @@ -61,7 +62,7 @@ export function addConnection( connection ) { * Toggle connection enable status. * @param {string} connectionId - Connection ID to switch. * - * @returns {object} Switch connection enable-status action. + * @return {object} Switch connection enable-status action. */ export function toggleConnection( connectionId ) { return { @@ -73,7 +74,7 @@ export function toggleConnection( connectionId ) { /** * Merge connections with fresh connections. * @param {Array} freshConnections - list of fresh connections - * @returns {Function} - a function to merge connections. + * @return {Function} - a function to merge connections. */ export function mergeConnections( freshConnections ) { return function ( { dispatch, select } ) { @@ -82,7 +83,7 @@ export function mergeConnections( freshConnections ) { const connections = []; const defaults = { done: false, - enabled: Boolean( select.numberOfSharesRemaining() ), + enabled: true, toggleable: true, }; @@ -113,9 +114,9 @@ export function mergeConnections( freshConnections ) { /** * Create an abort controller. * @param {AbortController} abortController - Abort controller. - * @param {string} requestType - Type of abort request. + * @param {string} requestType - Type of abort request. * - * @returns {object} - an action object. + * @return {object} - an action object. */ export function createAbortController( abortController, requestType ) { return { @@ -130,7 +131,7 @@ export function createAbortController( abortController, requestType ) { * * @param {string} requestType - Type of abort request. * - * @returns {object} - an action object. + * @return {object} - an action object. */ export function removeAbortControllers( requestType ) { return { @@ -144,7 +145,7 @@ export function removeAbortControllers( requestType ) { * * @param {string} requestType - Type of abort request. * - * @returns {Function} - a function to abort a request. + * @return {Function} - a function to abort a request. */ export function abortRequest( requestType ) { return function ( { dispatch, select } ) { @@ -162,7 +163,7 @@ export function abortRequest( requestType ) { /** * Abort the refresh connections request. * - * @returns {Function} - a function to abort a request. + * @return {Function} - a function to abort a request. */ export function abortRefreshConnectionsRequest() { return abortRequest( REQUEST_TYPE_REFRESH_CONNECTIONS ); @@ -171,13 +172,13 @@ export function abortRefreshConnectionsRequest() { /** * Effect handler which will refresh the connection test results. * - * @param {boolean} syncToMeta - Whether to sync the connection state to the post meta. - * @returns {Function} Refresh connection test results action. + * @param {boolean} syncToMeta - Whether to sync the connection state to the post meta. + * @return {Function} Refresh connection test results action. */ export function refreshConnectionTestResults( syncToMeta = false ) { return async function ( { dispatch, select } ) { try { - const path = select.connectionRefreshPath() || '/wpcom/v2/publicize/connection-test-results'; + const path = getSocialScriptData().api_paths.refreshConnections; // Wait until all connections are done updating/deleting. while ( @@ -212,7 +213,7 @@ export function refreshConnectionTestResults( syncToMeta = false ) { /** * Syncs the connections to the post meta. * - * @returns {Function} Sync connections to post meta action. + * @return {Function} Sync connections to post meta action. */ export function syncConnectionsToPostMeta() { return function ( { registry, select } ) { @@ -228,9 +229,9 @@ export function syncConnectionsToPostMeta() { /** * Toggles the connection enable-status. * - * @param {string} connectionId - Connection ID to switch. - * @param {boolean} syncToMeta - Whether to sync the connection state to the post meta. - * @returns {object} Switch connection enable-status action. + * @param {string} connectionId - Connection ID to switch. + * @param {boolean} syncToMeta - Whether to sync the connection state to the post meta. + * @return {object} Switch connection enable-status action. */ export function toggleConnectionById( connectionId, syncToMeta = true ) { return function ( { dispatch } ) { @@ -247,7 +248,7 @@ export function toggleConnectionById( connectionId, syncToMeta = true ) { * * @param {string} connectionId - Connection ID to delete. * - * @returns {object} Delete connection action. + * @return {object} Delete connection action. */ export function deleteConnection( connectionId ) { return { @@ -259,10 +260,10 @@ export function deleteConnection( connectionId ) { /** * Marks a connection as being deleted. * - * @param {string} connectionId - Connection ID to delete. - * @param {boolean} deleting - Whether the connection is being deleted. + * @param {string} connectionId - Connection ID to delete. + * @param {boolean} deleting - Whether the connection is being deleted. * - * @returns {object} Deleting connection action. + * @return {object} Deleting connection action. */ export function deletingConnection( connectionId, deleting = true ) { return { @@ -275,11 +276,11 @@ export function deletingConnection( connectionId, deleting = true ) { /** * Deletes a connection by disconnecting it. * - * @param {object} args - Arguments. - * @param {string | number} args.connectionId - Connection ID to delete. - * @param {boolean} [args.showSuccessNotice] - Whether to show a success notice. + * @param {object} args - Arguments. + * @param {string | number} args.connectionId - Connection ID to delete. + * @param {boolean} [args.showSuccessNotice] - Whether to show a success notice. * - * @returns {boolean} Whether the connection was deleted. + * @return {boolean} Whether the connection was deleted. */ export function deleteConnectionById( { connectionId, showSuccessNotice = true } ) { return async function ( { registry, dispatch } ) { @@ -331,9 +332,9 @@ let uniqueId = 1; /** * Creates a connection. * - * @param {Record} data - The data for API call. + * @param {Record} data - The data for API call. * @param {Record} optimisticData - Optimistic data for the connection. - * @returns {void} + * @return {void} */ export function createConnection( data, optimisticData = {} ) { return async function ( { registry, dispatch } ) { @@ -408,10 +409,10 @@ export function createConnection( data, optimisticData = {} ) { /** * Updates a connection. * - * @param {string} connectionId - Connection ID to update. - * @param {Record} data - The data. + * @param {string} connectionId - Connection ID to update. + * @param {Record} data - The data. * - * @returns {object} Delete connection action. + * @return {object} Delete connection action. */ export function updateConnection( connectionId, data ) { return { @@ -424,10 +425,10 @@ export function updateConnection( connectionId, data ) { /** * Marks a connection as being updating. * - * @param {string} connectionId - Connection ID being updated. - * @param {boolean} updating - Whether the connection is being updated. + * @param {string} connectionId - Connection ID being updated. + * @param {boolean} updating - Whether the connection is being updated. * - * @returns {object} Deleting connection action. + * @return {object} Deleting connection action. */ export function updatingConnection( connectionId, updating = true ) { return { @@ -442,7 +443,7 @@ export function updatingConnection( connectionId, updating = true ) { * * @param {string} reconnectingAccount - Account being reconnected. * - * @returns {object} Reconnecting account action. + * @return {object} Reconnecting account action. */ export function setReconnectingAccount( reconnectingAccount ) { return { @@ -454,9 +455,9 @@ export function setReconnectingAccount( reconnectingAccount ) { /** * Updates a connection. * - * @param {string} connectionId - Connection ID to update. - * @param {Record} data - The data for API call. - * @returns {void} + * @param {string} connectionId - Connection ID to update. + * @param {Record} data - The data for API call. + * @return {void} */ export function updateConnectionById( connectionId, data ) { return async function ( { dispatch, select } ) { @@ -505,7 +506,7 @@ export function updateConnectionById( connectionId, data ) { * * @param {boolean} isOpen - Whether the modal is open. * - * @returns {object} - An action object. + * @return {object} - An action object. */ export function toggleConnectionsModal( isOpen ) { return { @@ -517,7 +518,7 @@ export function toggleConnectionsModal( isOpen ) { /** * Opens the connections modal. * - * @returns {object} - An action object. + * @return {object} - An action object. */ export function openConnectionsModal() { return toggleConnectionsModal( true ); @@ -525,7 +526,7 @@ export function openConnectionsModal() { /** * Closes the connections modal. - * @returns {object} - An action object. + * @return {object} - An action object. */ export function closeConnectionsModal() { return toggleConnectionsModal( false ); diff --git a/projects/js-packages/publicize-components/src/social-store/actions/constants.ts b/projects/js-packages/publicize-components/src/social-store/actions/constants.ts index 634acf1a23fdd..4ce7e68b7c58d 100644 --- a/projects/js-packages/publicize-components/src/social-store/actions/constants.ts +++ b/projects/js-packages/publicize-components/src/social-store/actions/constants.ts @@ -25,3 +25,9 @@ export const REMOVE_ABORT_CONTROLLERS = 'REMOVE_ABORT_CONTROLLERS'; export const REQUEST_TYPE_DEFAULT = 'DEFAULT'; export const REQUEST_TYPE_REFRESH_CONNECTIONS = 'REFRESH_CONNECTIONS'; + +export const FETCH_POST_SHARE_STATUS = 'FETCH_POST_SHARE_STATUS' as const; + +export const RECEIVE_POST_SHARE_STATUS = 'RECEIVE_POST_SHARE_STATUS' as const; + +export const TOGGLE_SHARE_STATUS_MODAL = 'TOGGLE_SHARE_STATUS_MODAL' as const; diff --git a/projects/js-packages/publicize-components/src/social-store/actions/index.js b/projects/js-packages/publicize-components/src/social-store/actions/index.js index c214e9d7dd6c7..0bfa479c22fa7 100644 --- a/projects/js-packages/publicize-components/src/social-store/actions/index.js +++ b/projects/js-packages/publicize-components/src/social-store/actions/index.js @@ -1,10 +1,12 @@ import * as connectionData from './connection-data'; import siteSettingActions from './jetpack-settings'; import jetpackSocialSettings from './jetpack-social-settings'; +import * as shareStatus from './share-status'; import socialImageGeneratorSettingActions from './social-image-generator-settings'; import socialNotesSettings from './social-notes-settings'; const actions = { + ...shareStatus, ...siteSettingActions, ...socialImageGeneratorSettingActions, ...jetpackSocialSettings, diff --git a/projects/js-packages/publicize-components/src/social-store/actions/jetpack-settings.js b/projects/js-packages/publicize-components/src/social-store/actions/jetpack-settings.js index 1a6692d77791f..535928f4e16d3 100644 --- a/projects/js-packages/publicize-components/src/social-store/actions/jetpack-settings.js +++ b/projects/js-packages/publicize-components/src/social-store/actions/jetpack-settings.js @@ -12,8 +12,8 @@ export const TOGGLE_PUBLICIZE_MODULE = 'TOGGLE_PUBLICIZE_MODULE'; * Yield actions to update settings * * @param {object} settings - settings to apply. - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* updateJetpackSettings( settings ) { try { @@ -35,7 +35,7 @@ export function* updateJetpackSettings( settings ) { /** * Set state updating action * - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setUpdatingJetpackSettings() { return setJetpackSettings( { is_updating: true } ); @@ -44,7 +44,7 @@ export function setUpdatingJetpackSettings() { /** * Set state updating finished * - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setUpdatingJetpackSettingsDone() { return setJetpackSettings( { is_updating: false } ); @@ -54,7 +54,7 @@ export function setUpdatingJetpackSettingsDone() { * Set Jetpack settings action * * @param {object} options - Jetpack settings. - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setJetpackSettings( options ) { return { type: SET_JETPACK_SETTINGS, options }; diff --git a/projects/js-packages/publicize-components/src/social-store/actions/jetpack-social-settings.js b/projects/js-packages/publicize-components/src/social-store/actions/jetpack-social-settings.js index 0273a6fdf8f8f..23827a6261787 100644 --- a/projects/js-packages/publicize-components/src/social-store/actions/jetpack-social-settings.js +++ b/projects/js-packages/publicize-components/src/social-store/actions/jetpack-social-settings.js @@ -8,8 +8,8 @@ import { /** * Yield actions to refresh all of the Jetpack Social registered settings. * - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* refreshJetpackSocialSettings() { try { diff --git a/projects/js-packages/publicize-components/src/social-store/actions/share-status.ts b/projects/js-packages/publicize-components/src/social-store/actions/share-status.ts new file mode 100644 index 0000000000000..36e62ea6d4da5 --- /dev/null +++ b/projects/js-packages/publicize-components/src/social-store/actions/share-status.ts @@ -0,0 +1,72 @@ +import { SocialStoreState } from '../types'; +import { + FETCH_POST_SHARE_STATUS, + RECEIVE_POST_SHARE_STATUS, + TOGGLE_SHARE_STATUS_MODAL, +} from './constants'; + +/** + * Returns an action object used in signalling that the post share status + * has been requested and is loading. + * + * @param {number} postId - Post ID. + * @param {boolean} [loading] - Loading status. + * @return {object} Action object. + */ +export function fetchPostShareStatus( postId: number, loading = true ) { + return { + type: FETCH_POST_SHARE_STATUS, + postId, + loading, + }; +} + +/** + * Returns an action object used in signalling that the post share status has been received. + * + * @param {SocialStoreState[ 'shareStaus' ][ number ]} shareStatus - Post share status. + * @param {number} postId - Post ID. + * + * @return {object} Action object. + */ +export function receivePostShareStaus( + shareStatus: SocialStoreState[ 'shareStatus' ][ number ], + postId: number +) { + return { + type: RECEIVE_POST_SHARE_STATUS, + shareStatus, + postId, + }; +} + +/** + * Toggles the share status modal. + * + * @param {boolean} isOpen - Whether the modal is open. + * + * @return {object} - An action object. + */ +export function toggleShareStatusModal( isOpen: boolean ) { + return { + type: TOGGLE_SHARE_STATUS_MODAL, + isOpen, + }; +} + +/** + * Opens the share status modal. + * + * @return {object} - An action object. + */ +export function openShareStatusModal() { + return toggleShareStatusModal( true ); +} + +/** + * Closes the share status modal. + * @return {object} - An action object. + */ +export function closeShareStatusModal() { + return toggleShareStatusModal( false ); +} diff --git a/projects/js-packages/publicize-components/src/social-store/actions/social-image-generator-settings.js b/projects/js-packages/publicize-components/src/social-store/actions/social-image-generator-settings.js index 22d1f4917b733..73fc4ad0ae7f0 100644 --- a/projects/js-packages/publicize-components/src/social-store/actions/social-image-generator-settings.js +++ b/projects/js-packages/publicize-components/src/social-store/actions/social-image-generator-settings.js @@ -11,8 +11,8 @@ export const SET_SOCIAL_IMAGE_GENERATOR_SETTINGS = 'SET_SOCIAL_IMAGE_GENERATOR_S * Yield actions to update settings * * @param {object} settings - settings to apply. - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* updateSocialImageGeneratorSettings( settings ) { try { @@ -36,7 +36,7 @@ export function* updateSocialImageGeneratorSettings( settings ) { /** * Set state updating action * - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setUpdatingSocialImageGeneratorSettings() { return setSocialImageGeneratorSettings( { isUpdating: true } ); @@ -45,7 +45,7 @@ export function setUpdatingSocialImageGeneratorSettings() { /** * Set state updating finished * - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setUpdatingSocialImageGeneratorSettingsDone() { return setSocialImageGeneratorSettings( { isUpdating: false } ); @@ -55,7 +55,7 @@ export function setUpdatingSocialImageGeneratorSettingsDone() { * Set Social Image Generator settings action * * @param {object} options - Social Image Generator settings. - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setSocialImageGeneratorSettings( options ) { return { type: SET_SOCIAL_IMAGE_GENERATOR_SETTINGS, options }; @@ -64,8 +64,8 @@ export function setSocialImageGeneratorSettings( options ) { /** * Yield actions to refresh settings * - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* refreshSocialImageGeneratorSettings() { try { diff --git a/projects/js-packages/publicize-components/src/social-store/actions/social-notes-settings.js b/projects/js-packages/publicize-components/src/social-store/actions/social-notes-settings.js index f45f03a23a10f..35243885cd383 100644 --- a/projects/js-packages/publicize-components/src/social-store/actions/social-notes-settings.js +++ b/projects/js-packages/publicize-components/src/social-store/actions/social-notes-settings.js @@ -10,8 +10,8 @@ import { setJetpackSettings } from './jetpack-settings'; * Yield actions to update settings * * @param {object} settings - settings to apply. - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* updateSocialNotesSettings( settings ) { try { @@ -34,8 +34,8 @@ export function* updateSocialNotesSettings( settings ) { * Yield actions to update settings * * @param {object} config - config to update - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* updateSocialNotesConfig( config ) { const prevConfig = select( SOCIAL_STORE_ID ).getSocialNotesConfig(); @@ -55,8 +55,8 @@ export function* updateSocialNotesConfig( config ) { /** * Yield actions to refresh settings * - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* refreshSocialNotesSettings() { try { @@ -74,7 +74,7 @@ export function* refreshSocialNotesSettings() { /** * Set state updating action * - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setUpdatingSocialNotesSettings() { return setJetpackSettings( { social_notes_is_updating: true } ); @@ -83,7 +83,7 @@ export function setUpdatingSocialNotesSettings() { /** * Set state updating finished * - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setUpdatingSocialNotesSettingsDone() { return setJetpackSettings( { social_notes_is_updating: false } ); @@ -92,7 +92,7 @@ export function setUpdatingSocialNotesSettingsDone() { /** * Set state updating action * - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setUpdatingSocialNotesConfig() { return setJetpackSettings( { social_notes_config_is_updating: true } ); diff --git a/projects/js-packages/publicize-components/src/social-store/actions/test/connection-data.js b/projects/js-packages/publicize-components/src/social-store/actions/test/connection-data.js index 78d68ece7d2c9..86b84bc27c9b3 100644 --- a/projects/js-packages/publicize-components/src/social-store/actions/test/connection-data.js +++ b/projects/js-packages/publicize-components/src/social-store/actions/test/connection-data.js @@ -14,7 +14,7 @@ const post = { * * @param {boolean} initConnections - Whether to set initial connections. * - * @returns {WPDataRegistry} Registry. + * @return {WPDataRegistry} Registry. */ function createRegistryWithStores( initConnections = true ) { // Create a registry. @@ -139,10 +139,21 @@ describe( 'Social store actions: connectionData', () => { } ); describe( 'refreshConnectionTestResults', () => { + const refreshConnections = '/wpcom/v2/publicize/connection-test-results'; + beforeAll( () => { + global.JetpackScriptData = { + social: { + api_paths: { + refreshConnections, + }, + }, + }; + } ); + it( 'should refresh connection test results', async () => { // Mock apiFetch response. apiFetch.setFetchHandler( async ( { path } ) => { - if ( path.startsWith( '/wpcom/v2/publicize/connection-test-results' ) ) { + if ( path.startsWith( refreshConnections ) ) { return connections.map( connection => ( { ...connection, can_refresh: false, diff --git a/projects/js-packages/publicize-components/src/social-store/controls.js b/projects/js-packages/publicize-components/src/social-store/controls.js index a0418877b2be4..7830da3898d67 100644 --- a/projects/js-packages/publicize-components/src/social-store/controls.js +++ b/projects/js-packages/publicize-components/src/social-store/controls.js @@ -10,7 +10,7 @@ export const FETCH_JETPACK_SOCIAL_SETTINGS = 'FETCH_JETPACK_SOCIAL_SETTINGS'; /** * fetchJetpackSettings action * - * @returns {object} - an action object. + * @return {object} - an action object. */ export const fetchJetpackSettings = () => { return { @@ -22,7 +22,7 @@ export const fetchJetpackSettings = () => { * updateJetpackSettings action * * @param {*} settings - Jetpack settings object. - * @returns {object} - an action object. + * @return {object} - an action object. */ export const updateJetpackSettings = settings => { return { @@ -34,7 +34,7 @@ export const updateJetpackSettings = settings => { /** * fetchSocialImageGeneratorSettings action * - * @returns {object} - an action object. + * @return {object} - an action object. */ export const fetchSocialImageGeneratorSettings = () => { return { @@ -46,7 +46,7 @@ export const fetchSocialImageGeneratorSettings = () => { * updateSocialImageGeneratorSettings action * * @param {*} settings - Social Image Generator settings object. - * @returns {object} - an action object. + * @return {object} - an action object. */ export const updateSocialImageGeneratorSettings = settings => { return { @@ -58,7 +58,7 @@ export const updateSocialImageGeneratorSettings = settings => { /** * fetchJetpackSocialSettings action * - * @returns {object} - an action object. + * @return {object} - an action object. */ export const fetchJetpackSocialSettings = () => { return { diff --git a/projects/js-packages/publicize-components/src/social-store/reducer/connection-data.js b/projects/js-packages/publicize-components/src/social-store/reducer/connection-data.js index b99683e85605e..c8f350f077eb6 100644 --- a/projects/js-packages/publicize-components/src/social-store/reducer/connection-data.js +++ b/projects/js-packages/publicize-components/src/social-store/reducer/connection-data.js @@ -17,9 +17,9 @@ import { /** * Connection data reducer * - * @param {import('../types').ConnectionData} state - Current state. - * @param {object} action - Action object. - * @returns {import('../types').ConnectionData} The new state. + * @param {import('../types').ConnectionData} state - Current state. + * @param {object} action - Action object. + * @return {import('../types').ConnectionData} The new state. */ const connectionData = ( state = {}, action ) => { switch ( action.type ) { diff --git a/projects/js-packages/publicize-components/src/social-store/reducer/index.js b/projects/js-packages/publicize-components/src/social-store/reducer/index.js index e330313125616..cb7ae62ef5199 100644 --- a/projects/js-packages/publicize-components/src/social-store/reducer/index.js +++ b/projects/js-packages/publicize-components/src/social-store/reducer/index.js @@ -1,22 +1,21 @@ import { combineReducers } from '@wordpress/data'; import connectionData from './connection-data'; import jetpackSettings from './jetpack-settings'; -import sharesData from './shares-data'; +import { shareStatus } from './share-status'; import siteData from './site-data'; import socialImageGeneratorSettings from './social-image-generator-settings'; const reducer = combineReducers( { - sharesData, siteData, connectionData, jetpackSettings, socialImageGeneratorSettings, + shareStatus, hasPaidPlan: ( state = false ) => state, userConnectionUrl: ( state = '' ) => state, useAdminUiV1: ( state = false ) => state, featureFlags: ( state = false ) => state, hasPaidFeatures: ( state = false ) => state, - connectionRefreshPath: ( state = '' ) => state, } ); export default reducer; diff --git a/projects/js-packages/publicize-components/src/social-store/reducer/share-status.ts b/projects/js-packages/publicize-components/src/social-store/reducer/share-status.ts new file mode 100644 index 0000000000000..901ab94aeb7e1 --- /dev/null +++ b/projects/js-packages/publicize-components/src/social-store/reducer/share-status.ts @@ -0,0 +1,57 @@ +import { + FETCH_POST_SHARE_STATUS, + RECEIVE_POST_SHARE_STATUS, + TOGGLE_SHARE_STATUS_MODAL, +} from '../actions/constants'; +import { + fetchPostShareStatus, + receivePostShareStaus, + toggleShareStatusModal, +} from '../actions/share-status'; +import { SocialStoreState } from '../types'; + +type Action = + | ReturnType< + typeof fetchPostShareStatus | typeof receivePostShareStaus | typeof toggleShareStatusModal + > + | { type: 'default' }; + +/** + * Connection data reducer + * + * @param {SocialStoreState['shareStaus']} state - State object. + * @param {Action} action - Action object. + * + * @return {SocialStoreState['shareStaus']} - The updated state. + */ +export function shareStatus( + state: SocialStoreState[ 'shareStatus' ] = {}, + action: Action +): SocialStoreState[ 'shareStatus' ] { + switch ( action.type ) { + case FETCH_POST_SHARE_STATUS: + return { + ...state, + [ action.postId ]: { + shares: [], + ...state?.[ action.postId ], + loading: action.loading ?? true, + }, + }; + case RECEIVE_POST_SHARE_STATUS: + return { + ...state, + [ action.postId ]: { + ...action.shareStatus, + loading: false, + }, + }; + case TOGGLE_SHARE_STATUS_MODAL: + return { + ...state, + isModalOpen: action.isOpen, + }; + } + + return state; +} diff --git a/projects/js-packages/publicize-components/src/social-store/reducer/shares-data.js b/projects/js-packages/publicize-components/src/social-store/reducer/shares-data.js deleted file mode 100644 index ced3f29eef446..0000000000000 --- a/projects/js-packages/publicize-components/src/social-store/reducer/shares-data.js +++ /dev/null @@ -1,5 +0,0 @@ -const sharesData = ( state = {} ) => { - return state; -}; - -export default sharesData; diff --git a/projects/js-packages/publicize-components/src/social-store/resolvers.js b/projects/js-packages/publicize-components/src/social-store/resolvers.js index 8024cc5dd5c50..ab2e6308d17a0 100644 --- a/projects/js-packages/publicize-components/src/social-store/resolvers.js +++ b/projects/js-packages/publicize-components/src/social-store/resolvers.js @@ -1,14 +1,17 @@ +import apiFetch from '@wordpress/api-fetch'; import { store as editorStore } from '@wordpress/editor'; +import { normalizeShareStatus } from '../utils/share-status'; import { setConnections } from './actions/connection-data'; import { setJetpackSettings } from './actions/jetpack-settings'; +import { fetchPostShareStatus, receivePostShareStaus } from './actions/share-status'; import { setSocialImageGeneratorSettings } from './actions/social-image-generator-settings'; import { fetchJetpackSettings, fetchSocialImageGeneratorSettings } from './controls'; /** * Yield actions to get the Jetpack settings. * - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* getJetpackSettings() { try { @@ -25,8 +28,8 @@ export function* getJetpackSettings() { /** * Yield actions to get the Social Image Generator settings. * - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* getSocialImageGeneratorSettings() { try { @@ -43,7 +46,7 @@ export function* getSocialImageGeneratorSettings() { /** * Resolves the connections from the post. * - * @returns {Function} Resolver + * @return {Function} Resolver */ export function getConnections() { return function ( { dispatch, registry } ) { @@ -58,8 +61,36 @@ export function getConnections() { }; } +/** + * Resolves the post share status. + * + * @param {number} _postId - The post ID. + * + * @return {Function} Resolver + */ +export function getPostShareStatus( _postId ) { + return async ( { dispatch, registry } ) => { + // Default to the current post ID if none is provided. + const postId = _postId || registry.select( editorStore ).getCurrentPostId(); + + try { + dispatch( fetchPostShareStatus( postId ) ); + let result = await apiFetch( { + path: `jetpack/v4/social/share-status/${ postId }`, + } ); + + result = normalizeShareStatus( result ); + + dispatch( receivePostShareStaus( result, postId ) ); + } catch ( error ) { + dispatch( fetchPostShareStatus( postId, false ) ); + } + }; +} + export default { getJetpackSettings, getSocialImageGeneratorSettings, getConnections, + getPostShareStatus, }; diff --git a/projects/js-packages/publicize-components/src/social-store/selectors/connection-data.js b/projects/js-packages/publicize-components/src/social-store/selectors/connection-data.js index a9427c8333c78..2c4fd4542b5f8 100644 --- a/projects/js-packages/publicize-components/src/social-store/selectors/connection-data.js +++ b/projects/js-packages/publicize-components/src/social-store/selectors/connection-data.js @@ -5,7 +5,7 @@ import { REQUEST_TYPE_DEFAULT } from '../actions/constants'; * * @param {import("../types").SocialStoreState} state - State object. * - * @returns {Array} The connections list + * @return {Array} The connections list */ export function getConnections( state ) { return state.connectionData?.connections ?? []; @@ -14,10 +14,10 @@ export function getConnections( state ) { /** * Return a connection by its ID. * - * @param {import("../types").SocialStoreState} state - State object. - * @param {string} connectionId - The connection ID. + * @param {import("../types").SocialStoreState} state - State object. + * @param {string} connectionId - The connection ID. * - * @returns {import("../types").Connection | undefined} The connection. + * @return {import("../types").Connection | undefined} The connection. */ export function getConnectionById( state, connectionId ) { return getConnections( state ).find( connection => connection.connection_id === connectionId ); @@ -26,10 +26,10 @@ export function getConnectionById( state, connectionId ) { /** * Returns connections by service name/ID. * - * @param {import("../types").SocialStoreState} state - State object. - * @param {string} serviceName - The service name. + * @param {import("../types").SocialStoreState} state - State object. + * @param {string} serviceName - The service name. * - * @returns {Array} The connections. + * @return {Array} The connections. */ export function getConnectionsByService( state, serviceName ) { return getConnections( state ).filter( ( { service_name } ) => service_name === serviceName ); @@ -38,7 +38,7 @@ export function getConnectionsByService( state, serviceName ) { /** * Returns the connections admin URL from the store. * @param {import("../types").SocialStoreState} state - State object. - * @returns {string|null} The connections admin URL. + * @return {string|null} The connections admin URL. */ export function getConnectionsAdminUrl( state ) { return state.connectionData?.adminUrl ?? null; @@ -47,7 +47,7 @@ export function getConnectionsAdminUrl( state ) { /** * Returns whether there are connections in the store. * @param {import("../types").SocialStoreState} state - State object. - * @returns {boolean} Whether there are connections. + * @return {boolean} Whether there are connections. */ export function hasConnections( state ) { return getConnections( state ).length > 0; @@ -57,7 +57,7 @@ export function hasConnections( state ) { * Returns the failed Publicize connections. * * @param {import("../types").SocialStoreState} state - State object. - * @returns {Array} List of connections. + * @return {Array} List of connections. */ export function getFailedConnections( state ) { const connections = getConnections( state ); @@ -70,7 +70,7 @@ export function getFailedConnections( state ) { * iFor example, when LinkedIn switched its API from v1 to v2. * * @param {import("../types").SocialStoreState} state - State object. - * @returns {Array} List of service names that need reauthentication. + * @return {Array} List of service names that need reauthentication. */ export function getMustReauthConnections( state ) { const connections = getConnections( state ); @@ -84,7 +84,7 @@ export function getMustReauthConnections( state ) { * * @param {import("../types").SocialStoreState} state - State object. * - * @returns {Array} List of enabled connections. + * @return {Array} List of enabled connections. */ export function getEnabledConnections( state ) { return getConnections( state ).filter( connection => connection.enabled ); @@ -95,7 +95,7 @@ export function getEnabledConnections( state ) { * * @param {import("../types").SocialStoreState} state - State object. * - * @returns {Array} List of disabled connections. + * @return {Array} List of disabled connections. */ export function getDisabledConnections( state ) { return getConnections( state ).filter( connection => ! connection.enabled ); @@ -104,12 +104,12 @@ export function getDisabledConnections( state ) { /** * Get the profile details for a connection * - * @param {import("../types").SocialStoreState} state - State object. - * @param {string} service - The service name. - * @param {object} args - Arguments. - * @param {boolean} args.forceDefaults - Whether to use default values. + * @param {import("../types").SocialStoreState} state - State object. + * @param {string} service - The service name. + * @param {object} args - Arguments. + * @param {boolean} args.forceDefaults - Whether to use default values. * - * @returns {object} The profile details. + * @return {object} The profile details. */ export function getConnectionProfileDetails( state, service, { forceDefaults = false } = {} ) { let displayName = ''; @@ -137,7 +137,7 @@ export function getConnectionProfileDetails( state, service, { forceDefaults = f * Get the connections being deleted. * * @param {import("../types").SocialStoreState} state - State object. - * @returns {import("../types").ConnectionData['deletingConnections']} The connection being deleted. + * @return {import("../types").ConnectionData['deletingConnections']} The connection being deleted. */ export function getDeletingConnections( state ) { return state.connectionData?.deletingConnections ?? []; @@ -147,7 +147,7 @@ export function getDeletingConnections( state ) { * Get the connections being updated. * * @param {import("../types").SocialStoreState} state - State object. - * @returns {import("../types").ConnectionData['updatingConnections']} The connection being updated. + * @return {import("../types").ConnectionData['updatingConnections']} The connection being updated. */ export function getUpdatingConnections( state ) { return state.connectionData?.updatingConnections ?? []; @@ -157,7 +157,7 @@ export function getUpdatingConnections( state ) { * Get the account being reconnected * * @param {import("../types").SocialStoreState} state - State object. - * @returns {import("../types").ConnectionData['reconnectingAccount']} The account being reconnected. + * @return {import("../types").ConnectionData['reconnectingAccount']} The account being reconnected. */ export function getReconnectingAccount( state ) { return state.connectionData?.reconnectingAccount ?? ''; @@ -166,10 +166,10 @@ export function getReconnectingAccount( state ) { /** * Get the abort controllers for a specific request type. * - * @param {import("../types").SocialStoreState} state - State object. - * @param {string} requestType - The request type. + * @param {import("../types").SocialStoreState} state - State object. + * @param {string} requestType - The request type. * - * @returns {Array} The abort controllers. + * @return {Array} The abort controllers. */ export function getAbortControllers( state, requestType = REQUEST_TYPE_DEFAULT ) { return state.connectionData?.abortControllers?.[ requestType ] ?? []; @@ -178,10 +178,10 @@ export function getAbortControllers( state, requestType = REQUEST_TYPE_DEFAULT ) /** * Whether a mastodon account is already connected. * - * @param {import("../types").SocialStoreState} state - State object. - * @param {string} username - The mastodon username. + * @param {import("../types").SocialStoreState} state - State object. + * @param {string} username - The mastodon username. * - * @returns {boolean} Whether the mastodon account is already connected. + * @return {boolean} Whether the mastodon account is already connected. */ export function isMastodonAccountAlreadyConnected( state, username ) { return getConnectionsByService( state, 'mastodon' ).some( connection => { @@ -189,23 +189,12 @@ export function isMastodonAccountAlreadyConnected( state, username ) { } ); } -/** - * Returns the services list from the store. - * - * @param {import("../types").SocialStoreState} state - State object. - * - * @returns {Array} The services list - */ -export function getServices( state ) { - return state.connectionData?.services ?? []; -} - /** * Returns the latest KeyringResult from the store. * * @param {import("../types").SocialStoreState} state - State object. * - * @returns {import("../types").KeyringResult} The KeyringResult + * @return {import("../types").KeyringResult} The KeyringResult */ export function getKeyringResult( state ) { return state.connectionData?.keyringResult; @@ -215,7 +204,7 @@ export function getKeyringResult( state ) { * Whether the connections modal is open. * @param {import("../types").SocialStoreState} state - State object. * - * @returns {boolean} Whether the connections modal is open. + * @return {boolean} Whether the connections modal is open. */ export function isConnectionsModalOpen( state ) { return state.connectionData?.isConnectionsModalOpen ?? false; diff --git a/projects/js-packages/publicize-components/src/social-store/selectors/index.js b/projects/js-packages/publicize-components/src/social-store/selectors/index.js index ad6608112a2fe..888a83f13377b 100644 --- a/projects/js-packages/publicize-components/src/social-store/selectors/index.js +++ b/projects/js-packages/publicize-components/src/social-store/selectors/index.js @@ -1,6 +1,6 @@ import * as connectionDataSelectors from './connection-data'; import jetpackSettingSelectors from './jetpack-settings'; -import * as sharesData from './shares-data'; +import * as shareStatusSelectors from './share-status'; import siteDataSelectors from './site-data'; import socialImageGeneratorSettingsSelectors from './social-image-generator-settings'; @@ -8,13 +8,12 @@ const selectors = { ...siteDataSelectors, ...connectionDataSelectors, ...jetpackSettingSelectors, - ...sharesData, ...socialImageGeneratorSettingsSelectors, + ...shareStatusSelectors, userConnectionUrl: state => state.userConnectionUrl, useAdminUiV1: state => state.useAdminUiV1, featureFlags: state => state.featureFlags, hasPaidFeatures: state => state.hasPaidFeatures, - connectionRefreshPath: state => state.connectionRefreshPath, }; export default selectors; diff --git a/projects/js-packages/publicize-components/src/social-store/selectors/share-status.ts b/projects/js-packages/publicize-components/src/social-store/selectors/share-status.ts new file mode 100644 index 0000000000000..e12b27f345ac7 --- /dev/null +++ b/projects/js-packages/publicize-components/src/social-store/selectors/share-status.ts @@ -0,0 +1,32 @@ +import { createRegistrySelector } from '@wordpress/data'; +import { store as editorStore } from '@wordpress/editor'; +import { PostShareStatus, SocialStoreState } from '../types'; + +/** + * Get the post share status. + * + * @param {SocialStoreState} state - State object. + * @param {number} postId - The post ID. + * + * @return {PostShareStatus} - The post share status. + */ +export const getPostShareStatus = createRegistrySelector( + select => + ( state: SocialStoreState, postId?: number ): PostShareStatus => { + // Default to the current post ID if none is provided. + const id = postId || select( editorStore ).getCurrentPostId(); + + return state.shareStatus?.[ id ] ?? { shares: [] }; + } +); + +/** + * Whether the share status modal is open. + * + * @param {SocialStoreState} state - State object. + * + * @return {boolean} Whether the share status modal is open. + */ +export function isShareStatusModalOpen( state: SocialStoreState ) { + return state.shareStatus?.isModalOpen ?? false; +} diff --git a/projects/js-packages/publicize-components/src/social-store/selectors/shares-data.ts b/projects/js-packages/publicize-components/src/social-store/selectors/shares-data.ts deleted file mode 100644 index e1058747249ec..0000000000000 --- a/projects/js-packages/publicize-components/src/social-store/selectors/shares-data.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { SocialStoreState } from '../types'; -import settings from './jetpack-settings'; - -/** - * Whether the share limit is enabled. - * - * @param {SocialStoreState} state - Global state tree - * - * @returns {boolean} Whether the share limit is enabled - */ -export function isShareLimitEnabled( state: SocialStoreState ) { - return state.sharesData?.is_share_limit_enabled ?? false; -} - -/** - * Whether to show the share limits. - * - * @param {SocialStoreState} state - Global state tree - * - * @returns {boolean} Whether to show the share limits - */ -export function showShareLimits( state: SocialStoreState ) { - if ( settings.hasPaidPlan( state ) || state.hasPaidPlan ) { - return false; - } - return isShareLimitEnabled( state ); -} - -/** - * Returns the current share limit. - * - * @param {SocialStoreState} state - Global state tree - * - * @returns {number} Current share limit - */ -export function getShareLimit( state: SocialStoreState ) { - return state.sharesData?.share_limit ?? 30; -} - -/** - * Returns the total number of shares already used. - * - * @param {SocialStoreState} state - Global state tree - * - * @returns {number} Total number of shares used - */ -export function getSharesUsedCount( state: SocialStoreState ) { - return state.sharesData?.publicized_count ?? 0; -} - -/** - * Returns the number of shares scheduled. - * - * @param {SocialStoreState} state - Global state tree - * - * @returns {number} Number of shares scheduled - */ -export function getScheduledSharesCount( state: SocialStoreState ) { - return state.sharesData?.to_be_publicized_count ?? 0; -} - -/** - * Returns the total number of shares used and scheduled. - * - * @param {SocialStoreState} state - Global state tree - * - * @returns {number} Total number of shares used and scheduled - */ -export function getTotalSharesCount( state: SocialStoreState ) { - const count = getSharesUsedCount( state ) + getScheduledSharesCount( state ); - - return Math.max( count, 0 ); -} - -/** - * Number of posts shared this month - * - * @param {SocialStoreState} state - Global state tree - * - * @returns {number} Number of posts shared this month - */ -export function getSharedPostsCount( state: SocialStoreState ) { - return state.sharesData?.shared_posts_count ?? 0; -} - -/** - * Whether to show the advanced plan nudge. - * - * @param {SocialStoreState} state - Global state tree - * - * @returns {boolean} Whether to show the advanced plan nudge - */ -export function shouldShowAdvancedPlanNudge( state ) { - return state.sharesData?.show_advanced_plan_upgrade_nudge ?? false; -} - -export type NumberOfSharesRemainingOptions = { - /** - * Whether to include scheduled shares - */ - includeScheduled?: boolean; -}; - -/** - * Returns the number of shares remaining. - * - * @param {SocialStoreState} state - Global state tree - * @param {NumberOfSharesRemainingOptions} options - Options - * - * @returns {number} Number of shares remaining - */ -export function numberOfSharesRemaining( - state: SocialStoreState, - options: NumberOfSharesRemainingOptions = {} -) { - if ( ! showShareLimits( state ) ) { - return Infinity; - } - - // Allow partial options to be passed in - const { includeScheduled } = { - includeScheduled: true, - ...options, - }; - - const sharesUsed = getSharesUsedCount( state ); - const sharesLimit = getShareLimit( state ); - const scheduledShares = includeScheduled ? getScheduledSharesCount( state ) : 0; - - return Math.max( sharesLimit - sharesUsed - scheduledShares, 0 ); -} diff --git a/projects/js-packages/publicize-components/src/social-store/selectors/test/shares-data.test.js b/projects/js-packages/publicize-components/src/social-store/selectors/test/shares-data.test.js deleted file mode 100644 index 08fdb62f0cb17..0000000000000 --- a/projects/js-packages/publicize-components/src/social-store/selectors/test/shares-data.test.js +++ /dev/null @@ -1,241 +0,0 @@ -import { - getScheduledSharesCount, - getShareLimit, - getSharedPostsCount, - getSharesUsedCount, - getTotalSharesCount, - isShareLimitEnabled, - numberOfSharesRemaining, - shouldShowAdvancedPlanNudge, - showShareLimits, -} from '../shares-data'; - -describe( 'Social store selectors: sharesData', () => { - describe( 'isShareLimitEnabled', () => { - it( 'should return the default value when no data', () => { - expect( isShareLimitEnabled( {} ) ).toBe( false ); - expect( isShareLimitEnabled( { sharesData: {} } ) ).toBe( false ); - } ); - - it( 'should return the value from state', () => { - expect( isShareLimitEnabled( { sharesData: { is_share_limit_enabled: true } } ) ).toBe( - true - ); - expect( isShareLimitEnabled( { sharesData: { is_share_limit_enabled: false } } ) ).toBe( - false - ); - } ); - } ); - - describe( 'showShareLimits', () => { - it( 'should return the default value when no data', () => { - expect( showShareLimits( {} ) ).toBe( false ); - expect( showShareLimits( { sharesData: {} } ) ).toBe( false ); - } ); - - it( 'should fallback to isShareLimitEnabled if there is no paid plan', () => { - expect( showShareLimits( { sharesData: { is_share_limit_enabled: true } } ) ).toBe( true ); - expect( showShareLimits( { sharesData: { s_share_limit_enabled: false } } ) ).toBe( false ); - } ); - - it( 'should return false if there is a paid plan', () => { - expect( - showShareLimits( { - sharesData: { - is_share_limit_enabled: true, - }, - hasPaidPlan: true, - } ) - ).toBe( false ); - - expect( - showShareLimits( { - jetpackSettings: { showNudge: false }, - sharesData: { is_share_limit_enabled: true }, - } ) - ).toBe( false ); - } ); - } ); - - describe( 'getShareLimit', () => { - it( 'should return the default value when no data', () => { - expect( getShareLimit( {} ) ).toBe( 30 ); - expect( getShareLimit( { sharesData: {} } ) ).toBe( 30 ); - } ); - - it( 'should return the value from state', () => { - expect( getShareLimit( { sharesData: { share_limit: 100 } } ) ).toBe( 100 ); - expect( getShareLimit( { sharesData: { share_limit: 0 } } ) ).toBe( 0 ); - } ); - } ); - - describe( 'getSharesUsedCount', () => { - it( 'should return the default value when no data', () => { - expect( getSharesUsedCount( {} ) ).toBe( 0 ); - expect( getSharesUsedCount( { sharesData: {} } ) ).toBe( 0 ); - } ); - - it( 'should return the value from state', () => { - expect( getSharesUsedCount( { sharesData: { publicized_count: 100 } } ) ).toBe( 100 ); - expect( getSharesUsedCount( { sharesData: { publicized_count: 0 } } ) ).toBe( 0 ); - } ); - } ); - - describe( 'getScheduledSharesCount', () => { - it( 'should return the default value when no data', () => { - expect( getScheduledSharesCount( {} ) ).toBe( 0 ); - expect( getScheduledSharesCount( { sharesData: {} } ) ).toBe( 0 ); - } ); - - it( 'should return the value from state', () => { - expect( getScheduledSharesCount( { sharesData: { to_be_publicized_count: 100 } } ) ).toBe( - 100 - ); - expect( getScheduledSharesCount( { sharesData: { to_be_publicized_count: 0 } } ) ).toBe( 0 ); - } ); - } ); - - describe( 'getTotalSharesCount', () => { - it( 'should return the default value when no data', () => { - expect( getTotalSharesCount( {} ) ).toBe( 0 ); - expect( getTotalSharesCount( { sharesData: {} } ) ).toBe( 0 ); - } ); - - it( 'should return the value from state', () => { - const cases = [ - [ [ 100, 100 ], 200 ], - [ [ 0, 0 ], 0 ], - [ [ 100, 0 ], 100 ], - [ [ 0, 100 ], 100 ], - ]; - - for ( const [ [ publicized_count, to_be_publicized_count ], result ] of cases ) { - expect( - getTotalSharesCount( { - sharesData: { - to_be_publicized_count, - publicized_count, - }, - } ) - ).toBe( result ); - } - } ); - } ); - - describe( 'getSharedPostsCount', () => { - it( 'should return the default value when no data', () => { - expect( getSharedPostsCount( {} ) ).toBe( 0 ); - expect( getSharedPostsCount( { sharesData: {} } ) ).toBe( 0 ); - } ); - - it( 'should return the value from state', () => { - expect( getSharedPostsCount( { sharesData: { shared_posts_count: 100 } } ) ).toBe( 100 ); - expect( getSharedPostsCount( { sharesData: { shared_posts_count: 0 } } ) ).toBe( 0 ); - } ); - } ); - - describe( 'shouldShowAdvancedPlanNudge', () => { - it( 'should return the default value when no data', () => { - expect( shouldShowAdvancedPlanNudge( {} ) ).toBe( false ); - expect( shouldShowAdvancedPlanNudge( { sharesData: {} } ) ).toBe( false ); - } ); - - it( 'should return the value from state', () => { - expect( - shouldShowAdvancedPlanNudge( { sharesData: { show_advanced_plan_upgrade_nudge: true } } ) - ).toBe( true ); - - expect( - shouldShowAdvancedPlanNudge( { sharesData: { show_advanced_plan_upgrade_nudge: false } } ) - ).toBe( false ); - } ); - } ); - describe( 'numberOfSharesRemaining', () => { - it( 'should return infinity when share limits are not applied', () => { - expect( numberOfSharesRemaining( {} ) ).toBe( Infinity ); - expect( numberOfSharesRemaining( { sharesData: { is_share_limit_enabled: false } } ) ).toBe( - Infinity - ); - } ); - - it( 'should return 0 instead of negative number when limits are crossed', () => { - expect( - numberOfSharesRemaining( { - sharesData: { - is_share_limit_enabled: true, - publicized_count: 35, - }, - } ) - ).toBe( 0 ); - } ); - - const suites = [ - [ - 'should count used and scheduled shares', - { - includeScheduled: true, - }, - [ - { - sharesUsed: 10, - scheduledShares: 10, - result: 10, - }, - { - sharesUsed: 20, - scheduledShares: 10, - result: 0, - }, - { - sharesUsed: 0, - scheduledShares: 0, - result: 30, - }, - ], - ], - [ - 'should count used shares but not the scheduled shares', - { - includeScheduled: false, - }, - [ - { - sharesUsed: 10, - scheduledShares: 10, - result: 20, - }, - { - sharesUsed: 30, - scheduledShares: 10, - result: 0, - }, - { - sharesUsed: 0, - scheduledShares: 0, - result: 30, - }, - ], - ], - ]; - - for ( const [ name, args, cases ] of suites ) { - it( `${ name }`, () => { - for ( const { sharesUsed, scheduledShares, result } of cases ) { - expect( - numberOfSharesRemaining( - { - sharesData: { - is_share_limit_enabled: true, - publicized_count: sharesUsed, - to_be_publicized_count: scheduledShares, - share_limit: 30, - }, - }, - args - ) - ).toBe( result ); - } - } ); - } - } ); -} ); diff --git a/projects/js-packages/publicize-components/src/social-store/types.ts b/projects/js-packages/publicize-components/src/social-store/types.ts index 79ecd3ae19b2d..7e82f2dce230f 100644 --- a/projects/js-packages/publicize-components/src/social-store/types.ts +++ b/projects/js-packages/publicize-components/src/social-store/types.ts @@ -1,12 +1,3 @@ -export type SharesData = { - is_share_limit_enabled: boolean; - to_be_publicized_count: number; - share_limit: number; - publicized_count: number; - show_advanced_plan_upgrade_nudge: boolean; - shared_posts_count: number; -}; - export type ConnectionStatus = 'ok' | 'broken'; export type Connection = { @@ -29,16 +20,6 @@ export type Connection = { status: ConnectionStatus; }; -export type ConnectionService = { - ID: string; - label: string; - type: 'publicize' | 'other'; - description: string; - connect_URL: string; - external_users_only?: boolean; - multiple_external_user_ID_support?: boolean; -}; - export type ConnectionData = { connections: Connection[]; deletingConnections?: Array< number | string >; @@ -51,16 +32,38 @@ export type JetpackSettings = { showNudge?: boolean; }; +export type ShareStatusItem = Pick< + Connection, + 'connection_id' | 'profile_link' | 'profile_picture' +> & { + status: 'success' | 'failure'; + message: string; + timestamp: number; + service: string; + external_name: string; +}; + +export type PostShareStatus = { + shares: Array< ShareStatusItem >; + done?: boolean; + loading?: boolean; +}; + +export type ShareStatus = { + isModalOpen?: boolean; + [ PostId: number ]: PostShareStatus; +}; + // TODO we should have a consistent structure across all the pages - editor, dashboard, admin page etc. export type SocialStoreState = { connectionData: ConnectionData; - sharesData: SharesData; // on post editor hasPaidPlan?: boolean; // on Jetack Social admin page jetpackSettings?: JetpackSettings; useAdminUiV1?: boolean; featureFlags?: Record< string, boolean >; + shareStatus?: ShareStatus; }; export interface KeyringAdditionalUser { diff --git a/projects/js-packages/publicize-components/src/types/types.ts b/projects/js-packages/publicize-components/src/types/types.ts index 05adb13d3c4be..58c8fe8f50183 100644 --- a/projects/js-packages/publicize-components/src/types/types.ts +++ b/projects/js-packages/publicize-components/src/types/types.ts @@ -1,10 +1,34 @@ +export type SharesData = { + to_be_publicized_count: number; + publicized_count: number; + shared_posts_count: number; +}; + export interface FeatureFlags { useAdminUiV1: boolean; } +export type ConnectionService = { + ID: string; + label: string; + type: 'publicize' | 'other'; + description: string; + connect_URL: string; + external_users_only?: boolean; + multiple_external_user_ID_support?: boolean; +}; + +export interface ApiPaths { + refreshConnections: string; + resharePost: string; +} + export interface SocialScriptData { + api_paths: ApiPaths; is_publicize_enabled: boolean; feature_flags: FeatureFlags; + supported_services: Array< ConnectionService >; + shares_data: SharesData; } type JetpackSettingsSelectors = { @@ -21,18 +45,10 @@ type JetpackSettingsSelectors = { type ConnectionDataSelectors = { getConnections: () => Array< object >; - getServices: () => Array< object >; getConnectionsAdminUrl: () => string; hasConnections: () => boolean; }; -type SharesDataSelectors = { - getSharesCount: () => number; - getPostsCount: () => number; - isShareLimitEnabled: () => boolean; - numberOfSharesRemaining: () => number; -}; - type SiteDataSelectors = { getSiteData: () => Array< object >; getSiteTitle: () => string; @@ -59,6 +75,5 @@ type SocialImageGeneratorSettingsSelectors = { */ export type SocialStoreSelectors = JetpackSettingsSelectors & ConnectionDataSelectors & - SharesDataSelectors & SiteDataSelectors & SocialImageGeneratorSettingsSelectors; diff --git a/projects/js-packages/publicize-components/src/utils/get-share-message-max-length.js b/projects/js-packages/publicize-components/src/utils/get-share-message-max-length.js index b1817ee28f831..15c0ba8260ba1 100644 --- a/projects/js-packages/publicize-components/src/utils/get-share-message-max-length.js +++ b/projects/js-packages/publicize-components/src/utils/get-share-message-max-length.js @@ -7,7 +7,7 @@ const MAXIMUM_MESSAGE_LENGTH = 280 - ATTACHMENT_MESSAGE_PADDING - 1; /** * Get the maximum length that a share message can be. * - * @returns {number} The maximum length of a share message. + * @return {number} The maximum length of a share message. */ export function getShareMessageMaxLength() { return MAXIMUM_MESSAGE_LENGTH; diff --git a/projects/js-packages/publicize-components/src/utils/get-supported-additional-connections.js b/projects/js-packages/publicize-components/src/utils/get-supported-additional-connections.js index 7b4b3896eda45..7899eded54a76 100644 --- a/projects/js-packages/publicize-components/src/utils/get-supported-additional-connections.js +++ b/projects/js-packages/publicize-components/src/utils/get-supported-additional-connections.js @@ -3,7 +3,7 @@ import { getJetpackData } from '@automattic/jetpack-shared-extension-utils'; /** * Get a list of additional connections that are supported by the current plan. * - * @returns {Array} A list of connection names + * @return {Array} A list of connection names */ export function getSupportedAdditionalConnections() { return getJetpackData()?.social?.supportedAdditionalConnections || []; diff --git a/projects/js-packages/publicize-components/src/utils/request-external-access.js b/projects/js-packages/publicize-components/src/utils/request-external-access.js index e468fb67eff32..b38dccef8a3a8 100644 --- a/projects/js-packages/publicize-components/src/utils/request-external-access.js +++ b/projects/js-packages/publicize-components/src/utils/request-external-access.js @@ -8,8 +8,8 @@ import PopupMonitor from '@automattic/popup-monitor'; /** * Utility for requesting authorization of sharing services. - * @param {string} url - The URL to be loaded in the newly opened window. - * @param {requestCallback} cb - The callback that handles the response. + * @param {string} url - The URL to be loaded in the newly opened window. + * @param {requestCallback} cb - The callback that handles the response. */ export const requestExternalAccess = ( url, cb ) => { const popupMonitor = new PopupMonitor(); diff --git a/projects/js-packages/publicize-components/src/utils/script-data.ts b/projects/js-packages/publicize-components/src/utils/script-data.ts new file mode 100644 index 0000000000000..4db102747a639 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/script-data.ts @@ -0,0 +1,11 @@ +import { getScriptData } from '@automattic/jetpack-script-data'; +import { SocialScriptData } from '../types/types'; + +/** + * Get the social script data from the window object. + * + * @return {SocialScriptData} The social script data. + */ +export function getSocialScriptData(): SocialScriptData { + return getScriptData().social; +} diff --git a/projects/js-packages/publicize-components/src/utils/share-status.ts b/projects/js-packages/publicize-components/src/utils/share-status.ts new file mode 100644 index 0000000000000..8274971d1a172 --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/share-status.ts @@ -0,0 +1,16 @@ +import { PostShareStatus } from '../social-store/types'; + +/** + * Normalizes the share status object. + * + * @param {PostShareStatus} shareStatus - Share status object. + * @return {PostShareStatus} - Normalized share status object. + */ +export function normalizeShareStatus( shareStatus: PostShareStatus ) { + if ( shareStatus && 'shares' in shareStatus && shareStatus.done ) { + // Sort shares to show the latest shares on the top. + shareStatus.shares.sort( ( a, b ) => b.timestamp - a.timestamp ); + } + + return shareStatus; +} diff --git a/projects/js-packages/publicize-components/src/utils/shares-data.ts b/projects/js-packages/publicize-components/src/utils/shares-data.ts new file mode 100644 index 0000000000000..9dcafa007676a --- /dev/null +++ b/projects/js-packages/publicize-components/src/utils/shares-data.ts @@ -0,0 +1,47 @@ +import { getSocialScriptData } from './script-data'; + +/** + * Returns the shares data. + * + * @return {import('../types/types').SharesData} Shares data + */ +export function getSharesData() { + return getSocialScriptData().shares_data; +} +/** + * Returns the total number of shares already used. + * + * @return {number} Total number of shares used + */ +export function getSharesUsedCount() { + return getSharesData().publicized_count ?? 0; +} + +/** + * Returns the number of shares scheduled. + * + * @return {number} Number of shares scheduled + */ +export function getScheduledSharesCount() { + return getSharesData().to_be_publicized_count ?? 0; +} + +/** + * Returns the total number of shares used and scheduled. + * + * @return {number} Total number of shares used and scheduled + */ +export function getTotalSharesCount() { + const count = getSharesUsedCount() + getScheduledSharesCount(); + + return Math.max( count, 0 ); +} + +/** + * Number of posts shared this month + * + * @return {number} Number of posts shared this month + */ +export function getSharedPostsCount() { + return getSharesData().shared_posts_count ?? 0; +} diff --git a/projects/js-packages/publicize-components/src/utils/test-factory.js b/projects/js-packages/publicize-components/src/utils/test-factory.js index d1d951c2ae86a..7c2b310f63807 100644 --- a/projects/js-packages/publicize-components/src/utils/test-factory.js +++ b/projects/js-packages/publicize-components/src/utils/test-factory.js @@ -2,7 +2,6 @@ import { render, renderHook } from '@testing-library/react'; import { useSelect, useDispatch } from '@wordpress/data'; import ConnectionManagement from '../components/connection-management'; import { ConnectionManagementPageObject } from '../components/connection-management/tests/pageObjects/ConnectionManagementPage'; -import { useSupportedServices } from '../components/services/use-supported-services'; import useSocialMediaConnections from '../hooks/use-social-media-connections'; import { store } from '../social-store'; import { SUPPORTED_SERVICES_MOCK } from './test-constants'; @@ -12,10 +11,6 @@ jest.mock( '../hooks/use-social-media-connections', () => ( { default: jest.fn(), } ) ); -jest.mock( '../components/services/use-supported-services', () => ( { - useSupportedServices: jest.fn(), -} ) ); - export const setup = ( { connections = [ { service_name: 'twitter', connection_id: '1', display_name: 'Twitter', can_disconnect: true }, @@ -56,7 +51,12 @@ export const setup = ( { refresh: jest.fn(), } ); - useSupportedServices.mockReturnValue( SUPPORTED_SERVICES_MOCK ); + global.JetpackScriptData = { + ...global.JetpackScriptData, + social: { + supported_services: SUPPORTED_SERVICES_MOCK, + }, + }; return { stubDeleteConnectionById, diff --git a/projects/js-packages/publicize-components/src/utils/test-utils.js b/projects/js-packages/publicize-components/src/utils/test-utils.js index c572f00193b44..fa2f326be7bc6 100644 --- a/projects/js-packages/publicize-components/src/utils/test-utils.js +++ b/projects/js-packages/publicize-components/src/utils/test-utils.js @@ -69,7 +69,7 @@ export const connections = [ * * @param {object} postAttributes - Post attributes. * - * @returns {WPDataRegistry} Registry. + * @return {WPDataRegistry} Registry. */ export function createRegistryWithStores( postAttributes = {} ) { // Create a registry. @@ -104,7 +104,7 @@ export function createRegistryWithStores( postAttributes = {} ) { * * @param {number} count - Number of active connections to create. * - * @returns {Array} Array of active connections. + * @return {Array} Array of active connections. */ export function createActiveConnections( count ) { return [ @@ -118,3 +118,54 @@ export function createActiveConnections( count ) { }, ]; } + +const getMethod = options => + options.headers?.[ 'X-HTTP-Method-Override' ] || options.method || 'GET'; + +/** + * Get the mocked fetch handler for post publish fetch requests. + * + * @param {Record} postData - Data to be used in the fetch request. + * + * @return {(options: import('@wordpress/api-fetch/build-types/types').APIFetchOptions) => Promise} Promise resolving to the fetch response + */ +export function postPublishFetchHandler( postData ) { + /** + * The mocked fetch handler for post publish fetch requests. + * + * @param {import('@wordpress/api-fetch/build-types/types').APIFetchOptions} options - Fetch options. + * + * @return {Promise} Promise resolving to the fetch response + */ + return async function ( options ) { + const method = getMethod( options ); + const { path, data, parse = true } = options; + + const wrapReturn = parse + ? v => v + : v => + // Ideally we'd do `new Response( JSON.stringify( v ) )` here, but jsdom deletes that. Sigh. + // See https://github.com/jsdom/jsdom/issues/1724 + ( { + async json() { + return v; + }, + } ); + + if ( method === 'PUT' && path.startsWith( `/wp/v2/posts/${ testPost.id }` ) ) { + return wrapReturn( { ...postData, ...data } ); + } else if ( + // This URL is requested by the actions dispatched in this test. + // They are safe to ignore and are only listed here to avoid triggeringan error. + method === 'GET' && + path.startsWith( '/wp/v2/types/post' ) + ) { + return wrapReturn( {} ); + } + + throw { + code: 'unknown_path', + message: `Unknown path: ${ method } ${ path }`, + }; + }; +} diff --git a/projects/js-packages/react-data-sync-client/CHANGELOG.md b/projects/js-packages/react-data-sync-client/CHANGELOG.md index 6f945c3c9ac8e..178b1e3fa0bb9 100644 --- a/projects/js-packages/react-data-sync-client/CHANGELOG.md +++ b/projects/js-packages/react-data-sync-client/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.4] - 2024-08-29 +### Changed +- Updated package dependencies. [#39004] +- Updated package dependencies. [#39111] + ## [0.1.3] - 2024-06-10 ### Changed - Updated package dependencies. [#37380] @@ -42,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Added default param for callbacks to prevent crashes when none provided [#34910] +[0.1.4]: https://github.com/Automattic/jetpack-react-data-sync-client/compare/v0.1.3...v0.1.4 [0.1.3]: https://github.com/Automattic/jetpack-react-data-sync-client/compare/v0.1.2...v0.1.3 [0.1.2]: https://github.com/Automattic/jetpack-react-data-sync-client/compare/v0.1.1...v0.1.2 [0.1.1]: https://github.com/Automattic/jetpack-react-data-sync-client/compare/v0.1.0...v0.1.1 diff --git a/projects/js-packages/react-data-sync-client/composer.json b/projects/js-packages/react-data-sync-client/composer.json index 7eaf3c43ba67f..042fd443b4d7e 100644 --- a/projects/js-packages/react-data-sync-client/composer.json +++ b/projects/js-packages/react-data-sync-client/composer.json @@ -5,7 +5,7 @@ "license": "GPL-2.0-or-later", "require": {}, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "autoload": { diff --git a/projects/js-packages/react-data-sync-client/package.json b/projects/js-packages/react-data-sync-client/package.json index c87ed178ff0f9..87e2685262309 100644 --- a/projects/js-packages/react-data-sync-client/package.json +++ b/projects/js-packages/react-data-sync-client/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-react-data-sync-client", - "version": "0.1.3", + "version": "0.1.4", "description": "DataSync client for React", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/react-data-sync-client/#readme", "bugs": { @@ -29,7 +29,7 @@ "react": "18.3.1", "tslib": "2.5.0", "typescript": "5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1", "zod": "3.22.3" }, diff --git a/projects/js-packages/react-data-sync-client/src/DataSync.ts b/projects/js-packages/react-data-sync-client/src/DataSync.ts index e063d0d0c1539..8d3b78b76e4d7 100644 --- a/projects/js-packages/react-data-sync-client/src/DataSync.ts +++ b/projects/js-packages/react-data-sync-client/src/DataSync.ts @@ -65,8 +65,8 @@ export class DataSync< Schema extends z.ZodSchema, Value extends z.infer< Schema * This would make a request to: http://localhost/wp-json/namespace/key * * @param namespace - The namespace of the endpoint. This matches the name of the global variable (window.{namespace}.{endpoint_name}). - * @param key - The key of the value that's being synced. This is used to fetch the value from the global window object. - * @param schema - The Zod schema to validate the value against. This ensures that the value is of the expected type. + * @param key - The key of the value that's being synced. This is used to fetch the value from the global window object. + * @param schema - The Zod schema to validate the value against. This ensures that the value is of the expected type. */ constructor( namespace: string, @@ -129,7 +129,7 @@ export class DataSync< Schema extends z.ZodSchema, Value extends z.infer< Schema * Helper function to get values * from the window object and validate them. * - * @param valueName - The name of the value. For example, `posts`. + * @param valueName - The name of the value. For example, `posts`. * @param valueSchema - The Zod schema to validate the value against. * @returns The parsed value. */ @@ -175,11 +175,11 @@ export class DataSync< Schema extends z.ZodSchema, Value extends z.infer< Schema /** * Method to make a request to the endpoint. - * @param method - The request method. + * @param method - The request method. * @param partialPathname - The request path. - * @param value - Data to send when using POST. - * @param params - Append query params to the URL. Takes in an object of key/value pairs. - * @param abortSignal - The abort signal. + * @param value - Data to send when using POST. + * @param params - Append query params to the URL. Takes in an object of key/value pairs. + * @param abortSignal - The abort signal. * @returns The parsed value. * @throws ApiError * @throws Error @@ -276,9 +276,9 @@ export class DataSync< Schema extends z.ZodSchema, Value extends z.infer< Schema /** * Method to parse the request. - * @param method - The request method. + * @param method - The request method. * @param requestPath - The request path. - * @param value - The request parameters. + * @param value - The request parameters. * @param abortSignal - The abort signal. * @returns The parsed value. */ @@ -337,7 +337,7 @@ export class DataSync< Schema extends z.ZodSchema, Value extends z.infer< Schema /** * Method to attempt the request. - * @param url - The request URL. + * @param url - The request URL. * @param args - The request arguments. * @returns The result of the request. */ @@ -410,7 +410,7 @@ export class DataSync< Schema extends z.ZodSchema, Value extends z.infer< Schema /** * Trigger an endpoint action - * @param name - The name of the action. + * @param name - The name of the action. * @param value - The value to send to the endpoint. * @returns A direct response from the endpoint. */ diff --git a/projects/js-packages/react-data-sync-client/src/DataSyncHooks.ts b/projects/js-packages/react-data-sync-client/src/DataSyncHooks.ts index 603e7e0f862d1..cd18ca943c6e5 100644 --- a/projects/js-packages/react-data-sync-client/src/DataSyncHooks.ts +++ b/projects/js-packages/react-data-sync-client/src/DataSyncHooks.ts @@ -71,10 +71,10 @@ function buildQueryKey( key: string, params: Record< string, string | number > ) /** * React Query hook for DataSync. * @param namespace - The namespace of the endpoint. - * @param key - The key of the value that's being synced. - * @param schema - The Zod schema to validate the value against. - * @param config - React Query configuration. - * @param params - key/value pairs to be used as GET parameters. + * @param key - The key of the value that's being synced. + * @param schema - The Zod schema to validate the value against. + * @param config - React Query configuration. + * @param params - key/value pairs to be used as GET parameters. * @returns A tuple of React Query hooks. * @see https://tanstack.com/query/v5/docs/react/reference/useQuery * @see https://tanstack.com/query/v5/docs/react/reference/useMutation @@ -119,7 +119,7 @@ export function useDataSync< try { return datasync.getInitialValue(); } catch ( e ) { - return; + return undefined; } }, }; diff --git a/projects/js-packages/ai-client/changelog/renovate-wordpress-monorepo b/projects/js-packages/remove-asset-webpack-plugin/changelog/renovate-npm-webpack-vulnerability similarity index 100% rename from projects/js-packages/ai-client/changelog/renovate-wordpress-monorepo rename to projects/js-packages/remove-asset-webpack-plugin/changelog/renovate-npm-webpack-vulnerability diff --git a/projects/js-packages/remove-asset-webpack-plugin/package.json b/projects/js-packages/remove-asset-webpack-plugin/package.json index 9c18f0c6a2ac5..82d6f1a93d3a1 100644 --- a/projects/js-packages/remove-asset-webpack-plugin/package.json +++ b/projects/js-packages/remove-asset-webpack-plugin/package.json @@ -21,11 +21,11 @@ }, "devDependencies": { "jest": "29.7.0", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "peerDependencies": { - "webpack": "^5.8.0" + "webpack": "^5.94.0" }, "exports": { ".": "./src/index.js" diff --git a/projects/js-packages/components/changelog/renovate-storybook-monorepo b/projects/js-packages/scan/changelog/renovate-yoast-phpunit-polyfills-1.x similarity index 100% rename from projects/js-packages/components/changelog/renovate-storybook-monorepo rename to projects/js-packages/scan/changelog/renovate-yoast-phpunit-polyfills-1.x diff --git a/projects/js-packages/scan/composer.json b/projects/js-packages/scan/composer.json index 71c65802216c2..ba756697b6ef5 100644 --- a/projects/js-packages/scan/composer.json +++ b/projects/js-packages/scan/composer.json @@ -5,7 +5,7 @@ "license": "GPL-2.0-or-later", "require": {}, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "autoload": { diff --git a/projects/js-packages/script-data/CHANGELOG.md b/projects/js-packages/script-data/CHANGELOG.md index 4b3cc72517c19..483863296910b 100644 --- a/projects/js-packages/script-data/CHANGELOG.md +++ b/projects/js-packages/script-data/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.2] - 2024-08-21 +### Changed +- Internal updates. + ## [0.1.1] - 2024-08-12 ### Fixed - Add npm auto-publish to script-data package [#38826] @@ -13,4 +17,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added jetpack-script-data package to consolidate the logic for Jetpack Initial state [#38430] +[0.1.2]: https://github.com/Automattic/jetpack-script-data/compare/v0.1.1...v0.1.2 [0.1.1]: https://github.com/Automattic/jetpack-script-data/compare/v0.1.0...v0.1.1 diff --git a/projects/js-packages/script-data/package.json b/projects/js-packages/script-data/package.json index 7688537f442af..98db58435ae5f 100644 --- a/projects/js-packages/script-data/package.json +++ b/projects/js-packages/script-data/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/jetpack-script-data", - "version": "0.1.1", + "version": "0.1.2", "description": "A library to provide data for script handles and the corresponding utility functions for Jetpack.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/script-data/#readme", "bugs": { diff --git a/projects/js-packages/script-data/src/utils.ts b/projects/js-packages/script-data/src/utils.ts index e23463e308d06..690b6f4f7c298 100644 --- a/projects/js-packages/script-data/src/utils.ts +++ b/projects/js-packages/script-data/src/utils.ts @@ -1,7 +1,7 @@ /** * Get the script data from the window object. * - * @returns {import('./types').JetpackScriptData} The script data. + * @return {import('./types').JetpackScriptData} The script data. */ export function getScriptData() { return window.JetpackScriptData; @@ -10,7 +10,7 @@ export function getScriptData() { /** * Get the site data from the script data. * - * @returns {import('./types').SiteData} The site data. + * @return {import('./types').SiteData} The site data. */ export function getSiteData() { return getScriptData().site; @@ -21,7 +21,7 @@ export function getSiteData() { * * @param {string} [path] - The path to append to the admin URL. e.g. `admin.php?page=jetpack`. * - * @returns {string} The admin URL. + * @return {string} The admin URL. */ export function getAdminUrl( path = '' ) { return `${ getScriptData().site.admin_url }${ path }`; @@ -32,7 +32,7 @@ export function getAdminUrl( path = '' ) { * * @param {string} [section] - The section to append to the My Jetpack URL. e.g. `#/settings`. * - * @returns {string} The Jetpack admin page URL. + * @return {string} The Jetpack admin page URL. */ export function getJetpackAdminPageUrl( section = '' ) { return getAdminUrl( `admin.php?page=jetpack${ section }` ); @@ -43,7 +43,7 @@ export function getJetpackAdminPageUrl( section = '' ) { * * @param {string} [section] - The section to append to the My Jetpack URL. e.g. `#/connection`. * - * @returns {string} The My Jetpack URL. + * @return {string} The My Jetpack URL. */ export function getMyJetpackUrl( section = '' ) { return getAdminUrl( `admin.php?page=my-jetpack${ section }` ); @@ -52,7 +52,7 @@ export function getMyJetpackUrl( section = '' ) { /** * Get active features from the site plan. * - * @returns {import('./types').SitePlan['features']['active']} The active features. + * @return {import('./types').SitePlan['features']['active']} The active features. */ export function getActiveFeatures() { return getScriptData().site.plan?.features?.active ?? []; diff --git a/projects/js-packages/shared-extension-utils/CHANGELOG.md b/projects/js-packages/shared-extension-utils/CHANGELOG.md index c60b084d84151..f5b8a4391daab 100644 --- a/projects/js-packages/shared-extension-utils/CHANGELOG.md +++ b/projects/js-packages/shared-extension-utils/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.15.5] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + +## [0.15.4] - 2024-08-21 +### Changed +- Internal updates. + ## [0.15.3] - 2024-08-15 ### Changed - Updated package dependencies. [#38662] @@ -428,6 +436,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Core: prepare utility for release +[0.15.5]: https://github.com/Automattic/jetpack-shared-extension-utils/compare/0.15.4...0.15.5 +[0.15.4]: https://github.com/Automattic/jetpack-shared-extension-utils/compare/0.15.3...0.15.4 [0.15.3]: https://github.com/Automattic/jetpack-shared-extension-utils/compare/0.15.2...0.15.3 [0.15.2]: https://github.com/Automattic/jetpack-shared-extension-utils/compare/0.15.1...0.15.2 [0.15.1]: https://github.com/Automattic/jetpack-shared-extension-utils/compare/0.15.0...0.15.1 diff --git a/projects/js-packages/shared-extension-utils/composer.json b/projects/js-packages/shared-extension-utils/composer.json index 149e68b24de1f..b5edd782e8f9a 100644 --- a/projects/js-packages/shared-extension-utils/composer.json +++ b/projects/js-packages/shared-extension-utils/composer.json @@ -5,7 +5,7 @@ "license": "GPL-2.0-or-later", "require": {}, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "scripts": { diff --git a/projects/js-packages/shared-extension-utils/package.json b/projects/js-packages/shared-extension-utils/package.json index d9a37608e695e..7fcf654413932 100644 --- a/projects/js-packages/shared-extension-utils/package.json +++ b/projects/js-packages/shared-extension-utils/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/jetpack-shared-extension-utils", - "version": "0.15.3", + "version": "0.15.5", "description": "Utility functions used by the block editor extensions", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/shared-extension-utils/#readme", "bugs": { diff --git a/projects/js-packages/shared-extension-utils/src/components/jetpack-editor-panel-logo/index.jsx b/projects/js-packages/shared-extension-utils/src/components/jetpack-editor-panel-logo/index.jsx index 15f09ec6ec3f4..a8a5e551e3801 100644 --- a/projects/js-packages/shared-extension-utils/src/components/jetpack-editor-panel-logo/index.jsx +++ b/projects/js-packages/shared-extension-utils/src/components/jetpack-editor-panel-logo/index.jsx @@ -6,7 +6,7 @@ import './style.scss'; /** * The Jetpack logo used for block editor panels * - * @returns {React.Component} Jetpack logo component + * @return {React.Component} Jetpack logo component */ const JetpackEditorPanelLogo = () => ( { const { isModuleActive, isChangingStatus, isLoadingModules } = useSelect( diff --git a/projects/js-packages/shared-extension-utils/src/is-current-user-connected.js b/projects/js-packages/shared-extension-utils/src/is-current-user-connected.js index f2c14aa275194..43df9d9080a4b 100644 --- a/projects/js-packages/shared-extension-utils/src/is-current-user-connected.js +++ b/projects/js-packages/shared-extension-utils/src/is-current-user-connected.js @@ -3,7 +3,7 @@ import getJetpackData from './get-jetpack-data'; /** * Return whether the current user is connected to WP.com. * - * @returns {boolean} Whether the current user is connected. + * @return {boolean} Whether the current user is connected. */ export default function isCurrentUserConnected() { return getJetpackData()?.jetpack?.is_current_user_connected ?? false; diff --git a/projects/js-packages/shared-extension-utils/src/is-my-jetpack-available.js b/projects/js-packages/shared-extension-utils/src/is-my-jetpack-available.js index 7d6a92fd097e0..9019c81d7a0b5 100644 --- a/projects/js-packages/shared-extension-utils/src/is-my-jetpack-available.js +++ b/projects/js-packages/shared-extension-utils/src/is-my-jetpack-available.js @@ -6,7 +6,7 @@ import getJetpackData from './get-jetpack-data'; * @see https://github.com/Automattic/jetpack/pull/38500 introduced the is_my_jetpack_available flag * The value is the same that can be found on Initial_State.siteData.showMyJetpack (dashboard context) * - * @returns {boolean} Object indicating if My Jetpack is available (so to navigate to interstitials and product pages) + * @return {boolean} Object indicating if My Jetpack is available (so to navigate to interstitials and product pages) */ export default function isMyJetpackAvailable() { return getJetpackData()?.jetpack?.is_my_jetpack_available === true; diff --git a/projects/js-packages/shared-extension-utils/src/modules-state/actions.js b/projects/js-packages/shared-extension-utils/src/modules-state/actions.js index 6b17928ca63ef..628f305a488a3 100644 --- a/projects/js-packages/shared-extension-utils/src/modules-state/actions.js +++ b/projects/js-packages/shared-extension-utils/src/modules-state/actions.js @@ -12,11 +12,11 @@ export const SET_MODULE_UPDATING = 'SET_MODULE_UPDATING'; /** * Yield actions to update module status * - * @param {object} settings - Jetpack module settings. - * @param {string} settings.name - Jetpack module name. + * @param {object} settings - Jetpack module settings. + * @param {string} settings.name - Jetpack module name. * @param {boolean} settings.active - If the module is active or not. - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* updateJetpackModuleStatus( settings ) { try { @@ -36,8 +36,8 @@ export function* updateJetpackModuleStatus( settings ) { /** * Yield actions to update module status - * @yields {object} - an action object. - * @returns {boolean} - if operation is successful or not. + * @yield {object} - an action object. + * @return {boolean} - if operation is successful or not. */ export function* fetchModules() { // We don't fetch modules for Simple Site and aknowledge that all modules are active @@ -62,7 +62,7 @@ export function* fetchModules() { * Set modules as loading action * * @param {boolean} isLoading - If the modules are loading or not. - * @returns {object} - an action object. + * @return {object} - an action object. */ function setIsLoading( isLoading ) { return setJetpackModules( { isLoading } ); @@ -71,9 +71,9 @@ function setIsLoading( isLoading ) { /** * Set modules as updating action * - * @param {string} name - Name of the module. + * @param {string} name - Name of the module. * @param {boolean} isUpdating - If the modules are updating or not. - * @returns {object} - an action object. + * @return {object} - an action object. */ function setIsUpdating( name, isUpdating ) { return { type: SET_MODULE_UPDATING, name, isUpdating }; @@ -82,10 +82,10 @@ function setIsUpdating( name, isUpdating ) { /** * Set Jetpack module action * - * @param {object} options - Jetpack settings. - * @param {object} options.modules - Jetpack modules. + * @param {object} options - Jetpack settings. + * @param {object} options.modules - Jetpack modules. * @param {boolean} options.isLoading - If the modules are loading or not. - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setJetpackModules( options ) { return { type: SET_JETPACK_MODULES, options }; diff --git a/projects/js-packages/shared-extension-utils/src/modules-state/controls.js b/projects/js-packages/shared-extension-utils/src/modules-state/controls.js index 1b811a77d4687..fd348075738ac 100644 --- a/projects/js-packages/shared-extension-utils/src/modules-state/controls.js +++ b/projects/js-packages/shared-extension-utils/src/modules-state/controls.js @@ -6,7 +6,7 @@ export const UPDATE_JETPACK_MODULE_STATUS = 'UPDATE_JETPACK_MODULE_STATUS'; /** * fetchJetpackModules action * - * @returns {object} - an action object. + * @return {object} - an action object. */ export const fetchJetpackModules = () => { return { @@ -17,8 +17,8 @@ export const fetchJetpackModules = () => { /** * Updating single module status action * - * @param settings - Jetpack module settings. - * @param {string} settings.name - Jetpack module name. + * @param settings - Jetpack module settings. + * @param {string} settings.name - Jetpack module name. * @param {boolean} settings.active - If the module is active or not. */ diff --git a/projects/js-packages/shared-extension-utils/src/modules-state/resolvers.js b/projects/js-packages/shared-extension-utils/src/modules-state/resolvers.js index 7bdab717e1709..3b4032cc8777d 100644 --- a/projects/js-packages/shared-extension-utils/src/modules-state/resolvers.js +++ b/projects/js-packages/shared-extension-utils/src/modules-state/resolvers.js @@ -4,8 +4,8 @@ import { fetchJetpackModules } from './controls'; /** * Yield actions to get the Jetpack modules. * - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* getJetpackModules() { try { diff --git a/projects/js-packages/shared-extension-utils/src/plan-utils.js b/projects/js-packages/shared-extension-utils/src/plan-utils.js index 9899c8467210e..b3bcaed6fce0e 100644 --- a/projects/js-packages/shared-extension-utils/src/plan-utils.js +++ b/projects/js-packages/shared-extension-utils/src/plan-utils.js @@ -10,12 +10,12 @@ import { isAtomicSite, isSimpleSite } from './site-type-utils'; * Return the checkout URL to upgrade the site plan, * depending on the plan, postId, and postType site values. * - * @param {object} siteParams - Site params used to build the URL. + * @param {object} siteParams - Site params used to build the URL. * @param {string} siteParams.planSlug - Plan slug. - * @param {object} siteParams.plan - An object with details about the plan. - * @param {number} siteParams.postId - Post id. + * @param {object} siteParams.plan - An object with details about the plan. + * @param {number} siteParams.postId - Post id. * @param {string} siteParams.postType - Post type. - * @returns {string} Upgrade URL. + * @return {string} Upgrade URL. */ export function getUpgradeUrl( { planSlug, plan, postId, postType } ) { // WP.com plan objects have a dedicated `path_slug` field, Jetpack plan objects don't. @@ -88,7 +88,7 @@ export function getUpgradeUrl( { planSlug, plan, postId, postType } ) { * the block requires a paid plan. * * @param {string} name - Block name. - * @returns {boolean} True if the block is upgradable, false otherwise. + * @return {boolean} True if the block is upgradable, false otherwise. */ export function isUpgradable( name ) { if ( ! name ) { @@ -105,8 +105,8 @@ export function isUpgradable( name ) { * Checks whether the block requires a paid plan or not. * * @param {string} unavailableReason - The reason why block is unavailable - * @param {object} details - The block details - * @returns {string|boolean} Either false if the block doesn't require a paid plan, or the actual plan name it requires. + * @param {object} details - The block details + * @return {string|boolean} Either false if the block doesn't require a paid plan, or the actual plan name it requires. */ export function requiresPaidPlan( unavailableReason, details ) { if ( unavailableReason === 'missing_plan' ) { @@ -119,7 +119,7 @@ export function requiresPaidPlan( unavailableReason, details ) { * Returns the required plan slug for a passed block name. * * @param {string} name - Block name. - * @returns {string|boolean} Plan name if the block is upgradable, false otherwise. + * @return {string|boolean} Plan name if the block is upgradable, false otherwise. */ export function getRequiredPlan( name ) { if ( ! name ) { @@ -158,7 +158,7 @@ const usableBlockWithFreePlan = [ /** * Return whether upgrade nudges are enabled or not. * - * @returns {boolean} True if the Upgrade Nudge is enable. Otherwise, False. + * @return {boolean} True if the Upgrade Nudge is enable. Otherwise, False. */ export function isUpgradeNudgeEnabled() { return get( getJetpackData(), 'jetpack.enable_upgrade_nudge', false ); diff --git a/projects/js-packages/shared-extension-utils/src/register-jetpack-plugin.js b/projects/js-packages/shared-extension-utils/src/register-jetpack-plugin.js index d013656905c8c..e48c01b7e601a 100644 --- a/projects/js-packages/shared-extension-utils/src/register-jetpack-plugin.js +++ b/projects/js-packages/shared-extension-utils/src/register-jetpack-plugin.js @@ -4,9 +4,9 @@ import getJetpackExtensionAvailability from './get-jetpack-extension-availabilit /** * Registers a Gutenberg block if the availability requirements are met. * - * @param {string} name - The plugin's name + * @param {string} name - The plugin's name * @param {object} settings - The plugin's settings. - * @returns {object|boolean} Either false if the plugin is not available, or the results of `registerPlugin` + * @return {object|boolean} Either false if the plugin is not available, or the results of `registerPlugin` */ export default function registerJetpackPlugin( name, settings ) { const { available, unavailableReason } = getJetpackExtensionAvailability( name ); diff --git a/projects/js-packages/shared-extension-utils/src/site-type-utils.js b/projects/js-packages/shared-extension-utils/src/site-type-utils.js index 55d7b6785f9a9..6c491624b630c 100644 --- a/projects/js-packages/shared-extension-utils/src/site-type-utils.js +++ b/projects/js-packages/shared-extension-utils/src/site-type-utils.js @@ -3,7 +3,7 @@ import getJetpackData from './get-jetpack-data'; /** * Get the site type from environment * - * @returns {(string|null)} Site type + * @return {(string|null)} Site type */ function getSiteType() { return 'object' === typeof window && typeof window._currentSiteType === 'string' @@ -14,7 +14,7 @@ function getSiteType() { /** * Check if environment is Simple site. * - * @returns {boolean} True for Simple sites. + * @return {boolean} True for Simple sites. */ export function isSimpleSite() { return getSiteType() === 'simple'; @@ -23,7 +23,7 @@ export function isSimpleSite() { /** * Check if environment is Atomic site. * - * @returns {boolean} True for Atomic sites. + * @return {boolean} True for Atomic sites. */ export function isAtomicSite() { return getSiteType() === 'atomic'; @@ -32,7 +32,7 @@ export function isAtomicSite() { /** * Return whether the current blog is set to private. (if blog_public option is -1) * - * @returns {boolean} whether the current blog is set to private. + * @return {boolean} whether the current blog is set to private. */ export function isPrivateSite() { const jetpackData = getJetpackData(); @@ -43,7 +43,7 @@ export function isPrivateSite() { * Return whether the current site is coming soon (i.e. not launched yet). * This is only available for WordPress.com sites so far. * - * @returns {boolean} whether the current site is coming soon. + * @return {boolean} whether the current site is coming soon. */ export function isComingSoon() { const jetpackData = getJetpackData(); diff --git a/projects/js-packages/social-logos/CHANGELOG.md b/projects/js-packages/social-logos/CHANGELOG.md index cbc4f993cb773..16049d165c89c 100644 --- a/projects/js-packages/social-logos/CHANGELOG.md +++ b/projects/js-packages/social-logos/CHANGELOG.md @@ -1,3 +1,15 @@ +## [3.1.7] - 2024-08-23 +### Changed +- Internal updates. + +## [3.1.6] - 2024-08-21 +### Fixed +- Revert recent SVG image optimizations. [#38981] + +## [3.1.5] - 2024-08-19 +### Fixed +- Lossless image optimization for images (should improve performance with no visible changes). [#38750] + ## [3.1.4] - 2024-08-15 ### Changed - Updated package dependencies. [#38665] @@ -137,6 +149,9 @@ - Build: Refactored (aligned build system with Gridicons). +[3.1.7]: https://github.com/Automattic/social-logos/compare/v3.1.6...v3.1.7 +[3.1.6]: https://github.com/Automattic/social-logos/compare/v3.1.5...v3.1.6 +[3.1.5]: https://github.com/Automattic/social-logos/compare/v3.1.4...v3.1.5 [3.1.4]: https://github.com/Automattic/social-logos/compare/v3.1.3...v3.1.4 [3.1.3]: https://github.com/Automattic/social-logos/compare/v3.1.2...v3.1.3 [3.1.2]: https://github.com/Automattic/social-logos/compare/v3.1.1...v3.1.2 diff --git a/projects/js-packages/social-logos/package.json b/projects/js-packages/social-logos/package.json index 9598955582b50..0393fd816828e 100644 --- a/projects/js-packages/social-logos/package.json +++ b/projects/js-packages/social-logos/package.json @@ -1,6 +1,6 @@ { "name": "social-logos", - "version": "3.1.4", + "version": "3.1.7", "description": "A repository of all the social logos used on WordPress.com.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/social-logos/", "bugs": { diff --git a/projects/js-packages/social-logos/src/react/example.tsx b/projects/js-packages/social-logos/src/react/example.tsx index 01f2a757f8cf9..3c9b5a14171a9 100644 --- a/projects/js-packages/social-logos/src/react/example.tsx +++ b/projects/js-packages/social-logos/src/react/example.tsx @@ -1,3 +1,4 @@ +/* eslint-disable no-alert -- ok for demo */ import React, { useState } from 'react'; import { SocialLogo } from './social-logo'; import { SocialLogoData } from './social-logo-data'; @@ -6,7 +7,7 @@ import '../css/example.css'; /** * An example React component that displays all the social logos. * - * @returns {React.Component} The `SocialLogosExample` component. + * @return {React.Component} The `SocialLogosExample` component. */ function SocialLogosExample() { const [ useSmallIcons, setUseSmallIcons ] = useState( false ); diff --git a/projects/js-packages/social-logos/tools/svg-to-react-data.js b/projects/js-packages/social-logos/tools/svg-to-react-data.js index 75c15f85ad683..2cf23e4ef6909 100755 --- a/projects/js-packages/social-logos/tools/svg-to-react-data.js +++ b/projects/js-packages/social-logos/tools/svg-to-react-data.js @@ -17,7 +17,7 @@ process.chdir( rootDir ); /** * Transforms kebab case names to camel case. * @param {string} name - e.g.: foo-bar-baz - * @returns {string} e.g.: fooBarBaz + * @return {string} e.g.: fooBarBaz */ function kebabToCamelCase( name ) { const KEBAB_REGEX = /-(\w)/g; diff --git a/projects/js-packages/connection/changelog/renovate-storybook-monorepo b/projects/js-packages/storybook/changelog/renovate-npm-webpack-vulnerability similarity index 100% rename from projects/js-packages/connection/changelog/renovate-storybook-monorepo rename to projects/js-packages/storybook/changelog/renovate-npm-webpack-vulnerability diff --git a/projects/js-packages/image-guide/changelog/renovate-rollup-plugin-svelte-7.x b/projects/js-packages/storybook/changelog/renovate-yoast-phpunit-polyfills-1.x similarity index 100% rename from projects/js-packages/image-guide/changelog/renovate-rollup-plugin-svelte-7.x rename to projects/js-packages/storybook/changelog/renovate-yoast-phpunit-polyfills-1.x diff --git a/projects/js-packages/storybook/changelog/try-lossless-image-optmization-part-3 b/projects/js-packages/storybook/changelog/try-lossless-image-optmization-part-3 new file mode 100644 index 0000000000000..cf77a8b55bb43 --- /dev/null +++ b/projects/js-packages/storybook/changelog/try-lossless-image-optmization-part-3 @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Lossless image optimization for images (should improve performance with no visible changes). diff --git a/projects/js-packages/storybook/changelog/try-no-version-bumps-in-trunk b/projects/js-packages/storybook/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..91efe85c55e06 --- /dev/null +++ b/projects/js-packages/storybook/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/js-packages/storybook/changelog/update-jsdoc-comments-for-wp-coding-standards b/projects/js-packages/storybook/changelog/update-jsdoc-comments-for-wp-coding-standards new file mode 100644 index 0000000000000..0e655b2b8b7a3 --- /dev/null +++ b/projects/js-packages/storybook/changelog/update-jsdoc-comments-for-wp-coding-standards @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Reformat jsdoc comments. No change to meaning or functionality. + + diff --git a/projects/js-packages/storybook/composer.json b/projects/js-packages/storybook/composer.json index faf1f4b0fcfc3..5d39fec633912 100644 --- a/projects/js-packages/storybook/composer.json +++ b/projects/js-packages/storybook/composer.json @@ -5,7 +5,7 @@ "license": "GPL-2.0-or-later", "require": {}, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "autoload": { diff --git a/projects/js-packages/storybook/package.json b/projects/js-packages/storybook/package.json index e423f5340087d..6aeae685b5917 100644 --- a/projects/js-packages/storybook/package.json +++ b/projects/js-packages/storybook/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-storybook", - "version": "0.5.0-alpha", + "version": "0.4.1", "description": "Jetpack components storybook", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/storybook/#readme", "bugs": { @@ -67,7 +67,7 @@ "style-loader": "2.0.0", "ts-dedent": "2.2.0", "typescript": "5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "dependencies": { diff --git a/projects/js-packages/storybook/public/connect-right.png b/projects/js-packages/storybook/public/connect-right.png index 66f8710ac0634..4779757259f45 100644 Binary files a/projects/js-packages/storybook/public/connect-right.png and b/projects/js-packages/storybook/public/connect-right.png differ diff --git a/projects/js-packages/storybook/storybook/stories/playground/index.stories.jsx b/projects/js-packages/storybook/storybook/stories/playground/index.stories.jsx index 0ea0d37e9a9dc..7efa055212b17 100644 --- a/projects/js-packages/storybook/storybook/stories/playground/index.stories.jsx +++ b/projects/js-packages/storybook/storybook/stories/playground/index.stories.jsx @@ -18,7 +18,7 @@ import './style.scss'; /** * Render our playground component * - * @returns {React.Component} - The App + * @return {React.Component} - The App */ function App() { const [ blocks, updateBlocks ] = useState( [] ); diff --git a/projects/js-packages/image-guide/changelog/renovate-svelte-4.x b/projects/js-packages/svelte-data-sync-client/changelog/renovate-npm-webpack-vulnerability similarity index 100% rename from projects/js-packages/image-guide/changelog/renovate-svelte-4.x rename to projects/js-packages/svelte-data-sync-client/changelog/renovate-npm-webpack-vulnerability diff --git a/projects/js-packages/image-guide/changelog/renovate-svelte-preprocess-6.x b/projects/js-packages/svelte-data-sync-client/changelog/renovate-yoast-phpunit-polyfills-1.x similarity index 100% rename from projects/js-packages/image-guide/changelog/renovate-svelte-preprocess-6.x rename to projects/js-packages/svelte-data-sync-client/changelog/renovate-yoast-phpunit-polyfills-1.x diff --git a/projects/js-packages/svelte-data-sync-client/changelog/try-no-version-bumps-in-trunk b/projects/js-packages/svelte-data-sync-client/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..91efe85c55e06 --- /dev/null +++ b/projects/js-packages/svelte-data-sync-client/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/js-packages/svelte-data-sync-client/changelog/update-jsdoc-comments-for-wp-coding-standards b/projects/js-packages/svelte-data-sync-client/changelog/update-jsdoc-comments-for-wp-coding-standards new file mode 100644 index 0000000000000..0e655b2b8b7a3 --- /dev/null +++ b/projects/js-packages/svelte-data-sync-client/changelog/update-jsdoc-comments-for-wp-coding-standards @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Reformat jsdoc comments. No change to meaning or functionality. + + diff --git a/projects/js-packages/svelte-data-sync-client/composer.json b/projects/js-packages/svelte-data-sync-client/composer.json index b713819703c26..6f5acc91c2443 100644 --- a/projects/js-packages/svelte-data-sync-client/composer.json +++ b/projects/js-packages/svelte-data-sync-client/composer.json @@ -5,7 +5,7 @@ "license": "GPL-2.0-or-later", "require": {}, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "autoload": { diff --git a/projects/js-packages/svelte-data-sync-client/package.json b/projects/js-packages/svelte-data-sync-client/package.json index 2aed4f1ebb874..25a51ea543517 100644 --- a/projects/js-packages/svelte-data-sync-client/package.json +++ b/projects/js-packages/svelte-data-sync-client/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-svelte-data-sync-client", - "version": "0.3.6-alpha", + "version": "0.3.5", "description": "A Svelte.js client for the wp-js-data-sync package", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/svelte-data-sync-client/#readme", "type": "module", @@ -31,7 +31,7 @@ "svelte": "4.2.18", "tslib": "2.5.0", "typescript": "5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1", "zod": "3.22.3" }, diff --git a/projects/js-packages/svelte-data-sync-client/src/DataSync.ts b/projects/js-packages/svelte-data-sync-client/src/DataSync.ts index 6078418312657..b09bf418400b1 100644 --- a/projects/js-packages/svelte-data-sync-client/src/DataSync.ts +++ b/projects/js-packages/svelte-data-sync-client/src/DataSync.ts @@ -66,8 +66,8 @@ export class DataSync< Schema extends z.ZodSchema, Value extends z.infer< Schema * This would make a request to: http://localhost/wp-json/namespace/key * * @param namespace - The namespace of the endpoint. This matches the name of the global variable (window.{namespace}.{endpoint_name}). - * @param key - The key of the value that's being synced. This is used to fetch the value from the global window object. - * @param schema - The Zod schema to validate the value against. This ensures that the value is of the expected type. + * @param key - The key of the value that's being synced. This is used to fetch the value from the global window object. + * @param schema - The Zod schema to validate the value against. This ensures that the value is of the expected type. */ constructor( namespace: string, @@ -128,7 +128,7 @@ export class DataSync< Schema extends z.ZodSchema, Value extends z.infer< Schema * Helper function to get values * from the window object and validate them. * - * @param valueName - The name of the value. For example, `posts`. + * @param valueName - The name of the value. For example, `posts`. * @param valueSchema - The Zod schema to validate the value against. * @returns The parsed value. */ @@ -213,9 +213,9 @@ export class DataSync< Schema extends z.ZodSchema, Value extends z.infer< Schema /** * Method to parse the request. - * @param method - The request method. + * @param method - The request method. * @param requestPath - The request path. - * @param params - The request parameters. + * @param params - The request parameters. * @param abortSignal - The abort signal. * @returns The parsed value. */ @@ -240,7 +240,7 @@ export class DataSync< Schema extends z.ZodSchema, Value extends z.infer< Schema /** * Method to attempt the request. - * @param url - The request URL. + * @param url - The request URL. * @param args - The request arguments. * @returns The result of the request. */ diff --git a/projects/js-packages/partner-coupon/changelog/renovate-wordpress-monorepo b/projects/js-packages/videopress-core/changelog/renovate-npm-webpack-vulnerability similarity index 100% rename from projects/js-packages/partner-coupon/changelog/renovate-wordpress-monorepo rename to projects/js-packages/videopress-core/changelog/renovate-npm-webpack-vulnerability diff --git a/projects/js-packages/publicize-components/changelog/renovate-definitelytyped b/projects/js-packages/videopress-core/changelog/renovate-yoast-phpunit-polyfills-1.x#2 similarity index 100% rename from projects/js-packages/publicize-components/changelog/renovate-definitelytyped rename to projects/js-packages/videopress-core/changelog/renovate-yoast-phpunit-polyfills-1.x#2 diff --git a/projects/js-packages/videopress-core/changelog/update-jsdoc-comments-for-wp-coding-standards b/projects/js-packages/videopress-core/changelog/update-jsdoc-comments-for-wp-coding-standards new file mode 100644 index 0000000000000..0e655b2b8b7a3 --- /dev/null +++ b/projects/js-packages/videopress-core/changelog/update-jsdoc-comments-for-wp-coding-standards @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Reformat jsdoc comments. No change to meaning or functionality. + + diff --git a/projects/js-packages/videopress-core/composer.json b/projects/js-packages/videopress-core/composer.json index 739a49babb18b..5d6c38e379d32 100644 --- a/projects/js-packages/videopress-core/composer.json +++ b/projects/js-packages/videopress-core/composer.json @@ -5,7 +5,7 @@ "license": "GPL-2.0-or-later", "require": {}, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "autoload": { diff --git a/projects/js-packages/videopress-core/package.json b/projects/js-packages/videopress-core/package.json index 311d09bb60c1c..90aeb4fbdb9a4 100644 --- a/projects/js-packages/videopress-core/package.json +++ b/projects/js-packages/videopress-core/package.json @@ -29,7 +29,7 @@ "@types/jest": "29.5.12", "tslib": "2.5.0", "typescript": "5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "exports": { diff --git a/projects/js-packages/videopress-core/src/index.ts b/projects/js-packages/videopress-core/src/index.ts index f72f62621a2e4..8a75100bf2985 100644 --- a/projects/js-packages/videopress-core/src/index.ts +++ b/projects/js-packages/videopress-core/src/index.ts @@ -6,7 +6,7 @@ * * @param {number} a - First number. * @param {number} b - Second number. - * @returns {number} The sum. + * @return {number} The sum. */ export function addition( a: number, b: number ): number { return a + b; diff --git a/projects/js-packages/webpack-config/CHANGELOG.md b/projects/js-packages/webpack-config/CHANGELOG.md index 40355c4761cf3..1c56c7a4d75be 100644 --- a/projects/js-packages/webpack-config/CHANGELOG.md +++ b/projects/js-packages/webpack-config/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 3.3.3 - 2024-08-29 +### Changed +- Updated package dependencies. [#39111] + +## 3.3.2 - 2024-08-21 +### Changed +- Internal updates. + ## 3.3.1 - 2024-08-15 ### Changed - Updated package dependencies. [#38662] diff --git a/projects/js-packages/webpack-config/package.json b/projects/js-packages/webpack-config/package.json index 55647959f00bc..73946fa946f12 100644 --- a/projects/js-packages/webpack-config/package.json +++ b/projects/js-packages/webpack-config/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-webpack-config", - "version": "3.3.1", + "version": "3.3.3", "description": "Library of pieces for webpack config in Jetpack projects.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/webpack-config/#readme", "bugs": { @@ -43,14 +43,14 @@ "@babel/core": "7.24.7", "@babel/runtime": "7.24.7", "typescript": "5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "peerDependencies": { "@babel/core": "^7.0.0", "@babel/runtime": "7.24.7", "typescript": ">=4.9.5", - "webpack": "^5.67.0" + "webpack": "^5.94.0" }, "peerDependenciesMeta": { "@babel/core": { diff --git a/projects/js-packages/webpack-config/src/webpack/pnpm-deterministic-ids.js b/projects/js-packages/webpack-config/src/webpack/pnpm-deterministic-ids.js index 806a7ec2d7ae3..c10a633dfc0ed 100644 --- a/projects/js-packages/webpack-config/src/webpack/pnpm-deterministic-ids.js +++ b/projects/js-packages/webpack-config/src/webpack/pnpm-deterministic-ids.js @@ -26,7 +26,7 @@ const PNPM_PATH_REGEXP = * up with colliding identifiers, but Webpack already handles that. * * @param {string} identifier - Identifier. - * @returns {string} Transformed identifier. + * @return {string} Transformed identifier. */ function fixPnpmPaths( identifier ) { return identifier.replace( PNPM_PATH_REGEXP, '.pnpm/$1' ); @@ -44,7 +44,7 @@ class PnpmDeterministicModuleIdsPlugin { * Apply the plugin * * @param {Compiler} compiler - the compiler instance - * @returns {void} + * @return {void} */ apply( compiler ) { compiler.hooks.compilation.tap( 'PnpmDeterministicModuleIdsPlugin', compilation => { diff --git a/projects/js-packages/webpack-config/src/webpack/terser.js b/projects/js-packages/webpack-config/src/webpack/terser.js index db2d7e57cca73..4c38d8320d33e 100644 --- a/projects/js-packages/webpack-config/src/webpack/terser.js +++ b/projects/js-packages/webpack-config/src/webpack/terser.js @@ -11,10 +11,10 @@ const browsers = browserslist( * Terser's function to decide which comments to preserve. * * @see https://github.com/terser/terser/blob/v5.9.0/lib/output.js#L171-L177 - * @param {object} comment - Comment object. - * @param {string} comment.type - Comment type. + * @param {object} comment - Comment object. + * @param {string} comment.type - Comment type. * @param {string} comment.value - Comment text. - * @returns {boolean} Whether to keep it. + * @return {boolean} Whether to keep it. */ function isSomeComments( comment ) { return ( @@ -28,10 +28,10 @@ function isSomeComments( comment ) { * * @see https://github.com/php-gettext/Gettext/blob/4.x/src/Utils/ParsedComment.php#L53-L73 * @see https://github.com/wp-cli/i18n-command/blob/v2.2.9/src/JsCodeExtractor.php#L15 - * @param {object} comment - Comment object. - * @param {string} comment.type - Comment type. + * @param {object} comment - Comment object. + * @param {string} comment.type - Comment type. * @param {string} comment.value - Comment text. - * @returns {boolean} Whether to keep it. + * @return {boolean} Whether to keep it. */ function isTranslatorsComment( comment ) { return ( @@ -96,7 +96,7 @@ if ( * * @param {*} a - Object A. * @param {*} b - Object B. - * @returns {*} Result: + * @return {*} Result: * - If A and B are both plain objects, like { ...a, ...b }. * - If they're arrays, elements of B replace those of A. * - If B is undefined, A. Else B. diff --git a/projects/js-packages/webpack-config/src/webpack/transpile-rule.js b/projects/js-packages/webpack-config/src/webpack/transpile-rule.js index 0d7e3e576de4e..afa09f0417c4a 100644 --- a/projects/js-packages/webpack-config/src/webpack/transpile-rule.js +++ b/projects/js-packages/webpack-config/src/webpack/transpile-rule.js @@ -5,7 +5,7 @@ const path = require( 'path' ); * Make the condition to include certain node_modules prefixes. * * @param {string[]} modules - Module prefixes to include. - * @returns {Function} Condition function. + * @return {Function} Condition function. */ function makeIncludeNodeModulesCondition( modules ) { return file => { diff --git a/projects/packages/a8c-mc-stats/CHANGELOG.md b/projects/packages/a8c-mc-stats/CHANGELOG.md index ee8ebb51fcbaf..1e7d3ab7c2a9f 100644 --- a/projects/packages/a8c-mc-stats/CHANGELOG.md +++ b/projects/packages/a8c-mc-stats/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.2] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## [2.0.1] - 2024-03-12 ### Changed - Internal updates. @@ -135,6 +139,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Creates the MC Stats package +[2.0.2]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v2.0.1...v2.0.2 [2.0.1]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v2.0.0...v2.0.1 [2.0.0]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v1.4.22...v2.0.0 [1.4.22]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v1.4.21...v1.4.22 diff --git a/projects/packages/a8c-mc-stats/composer.json b/projects/packages/a8c-mc-stats/composer.json index 699281fa76032..254e7e80a8558 100644 --- a/projects/packages/a8c-mc-stats/composer.json +++ b/projects/packages/a8c-mc-stats/composer.json @@ -7,7 +7,7 @@ "php": ">=7.0" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "suggest": { diff --git a/projects/packages/admin-ui/CHANGELOG.md b/projects/packages/admin-ui/CHANGELOG.md index 5cec974ff7626..4fcb27c498e96 100644 --- a/projects/packages/admin-ui/CHANGELOG.md +++ b/projects/packages/admin-ui/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.4.4] - 2024-08-29 +### Changed +- Admin menu: change order of Jetpack sub-menu items [#39095] + +## [0.4.3] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## [0.4.2] - 2024-04-22 ### Changed - Internal updates. @@ -148,6 +156,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixing menu visibility issues. +[0.4.4]: https://github.com/Automattic/jetpack-admin-ui/compare/0.4.3...0.4.4 +[0.4.3]: https://github.com/Automattic/jetpack-admin-ui/compare/0.4.2...0.4.3 [0.4.2]: https://github.com/Automattic/jetpack-admin-ui/compare/0.4.1...0.4.2 [0.4.1]: https://github.com/Automattic/jetpack-admin-ui/compare/0.4.0...0.4.1 [0.4.0]: https://github.com/Automattic/jetpack-admin-ui/compare/0.3.2...0.4.0 diff --git a/projects/packages/admin-ui/composer.json b/projects/packages/admin-ui/composer.json index 3bc07bfbed192..b3eec38c9cea0 100644 --- a/projects/packages/admin-ui/composer.json +++ b/projects/packages/admin-ui/composer.json @@ -7,7 +7,7 @@ "php": ">=7.0" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/jetpack-logo": "@dev", "automattic/wordbless": "dev-master" diff --git a/projects/packages/admin-ui/package.json b/projects/packages/admin-ui/package.json index 92416c7682b9d..d507626bfdab0 100644 --- a/projects/packages/admin-ui/package.json +++ b/projects/packages/admin-ui/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-admin-ui", - "version": "0.4.2", + "version": "0.4.4", "description": "Generic Jetpack wp-admin UI elements", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/admin-ui/#readme", "bugs": { diff --git a/projects/packages/admin-ui/src/class-admin-menu.php b/projects/packages/admin-ui/src/class-admin-menu.php index 24951e19472f6..407271c30c859 100644 --- a/projects/packages/admin-ui/src/class-admin-menu.php +++ b/projects/packages/admin-ui/src/class-admin-menu.php @@ -13,7 +13,7 @@ */ class Admin_Menu { - const PACKAGE_VERSION = '0.4.2'; + const PACKAGE_VERSION = '0.4.4'; /** * Whether this class has been initialized @@ -58,7 +58,7 @@ function () { remove_action( 'admin_menu', array( 'Akismet_Admin', 'admin_menu' ), 5 ); // Add an Anti-spam menu item for Jetpack. - self::add_menu( __( 'Akismet Anti-spam', 'jetpack-admin-ui' ), __( 'Akismet Anti-spam', 'jetpack-admin-ui' ), 'manage_options', 'akismet-key-config', array( 'Akismet_Admin', 'display_page' ) ); + self::add_menu( __( 'Akismet Anti-spam', 'jetpack-admin-ui' ), __( 'Akismet Anti-spam', 'jetpack-admin-ui' ), 'manage_options', 'akismet-key-config', array( 'Akismet_Admin', 'display_page' ), 6 ); }, 4 ); diff --git a/projects/packages/assets/CHANGELOG.md b/projects/packages/assets/CHANGELOG.md index bcbf69dbf848b..9ec4e5ba4f68c 100644 --- a/projects/packages/assets/CHANGELOG.md +++ b/projects/packages/assets/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.3.5] - 2024-08-29 +### Changed +- Updated package dependencies. [#39111] + +## [2.3.4] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + +## [2.3.3] - 2024-08-21 +### Changed +- i18n loader script & React JSX runtime: load scripts in the footer. [#38929] + ## [2.3.2] - 2024-08-15 ### Changed - Updated package dependencies. [#38662] @@ -474,6 +486,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Statically access asset tools +[2.3.5]: https://github.com/Automattic/jetpack-assets/compare/v2.3.4...v2.3.5 +[2.3.4]: https://github.com/Automattic/jetpack-assets/compare/v2.3.3...v2.3.4 +[2.3.3]: https://github.com/Automattic/jetpack-assets/compare/v2.3.2...v2.3.3 [2.3.2]: https://github.com/Automattic/jetpack-assets/compare/v2.3.1...v2.3.2 [2.3.1]: https://github.com/Automattic/jetpack-assets/compare/v2.3.0...v2.3.1 [2.3.0]: https://github.com/Automattic/jetpack-assets/compare/v2.2.0...v2.3.0 diff --git a/projects/packages/assets/composer.json b/projects/packages/assets/composer.json index ddd58c954f41f..623e950b35ad2 100644 --- a/projects/packages/assets/composer.json +++ b/projects/packages/assets/composer.json @@ -9,7 +9,7 @@ }, "require-dev": { "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0" }, diff --git a/projects/packages/assets/package.json b/projects/packages/assets/package.json index 7acf696dc8a5a..7ca99f8b70201 100644 --- a/projects/packages/assets/package.json +++ b/projects/packages/assets/package.json @@ -19,7 +19,7 @@ "@wordpress/browserslist-config": "6.5.0", "jest": "29.7.0", "md5-es": "1.8.2", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" } } diff --git a/projects/packages/assets/src/class-assets.php b/projects/packages/assets/src/class-assets.php index 303c9459282d7..3177ab69573b6 100644 --- a/projects/packages/assets/src/class-assets.php +++ b/projects/packages/assets/src/class-assets.php @@ -510,24 +510,31 @@ public static function wp_default_scripts_hook( $wp_scripts ) { } $url = self::normalize_path( plugins_url( $path, __FILE__ ) ); $url = add_query_arg( 'minify', 'true', $url ); - $wp_scripts->add( 'wp-jp-i18n-loader', $url, $asset['dependencies'], $asset['version'] ); + + $handle = 'wp-jp-i18n-loader'; + + $wp_scripts->add( $handle, $url, $asset['dependencies'], $asset['version'] ); + + // Ensure the script is loaded in the footer and deferred. + $wp_scripts->add_data( $handle, 'group', 1 ); + if ( ! is_array( $data ) || ! isset( $data['baseUrl'] ) || ! ( is_string( $data['baseUrl'] ) || false === $data['baseUrl'] ) || ! isset( $data['locale'] ) || ! is_string( $data['locale'] ) || ! isset( $data['domainMap'] ) || ! is_array( $data['domainMap'] ) || ! isset( $data['domainPaths'] ) || ! is_array( $data['domainPaths'] ) ) { - $wp_scripts->add_inline_script( 'wp-jp-i18n-loader', 'console.warn( "I18n state deleted by jetpack_i18n_state hook" );' ); + $wp_scripts->add_inline_script( $handle, 'console.warn( "I18n state deleted by jetpack_i18n_state hook" );' ); } elseif ( ! $data['baseUrl'] ) { - $wp_scripts->add_inline_script( 'wp-jp-i18n-loader', 'console.warn( "Failed to determine languages base URL. Is WP_LANG_DIR in the WordPress root?" );' ); + $wp_scripts->add_inline_script( $handle, 'console.warn( "Failed to determine languages base URL. Is WP_LANG_DIR in the WordPress root?" );' ); } else { $data['domainMap'] = (object) $data['domainMap']; // Ensure it becomes a json object. $data['domainPaths'] = (object) $data['domainPaths']; // Ensure it becomes a json object. - $wp_scripts->add_inline_script( 'wp-jp-i18n-loader', 'wp.jpI18nLoader.state = ' . wp_json_encode( $data, JSON_UNESCAPED_SLASHES ) . ';' ); + $wp_scripts->add_inline_script( $handle, 'wp.jpI18nLoader.state = ' . wp_json_encode( $data, JSON_UNESCAPED_SLASHES ) . ';' ); } // Deprecated state module: Depend on wp-i18n to ensure global `wp` exists and because anything needing this will need that too. - $wp_scripts->add( 'wp-jp-i18n-state', false, array( 'wp-deprecated', 'wp-jp-i18n-loader' ) ); + $wp_scripts->add( 'wp-jp-i18n-state', false, array( 'wp-deprecated', $handle ) ); $wp_scripts->add_inline_script( 'wp-jp-i18n-state', 'wp.deprecated( "wp-jp-i18n-state", { alternative: "wp-jp-i18n-loader" } );' ); $wp_scripts->add_inline_script( 'wp-jp-i18n-state', 'wp.jpI18nState = wp.jpI18nLoader.state;' ); @@ -535,6 +542,7 @@ public static function wp_default_scripts_hook( $wp_scripts ) { // @todo Remove this when we drop support for WordPress 6.5, as well as the script inclusion in test_wp_default_scripts_hook. $jsx_url = self::normalize_path( plugins_url( '../build/react-jsx-runtime.js', __FILE__ ) ); $wp_scripts->add( 'react-jsx-runtime', $jsx_url, array( 'react' ), '18.3.1', true ); + $wp_scripts->add_data( 'react-jsx-runtime', 'group', 1 ); } // endregion . diff --git a/projects/packages/assets/src/js/i18n-loader.js b/projects/packages/assets/src/js/i18n-loader.js index 2124ea5686f4e..664e4f21a130a 100644 --- a/projects/packages/assets/src/js/i18n-loader.js +++ b/projects/packages/assets/src/js/i18n-loader.js @@ -20,10 +20,10 @@ module.exports = { /** * Download and register translations for a bundle. * - * @param {string} path - Bundle path being fetched. May have a query part. - * @param {string} domain - Text domain to register into. + * @param {string} path - Bundle path being fetched. May have a query part. + * @param {string} domain - Text domain to register into. * @param {string} location - Location for the translation: 'plugin', 'theme', or 'core'. - * @returns {Promise} Resolved when the translations are registered, or rejected with an `Error`. + * @return {Promise} Resolved when the translations are registered, or rejected with an `Error`. */ async downloadI18n( path, domain, location ) { const state = this.state; diff --git a/projects/packages/assets/tests/php/test-assets.php b/projects/packages/assets/tests/php/test-assets.php index c3a53b0660fa0..426fea7dc6cb0 100644 --- a/projects/packages/assets/tests/php/test-assets.php +++ b/projects/packages/assets/tests/php/test-assets.php @@ -729,7 +729,7 @@ function ( $v ) { // @phan-suppress-next-line PhanDeprecatedFunction -- Keep using setMethods until we drop PHP 7.0 support. $mock = $this->getMockBuilder( \stdClass::class ) - ->setMethods( array( 'add', 'add_inline_script' ) ) + ->setMethods( array( 'add', 'add_inline_script', 'add_data' ) ) ->getMock(); // Unfortunately PHPUnit deprecated withConsecutive with no replacement, so we have to roll our own version. @@ -785,6 +785,13 @@ function ( $value ) use ( $value_sets, $i ) { array( 'wp-jp-i18n-state', 'wp.jpI18nState = wp.jpI18nLoader.state;' ) ) ); + $mock->expects( $this->exactly( 2 ) )->method( 'add_data' ) + ->with( + ...$with_consecutive( + array( 'wp-jp-i18n-loader', 'group', 1 ), + array( 'react-jsx-runtime', 'group', 1 ) + ) + ); // @phan-suppress-next-line PhanTypeMismatchArgument -- We don't have a WP_Scripts definition to create a mock from. 🤷 Assets::wp_default_scripts_hook( $mock ); diff --git a/projects/packages/autoloader/CHANGELOG.md b/projects/packages/autoloader/CHANGELOG.md index b253cfe24e48a..317e9131ee7ed 100644 --- a/projects/packages/autoloader/CHANGELOG.md +++ b/projects/packages/autoloader/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.0.10] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + ## [3.0.9] - 2024-07-10 ### Fixed - Avoid a deprecation notice in `Autoloader_Locator::find_latest_autoloader()`. [#38245] @@ -368,6 +372,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add Custom Autoloader +[3.0.10]: https://github.com/Automattic/jetpack-autoloader/compare/v3.0.9...v3.0.10 [3.0.9]: https://github.com/Automattic/jetpack-autoloader/compare/v3.0.8...v3.0.9 [3.0.8]: https://github.com/Automattic/jetpack-autoloader/compare/v3.0.7...v3.0.8 [3.0.7]: https://github.com/Automattic/jetpack-autoloader/compare/v3.0.6...v3.0.7 diff --git a/projects/packages/autoloader/composer.json b/projects/packages/autoloader/composer.json index d0b36576a7a79..a41c97a16e94f 100644 --- a/projects/packages/autoloader/composer.json +++ b/projects/packages/autoloader/composer.json @@ -17,7 +17,7 @@ }, "require-dev": { "composer/composer": "^1.1 || ^2.0", - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "autoload": { diff --git a/projects/packages/autoloader/src/AutoloadGenerator.php b/projects/packages/autoloader/src/AutoloadGenerator.php index 2e9a311cb3163..48f931f2ad16a 100644 --- a/projects/packages/autoloader/src/AutoloadGenerator.php +++ b/projects/packages/autoloader/src/AutoloadGenerator.php @@ -21,7 +21,7 @@ */ class AutoloadGenerator { - const VERSION = '3.0.9'; + const VERSION = '3.0.10'; /** * IO object. diff --git a/projects/packages/backup-helper-script-manager/CHANGELOG.md b/projects/packages/backup-helper-script-manager/CHANGELOG.md index b39cdad83ee69..620d7ab45e900 100644 --- a/projects/packages/backup-helper-script-manager/CHANGELOG.md +++ b/projects/packages/backup-helper-script-manager/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.7] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + ## [0.2.6] - 2024-04-08 ### Changed - Internal updates. @@ -37,6 +41,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Initial release (improved helper script installer logging). [#34297] +[0.2.7]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.2.6...v0.2.7 [0.2.6]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.2.5...v0.2.6 [0.2.5]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.2.4...v0.2.5 [0.2.4]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.2.3...v0.2.4 diff --git a/projects/packages/backup-helper-script-manager/composer.json b/projects/packages/backup-helper-script-manager/composer.json index 2ed1700b04328..d608b1a7651ba 100644 --- a/projects/packages/backup-helper-script-manager/composer.json +++ b/projects/packages/backup-helper-script-manager/composer.json @@ -7,7 +7,7 @@ "php": ">=7.0" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev" }, diff --git a/projects/packages/backup/CHANGELOG.md b/projects/packages/backup/CHANGELOG.md index 8329af3a4654c..d1fbe87d90a08 100644 --- a/projects/packages/backup/CHANGELOG.md +++ b/projects/packages/backup/CHANGELOG.md @@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.4.5] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + +## [3.4.4] - 2024-08-21 +### Fixed +- Decoupled backup connection screens from useConnection hook to avoid unnecessary loading and prevent duplicated API calls. [#38948] +- Revert recent SVG image optimizations. [#38981] + +## [3.4.3] - 2024-08-19 +### Changed +- Update dependencies. [#38861] [#38662] + +### Fixed +- Lossless image optimization for images (should improve performance with no visible changes). [#38750] + ## [3.4.2] - 2024-07-22 ### Changed - Update dependencies. [#38402] @@ -660,6 +676,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add API endpoints and Jetpack Backup package for managing Help… +[3.4.5]: https://github.com/Automattic/jetpack-backup/compare/v3.4.4...v3.4.5 +[3.4.4]: https://github.com/Automattic/jetpack-backup/compare/v3.4.3...v3.4.4 +[3.4.3]: https://github.com/Automattic/jetpack-backup/compare/v3.4.2...v3.4.3 [3.4.2]: https://github.com/Automattic/jetpack-backup/compare/v3.4.1...v3.4.2 [3.4.1]: https://github.com/Automattic/jetpack-backup/compare/v3.4.0...v3.4.1 [3.4.0]: https://github.com/Automattic/jetpack-backup/compare/v3.3.17...v3.4.0 diff --git a/projects/js-packages/publicize-components/changelog/renovate-wordpress-monorepo b/projects/packages/backup/changelog/renovate-npm-webpack-vulnerability similarity index 100% rename from projects/js-packages/publicize-components/changelog/renovate-wordpress-monorepo rename to projects/packages/backup/changelog/renovate-npm-webpack-vulnerability diff --git a/projects/packages/backup/changelog/update-jetpack-menu-item-order b/projects/packages/backup/changelog/update-jetpack-menu-item-order new file mode 100644 index 0000000000000..4bfbd859ba2bf --- /dev/null +++ b/projects/packages/backup/changelog/update-jetpack-menu-item-order @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Admin menu: change order of Jetpack sub-menu items diff --git a/projects/packages/backup/composer.json b/projects/packages/backup/composer.json index fae2778f6865d..0fdc0b5761151 100644 --- a/projects/packages/backup/composer.json +++ b/projects/packages/backup/composer.json @@ -18,7 +18,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/wordbless": "@dev" }, "suggest": { diff --git a/projects/packages/backup/package.json b/projects/packages/backup/package.json index 65e4b10ee9a13..028ccc52c2f59 100644 --- a/projects/packages/backup/package.json +++ b/projects/packages/backup/package.json @@ -56,7 +56,7 @@ "jest-environment-jsdom": "29.7.0", "sass": "1.64.1", "sass-loader": "12.4.0", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" } } diff --git a/projects/packages/backup/src/class-jetpack-backup.php b/projects/packages/backup/src/class-jetpack-backup.php index d75fb1717eaf7..b6e0fd3bafad7 100644 --- a/projects/packages/backup/src/class-jetpack-backup.php +++ b/projects/packages/backup/src/class-jetpack-backup.php @@ -124,7 +124,8 @@ public static function initialize() { _x( 'VaultPress Backup', 'The Jetpack VaultPress Backup product name, without the Jetpack prefix', 'jetpack-backup-pkg' ), 'manage_options', 'jetpack-backup', - array( __CLASS__, 'plugin_settings_page' ) + array( __CLASS__, 'plugin_settings_page' ), + 7 ); add_action( 'load-' . $page_suffix, array( __CLASS__, 'admin_init' ) ); diff --git a/projects/packages/backup/src/class-package-version.php b/projects/packages/backup/src/class-package-version.php index 410577279c158..14e94858de066 100644 --- a/projects/packages/backup/src/class-package-version.php +++ b/projects/packages/backup/src/class-package-version.php @@ -16,7 +16,7 @@ */ class Package_Version { - const PACKAGE_VERSION = '3.4.3-alpha'; + const PACKAGE_VERSION = '3.4.5'; const PACKAGE_SLUG = 'backup'; diff --git a/projects/packages/backup/src/js/components/Admin/header.js b/projects/packages/backup/src/js/components/Admin/header.js index 0397808ca8208..9a4db84b3b1cd 100644 --- a/projects/packages/backup/src/js/components/Admin/header.js +++ b/projects/packages/backup/src/js/components/Admin/header.js @@ -30,7 +30,7 @@ const Header = () => { }; const useShowActivateLicenseLink = () => { - const [ connectionStatus ] = useConnection(); + const connectionStatus = useConnection(); const isFullyConnected = useIsFullyConnected(); const { capabilitiesLoaded, hasBackupPlan } = useCapabilities(); diff --git a/projects/packages/backup/src/js/components/Admin/hooks.js b/projects/packages/backup/src/js/components/Admin/hooks.js index 74c4a97af7d5d..89515253952f8 100644 --- a/projects/packages/backup/src/js/components/Admin/hooks.js +++ b/projects/packages/backup/src/js/components/Admin/hooks.js @@ -3,7 +3,7 @@ import { useEffect, useMemo, useState } from '@wordpress/element'; import useConnection from '../../hooks/useConnection'; export const useIsFullyConnected = () => { - const [ connectionStatus ] = useConnection(); + const connectionStatus = useConnection(); return useMemo( () => { const connectionLoaded = 0 < Object.keys( connectionStatus ).length; @@ -13,7 +13,7 @@ export const useIsFullyConnected = () => { export const useIsSecondaryAdminNotConnected = () => { const isFullyConnected = useIsFullyConnected(); - const [ connectionStatus ] = useConnection(); + const connectionStatus = useConnection(); return useMemo( () => { return isFullyConnected && ! connectionStatus.isUserConnected; diff --git a/projects/packages/backup/src/js/components/Admin/index.js b/projects/packages/backup/src/js/components/Admin/index.js index 4a1e694cb34e8..c05e00ab609f6 100644 --- a/projects/packages/backup/src/js/components/Admin/index.js +++ b/projects/packages/backup/src/js/components/Admin/index.js @@ -17,6 +17,8 @@ import useBackupsState from '../../hooks/useBackupsState'; import useCapabilities from '../../hooks/useCapabilities'; import useConnection from '../../hooks/useConnection'; import { Backups, Loading as BackupsLoadingPlaceholder } from '../Backups'; +import { BackupConnectionScreen } from '../backup-connection-screen'; +import { BackupSecondaryAdminConnectionScreen } from '../backup-connection-screen/secondary-admin'; import BackupStorageSpace from '../backup-storage-space'; import ReviewRequest from '../review-request'; import Header from './header'; @@ -31,7 +33,7 @@ import '../masthead/masthead-style.scss'; /* eslint react/react-in-jsx-scope: 0 */ const Admin = () => { - const [ connectionStatus, , BackupSecondaryAdminConnectionScreen ] = useConnection(); + const connectionStatus = useConnection(); const { tracks } = useAnalytics(); const { hasConnectionError } = useConnectionErrorNotice(); const connectionLoaded = 0 < Object.keys( connectionStatus ).length; @@ -119,7 +121,7 @@ const Admin = () => { // Render additional segments for the backup admin page under the jp-hero section. // If the user has a backup plan and is connected, we render the storage space segment. const BackupSegments = ( { hasBackupPlan, connectionLoaded } ) => { - const [ connectionStatus ] = useConnection(); + const connectionStatus = useConnection(); const { tracks } = useAnalytics(); const trackLearnMoreClick = useCallback( () => { @@ -337,8 +339,6 @@ const LoadedState = ( { capabilities, isFullyConnected, } ) => { - const [ , BackupConnectionScreen ] = useConnection(); - if ( ! isFullyConnected ) { return ( diff --git a/projects/packages/backup/src/js/components/back-up-now/hooks.js b/projects/packages/backup/src/js/components/back-up-now/hooks.js index a5cdb768f2f0d..7d44c382197ae 100644 --- a/projects/packages/backup/src/js/components/back-up-now/hooks.js +++ b/projects/packages/backup/src/js/components/back-up-now/hooks.js @@ -4,7 +4,7 @@ import useConnection from '../../hooks/useConnection'; import { useIsFullyConnected } from '../Admin/hooks'; export const useShowBackUpNow = () => { - const [ connectionStatus ] = useConnection(); + const connectionStatus = useConnection(); const isFullyConnected = useIsFullyConnected(); const { capabilitiesLoaded, hasBackupPlan } = useCapabilities(); diff --git a/projects/packages/backup/src/js/components/backup-connection-screen/assets/ben-giordano-testimonial.png b/projects/packages/backup/src/js/components/backup-connection-screen/assets/ben-giordano-testimonial.png new file mode 100644 index 0000000000000..ce8c8d0f1ed26 Binary files /dev/null and b/projects/packages/backup/src/js/components/backup-connection-screen/assets/ben-giordano-testimonial.png differ diff --git a/projects/packages/backup/src/js/components/backup-connection-screen/assets/connect-backup.png b/projects/packages/backup/src/js/components/backup-connection-screen/assets/connect-backup.png new file mode 100644 index 0000000000000..4787d6c77b0bd Binary files /dev/null and b/projects/packages/backup/src/js/components/backup-connection-screen/assets/connect-backup.png differ diff --git a/projects/packages/backup/src/js/components/backup-connection-screen/assets/tim-ferriss-testimonial.png b/projects/packages/backup/src/js/components/backup-connection-screen/assets/tim-ferriss-testimonial.png new file mode 100644 index 0000000000000..39f78d9684a46 Binary files /dev/null and b/projects/packages/backup/src/js/components/backup-connection-screen/assets/tim-ferriss-testimonial.png differ diff --git a/projects/packages/backup/src/js/components/backup-connection-screen/index.js b/projects/packages/backup/src/js/components/backup-connection-screen/index.js new file mode 100644 index 0000000000000..a8c7ab6babcc3 --- /dev/null +++ b/projects/packages/backup/src/js/components/backup-connection-screen/index.js @@ -0,0 +1,83 @@ +import { JetpackVaultPressBackupLogo, Testimonials } from '@automattic/jetpack-components'; +import { ConnectScreenRequiredPlan } from '@automattic/jetpack-connection'; +import apiFetch from '@wordpress/api-fetch'; +import { useSelect } from '@wordpress/data'; +import { useCallback } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import React from 'react'; +import { useBackupProductInfo } from '../../hooks/use-backup-product-info'; +import { STORE_ID } from '../../store'; +import BackupPromotionBlock from '../backup-promotion'; +import { BackupVideoSection } from '../backup-video-section'; +import { WhyINeedVPBackup } from '../why-i-need-vp-backup'; +import benGiordanoTestimonial from './assets/ben-giordano-testimonial.png'; +import timFerrissTestimonial from './assets/tim-ferriss-testimonial.png'; + +const testimonials = [ + { + quote: __( + 'Millions of people depend on my site, and downtime isn’t an option. Jetpack VaultPress Backup handles my site security and backups so I can focus on creation.', + 'jetpack-backup-pkg' + ), + author: 'Tim Ferriss', + profession: __( 'Author / Investor / Podcaster', 'jetpack-backup-pkg' ), + img: timFerrissTestimonial, + }, + { + quote: __( + 'Our developers use VaultPress Backup all the time. It’s a one‑click way to return to where we were before things got wonky. It gives us a little emergency parachute so if we’re working on a customization that breaks everything, we lose minutes, not hours.', + 'jetpack-backup-pkg' + ), + author: 'Ben Giordano', + profession: __( 'Founder, FreshySites.com', 'jetpack-backup-pkg' ), + + img: benGiordanoTestimonial, + }, +]; + +export const BackupConnectionScreen = () => { + const APINonce = useSelect( select => select( STORE_ID ).getAPINonce(), [] ); + const APIRoot = useSelect( select => select( STORE_ID ).getAPIRoot(), [] ); + const registrationNonce = useSelect( select => select( STORE_ID ).getRegistrationNonce(), [] ); + const { price, priceAfter } = useBackupProductInfo(); + + const checkSiteHasBackupProduct = useCallback( + () => apiFetch( { path: '/jetpack/v4/has-backup-plan' } ), + [] + ); + + return ( + <> + } + pricingTitle={ __( 'VaultPress Backup', 'jetpack-backup-pkg' ) } + title={ __( 'The best real-time WordPress backups', 'jetpack-backup-pkg' ) } + apiRoot={ APIRoot } + apiNonce={ APINonce } + registrationNonce={ registrationNonce } + from="jetpack-backup" + redirectUri="admin.php?page=jetpack-backup" + wpcomProductSlug="jetpack_backup_t1_yearly" + siteProductAvailabilityHandler={ checkSiteHasBackupProduct } + logo={ <> } + rna + > + + + + + + + + + + ); +}; diff --git a/projects/packages/backup/src/js/components/backup-connection-screen/secondary-admin.js b/projects/packages/backup/src/js/components/backup-connection-screen/secondary-admin.js new file mode 100644 index 0000000000000..a02b5c6be42d9 --- /dev/null +++ b/projects/packages/backup/src/js/components/backup-connection-screen/secondary-admin.js @@ -0,0 +1,32 @@ +import { JetpackVaultPressBackupLogo } from '@automattic/jetpack-components'; +import { ConnectScreen } from '@automattic/jetpack-connection'; +import { useSelect } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; +import React from 'react'; +import { STORE_ID } from '../../store'; +import connectImage from './assets/connect-backup.png'; + +export const BackupSecondaryAdminConnectionScreen = () => { + const APINonce = useSelect( select => select( STORE_ID ).getAPINonce(), [] ); + const APIRoot = useSelect( select => select( STORE_ID ).getAPIRoot(), [] ); + const registrationNonce = useSelect( select => select( STORE_ID ).getRegistrationNonce(), [] ); + + return ( + } + > +

+ It looks like your site already has a backup plan activated. All you need to do is log in + with your WordPress account. +

+
+ ); +}; diff --git a/projects/packages/backup/src/js/components/backup-promotion/index.jsx b/projects/packages/backup/src/js/components/backup-promotion/index.jsx index c20d6fc43cece..dbc38e72c3854 100644 --- a/projects/packages/backup/src/js/components/backup-promotion/index.jsx +++ b/projects/packages/backup/src/js/components/backup-promotion/index.jsx @@ -4,7 +4,7 @@ import React from 'react'; /** * BackupPromotion component definition. * - * @returns {React.Component} BackupPromotion component. + * @return {React.Component} BackupPromotion component. */ export default function BackupPromotion() { return ( diff --git a/projects/packages/backup/src/js/components/backup-storage-space/index.jsx b/projects/packages/backup/src/js/components/backup-storage-space/index.jsx index e7836332b1a07..c7f073e7af56d 100644 --- a/projects/packages/backup/src/js/components/backup-storage-space/index.jsx +++ b/projects/packages/backup/src/js/components/backup-storage-space/index.jsx @@ -9,7 +9,7 @@ import StorageUsageDetails from './storage-usage-details'; import { getUsageLevel, StorageUsageLevels } from './storage-usage-levels'; const BackupStorageSpace = () => { - const [ connectionStatus ] = useConnection(); + const connectionStatus = useConnection(); const isFetchingPolicies = useSelect( select => select( STORE_ID ).isFetchingBackupPolicies() ); const isFetchingSize = useSelect( select => select( STORE_ID ).isFetchingBackupSize() ); const hasBackupSizeLoaded = useSelect( select => select( STORE_ID ).hasBackupSizeLoaded() ); diff --git a/projects/packages/backup/src/js/components/backup-video-section/images/jetpack-backup-video-thumbnail.png b/projects/packages/backup/src/js/components/backup-video-section/images/jetpack-backup-video-thumbnail.png index 5491d784db63f..8c0c261498930 100644 Binary files a/projects/packages/backup/src/js/components/backup-video-section/images/jetpack-backup-video-thumbnail.png and b/projects/packages/backup/src/js/components/backup-video-section/images/jetpack-backup-video-thumbnail.png differ diff --git a/projects/packages/backup/src/js/hooks/assets/ben-giordano-testimonial.png b/projects/packages/backup/src/js/hooks/assets/ben-giordano-testimonial.png deleted file mode 100644 index c6e3794192004..0000000000000 Binary files a/projects/packages/backup/src/js/hooks/assets/ben-giordano-testimonial.png and /dev/null differ diff --git a/projects/packages/backup/src/js/hooks/assets/connect-backup.png b/projects/packages/backup/src/js/hooks/assets/connect-backup.png deleted file mode 100644 index 8713c5abac51b..0000000000000 Binary files a/projects/packages/backup/src/js/hooks/assets/connect-backup.png and /dev/null differ diff --git a/projects/packages/backup/src/js/hooks/assets/connect-right.png b/projects/packages/backup/src/js/hooks/assets/connect-right.png index 66f8710ac0634..4779757259f45 100644 Binary files a/projects/packages/backup/src/js/hooks/assets/connect-right.png and b/projects/packages/backup/src/js/hooks/assets/connect-right.png differ diff --git a/projects/packages/backup/src/js/hooks/assets/tim-ferriss-testimonial.png b/projects/packages/backup/src/js/hooks/assets/tim-ferriss-testimonial.png deleted file mode 100644 index 170f2c5fe5efc..0000000000000 Binary files a/projects/packages/backup/src/js/hooks/assets/tim-ferriss-testimonial.png and /dev/null differ diff --git a/projects/packages/backup/src/js/hooks/use-backup-product-info.js b/projects/packages/backup/src/js/hooks/use-backup-product-info.js new file mode 100644 index 0000000000000..2aebae719d793 --- /dev/null +++ b/projects/packages/backup/src/js/hooks/use-backup-product-info.js @@ -0,0 +1,29 @@ +import apiFetch from '@wordpress/api-fetch'; +import { useState, useEffect, useCallback } from '@wordpress/element'; + +/** + * Custom hook to fetch and manage backup product pricing information. + * + * @return {object} An object containing the current product price and the price after any introductory offer. + */ +export function useBackupProductInfo() { + const [ price, setPrice ] = useState( 0 ); + const [ priceAfter, setPriceAfter ] = useState( 0 ); + + const fetchBackupProductInfo = useCallback( () => { + return apiFetch( { path: '/jetpack/v4/backup-promoted-product-info' } ); + }, [] ); + + useEffect( () => { + fetchBackupProductInfo().then( res => { + setPrice( res.cost / 12 ); + if ( res.introductory_offer ) { + setPriceAfter( res.introductory_offer.cost_per_interval / 12 ); + } else { + setPriceAfter( res.cost / 12 ); + } + } ); + }, [ fetchBackupProductInfo ] ); + + return { price, priceAfter }; +} diff --git a/projects/packages/backup/src/js/hooks/useCapabilities.js b/projects/packages/backup/src/js/hooks/useCapabilities.js index 797b3bfcf29b8..9e1c6b6302f4c 100644 --- a/projects/packages/backup/src/js/hooks/useCapabilities.js +++ b/projects/packages/backup/src/js/hooks/useCapabilities.js @@ -5,13 +5,13 @@ import useConnection from './useConnection'; /** * Return information and loader of Backup functioality Capabilities * - * @returns {object} capabilities, capabilitiesError, capabilitiesLoaded, fetchCapabilities + * @return {object} capabilities, capabilitiesError, capabilitiesLoaded, fetchCapabilities */ export default function useCapabilities() { const [ capabilities, setCapabilities ] = useState( null ); const [ capabilitiesError, setCapabilitiesError ] = useState( null ); const [ capabilitiesLoaded, setCapabilitiesLoaded ] = useState( false ); - const [ connectionStatus ] = useConnection(); + const connectionStatus = useConnection(); useEffect( () => { const connectionLoaded = 0 < Object.keys( connectionStatus ).length; diff --git a/projects/packages/backup/src/js/hooks/useConnection.js b/projects/packages/backup/src/js/hooks/useConnection.js index 8edd192ac6018..05345c7c9b639 100644 --- a/projects/packages/backup/src/js/hooks/useConnection.js +++ b/projects/packages/backup/src/js/hooks/useConnection.js @@ -1,133 +1,16 @@ -import { JetpackVaultPressBackupLogo, Testimonials } from '@automattic/jetpack-components'; -import { - ConnectScreenRequiredPlan, - ConnectScreen, - CONNECTION_STORE_ID, -} from '@automattic/jetpack-connection'; -import apiFetch from '@wordpress/api-fetch'; +import { CONNECTION_STORE_ID } from '@automattic/jetpack-connection'; import { useSelect } from '@wordpress/data'; -import { useState, useEffect } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import React, { useCallback } from 'react'; -import BackupPromotionBlock from '../components/backup-promotion'; -import { BackupVideoSection } from '../components/backup-video-section'; -import { WhyINeedVPBackup } from '../components/why-i-need-vp-backup'; -import { STORE_ID } from '../store'; -import benGiordanoTestimonial from './assets/ben-giordano-testimonial.png'; -import connectImage from './assets/connect-backup.png'; -import timFerrissTestimonial from './assets/tim-ferriss-testimonial.png'; - -const testimonials = [ - { - quote: __( - 'Millions of people depend on my site, and downtime isn’t an option. Jetpack VaultPress Backup handles my site security and backups so I can focus on creation.', - 'jetpack-backup-pkg' - ), - author: 'Tim Ferriss', - profession: __( 'Author / Investor / Podcaster', 'jetpack-backup-pkg' ), - img: timFerrissTestimonial, - }, - { - quote: __( - 'Our developers use VaultPress Backup all the time. It’s a one‑click way to return to where we were before things got wonky. It gives us a little emergency parachute so if we’re working on a customization that breaks everything, we lose minutes, not hours.', - 'jetpack-backup-pkg' - ), - author: 'Ben Giordano', - profession: __( 'Founder, FreshySites.com', 'jetpack-backup-pkg' ), - - img: benGiordanoTestimonial, - }, -]; /** - * Expose the `connectionStatus` state object and `BackupConnectionScreen` to show a component used for connection. + * Expose the `connectionStatus` state object from the Jetpack connection store. * - * @returns {Array} connectionStatus, BackupConnectionScreen + * @return {object} connectionStatus The connection status object. */ export default function useConnection() { - const APINonce = useSelect( select => select( STORE_ID ).getAPINonce(), [] ); - const APIRoot = useSelect( select => select( STORE_ID ).getAPIRoot(), [] ); - const registrationNonce = useSelect( select => select( STORE_ID ).getRegistrationNonce(), [] ); const connectionStatus = useSelect( select => select( CONNECTION_STORE_ID ).getConnectionStatus(), [] ); - const [ price, setPrice ] = useState( 0 ); - const [ priceAfter, setPriceAfter ] = useState( 0 ); - - const checkSiteHasBackupProduct = useCallback( - () => apiFetch( { path: '/jetpack/v4/has-backup-plan' } ), - [] - ); - - useEffect( () => { - apiFetch( { path: '/jetpack/v4/backup-promoted-product-info' } ).then( res => { - setPrice( res.cost / 12 ); - if ( res.introductory_offer ) { - setPriceAfter( res.introductory_offer.cost_per_interval / 12 ); - } else { - setPriceAfter( res.cost / 12 ); - } - } ); - }, [] ); - - const BackupConnectionScreen = () => { - return ( - <> - } - pricingTitle={ __( 'VaultPress Backup', 'jetpack-backup-pkg' ) } - title={ __( 'The best real-time WordPress backups', 'jetpack-backup-pkg' ) } - apiRoot={ APIRoot } - apiNonce={ APINonce } - registrationNonce={ registrationNonce } - from="jetpack-backup" - redirectUri="admin.php?page=jetpack-backup" - wpcomProductSlug="jetpack_backup_t1_yearly" - siteProductAvailabilityHandler={ checkSiteHasBackupProduct } - logo={ <> } - rna - > - - - - - - - - - - ); - }; - - const BackupSecondaryAdminConnectionScreen = () => { - return ( - } - > -

- It looks like your site already has a backup plan activated. All you need to do is log in - with your WordPress account. -

-
- ); - }; - return [ connectionStatus, BackupConnectionScreen, BackupSecondaryAdminConnectionScreen ]; + return connectionStatus; } diff --git a/projects/packages/blaze/CHANGELOG.md b/projects/packages/blaze/CHANGELOG.md index c9e3c3a4fd953..5b5f7bd2bf69a 100644 --- a/projects/packages/blaze/CHANGELOG.md +++ b/projects/packages/blaze/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.22.7] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + +## [0.22.6] - 2024-08-21 +### Changed +- Internal updates. + +## [0.22.5] - 2024-08-19 +### Changed +- Updated package dependencies. [#38662] + ## [0.22.4] - 2024-08-12 ### Changed - Allows request to the v1.1 endpoints of Blaze campaigns [#38771] @@ -420,6 +432,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Updated package dependencies. [#27906] +[0.22.7]: https://github.com/automattic/jetpack-blaze/compare/v0.22.6...v0.22.7 +[0.22.6]: https://github.com/automattic/jetpack-blaze/compare/v0.22.5...v0.22.6 +[0.22.5]: https://github.com/automattic/jetpack-blaze/compare/v0.22.4...v0.22.5 [0.22.4]: https://github.com/automattic/jetpack-blaze/compare/v0.22.3...v0.22.4 [0.22.3]: https://github.com/automattic/jetpack-blaze/compare/v0.22.2...v0.22.3 [0.22.2]: https://github.com/automattic/jetpack-blaze/compare/v0.22.1...v0.22.2 diff --git a/projects/packages/backup/changelog/renovate-wordpress-monorepo b/projects/packages/blaze/changelog/renovate-npm-webpack-vulnerability similarity index 100% rename from projects/packages/backup/changelog/renovate-wordpress-monorepo rename to projects/packages/blaze/changelog/renovate-npm-webpack-vulnerability diff --git a/projects/packages/blaze/composer.json b/projects/packages/blaze/composer.json index 7701f03b155e4..3425feb962db5 100644 --- a/projects/packages/blaze/composer.json +++ b/projects/packages/blaze/composer.json @@ -14,7 +14,7 @@ "automattic/jetpack-sync": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev" }, diff --git a/projects/packages/blaze/package.json b/projects/packages/blaze/package.json index cf88e4dce3ca5..88518163d68ed 100644 --- a/projects/packages/blaze/package.json +++ b/projects/packages/blaze/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-blaze", - "version": "0.22.5-alpha", + "version": "0.22.7", "description": "Attract high-quality traffic to your site using Blaze. Using this service, you can advertise a post or page on some of the millions of pages across WordPress.com and Tumblr from just $5 per day.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/blaze/#readme", "bugs": { @@ -44,7 +44,7 @@ "@wordpress/browserslist-config": "6.5.0", "sass": "1.64.1", "sass-loader": "12.4.0", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "browserslist": [ diff --git a/projects/packages/blaze/src/class-dashboard.php b/projects/packages/blaze/src/class-dashboard.php index 91b3e8485a7c9..980d526ba2aa7 100644 --- a/projects/packages/blaze/src/class-dashboard.php +++ b/projects/packages/blaze/src/class-dashboard.php @@ -21,7 +21,7 @@ class Dashboard { * * @var string */ - const PACKAGE_VERSION = '0.22.5-alpha'; + const PACKAGE_VERSION = '0.22.7'; /** * List of dependencies needed to render the dashboard in wp-admin. diff --git a/projects/packages/blaze/src/js/icon.js b/projects/packages/blaze/src/js/icon.js index 060019cff96ea..fb2f4cb5dd0c6 100644 --- a/projects/packages/blaze/src/js/icon.js +++ b/projects/packages/blaze/src/js/icon.js @@ -3,7 +3,7 @@ import { SVG, Path, G } from '@wordpress/components'; /** * Blaze Fire Icon. * - * @returns {Element} Icon component. + * @return {Element} Icon component. */ export default function BlazeIcon() { return ( diff --git a/projects/packages/blocks/CHANGELOG.md b/projects/packages/blocks/CHANGELOG.md index a99ea32e92bd5..c20f102fe9bc7 100644 --- a/projects/packages/blocks/CHANGELOG.md +++ b/projects/packages/blocks/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.5] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## [2.0.4] - 2024-05-20 ### Changed - Internal updates. @@ -186,6 +190,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Blocks: introduce new package for block management +[2.0.5]: https://github.com/Automattic/jetpack-blocks/compare/v2.0.4...v2.0.5 [2.0.4]: https://github.com/Automattic/jetpack-blocks/compare/v2.0.3...v2.0.4 [2.0.3]: https://github.com/Automattic/jetpack-blocks/compare/v2.0.2...v2.0.3 [2.0.2]: https://github.com/Automattic/jetpack-blocks/compare/v2.0.1...v2.0.2 diff --git a/projects/packages/blocks/composer.json b/projects/packages/blocks/composer.json index bedbda588d8d2..f3855aa843aee 100644 --- a/projects/packages/blocks/composer.json +++ b/projects/packages/blocks/composer.json @@ -10,7 +10,7 @@ "require-dev": { "automattic/wordbless": "dev-master", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "suggest": { diff --git a/projects/packages/boost-core/CHANGELOG.md b/projects/packages/boost-core/CHANGELOG.md index 9e55f68e88956..ac48344245994 100644 --- a/projects/packages/boost-core/CHANGELOG.md +++ b/projects/packages/boost-core/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.9] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + ## [0.2.8] - 2024-08-15 ### Fixed - Fix incorrect next-version tokens in php `@since` and/or `@deprecated` docs. [#38869] @@ -61,6 +65,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Introduce new package. [#31163] +[0.2.9]: https://github.com/Automattic/jetpack-boost-core/compare/v0.2.8...v0.2.9 [0.2.8]: https://github.com/Automattic/jetpack-boost-core/compare/v0.2.7...v0.2.8 [0.2.7]: https://github.com/Automattic/jetpack-boost-core/compare/v0.2.6...v0.2.7 [0.2.6]: https://github.com/Automattic/jetpack-boost-core/compare/v0.2.5...v0.2.6 diff --git a/projects/packages/boost-core/composer.json b/projects/packages/boost-core/composer.json index a58854c088751..01e1e32fb174e 100644 --- a/projects/packages/boost-core/composer.json +++ b/projects/packages/boost-core/composer.json @@ -8,7 +8,7 @@ "automattic/jetpack-connection": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master" }, diff --git a/projects/packages/boost-core/package.json b/projects/packages/boost-core/package.json index e923215be7dbb..7941e894ee8a3 100644 --- a/projects/packages/boost-core/package.json +++ b/projects/packages/boost-core/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-boost-core", - "version": "0.2.8", + "version": "0.2.9", "description": "Core functionality for boost and relevant packages to depend on", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/boost-core/#readme", "bugs": { diff --git a/projects/packages/boost-speed-score/CHANGELOG.md b/projects/packages/boost-speed-score/CHANGELOG.md index 3ea1de4b29370..dea0fbb7e2ad0 100644 --- a/projects/packages/boost-speed-score/CHANGELOG.md +++ b/projects/packages/boost-speed-score/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.12] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + ## [0.3.11] - 2024-04-22 ### Changed - Internal updates. @@ -84,6 +88,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add a new package for Boost Speed Score [#30914] - Add a new argument to `Speed_Score` to identify where the request was made from (e.g. 'boost-plugin', 'jetpack-dashboard', etc). [#31012] +[0.3.12]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.3.11...v0.3.12 [0.3.11]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.3.10...v0.3.11 [0.3.10]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.3.9...v0.3.10 [0.3.9]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.3.8...v0.3.9 diff --git a/projects/packages/boost-speed-score/composer.json b/projects/packages/boost-speed-score/composer.json index ec661caeeb671..a8faac31ad742 100644 --- a/projects/packages/boost-speed-score/composer.json +++ b/projects/packages/boost-speed-score/composer.json @@ -4,7 +4,7 @@ "type": "jetpack-library", "license": "GPL-2.0-or-later", "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "brain/monkey": "^2.6" }, diff --git a/projects/packages/boost-speed-score/src/class-speed-score.php b/projects/packages/boost-speed-score/src/class-speed-score.php index dae109cee8ebf..c229785a2c3d4 100644 --- a/projects/packages/boost-speed-score/src/class-speed-score.php +++ b/projects/packages/boost-speed-score/src/class-speed-score.php @@ -23,7 +23,7 @@ */ class Speed_Score { - const PACKAGE_VERSION = '0.3.11'; + const PACKAGE_VERSION = '0.3.12'; /** * Array of module slugs that are currently active and can impact speed score. diff --git a/projects/packages/calypsoify/CHANGELOG.md b/projects/packages/calypsoify/CHANGELOG.md index 069ec60176425..b5f89150e726f 100644 --- a/projects/packages/calypsoify/CHANGELOG.md +++ b/projects/packages/calypsoify/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.4] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + +## [0.1.3] - 2024-08-19 +### Changed +- Updated package dependencies. [#38662] + ## [0.1.2] - 2024-07-08 ### Changed - Updated package dependencies. [#38132] @@ -25,5 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Calypsoify: Load feature from the Calypsoify package. [#37375] - Updated package dependencies. [#37379] +[0.1.4]: https://github.com/Automattic/jetpack-calypsoify/compare/v0.1.3...v0.1.4 +[0.1.3]: https://github.com/Automattic/jetpack-calypsoify/compare/v0.1.2...v0.1.3 [0.1.2]: https://github.com/Automattic/jetpack-calypsoify/compare/v0.1.1...v0.1.2 [0.1.1]: https://github.com/Automattic/jetpack-calypsoify/compare/v0.1.0...v0.1.1 diff --git a/projects/packages/blaze/changelog/renovate-wordpress-monorepo b/projects/packages/calypsoify/changelog/renovate-npm-webpack-vulnerability similarity index 100% rename from projects/packages/blaze/changelog/renovate-wordpress-monorepo rename to projects/packages/calypsoify/changelog/renovate-npm-webpack-vulnerability diff --git a/projects/packages/calypsoify/composer.json b/projects/packages/calypsoify/composer.json index 30912133997de..7c9a514cfb6ec 100644 --- a/projects/packages/calypsoify/composer.json +++ b/projects/packages/calypsoify/composer.json @@ -9,7 +9,7 @@ "automattic/jetpack-status": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "autoload": { diff --git a/projects/packages/calypsoify/package.json b/projects/packages/calypsoify/package.json index cba642c781199..162bb378d404f 100644 --- a/projects/packages/calypsoify/package.json +++ b/projects/packages/calypsoify/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-calypsoify", - "version": "0.1.3-alpha", + "version": "0.1.4", "description": "Calypsoify is designed to make sure specific wp-admin pages include navigation that prioritizes the Calypso navigation experience.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/calypsoify/#readme", "bugs": { @@ -32,7 +32,7 @@ "core-js": "3.23.5", "sass": "1.64.1", "sass-loader": "12.4.0", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" } } diff --git a/projects/packages/calypsoify/src/class-jetpack-calypsoify.php b/projects/packages/calypsoify/src/class-jetpack-calypsoify.php index 5387a07419d89..6c66a2ec5649c 100644 --- a/projects/packages/calypsoify/src/class-jetpack-calypsoify.php +++ b/projects/packages/calypsoify/src/class-jetpack-calypsoify.php @@ -15,7 +15,7 @@ */ class Jetpack_Calypsoify { - const PACKAGE_VERSION = '0.1.3-alpha'; + const PACKAGE_VERSION = '0.1.4'; /** * Singleton instance of `Jetpack_Calypsoify`. diff --git a/projects/packages/changelogger/CHANGELOG.md b/projects/packages/changelogger/CHANGELOG.md index 79f91ff317bf5..8fada1afe9231 100644 --- a/projects/packages/changelogger/CHANGELOG.md +++ b/projects/packages/changelogger/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [4.2.6] - 2024-08-22 +### Changed +- Updated package dependencies. [#39004] + ## [4.2.5] - 2024-06-27 ### Changed - Skip querying `git` in `changelogger version` command. We don't need the timestamp or PR number for that operation. [#38074] @@ -240,6 +244,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Added - Initial version. +[4.2.6]: https://github.com/Automattic/jetpack-changelogger/compare/4.2.5...4.2.6 [4.2.5]: https://github.com/Automattic/jetpack-changelogger/compare/4.2.4...4.2.5 [4.2.4]: https://github.com/Automattic/jetpack-changelogger/compare/4.2.3...4.2.4 [4.2.3]: https://github.com/Automattic/jetpack-changelogger/compare/4.2.2...4.2.3 diff --git a/projects/packages/changelogger/composer.json b/projects/packages/changelogger/composer.json index c954a546291d2..60b48784d76e9 100644 --- a/projects/packages/changelogger/composer.json +++ b/projects/packages/changelogger/composer.json @@ -15,7 +15,7 @@ "symfony/process": "^3.4 || ^4.4 || ^5.2 || ^6.0 || ^7.0" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0" }, "autoload": { diff --git a/projects/packages/changelogger/src/Application.php b/projects/packages/changelogger/src/Application.php index 31423ae20a727..d70b65acc2f0b 100644 --- a/projects/packages/changelogger/src/Application.php +++ b/projects/packages/changelogger/src/Application.php @@ -19,7 +19,7 @@ */ class Application extends SymfonyApplication { - const VERSION = '4.2.5'; + const VERSION = '4.2.6'; /** * Constructor. diff --git a/projects/packages/calypsoify/changelog/renovate-wordpress-monorepo b/projects/packages/chatbot/changelog/renovate-yoast-phpunit-polyfills-1.x#2 similarity index 100% rename from projects/packages/calypsoify/changelog/renovate-wordpress-monorepo rename to projects/packages/chatbot/changelog/renovate-yoast-phpunit-polyfills-1.x#2 diff --git a/projects/packages/chatbot/composer.json b/projects/packages/chatbot/composer.json index 3eb7a5e0e654d..064222eefdb78 100644 --- a/projects/packages/chatbot/composer.json +++ b/projects/packages/chatbot/composer.json @@ -7,7 +7,7 @@ "php": ">=7.0" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master" }, diff --git a/projects/packages/classic-theme-helper/.phan/baseline.php b/projects/packages/classic-theme-helper/.phan/baseline.php index 8b19e8c51bca0..aede0f74752cc 100644 --- a/projects/packages/classic-theme-helper/.phan/baseline.php +++ b/projects/packages/classic-theme-helper/.phan/baseline.php @@ -10,6 +10,7 @@ return [ // # Issue statistics: // PhanTypeMismatchArgumentInternal : 10+ occurrences + // PhanTypePossiblyInvalidDimOffset : 8 occurrences // PhanUndeclaredClassMethod : 7 occurrences // PhanUndeclaredClassReference : 4 occurrences // PhanTypeInvalidDimOffset : 2 occurrences @@ -17,7 +18,6 @@ // PhanTypeComparisonToArray : 1 occurrence // PhanTypeMismatchArgumentProbablyReal : 1 occurrence // PhanTypeMismatchProperty : 1 occurrence - // PhanTypePossiblyInvalidDimOffset : 1 occurrence // PhanUndeclaredTypeProperty : 1 occurrence // Currently, file_suppressions and directory_suppressions are the only supported suppressions @@ -25,6 +25,7 @@ '_inc/lib/tonesque.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentInternal', 'PhanTypeMismatchArgumentProbablyReal'], 'src/class-featured-content.php' => ['PhanTypeComparisonToArray', 'PhanTypeInvalidDimOffset', 'PhanTypeMismatchArgument', 'PhanTypeMismatchProperty', 'PhanTypePossiblyInvalidDimOffset'], 'src/class-social-links.php' => ['PhanUndeclaredClassMethod', 'PhanUndeclaredClassReference', 'PhanUndeclaredTypeProperty'], + 'src/content-options/featured-images-fallback.php' => ['PhanTypePossiblyInvalidDimOffset'], ], // 'directory_suppressions' => ['src/directory_name' => ['PhanIssueName1', 'PhanIssueName2']] can be manually added if needed. // (directory_suppressions will currently be ignored by subsequent calls to --save-baseline, but may be preserved in future Phan releases) diff --git a/projects/packages/classic-theme-helper/CHANGELOG.md b/projects/packages/classic-theme-helper/CHANGELOG.md index 27a12a88cce67..b17d88e20ff0e 100644 --- a/projects/packages/classic-theme-helper/CHANGELOG.md +++ b/projects/packages/classic-theme-helper/CHANGELOG.md @@ -5,6 +5,30 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.5.3] - 2024-08-26 +### Changed +- Site Breadcrumbs: Requiring the feature from the Classic Theme Helper package [#38931] + +## [0.5.2] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + +## [0.5.1] - 2024-08-21 +### Fixed +- Revert recent SVG image optimizations. [#38981] +- Social Menus: fix SVG format. [#38966] + +## [0.5.0] - 2024-08-19 +### Added +- Site Breadcrumbs: Copying functionality file into Classic Theme Helper package. [#38880] +- Social Links: Requiring feature from Classic Theme Helper package instead of Jetpack module. [#38730] + +### Changed +- Updated package dependencies. [#38662] + +### Fixed +- Lossless image optimization for images (should improve performance with no visible changes). [#38750] + ## [0.4.5] - 2024-08-12 ### Changed - Social Links: Modified package file - new functions, modified function types, added imports [#38738] @@ -62,6 +86,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Add wordpress folder on gitignore. [#37177] +[0.5.3]: https://github.com/Automattic/jetpack-classic-theme-helper/compare/v0.5.2...v0.5.3 +[0.5.2]: https://github.com/Automattic/jetpack-classic-theme-helper/compare/v0.5.1...v0.5.2 +[0.5.1]: https://github.com/Automattic/jetpack-classic-theme-helper/compare/v0.5.0...v0.5.1 +[0.5.0]: https://github.com/Automattic/jetpack-classic-theme-helper/compare/v0.4.5...v0.5.0 [0.4.5]: https://github.com/Automattic/jetpack-classic-theme-helper/compare/v0.4.4...v0.4.5 [0.4.4]: https://github.com/Automattic/jetpack-classic-theme-helper/compare/v0.4.3...v0.4.4 [0.4.3]: https://github.com/Automattic/jetpack-classic-theme-helper/compare/v0.4.2...v0.4.3 diff --git a/projects/packages/classic-theme-helper/changelog/add-content-options-to-classic-theme-helper-package b/projects/packages/classic-theme-helper/changelog/add-content-options-to-classic-theme-helper-package new file mode 100644 index 0000000000000..b1e4bf94b9776 --- /dev/null +++ b/projects/packages/classic-theme-helper/changelog/add-content-options-to-classic-theme-helper-package @@ -0,0 +1,4 @@ +Significance: patch +Type: added + +Content Options: Moving content to Classic Theme Helper package. diff --git a/projects/packages/classic-theme-helper/changelog/add-require-social-links-classic-theme-helper-package b/projects/packages/classic-theme-helper/changelog/add-require-social-links-classic-theme-helper-package deleted file mode 100644 index 99c5a34195c63..0000000000000 --- a/projects/packages/classic-theme-helper/changelog/add-require-social-links-classic-theme-helper-package +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: added - -Social Links: Requiring feature from Classic Theme Helper package instead of Jetpack module. diff --git a/projects/packages/classic-theme-helper/changelog/add-site-breadcrumbs-to-classic-theme-helper-package b/projects/packages/classic-theme-helper/changelog/add-site-breadcrumbs-to-classic-theme-helper-package deleted file mode 100644 index 8155da111b36f..0000000000000 --- a/projects/packages/classic-theme-helper/changelog/add-site-breadcrumbs-to-classic-theme-helper-package +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: added - -Site Breadcrumbs: Copying functionality file into Classic Theme Helper package. diff --git a/projects/packages/classic-theme-helper/changelog/renovate-lock-file-maintenance b/projects/packages/classic-theme-helper/changelog/renovate-lock-file-maintenance deleted file mode 100644 index 3109d07526368..0000000000000 --- a/projects/packages/classic-theme-helper/changelog/renovate-lock-file-maintenance +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: changed -Comment: Update Phan baseline. - - diff --git a/projects/packages/classic-theme-helper/changelog/renovate-wordpress-monorepo b/projects/packages/classic-theme-helper/changelog/renovate-npm-webpack-vulnerability similarity index 100% rename from projects/packages/classic-theme-helper/changelog/renovate-wordpress-monorepo rename to projects/packages/classic-theme-helper/changelog/renovate-npm-webpack-vulnerability diff --git a/projects/packages/classic-theme-helper/composer.json b/projects/packages/classic-theme-helper/composer.json index 31d9c1b14547c..dae4cae42f208 100644 --- a/projects/packages/classic-theme-helper/composer.json +++ b/projects/packages/classic-theme-helper/composer.json @@ -8,7 +8,7 @@ "automattic/jetpack-assets": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master" }, diff --git a/projects/packages/classic-theme-helper/package.json b/projects/packages/classic-theme-helper/package.json index 216b638804f64..542f68af2ec9a 100644 --- a/projects/packages/classic-theme-helper/package.json +++ b/projects/packages/classic-theme-helper/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-classic-theme-helper", - "version": "0.5.0-alpha", + "version": "0.5.3", "description": "Features used with classic themes", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/classic-theme-helper/#readme", "bugs": { @@ -37,7 +37,7 @@ "postcss-loader": "6.2.0", "sass": "1.64.1", "sass-loader": "12.4.0", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" } } diff --git a/projects/packages/classic-theme-helper/src/class-main.php b/projects/packages/classic-theme-helper/src/class-main.php index 1ffdf94a4279c..227747fc7eaa0 100644 --- a/projects/packages/classic-theme-helper/src/class-main.php +++ b/projects/packages/classic-theme-helper/src/class-main.php @@ -14,7 +14,7 @@ */ class Main { - const PACKAGE_VERSION = '0.5.0-alpha'; + const PACKAGE_VERSION = '0.5.3'; /** * Modules to include. @@ -23,6 +23,7 @@ class Main { */ public $modules = array( 'responsive-videos.php', + 'site-breadcrumbs.php', 'social-menu.php', 'jetpack-color.php', ); diff --git a/projects/packages/classic-theme-helper/src/content-options.php b/projects/packages/classic-theme-helper/src/content-options.php new file mode 100644 index 0000000000000..8a14c3dc78912 --- /dev/null +++ b/projects/packages/classic-theme-helper/src/content-options.php @@ -0,0 +1,170 @@ + 'content', // the default setting of the theme: 'content', 'excerpt' or array( 'content', 'excerpt' ) for themes mixing both display. + 'author-bio' => true, // display or not the author bio: true or false. + 'author-bio-default' => false, // the default setting of the author bio, if it's being displayed or not: true or false (only required if false). + 'avatar-default' => true, // display or not the default avatar for the author bio: true or false. + 'masonry' => '.site-main', // a CSS selector matching the elements that triggers a masonry refresh if the theme is using a masonry layout. + 'post-details' => array( + 'stylesheet' => 'themeslug-style', // name of the theme's stylesheet. + 'date' => '.posted-on', // a CSS selector matching the elements that display the post date. + 'categories' => '.cat-links', // a CSS selector matching the elements that display the post categories. + 'tags' => '.tags-links', // a CSS selector matching the elements that display the post tags. + 'author' => '.byline', // a CSS selector matching the elements that display the post author. + 'comment' => '.comments-link', // a CSS selector matching the elements that display the comment link. + ), + 'featured-images' => array( + 'archive' => true, // enable or not the featured image check for archive pages: true or false. + 'archive-default' => false, // the default setting of the featured image on archive pages, if it's being displayed or not: true or false (only required if false). + 'post' => true, // enable or not the featured image check for single posts: true or false. + 'post-default' => false, // the default setting of the featured image on single posts, if it's being displayed or not: true or false (only required if false). + 'page' => true, // enable or not the featured image check for single pages: true or false. + 'page-default' => false, // the default setting of the featured image on single pages, if it's being displayed or not: true or false (only required if false). + 'portfolio' => true, // enable or not the featured image check for single projects: true or false. + 'portfolio-default' => false, // the default setting of the featured image on single projects, if it's being displayed or not: true or false (only required if false). + 'fallback' => true, // enable or not the featured image fallback: true or false. + 'fallback-default' => true, // the default setting for featured image fallbacks: true or false (only required if false) + ), + ) ); + */ + +if ( ! function_exists( 'jetpack_content_options_init' ) ) { + + /** + * Activate the Content Options plugin. + * + * @uses current_theme_supports() + */ + function jetpack_content_options_init() { + // If the theme doesn't support 'jetpack-content-options', don't continue. + if ( ! current_theme_supports( 'jetpack-content-options' ) ) { + return; + } + + // Load the Customizer options. + require __DIR__ . '/content-options/customizer.php'; + + // Load Blog Display function. + require __DIR__ . '/content-options/blog-display.php'; + + // Load Author Bio function. + require __DIR__ . '/content-options/author-bio.php'; + + // Load Post Details function. + require __DIR__ . '/content-options/post-details.php'; + + // Load Featured Images function. + if ( jetpack_featured_images_should_load() ) { + require __DIR__ . '/content-options/featured-images.php'; + } + + // Load Featured Images Fallback function. + if ( jetpack_featured_images_fallback_should_load() ) { + require __DIR__ . '/content-options/featured-images-fallback.php'; + } + } + add_action( 'init', 'jetpack_content_options_init' ); + +} + +if ( ! function_exists( 'jetpack_featured_images_get_settings' ) ) { + + /** + * Get featured images settings using the jetpack-content-options theme support. + */ + function jetpack_featured_images_get_settings() { + $options = get_theme_support( 'jetpack-content-options' ); + + $featured_images = ( ! empty( $options[0]['featured-images'] ) ) ? $options[0]['featured-images'] : null; + + $settings = array( + 'archive' => ( ! empty( $featured_images['archive'] ) ) ? $featured_images['archive'] : null, + 'post' => ( ! empty( $featured_images['post'] ) ) ? $featured_images['post'] : null, + 'page' => ( ! empty( $featured_images['page'] ) ) ? $featured_images['page'] : null, + 'portfolio' => ( ! empty( $featured_images['portfolio'] ) ) ? $featured_images['portfolio'] : null, + 'archive-default' => ( isset( $featured_images['archive-default'] ) && false === $featured_images['archive-default'] ) ? '' : 1, + 'post-default' => ( isset( $featured_images['post-default'] ) && false === $featured_images['post-default'] ) ? '' : 1, + 'page-default' => ( isset( $featured_images['page-default'] ) && false === $featured_images['page-default'] ) ? '' : 1, + 'portfolio-default' => ( isset( $featured_images['portfolio-default'] ) && false === $featured_images['portfolio-default'] ) ? '' : 1, + 'fallback' => ( ! empty( $featured_images['fallback'] ) ) ? $featured_images['fallback'] : null, + 'fallback-default' => ( isset( $featured_images['fallback-default'] ) && false === $featured_images['fallback-default'] ) ? '' : 1, + ); + + $settings = array_merge( + $settings, + array( + 'archive-option' => get_option( 'jetpack_content_featured_images_archive', $settings['archive-default'] ), + 'post-option' => get_option( 'jetpack_content_featured_images_post', $settings['post-default'] ), + 'page-option' => get_option( 'jetpack_content_featured_images_page', $settings['page-default'] ), + 'portfolio-option' => get_option( 'jetpack_content_featured_images_portfolio', $settings['portfolio-default'] ), + 'fallback-option' => get_option( 'jetpack_content_featured_images_fallback', $settings['fallback-default'] ), + ) + ); + + return $settings; + } + +} + +if ( ! function_exists( 'jetpack_featured_images_should_load' ) ) { + + /** + * Determine if the Jetpack Featured Images should be load. + */ + function jetpack_featured_images_should_load() { + // If the theme doesn't support post thumbnails, don't continue. + if ( ! current_theme_supports( 'post-thumbnails' ) ) { + return false; + } + + $opts = jetpack_featured_images_get_settings(); + + // If the theme doesn't support archive, post and page or if all the options are ticked and we aren't in the customizer, don't continue. + if ( + ( true !== $opts['archive'] && true !== $opts['post'] && true !== $opts['page'] ) + || ( 1 === $opts['archive-option'] && 1 === $opts['post-option'] && 1 === $opts['page-option'] && ! is_customize_preview() ) + ) { + return false; + } + + return true; + } + +} + +if ( ! function_exists( 'jetpack_featured_images_fallback_should_load' ) ) { + + /** + * Determine if the Jetpack Featured Images fallback should load. + */ + function jetpack_featured_images_fallback_should_load() { + // If the theme doesn't support post thumbnails, don't continue. + if ( ! current_theme_supports( 'post-thumbnails' ) ) { + return false; + } + + $opts = jetpack_featured_images_get_settings(); + + // If the theme doesn't support fallback, don't continue. + if ( true !== $opts['fallback'] ) { + return false; + } + + return true; + } + +} diff --git a/projects/packages/classic-theme-helper/src/content-options/author-bio.php b/projects/packages/classic-theme-helper/src/content-options/author-bio.php new file mode 100644 index 0000000000000..93ab623ce0668 --- /dev/null +++ b/projects/packages/classic-theme-helper/src/content-options/author-bio.php @@ -0,0 +1,107 @@ + + + '404' ) ); + $headers = get_headers( $url ); + + // If 200 is found, the user has a Gravatar; otherwise, they don't. + return preg_match( '|200|', $headers[0] ) ? true : false; + } + +} diff --git a/projects/packages/classic-theme-helper/src/content-options/blog-display.php b/projects/packages/classic-theme-helper/src/content-options/blog-display.php new file mode 100644 index 0000000000000..7cfca8e5f2e41 --- /dev/null +++ b/projects/packages/classic-theme-helper/src/content-options/blog-display.php @@ -0,0 +1,302 @@ +post_excerpt ) ) { + $text = strip_shortcodes( $post->post_content ); + $text = str_replace( ']]>', ']]>', $text ); + $text = wp_strip_all_tags( $text ); + /** This filter is documented in wp-includes/formatting.php */ + $excerpt_length = apply_filters( 'excerpt_length', 55 ); + /** This filter is documented in wp-includes/formatting.php */ + $excerpt_more = apply_filters( 'excerpt_more', ' [...]' ); + + /* + * translators: If your word count is based on single characters (e.g. East Asian characters), + * enter 'characters_excluding_spaces' or 'characters_including_spaces'. Otherwise, enter 'words'. + * Do not translate into your own language. + */ + if ( strpos( _x( 'words', 'Word count type. Do not translate!', 'jetpack-classic-theme-helper' ), 'characters' ) === 0 && preg_match( '/^utf\-?8$/i', get_option( 'blog_charset' ) ) ) { + $text = trim( preg_replace( "/[\n\r\t ]+/", ' ', $text ), ' ' ); + preg_match_all( '/./u', $text, $words ); + $words = array_slice( $words[0], 0, $excerpt_length + 1 ); + $sep = ''; + } else { + $words = preg_split( "/[\n\r\t ]+/", $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY ); + $sep = ' '; + } + + if ( count( $words ) > $excerpt_length ) { + array_pop( $words ); + $text = implode( $sep, $words ); + $text .= $excerpt_more; + } else { + $text = implode( $sep, $words ); + } + } else { + $text = wp_kses_post( $post->post_excerpt ); + } + return sprintf( '

%s

', $text ); + } + +} + +if ( ! function_exists( 'jetpack_the_content_to_the_excerptt' ) ) { + + /** + * Display Excerpt instead of Content. + * + * @param string $content Post content. + */ + function jetpack_the_content_to_the_excerpt( $content ) { + if ( ( is_home() || is_archive() ) && ! is_post_type_archive( array( 'jetpack-testimonial', 'jetpack-portfolio', 'product' ) ) ) { + if ( post_password_required() ) { + $excerpt = sprintf( '

%s

', esc_html__( 'There is no excerpt because this is a protected post.', 'jetpack-classic-theme-helper' ) ); + } else { + $excerpt = jetpack_blog_display_custom_excerpt(); + } + } + if ( empty( $excerpt ) ) { + return $content; + } else { + return $excerpt; + } + } + +} + +if ( ! function_exists( 'jetpack_the_excerpt_to_the_content' ) ) { + + /** + * Display Content instead of Excerpt. + * + * @param string $content The post excerpt. + */ + function jetpack_the_excerpt_to_the_content( $content ) { + if ( ( is_home() || is_archive() ) && ! is_post_type_archive( array( 'jetpack-testimonial', 'jetpack-portfolio', 'product' ) ) ) { + ob_start(); + the_content( + sprintf( + wp_kses( + /* translators: %s: Name of current post. Only visible to screen readers */ + __( 'Continue reading "%s"', 'jetpack-classic-theme-helper' ), + array( + 'span' => array( + 'class' => array(), + ), + ) + ), + get_the_title() + ) + ); + $content = ob_get_clean(); + } + return $content; + } + +} + +if ( ! function_exists( 'jetpack_the_content_customizer' ) ) { + + /** + * Display both Content and Excerpt instead of Content in the Customizer so live preview can switch between them. + * + * @param string $content The post content. + */ + function jetpack_the_content_customizer( $content ) { + $class = jetpack_the_content_customizer_class(); + if ( ( is_home() || is_archive() ) && ! is_post_type_archive( array( 'jetpack-testimonial', 'jetpack-portfolio', 'product' ) ) ) { + if ( post_password_required() ) { + $excerpt = sprintf( '

%s

', esc_html__( 'There is no excerpt because this is a protected post.', 'jetpack-classic-theme-helper' ) ); + } else { + $excerpt = jetpack_blog_display_custom_excerpt(); + } + } + if ( empty( $excerpt ) ) { + return $content; + } else { + return sprintf( '
%s
%s
', $class, $content, $class, $excerpt ); + } + } + +} + +if ( ! function_exists( 'jetpack_the_excerpt_customizer' ) ) { + + /** + * Display both Content and Excerpt instead of Excerpt in the Customizer so live preview can switch between them. + * + * @param string $excerpt The post excerpt. + */ + function jetpack_the_excerpt_customizer( $excerpt ) { + if ( ( is_home() || is_archive() ) && ! is_post_type_archive( array( 'jetpack-testimonial', 'jetpack-portfolio', 'product' ) ) ) { + ob_start(); + the_content( + sprintf( + wp_kses( + /* translators: %s: Name of current post. Only visible to screen readers */ + __( 'Continue reading "%s"', 'jetpack-classic-theme-helper' ), + array( + 'span' => array( + 'class' => array(), + ), + ) + ), + get_the_title() + ) + ); + $content = ob_get_clean(); + } + if ( empty( $content ) ) { + return $excerpt; + } else { + return sprintf( '
%s
%s
', $content, $excerpt ); + } + } + +} + +if ( ! function_exists( 'jetpack_the_excerpt_mixed_customizer' ) ) { + + /** + * Display Content instead of Excerpt in the Customizer when theme uses a 'Mixed' display. + * + * @param string $content The post excerpt. + */ + function jetpack_the_excerpt_mixed_customizer( $content ) { + if ( ( is_home() || is_archive() ) && ! is_post_type_archive( array( 'jetpack-testimonial', 'jetpack-portfolio', 'product' ) ) ) { + jetpack_the_content_customizer_class( 'output-the-excerpt' ); + ob_start(); + the_content(); + $content = ob_get_clean(); + } + return $content; + } + +} + +if ( ! function_exists( 'jetpack_the_content_customizer_class' ) ) { + + /** + * Returns a class value, `output-the-content` by default. + * Used for themes with a 'Mixed' Blog Display so we can tell which output is by default. + * + * @param string|null $new_class CSS class added to content container. + */ + function jetpack_the_content_customizer_class( $new_class = null ) { + static $class; + if ( isset( $new_class ) ) { + // Assign a new class and return. + $class = $new_class; + } elseif ( isset( $class ) ) { + // Reset the class after getting value. + $prev_class = $class; + $class = null; + return $prev_class; + } else { + // Return default class value. + return 'output-the-content'; + } + } + +} + +if ( is_customize_preview() ) { + /* + * Display Content and Excerpt if the default Blog Display is 'Content' + * and we are in the Customizer. + */ + if ( 'content' === $blog_display ) { + add_filter( 'the_content', 'jetpack_the_content_customizer' ); + } + + /* + * Display Content and Excerpt if the default Blog Display is 'Excerpt' + * and we are in the Customizer. + */ + if ( 'excerpt' === $blog_display ) { + add_filter( 'the_excerpt', 'jetpack_the_excerpt_customizer' ); + } + + /* + * Display Content and Excerpt if the default Blog Display is 'Mixed' + * and we are in the Customizer. + */ + if ( 'mixed' === $blog_display ) { + add_filter( 'the_content', 'jetpack_the_content_customizer' ); + add_filter( 'the_excerpt', 'jetpack_the_excerpt_mixed_customizer' ); + } +} else { + $display_option = get_option( 'jetpack_content_blog_display', $blog_display ); + + /* + * Display Excerpt if the default Blog Display is 'Content' + * or default Blog Display is 'Mixed' + * and the Option picked is 'Post Excerpt' + * and we aren't in the Customizer. + */ + if ( ( 'content' === $blog_display || 'mixed' === $blog_display ) && 'excerpt' === $display_option ) { + add_filter( 'the_content', 'jetpack_the_content_to_the_excerpt' ); + } + + /* + * Display Content if the default Blog Display is 'Excerpt' + * or default Blog Display is 'Mixed' + * and the Option picked is 'Full Post' + * and we aren't in the Customizer. + */ + if ( ( 'excerpt' === $blog_display || 'mixed' === $blog_display ) && 'content' === $display_option ) { + add_filter( 'the_excerpt', 'jetpack_the_excerpt_to_the_content' ); + } +} diff --git a/projects/packages/classic-theme-helper/src/content-options/customizer.js b/projects/packages/classic-theme-helper/src/content-options/customizer.js new file mode 100644 index 0000000000000..e853604242cdd --- /dev/null +++ b/projects/packages/classic-theme-helper/src/content-options/customizer.js @@ -0,0 +1,218 @@ +/* global blogDisplay, postDetails */ + +/** + * customizer.js + * + * Theme Customizer enhancements for a better user experience. + * + * Contains handlers to make Theme Customizer preview reload changes asynchronously. + * @param $ + */ + +jQuery( function ( $, wp ) { + // Blog Display + wp.customize( 'jetpack_content_blog_display', function ( value ) { + if ( 'content' === blogDisplay.display ) { + $( '.jetpack-blog-display.jetpack-the-excerpt' ).css( { + clip: 'rect(1px, 1px, 1px, 1px)', + position: 'absolute', + } ); + $( '.jetpack-blog-display.jetpack-the-content' ).css( { + clip: 'auto', + position: 'relative', + } ); + } else if ( 'excerpt' === blogDisplay.display ) { + $( '.jetpack-blog-display.jetpack-the-content' ).css( { + clip: 'rect(1px, 1px, 1px, 1px)', + position: 'absolute', + } ); + $( '.jetpack-blog-display.jetpack-the-excerpt' ).css( { + clip: 'auto', + position: 'relative', + } ); + } else if ( 'mixed' === blogDisplay.display ) { + $( '.jetpack-blog-display.jetpack-the-content.output-the-content' ).css( { + clip: 'auto', + position: 'relative', + } ); + $( '.jetpack-blog-display.jetpack-the-excerpt.output-the-content' ).css( { + clip: 'rect(1px, 1px, 1px, 1px)', + position: 'absolute', + } ); + $( '.jetpack-blog-display.jetpack-the-content.output-the-excerpt' ).css( { + clip: 'rect(1px, 1px, 1px, 1px)', + position: 'absolute', + } ); + $( '.jetpack-blog-display.jetpack-the-excerpt.output-the-excerpt' ).css( { + clip: 'auto', + position: 'relative', + } ); + } + value.bind( function ( to ) { + if ( 'content' === to ) { + $( '.jetpack-blog-display.jetpack-the-excerpt' ).css( { + clip: 'rect(1px, 1px, 1px, 1px)', + position: 'absolute', + } ); + $( '.jetpack-blog-display.jetpack-the-content' ).css( { + clip: 'auto', + position: 'relative', + } ); + } else if ( 'excerpt' === to ) { + $( '.jetpack-blog-display.jetpack-the-content' ).css( { + clip: 'rect(1px, 1px, 1px, 1px)', + position: 'absolute', + } ); + $( '.jetpack-blog-display.jetpack-the-excerpt' ).css( { + clip: 'auto', + position: 'relative', + } ); + } else if ( 'mixed' === to ) { + $( '.jetpack-blog-display.jetpack-the-content.output-the-content' ).css( { + clip: 'auto', + position: 'relative', + } ); + $( '.jetpack-blog-display.jetpack-the-excerpt.output-the-content' ).css( { + clip: 'rect(1px, 1px, 1px, 1px)', + position: 'absolute', + } ); + $( '.jetpack-blog-display.jetpack-the-content.output-the-excerpt' ).css( { + clip: 'rect(1px, 1px, 1px, 1px)', + position: 'absolute', + } ); + $( '.jetpack-blog-display.jetpack-the-excerpt.output-the-excerpt' ).css( { + clip: 'auto', + position: 'relative', + } ); + } + if ( blogDisplay.masonry ) { + $( blogDisplay.masonry ).masonry(); + } + } ); + } ); + + // Post Details: Date. + wp.customize( 'jetpack_content_post_details_date', function ( value ) { + value.bind( function ( to ) { + if ( false === to ) { + $( postDetails.date ).css( { + clip: 'rect(1px, 1px, 1px, 1px)', + height: '1px', + overflow: 'hidden', + position: 'absolute', + width: '1px', + } ); + $( 'body' ).addClass( 'date-hidden' ); + } else { + $( postDetails.date ).css( { + clip: 'auto', + height: 'auto', + overflow: 'auto', + position: 'relative', + width: 'auto', + } ); + $( 'body' ).removeClass( 'date-hidden' ); + } + } ); + } ); + + // Post Details: Categories. + wp.customize( 'jetpack_content_post_details_categories', function ( value ) { + value.bind( function ( to ) { + if ( false === to ) { + $( postDetails.categories ).css( { + clip: 'rect(1px, 1px, 1px, 1px)', + height: '1px', + overflow: 'hidden', + position: 'absolute', + width: '1px', + } ); + $( 'body' ).addClass( 'categories-hidden' ); + } else { + $( postDetails.categories ).css( { + clip: 'auto', + height: 'auto', + overflow: 'auto', + position: 'relative', + width: 'auto', + } ); + $( 'body' ).removeClass( 'categories-hidden' ); + } + } ); + } ); + + // Post Details: Tags. + wp.customize( 'jetpack_content_post_details_tags', function ( value ) { + value.bind( function ( to ) { + if ( false === to ) { + $( postDetails.tags ).css( { + clip: 'rect(1px, 1px, 1px, 1px)', + height: '1px', + overflow: 'hidden', + position: 'absolute', + width: '1px', + } ); + $( 'body' ).addClass( 'tags-hidden' ); + } else { + $( postDetails.tags ).css( { + clip: 'auto', + height: 'auto', + overflow: 'auto', + position: 'relative', + width: 'auto', + } ); + $( 'body' ).removeClass( 'tags-hidden' ); + } + } ); + } ); + + // Post Details: Author. + wp.customize( 'jetpack_content_post_details_author', function ( value ) { + value.bind( function ( to ) { + if ( false === to ) { + $( postDetails.author ).css( { + clip: 'rect(1px, 1px, 1px, 1px)', + height: '1px', + overflow: 'hidden', + position: 'absolute', + width: '1px', + } ); + $( 'body' ).addClass( 'author-hidden' ); + } else { + $( postDetails.author ).css( { + clip: 'auto', + height: 'auto', + overflow: 'auto', + position: 'relative', + width: 'auto', + } ); + $( 'body' ).removeClass( 'author-hidden' ); + } + } ); + } ); + + // Post Details: Comment link. + wp.customize( 'jetpack_content_post_details_comment', function ( value ) { + value.bind( function ( to ) { + if ( false === to ) { + $( postDetails.comment ).css( { + clip: 'rect(1px, 1px, 1px, 1px)', + height: '1px', + overflow: 'hidden', + position: 'absolute', + width: '1px', + } ); + $( 'body' ).addClass( 'comment-hidden' ); + } else { + $( postDetails.comment ).css( { + clip: 'auto', + height: 'auto', + overflow: 'auto', + position: 'relative', + width: 'auto', + } ); + $( 'body' ).removeClass( 'comment-hidden' ); + } + } ); + } ); +} )( jQuery ); diff --git a/projects/packages/classic-theme-helper/src/content-options/customizer.php b/projects/packages/classic-theme-helper/src/content-options/customizer.php new file mode 100644 index 0000000000000..7cbe45cac7a59 --- /dev/null +++ b/projects/packages/classic-theme-helper/src/content-options/customizer.php @@ -0,0 +1,521 @@ + + label ); ?> + add_section( + 'jetpack_content_options', + array( + 'title' => esc_html__( 'Content Options', 'jetpack-classic-theme-helper' ), + 'theme_supports' => 'jetpack-content-options', + 'priority' => 100, + ) + ); + + // Add Blog Display option. + if ( in_array( $blog_display, array( 'content', 'excerpt', 'mixed' ), true ) ) { + if ( 'mixed' === $blog_display ) { + $blog_display_choices = array( + 'content' => esc_html__( 'Full post', 'jetpack-classic-theme-helper' ), + 'excerpt' => esc_html__( 'Post excerpt', 'jetpack-classic-theme-helper' ), + 'mixed' => esc_html__( 'Default', 'jetpack-classic-theme-helper' ), + ); + + $blog_display_description = esc_html__( 'Choose between a full post or an excerpt for the blog and archive pages, or opt for the theme\'s default combination of excerpt and full post.', 'jetpack-classic-theme-helper' ); + } else { + $blog_display_choices = array( + 'content' => esc_html__( 'Full post', 'jetpack-classic-theme-helper' ), + 'excerpt' => esc_html__( 'Post excerpt', 'jetpack-classic-theme-helper' ), + ); + + $blog_display_description = esc_html__( 'Choose between a full post or an excerpt for the blog and archive pages.', 'jetpack-classic-theme-helper' ); + + if ( 'mixed' === get_option( 'jetpack_content_blog_display' ) ) { + update_option( 'jetpack_content_blog_display', $blog_display ); + } + } + + $wp_customize->add_setting( + 'jetpack_content_blog_display', + array( + 'default' => $blog_display, + 'type' => 'option', + 'transport' => 'postMessage', + 'sanitize_callback' => 'jetpack_content_options_sanitize_blog_display', + ) + ); + + $wp_customize->add_control( + 'jetpack_content_blog_display', + array( + 'section' => 'jetpack_content_options', + 'label' => esc_html__( 'Blog Display', 'jetpack-classic-theme-helper' ), + 'description' => $blog_display_description, + 'type' => 'radio', + 'choices' => $blog_display_choices, + ) + ); + } + + // Add Author Bio option. + if ( true === $author_bio ) { + $wp_customize->add_setting( 'jetpack_content_author_bio_title' ); + + $wp_customize->add_control( + new Jetpack_Customize_Control_Title( + $wp_customize, + 'jetpack_content_author_bio_title', + array( + 'section' => 'jetpack_content_options', + 'label' => esc_html__( 'Author Bio', 'jetpack-classic-theme-helper' ), + 'type' => 'title', + ) + ) + ); + + $wp_customize->add_setting( + 'jetpack_content_author_bio', + array( + 'default' => $author_bio_default, + 'type' => 'option', + 'sanitize_callback' => 'jetpack_content_options_sanitize_checkbox', + ) + ); + + $wp_customize->add_control( + 'jetpack_content_author_bio', + array( + 'section' => 'jetpack_content_options', + 'label' => esc_html__( 'Display on single posts', 'jetpack-classic-theme-helper' ), + 'type' => 'checkbox', + ) + ); + } + + // Add Post Details options. + if ( ( ! empty( $post_details ) ) + && ( ! empty( $post_details['stylesheet'] ) ) + && ( ! empty( $date ) + || ! empty( $categories ) + || ! empty( $tags ) + || ! empty( $author ) + || ! empty( $comment ) ) ) { + $wp_customize->add_setting( 'jetpack_content_post_details_title' ); + + $wp_customize->add_control( + new Jetpack_Customize_Control_Title( + $wp_customize, + 'jetpack_content_post_details_title', + array( + 'section' => 'jetpack_content_options', + 'label' => esc_html__( 'Post Details', 'jetpack-classic-theme-helper' ), + 'type' => 'title', + ) + ) + ); + + // Post Details: Date. + if ( ! empty( $date ) ) { + $wp_customize->add_setting( + 'jetpack_content_post_details_date', + array( + 'default' => 1, + 'type' => 'option', + 'transport' => 'postMessage', + 'sanitize_callback' => 'jetpack_content_options_sanitize_checkbox', + ) + ); + + $wp_customize->add_control( + 'jetpack_content_post_details_date', + array( + 'section' => 'jetpack_content_options', + 'label' => esc_html__( 'Display date', 'jetpack-classic-theme-helper' ), + 'type' => 'checkbox', + ) + ); + } + + // Post Details: Categories. + if ( ! empty( $categories ) ) { + $wp_customize->add_setting( + 'jetpack_content_post_details_categories', + array( + 'default' => 1, + 'type' => 'option', + 'transport' => 'postMessage', + 'sanitize_callback' => 'jetpack_content_options_sanitize_checkbox', + ) + ); + + $wp_customize->add_control( + 'jetpack_content_post_details_categories', + array( + 'section' => 'jetpack_content_options', + 'label' => esc_html__( 'Display categories', 'jetpack-classic-theme-helper' ), + 'type' => 'checkbox', + ) + ); + } + + // Post Details: Tags. + if ( ! empty( $tags ) ) { + $wp_customize->add_setting( + 'jetpack_content_post_details_tags', + array( + 'default' => 1, + 'type' => 'option', + 'transport' => 'postMessage', + 'sanitize_callback' => 'jetpack_content_options_sanitize_checkbox', + ) + ); + + $wp_customize->add_control( + 'jetpack_content_post_details_tags', + array( + 'section' => 'jetpack_content_options', + 'label' => esc_html__( 'Display tags', 'jetpack-classic-theme-helper' ), + 'type' => 'checkbox', + ) + ); + } + + // Post Details: Author. + if ( ! empty( $author ) ) { + $wp_customize->add_setting( + 'jetpack_content_post_details_author', + array( + 'default' => 1, + 'type' => 'option', + 'transport' => 'postMessage', + 'sanitize_callback' => 'jetpack_content_options_sanitize_checkbox', + ) + ); + + $wp_customize->add_control( + 'jetpack_content_post_details_author', + array( + 'section' => 'jetpack_content_options', + 'label' => esc_html__( 'Display author', 'jetpack-classic-theme-helper' ), + 'type' => 'checkbox', + ) + ); + } + + // Post Details: Comment link. + if ( ! empty( $comment ) ) { + $wp_customize->add_setting( + 'jetpack_content_post_details_comment', + array( + 'default' => 1, + 'type' => 'option', + 'transport' => 'postMessage', + 'sanitize_callback' => 'jetpack_content_options_sanitize_checkbox', + ) + ); + + $wp_customize->add_control( + 'jetpack_content_post_details_comment', + array( + 'section' => 'jetpack_content_options', + 'label' => esc_html__( 'Display comment link', 'jetpack-classic-theme-helper' ), + 'type' => 'checkbox', + ) + ); + } + } + + // Add Featured Images options. + if ( true === $fi_archive || true === $fi_post || true === $fi_page || true === $fi_portfolio || true === $fi_fallback ) { + $wp_customize->add_setting( 'jetpack_content_featured_images_title' ); + + $wp_customize->add_control( + new Jetpack_Customize_Control_Title( + $wp_customize, + 'jetpack_content_featured_images_title', + array( + 'section' => 'jetpack_content_options', + 'label' => esc_html__( 'Featured Images', 'jetpack-classic-theme-helper' ) . sprintf( '%1$s', esc_html__( 'Learn more about Featured Images', 'jetpack-classic-theme-helper' ) ), + 'type' => 'title', + 'active_callback' => 'jetpack_post_thumbnail_supports', + ) + ) + ); + + // Featured Images: Archive. + if ( true === $fi_archive ) { + $wp_customize->add_setting( + 'jetpack_content_featured_images_archive', + array( + 'default' => $fi_archive_default, + 'type' => 'option', + 'sanitize_callback' => 'jetpack_content_options_sanitize_checkbox', + ) + ); + + $wp_customize->add_control( + 'jetpack_content_featured_images_archive', + array( + 'section' => 'jetpack_content_options', + 'label' => esc_html__( 'Display on blog and archives', 'jetpack-classic-theme-helper' ), + 'type' => 'checkbox', + 'active_callback' => 'jetpack_post_thumbnail_supports', + ) + ); + } + + // Featured Images: Post. + if ( true === $fi_post ) { + $wp_customize->add_setting( + 'jetpack_content_featured_images_post', + array( + 'default' => $fi_post_default, + 'type' => 'option', + 'sanitize_callback' => 'jetpack_content_options_sanitize_checkbox', + ) + ); + + $wp_customize->add_control( + 'jetpack_content_featured_images_post', + array( + 'section' => 'jetpack_content_options', + 'label' => esc_html__( 'Display on single posts', 'jetpack-classic-theme-helper' ), + 'type' => 'checkbox', + 'active_callback' => 'jetpack_post_thumbnail_supports', + ) + ); + } + + // Featured Images: Page. + if ( true === $fi_page ) { + $wp_customize->add_setting( + 'jetpack_content_featured_images_page', + array( + 'default' => $fi_page_default, + 'type' => 'option', + 'sanitize_callback' => 'jetpack_content_options_sanitize_checkbox', + ) + ); + + $wp_customize->add_control( + 'jetpack_content_featured_images_page', + array( + 'section' => 'jetpack_content_options', + 'label' => esc_html__( 'Display on pages', 'jetpack-classic-theme-helper' ), + 'type' => 'checkbox', + 'active_callback' => 'jetpack_post_thumbnail_supports', + ) + ); + } + + // Featured Images: Portfolio. + if ( true === $fi_portfolio && post_type_exists( 'jetpack-portfolio' ) ) { + $wp_customize->add_setting( + 'jetpack_content_featured_images_portfolio', + array( + 'default' => $fi_portfolio_default, + 'type' => 'option', + 'sanitize_callback' => 'jetpack_content_options_sanitize_checkbox', + ) + ); + + $wp_customize->add_control( + 'jetpack_content_featured_images_portfolio', + array( + 'section' => 'jetpack_content_options', + 'label' => esc_html__( 'Display on single projects', 'jetpack-classic-theme-helper' ), + 'type' => 'checkbox', + 'active_callback' => 'jetpack_post_thumbnail_supports', + ) + ); + } + + // Featured Images: Fallback. + if ( true === $fi_fallback ) { + $wp_customize->add_setting( + 'jetpack_content_featured_images_fallback', + array( + 'default' => $fi_fallback_default, + 'type' => 'option', + 'sanitize_callback' => 'jetpack_content_options_sanitize_checkbox', + ) + ); + + $wp_customize->add_control( + 'jetpack_content_featured_images_fallback', + array( + 'section' => 'jetpack_content_options', + 'label' => esc_html__( 'Automatically use first image in post', 'jetpack-classic-theme-helper' ), + 'type' => 'checkbox', + 'active_callback' => 'jetpack_post_thumbnail_supports', + ) + ); + } + } + } + add_action( 'customize_register', 'jetpack_content_options_customize_register' ); + +} + +if ( ! function_exists( 'jetpack_post_thumbnail_supports' ) ) { + + /** + * Return whether the theme supports Post Thumbnails. + */ + function jetpack_post_thumbnail_supports() { + return ( current_theme_supports( 'post-thumbnails' ) ); + } + +} + +if ( ! function_exists( 'jetpack_content_options_sanitize_checkbox' ) ) { + + /** + * Sanitize the checkbox. + * + * @param int $input The unsanitized value from the setting. + * @return int|string + */ + function jetpack_content_options_sanitize_checkbox( $input ) { + return ( 1 === (int) $input ) ? 1 : ''; + } + +} + +if ( ! function_exists( 'jetpack_content_options_sanitize_blog_display' ) ) { + + /** + * Sanitize the Display value. + * + * @param string $display The unsanitized value from the setting. + * @return string + */ + function jetpack_content_options_sanitize_blog_display( $display ) { + if ( ! in_array( $display, array( 'content', 'excerpt', 'mixed' ), true ) ) { + $display = 'content'; + } + return $display; + } + +} + +if ( ! function_exists( 'jetpack_content_options_customize_preview_js' ) ) { + + /** + * Binds JS handlers to make Theme Customizer preview reload changes asynchronously. + */ + function jetpack_content_options_customize_preview_js() { + $options = get_theme_support( 'jetpack-content-options' ); + $blog_display = ( ! empty( $options[0]['blog-display'] ) ) ? $options[0]['blog-display'] : null; + $blog_display = preg_grep( '/^(content|excerpt)$/', (array) $blog_display ); + sort( $blog_display ); + $blog_display = implode( ', ', $blog_display ); + $blog_display = ( 'content, excerpt' === $blog_display ) ? 'mixed' : $blog_display; + $masonry = ( ! empty( $options[0]['masonry'] ) ) ? $options[0]['masonry'] : null; + $post_details = ( ! empty( $options[0]['post-details'] ) ) ? $options[0]['post-details'] : null; + $date = ( ! empty( $post_details['date'] ) ) ? $post_details['date'] : null; + $categories = ( ! empty( $post_details['categories'] ) ) ? $post_details['categories'] : null; + $tags = ( ! empty( $post_details['tags'] ) ) ? $post_details['tags'] : null; + $author = ( ! empty( $post_details['author'] ) ) ? $post_details['author'] : null; + $comment = ( ! empty( $post_details['comment'] ) ) ? $post_details['comment'] : null; + + wp_enqueue_script( 'jetpack-content-options-customizer', plugins_url( 'customizer.js', __FILE__ ), array( 'jquery', 'customize-preview' ), '1.0', true ); + + wp_localize_script( + 'jetpack-content-options-customizer', + 'blogDisplay', + array( + 'display' => get_option( 'jetpack_content_blog_display', $blog_display ), + 'masonry' => $masonry, + ) + ); + + wp_localize_script( + 'jetpack-content-options-customizer', + 'postDetails', + array( + 'date' => $date, + 'categories' => $categories, + 'tags' => $tags, + 'author' => $author, + 'comment' => $comment, + ) + ); + } + add_action( 'customize_preview_init', 'jetpack_content_options_customize_preview_js' ); + +} diff --git a/projects/packages/classic-theme-helper/src/content-options/featured-images-fallback.php b/projects/packages/classic-theme-helper/src/content-options/featured-images-fallback.php new file mode 100644 index 0000000000000..3de86c7d7573c --- /dev/null +++ b/projects/packages/classic-theme-helper/src/content-options/featured-images-fallback.php @@ -0,0 +1,243 @@ + false, + 'from_slideshow' => true, + 'from_gallery' => true, + 'from_attachment' => false, + ); + + // @phan-suppress-next-line PhanUndeclaredClassMethod -- We we've checked the class exists earlier. + $image = Jetpack_PostImages::get_image( $post_id, $args ); + + if ( ! empty( $image ) ) { + $image['width'] = ''; + $image['height'] = ''; + $image['crop'] = ''; + + if ( array_key_exists( $size, $_wp_additional_image_sizes ) ) { + $image['width'] = $_wp_additional_image_sizes[ $size ]['width']; + $image['height'] = $_wp_additional_image_sizes[ $size ]['height']; + $image['crop'] = $_wp_additional_image_sizes[ $size ]['crop']; + } + + // Force `crop` to be a simple boolean, to avoid dealing with WP crop positions. + $image['crop'] = boolval( $image['crop'] ); + + $image_sizes = ''; + + $width = isset( $image['width'] ) ? intval( $image['width'] ) : null; + $height = isset( $image['height'] ) ? intval( $image['height'] ) : null; + + if ( ! empty( $image['src_width'] ) && ! empty( $image['src_height'] ) && ! empty( $image['width'] ) && ! empty( $image['height'] ) ) { + $src_width = intval( $image['src_width'] ); + $src_height = intval( $image['src_height'] ); + + // If we're aware of the source dimensions, calculate the final image height and width. + // This allows us to provide them as attributes in the `` tag, to avoid layout shifts. + // It also allows us to calculate a `srcset`. + if ( $image['crop'] ) { + // If we're cropping, the final dimensions are calculated independently of each other. + $width = min( $width, $src_width ); + $height = min( $height, $src_height ); + } else { + // If we're not cropping, we need to preserve aspect ratio. + $dims = wp_constrain_dimensions( $src_width, $src_height, $width, $height ); + $width = $dims[0]; + $height = $dims[1]; + } + + $image_src = Jetpack_PostImages::fit_image_url( $image['src'], $width, $height ); // @phan-suppress-current-line PhanUndeclaredClassMethod -- We've checked the class exists earlier. + $image_srcset = Jetpack_PostImages::generate_cropped_srcset( $image, $width, $height, true ); // @phan-suppress-current-line PhanUndeclaredClassMethod -- We've checked the class exists earlier. + $image_sizes = 'min(' . $width . 'px, 100vw)'; + } else { + // If we're not aware of the source dimensions, leave the size calculations to the CDN, and + // fall back to a simpler `` tag without `width`/`height` or `srcset`. + $image_src = Jetpack_PostImages::fit_image_url( $image['src'], $image['width'], $image['height'] ); // @phan-suppress-current-line PhanUndeclaredClassMethod -- We've checked the class exists earlier. + + // Use the theme's crop setting rather than forcing to true. + $image_src = add_query_arg( 'crop', $image['crop'], $image_src ); + + $image_srcset = null; + $image_sizes = null; + } + + $default_attr = array( + 'srcset' => $image_srcset, + 'sizes' => $image_sizes, + 'loading' => is_singular() ? 'eager' : 'lazy', + 'decoding' => 'async', + 'title' => wp_strip_all_tags( get_the_title() ), + 'alt' => '', + 'class' => "attachment-$size wp-post-image", + ); + + $image_attr = wp_parse_args( $attr, $default_attr ); + $hwstring = image_hwstring( $width, $height ); + + $html = rtrim( " $value ) { + if ( $value ) { + $html .= " $name=" . '"' . esc_attr( $value ) . '"'; + } + } + + $html .= ' />'; + + return trim( $html ); + } + } + + return trim( $html ); + } + add_filter( 'post_thumbnail_html', 'jetpack_featured_images_fallback_get_image', 10, 5 ); + +} + +if ( ! function_exists( 'jetpack_featured_images_fallback_get_image_src' ) ) { + + /** + * Get URL of one image from a specified post in the following order: + * Featured Image then first image from the_content HTML + * + * @param int $post_id The post ID to check. + * @param int $post_thumbnail_id The ID of the featured image. + * @param string $size The image size to return, defaults to 'post-thumbnail'. + * + * @return string|null $image_src The URL of the thumbnail image. + */ + function jetpack_featured_images_fallback_get_image_src( $post_id, $post_thumbnail_id, $size ) { + $image_src = wp_get_attachment_image_src( $post_thumbnail_id, $size ); + $image_src = ( ! empty( $image_src[0] ) ) ? $image_src[0] : ''; + $opts = jetpack_featured_images_get_settings(); + + if ( ! empty( $image_src ) || (bool) 1 !== (bool) $opts['fallback-option'] ) { + return esc_url( $image_src ); + } + + if ( jetpack_featured_images_should_load() ) { + if ( ( true === $opts['archive'] && ( is_home() || is_archive() || is_search() ) && ! $opts['archive-option'] ) + || ( true === $opts['post'] && is_single() && ! $opts['post-option'] ) ) { + return esc_url( $image_src ); + } + } + + if ( class_exists( 'Jetpack_PostImages' ) ) { + global $_wp_additional_image_sizes; + + $args = array( + 'from_thumbnail' => false, + 'from_slideshow' => true, + 'from_gallery' => true, + 'from_attachment' => false, + ); + + $image = Jetpack_PostImages::get_image( $post_id, $args ); // @phan-suppress-current-line PhanUndeclaredClassMethod -- We've checked the class exists earlier. + + if ( ! empty( $image ) ) { + $image['width'] = ''; + $image['height'] = ''; + $image['crop'] = ''; + + if ( array_key_exists( $size, $_wp_additional_image_sizes ) ) { + $image['width'] = $_wp_additional_image_sizes[ $size ]['width']; + $image['height'] = $_wp_additional_image_sizes[ $size ]['height']; + $image['crop'] = $_wp_additional_image_sizes[ $size ]['crop']; + } + + $image_src = Jetpack_PostImages::fit_image_url( $image['src'], $image['width'], $image['height'] ); // @phan-suppress-current-line PhanUndeclaredClassMethod -- We've checked the class exists earlier. + + // Use the theme's crop setting rather than forcing to true. + $image_src = add_query_arg( 'crop', $image['crop'], $image_src ); + + return esc_url( $image_src ); + } + } + + return esc_url( $image_src ); + } + +} + +if ( ! function_exists( 'jetpack_has_featured_image' ) ) { + + /** + * Check if post has an image attached, including a fallback. + * + * @param int $post The post ID to check. + * + * @return bool + */ + function jetpack_has_featured_image( $post = null ) { + return (bool) get_the_post_thumbnail( $post ); + } + +} + +if ( ! function_exists( 'jetpack_featured_images_post_class' ) ) { + + /** + * Adds custom class to the array of post classes. + * + * @param array $classes Classes for the post element. + * @param array $class Optional. Comma separated list of additional classes. + * @param int $post_id Unique The post ID to check. + * + * @return array $classes + */ + function jetpack_featured_images_post_class( $classes, $class, $post_id ) { + $post_password_required = post_password_required( $post_id ); + $opts = jetpack_featured_images_get_settings(); + + if ( jetpack_has_featured_image( $post_id ) && (bool) 1 === (bool) $opts['fallback-option'] && ! is_attachment() && ! $post_password_required && 'post' === get_post_type() ) { + $classes[] = 'has-post-thumbnail'; + $classes[] = 'fallback-thumbnail'; + } + + return $classes; + } + add_filter( 'post_class', 'jetpack_featured_images_post_class', 10, 3 ); + +} diff --git a/projects/packages/classic-theme-helper/src/content-options/featured-images.php b/projects/packages/classic-theme-helper/src/content-options/featured-images.php new file mode 100644 index 0000000000000..b1ea3d960cd0e --- /dev/null +++ b/projects/packages/classic-theme-helper/src/content-options/featured-images.php @@ -0,0 +1,130 @@ +get( 'page_id' ); + $is_static_front_page = 'page' === get_option( 'show_on_front' ); + + $is_shop_page = false; + if ( $is_static_front_page && $front_page_id === $current_page_id ) { + $is_shop_page = function_exists( 'wc_get_page_id' ) && wc_get_page_id( 'shop' ) === $current_page_id; // @phan-suppress-current-line PhanUndeclaredFunction -- We're checking the function exists first. + } elseif ( function_exists( 'is_shop' ) ) { + $is_shop_page = is_shop(); // @phan-suppress-current-line PhanUndeclaredFunction -- We're checking the function exists first. + } + + return $is_shop_page; + } + +} diff --git a/projects/packages/classic-theme-helper/src/content-options/post-details.php b/projects/packages/classic-theme-helper/src/content-options/post-details.php new file mode 100644 index 0000000000000..3e4fbc3f9f526 --- /dev/null +++ b/projects/packages/classic-theme-helper/src/content-options/post-details.php @@ -0,0 +1,180 @@ + diff --git a/projects/packages/connection/src/js/tracks-callables.js b/projects/packages/connection/src/js/tracks-callables.js index 081a6abc660ad..53512ad689883 100644 --- a/projects/packages/connection/src/js/tracks-callables.js +++ b/projects/packages/connection/src/js/tracks-callables.js @@ -14,9 +14,9 @@ const debug = console.error; // eslint-disable-line no-console /** * Build a query string. * - * @param {string|object} group - Stat group, or object mapping groups to names. - * @param {string} [name] - Stat name, when `group` is a string. - * @returns {string} Query string fragment. + * @param {string|object} group - Stat group, or object mapping groups to names. + * @param {string} [name] - Stat name, when `group` is a string. + * @return {string} Query string fragment. */ function buildQuerystring( group, name ) { let uriComponent = ''; diff --git a/projects/packages/connection/src/sso/class-sso.php b/projects/packages/connection/src/sso/class-sso.php index 2c04f13c7820e..b1c69934c0d16 100644 --- a/projects/packages/connection/src/sso/class-sso.php +++ b/projects/packages/connection/src/sso/class-sso.php @@ -446,13 +446,6 @@ private function wants_to_login() { return $wants_to_login; } - /** - * Checks to determine if the user has indicated they want to use the wp-admin interface. - */ - private function use_wp_admin_interface() { - return 'wp-admin' === get_option( 'wpcom_admin_interface' ); - } - /** * Initialization for a SSO request. */ @@ -510,7 +503,7 @@ public function login_init() { * to the WordPress.com login page AND that the request to wp-login.php * is not something other than login (Like logout!) */ - if ( ! $this->use_wp_admin_interface() && Helpers::bypass_login_forward_wpcom() && $this->wants_to_login() ) { + if ( Helpers::bypass_login_forward_wpcom() && $this->wants_to_login() ) { add_filter( 'allowed_redirect_hosts', array( Helpers::class, 'allowed_redirect_hosts' ) ); $reauth = ! empty( $_GET['force_reauth'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $sso_url = $this->get_sso_url_or_die( $reauth ); diff --git a/projects/packages/constants/CHANGELOG.md b/projects/packages/constants/CHANGELOG.md index 15d729d465dc4..842f3a81f3e7a 100644 --- a/projects/packages/constants/CHANGELOG.md +++ b/projects/packages/constants/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.4] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## [2.0.3] - 2024-05-29 ### Fixed - Fix phpdoc type on `Constants::set_constant()` value parameter. [#37606] @@ -170,6 +174,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Packages: Finish the constants package +[2.0.4]: https://github.com/Automattic/jetpack-constants/compare/v2.0.3...v2.0.4 [2.0.3]: https://github.com/Automattic/jetpack-constants/compare/v2.0.2...v2.0.3 [2.0.2]: https://github.com/Automattic/jetpack-constants/compare/v2.0.1...v2.0.2 [2.0.1]: https://github.com/Automattic/jetpack-constants/compare/v2.0.0...v2.0.1 diff --git a/projects/packages/constants/composer.json b/projects/packages/constants/composer.json index 1c2f066504422..cbecbea33bf72 100644 --- a/projects/packages/constants/composer.json +++ b/projects/packages/constants/composer.json @@ -8,7 +8,7 @@ }, "require-dev": { "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "suggest": { diff --git a/projects/packages/device-detection/CHANGELOG.md b/projects/packages/device-detection/CHANGELOG.md index 1adce0dcb9b37..5b3988d68a969 100644 --- a/projects/packages/device-detection/CHANGELOG.md +++ b/projects/packages/device-detection/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.1.4] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## [2.1.3] - 2024-04-08 ### Added - Added functionality for extracting the browser and desktop platform from a user agent. [#36568] @@ -196,6 +200,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Moving jetpack_is_mobile into a package +[2.1.4]: https://github.com/Automattic/jetpack-device-detection/compare/v2.1.3...v2.1.4 [2.1.3]: https://github.com/Automattic/jetpack-device-detection/compare/v2.1.2...v2.1.3 [2.1.2]: https://github.com/Automattic/jetpack-device-detection/compare/v2.1.1...v2.1.2 [2.1.1]: https://github.com/Automattic/jetpack-device-detection/compare/v2.1.0...v2.1.1 diff --git a/projects/packages/device-detection/composer.json b/projects/packages/device-detection/composer.json index a53234dec72f7..62b748a0af24b 100644 --- a/projects/packages/device-detection/composer.json +++ b/projects/packages/device-detection/composer.json @@ -7,7 +7,7 @@ "php": ">=7.0" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "suggest": { diff --git a/projects/packages/error/CHANGELOG.md b/projects/packages/error/CHANGELOG.md index 5796cf2f31e36..486f3b5ac18e1 100644 --- a/projects/packages/error/CHANGELOG.md +++ b/projects/packages/error/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.3] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + ## [2.0.2] - 2024-03-25 ### Changed - Internal updates. @@ -140,6 +144,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Packages: Introduce a jetpack-error package +[2.0.3]: https://github.com/Automattic/jetpack-error/compare/v2.0.2...v2.0.3 [2.0.2]: https://github.com/Automattic/jetpack-error/compare/v2.0.1...v2.0.2 [2.0.1]: https://github.com/Automattic/jetpack-error/compare/v2.0.0...v2.0.1 [2.0.0]: https://github.com/Automattic/jetpack-error/compare/v1.3.21...v2.0.0 diff --git a/projects/packages/error/composer.json b/projects/packages/error/composer.json index b65b3ea45e1de..289b152af21c0 100644 --- a/projects/packages/error/composer.json +++ b/projects/packages/error/composer.json @@ -7,7 +7,7 @@ "php": ">=7.0" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "suggest": { diff --git a/projects/packages/explat/CHANGELOG.md b/projects/packages/explat/CHANGELOG.md index f42da5de8bf24..f21f4f6e5b5ca 100644 --- a/projects/packages/explat/CHANGELOG.md +++ b/projects/packages/explat/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.5] - 2024-08-29 +### Changed +- Updated package dependencies. [#39111] + +## [0.1.4] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + +## [0.1.3] - 2024-08-21 +### Changed +- Internal updates. + ## [0.1.2] - 2024-08-15 ### Changed - Updated package dependencies. [#38662] @@ -23,5 +35,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - ExPlat: add condition to prevent fetching the experiment assignment if there's not anon id (meaning that Tracks is likely disabled) [#38327] - Updated package dependencies. [#38132] +[0.1.5]: https://github.com/Automattic/jetpack-explat/compare/v0.1.4...v0.1.5 +[0.1.4]: https://github.com/Automattic/jetpack-explat/compare/v0.1.3...v0.1.4 +[0.1.3]: https://github.com/Automattic/jetpack-explat/compare/v0.1.2...v0.1.3 [0.1.2]: https://github.com/Automattic/jetpack-explat/compare/v0.1.1...v0.1.2 [0.1.1]: https://github.com/Automattic/jetpack-explat/compare/v0.1.0...v0.1.1 diff --git a/projects/packages/explat/composer.json b/projects/packages/explat/composer.json index 3d90fafceb5e3..eff79eadfba11 100644 --- a/projects/packages/explat/composer.json +++ b/projects/packages/explat/composer.json @@ -8,7 +8,7 @@ "automattic/jetpack-connection": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "autoload": { diff --git a/projects/packages/explat/package.json b/projects/packages/explat/package.json index 207187c492299..ec471c50d61e8 100644 --- a/projects/packages/explat/package.json +++ b/projects/packages/explat/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-explat", - "version": "0.1.2", + "version": "0.1.5", "description": "A package for running A/B tests on the Experimentation Platform (ExPlat) in the plugin.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/explat/#readme", "bugs": { @@ -29,7 +29,7 @@ "@types/qs": "6.9.15", "jest": "29.7.0", "typescript": "5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "exports": { diff --git a/projects/packages/explat/src/class-explat.php b/projects/packages/explat/src/class-explat.php index f0d12411f5770..4ca261a4dcf7e 100644 --- a/projects/packages/explat/src/class-explat.php +++ b/projects/packages/explat/src/class-explat.php @@ -20,7 +20,7 @@ class ExPlat { * * @var string */ - const PACKAGE_VERSION = '0.1.2'; + const PACKAGE_VERSION = '0.1.5'; /** * Initializer. diff --git a/projects/packages/explat/src/client/anon.ts b/projects/packages/explat/src/client/anon.ts index 489c251be4fd0..5afc6b9060fce 100644 --- a/projects/packages/explat/src/client/anon.ts +++ b/projects/packages/explat/src/client/anon.ts @@ -10,7 +10,7 @@ const anonIdPollingIntervalMaxAttempts = 100; // 50 * 100 = 5000 = 5 seconds /** * Gather w.js anonymous cookie, tk_ai * - * @returns {?string} The anonymous cookie value, or null if it doesn't exist + * @return {?string} The anonymous cookie value, or null if it doesn't exist */ export const readAnonCookie = (): string | null => { return cookie.parse( document.cookie ).tk_ai || null; @@ -31,7 +31,7 @@ export const readAnonCookie = (): string | null => { * * Throws on error. * - * @returns {Promise} The anonymous cookie value, or null if it doesn't exist + * @return {Promise} The anonymous cookie value, or null if it doesn't exist */ export const initializeAnonId = async (): Promise< string | null > => { let attempt = 0; diff --git a/projects/packages/forms/CHANGELOG.md b/projects/packages/forms/CHANGELOG.md index 08cae892c0c70..d5f19ac9934e7 100644 --- a/projects/packages/forms/CHANGELOG.md +++ b/projects/packages/forms/CHANGELOG.md @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.32.11] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + +## [0.32.10] - 2024-08-21 +### Changed +- Internal updates. + +## [0.32.9] - 2024-08-19 +### Changed +- Updated package dependencies. [#38662] + +### Fixed +- Lossless image optimization for images (should improve performance with no visible changes). [#38750] + ## [0.32.8] - 2024-08-12 ### Added - React 19 compatibility: Making sure useRef includes an argument. [#38765] @@ -623,6 +638,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added a new jetpack/forms package [#28409] - Added a public load_contact_form method for initializing the contact form module. [#28416] +[0.32.11]: https://github.com/automattic/jetpack-forms/compare/v0.32.10...v0.32.11 +[0.32.10]: https://github.com/automattic/jetpack-forms/compare/v0.32.9...v0.32.10 +[0.32.9]: https://github.com/automattic/jetpack-forms/compare/v0.32.8...v0.32.9 [0.32.8]: https://github.com/automattic/jetpack-forms/compare/v0.32.7...v0.32.8 [0.32.7]: https://github.com/automattic/jetpack-forms/compare/v0.32.6...v0.32.7 [0.32.6]: https://github.com/automattic/jetpack-forms/compare/v0.32.5...v0.32.6 diff --git a/projects/packages/forms/assets/images/ai-forms.png b/projects/packages/forms/assets/images/ai-forms.png index 9037ceac78cc4..48b1a8e1ca229 100644 Binary files a/projects/packages/forms/assets/images/ai-forms.png and b/projects/packages/forms/assets/images/ai-forms.png differ diff --git a/projects/packages/forms/assets/images/contact-form.png b/projects/packages/forms/assets/images/contact-form.png index 0adbb4fa96121..072e4797dc5ab 100644 Binary files a/projects/packages/forms/assets/images/contact-form.png and b/projects/packages/forms/assets/images/contact-form.png differ diff --git a/projects/packages/forms/assets/images/feedback-form.png b/projects/packages/forms/assets/images/feedback-form.png index 5509e66ff852a..fa0891cf932b7 100644 Binary files a/projects/packages/forms/assets/images/feedback-form.png and b/projects/packages/forms/assets/images/feedback-form.png differ diff --git a/projects/packages/forms/assets/images/google-sheets-icon.png b/projects/packages/forms/assets/images/google-sheets-icon.png index b855baf3e7b7c..8ffc4499f4696 100644 Binary files a/projects/packages/forms/assets/images/google-sheets-icon.png and b/projects/packages/forms/assets/images/google-sheets-icon.png differ diff --git a/projects/packages/forms/assets/images/registration-form.png b/projects/packages/forms/assets/images/registration-form.png index b916e2e1f50be..469c8eaf8a34a 100644 Binary files a/projects/packages/forms/assets/images/registration-form.png and b/projects/packages/forms/assets/images/registration-form.png differ diff --git a/projects/packages/forms/assets/images/responses-inbox-wp-com.png b/projects/packages/forms/assets/images/responses-inbox-wp-com.png index 6ce4831669af7..ffb940baea286 100644 Binary files a/projects/packages/forms/assets/images/responses-inbox-wp-com.png and b/projects/packages/forms/assets/images/responses-inbox-wp-com.png differ diff --git a/projects/packages/forms/assets/images/responses-inbox.png b/projects/packages/forms/assets/images/responses-inbox.png index 423ffa2afba49..490e09e169a2d 100644 Binary files a/projects/packages/forms/assets/images/responses-inbox.png and b/projects/packages/forms/assets/images/responses-inbox.png differ diff --git a/projects/packages/forms/assets/images/salesforce-icon.png b/projects/packages/forms/assets/images/salesforce-icon.png index 16b2f8128fc2a..c8dc8a581c42b 100644 Binary files a/projects/packages/forms/assets/images/salesforce-icon.png and b/projects/packages/forms/assets/images/salesforce-icon.png differ diff --git a/projects/packages/forms/changelog/fix-choice-field-caret b/projects/packages/forms/changelog/fix-choice-field-caret new file mode 100644 index 0000000000000..93120cce24a34 --- /dev/null +++ b/projects/packages/forms/changelog/fix-choice-field-caret @@ -0,0 +1,5 @@ +Significance: patch +Type: fixed +Comment: Move Single and Multiple Choice input caret to the end on focus + + diff --git a/projects/packages/forms/changelog/fix-dropdown-failing-e2e-test b/projects/packages/forms/changelog/fix-dropdown-failing-e2e-test new file mode 100644 index 0000000000000..b38b38100393a --- /dev/null +++ b/projects/packages/forms/changelog/fix-dropdown-failing-e2e-test @@ -0,0 +1,5 @@ +Significance: patch +Type: fixed +Comment: Render option field as a div in the editor + + diff --git a/projects/packages/jetpack-mu-wpcom/changelog/renovate-wordpress-monorepo b/projects/packages/forms/changelog/renovate-npm-webpack-vulnerability similarity index 100% rename from projects/packages/jetpack-mu-wpcom/changelog/renovate-wordpress-monorepo rename to projects/packages/forms/changelog/renovate-npm-webpack-vulnerability diff --git a/projects/packages/forms/changelog/try-no-version-bumps-in-trunk b/projects/packages/forms/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..91efe85c55e06 --- /dev/null +++ b/projects/packages/forms/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/packages/forms/changelog/update-contact-form-block-api b/projects/packages/forms/changelog/update-contact-form-block-api new file mode 100644 index 0000000000000..dbc5ada1eb81e --- /dev/null +++ b/projects/packages/forms/changelog/update-contact-form-block-api @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Forms: update child blocks to Block API v3 diff --git a/projects/packages/forms/composer.json b/projects/packages/forms/composer.json index d1d6ceb114b1e..4a41f8a50b68b 100644 --- a/projects/packages/forms/composer.json +++ b/projects/packages/forms/composer.json @@ -13,7 +13,7 @@ "automattic/jetpack-sync": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/jetpack-connection": "@dev", "automattic/wordbless": "^0.4.1" diff --git a/projects/packages/forms/package.json b/projects/packages/forms/package.json index 739428c16abf6..f2069286ad9d0 100644 --- a/projects/packages/forms/package.json +++ b/projects/packages/forms/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-forms", - "version": "0.32.9-alpha", + "version": "0.32.11", "description": "Jetpack Forms", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/forms/#readme", "bugs": { @@ -54,7 +54,7 @@ "redux-thunk": "2.3.0", "sass": "1.64.1", "semver": "7.5.2", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "devDependencies": { diff --git a/projects/packages/forms/src/blocks/contact-form/child-blocks.js b/projects/packages/forms/src/blocks/contact-form/child-blocks.js index d7b89470fbb7a..30db4224f093d 100644 --- a/projects/packages/forms/src/blocks/contact-form/child-blocks.js +++ b/projects/packages/forms/src/blocks/contact-form/child-blocks.js @@ -1,4 +1,4 @@ -import { InnerBlocks } from '@wordpress/block-editor'; +import { InnerBlocks, useBlockProps } from '@wordpress/block-editor'; import { createBlock, getBlockType } from '@wordpress/blocks'; import { Path } from '@wordpress/components'; import { Fragment } from '@wordpress/element'; @@ -17,6 +17,7 @@ import { useFormWrapper } from './util/form'; import renderMaterialIcon from './util/render-material-icon'; const FieldDefaults = { + apiVersion: 3, category: 'contact-form', supports: { reusable: false, @@ -229,6 +230,7 @@ const FieldDefaults = { }; const OptionFieldDefaults = { + apiVersion: 3, category: 'contact-form', edit: JetpackFieldOptionEdit, attributes: { @@ -675,7 +677,15 @@ export const childBlocks = [ /> ), edit: editMultiField( 'checkbox' ), - save: () => , + save: () => { + const blockProps = useBlockProps.save(); + + return ( +
+ +
+ ); + }, attributes: { ...FieldDefaults.attributes, label: { @@ -713,7 +723,15 @@ export const childBlocks = [ ), edit: editMultiField( 'radio' ), - save: () => , + save: () => { + const blockProps = useBlockProps.save(); + + return ( +
+ +
+ ); + }, attributes: { ...FieldDefaults.attributes, label: { diff --git a/projects/packages/forms/src/blocks/contact-form/components/jetpack-field-checkbox.js b/projects/packages/forms/src/blocks/contact-form/components/jetpack-field-checkbox.js index 5f5ab1a645c57..06a0782c60db0 100644 --- a/projects/packages/forms/src/blocks/contact-form/components/jetpack-field-checkbox.js +++ b/projects/packages/forms/src/blocks/contact-form/components/jetpack-field-checkbox.js @@ -3,6 +3,7 @@ import { InspectorControls, PanelColorSettings, BlockControls, + useBlockProps, } from '@wordpress/block-editor'; import { PanelBody, ToggleControl } from '@wordpress/components'; import { compose, withInstanceId } from '@wordpress/compose'; @@ -27,6 +28,11 @@ function JetpackFieldCheckbox( props ) { } = props; const { blockStyle } = useJetpackFieldStyles( attributes ); + const blockProps = useBlockProps( { + id: `jetpack-field-checkbox-${ instanceId }`, + className: 'jetpack-field jetpack-field-checkbox', + style: blockStyle, + } ); return ( <> @@ -37,11 +43,7 @@ function JetpackFieldCheckbox( props ) { /> -
+
{ + const blockProps = useBlockProps( { + id: `jetpack-field-consent-${ instanceId }`, + className: 'jetpack-field jetpack-field-consent', + } ); + return ( -
+
{ consentType === 'explicit' && ( ) } diff --git a/projects/packages/forms/src/blocks/contact-form/components/jetpack-field-datepicker.js b/projects/packages/forms/src/blocks/contact-form/components/jetpack-field-datepicker.js index 6ba9ba74ceda8..ab41c2a6d3977 100644 --- a/projects/packages/forms/src/blocks/contact-form/components/jetpack-field-datepicker.js +++ b/projects/packages/forms/src/blocks/contact-form/components/jetpack-field-datepicker.js @@ -1,3 +1,4 @@ +import { useBlockProps } from '@wordpress/block-editor'; import { SelectControl } from '@wordpress/components'; import { compose } from '@wordpress/compose'; import { __ } from '@wordpress/i18n'; @@ -40,15 +41,17 @@ const JetpackDatePicker = props => { const { blockStyle, fieldStyle } = useJetpackFieldStyles( attributes ); const formStyle = useFormStyle( clientId ); - - const classes = clsx( 'jetpack-field', { - 'is-selected': isSelected, - 'has-placeholder': !! placeholder, + const blockProps = useBlockProps( { + className: clsx( 'jetpack-field', { + 'is-selected': isSelected, + 'has-placeholder': !! placeholder, + } ), + style: blockStyle, } ); return ( <> -
+
+
-
+
{ return createBlock( name, { @@ -48,45 +46,38 @@ export const JetpackFieldOptionEdit = ( { removeBlock( clientId ); }; - const onFocus = () => { - // TODO: move cursor to end - }; + const handleFocus = e => moveCaretToEnd( e.target ); - useEffect( () => { - const element = labelRef.current; + const supportsSplitting = supportsParagraphSplitting(); + const type = name.replace( 'jetpack/field-option-', '' ); + const classes = clsx( 'jetpack-field-option', `field-option-${ type }` ); - element?.addEventListener( 'focus', onFocus ); + useEffect( () => { + const input = document.getElementById( blockProps.id ); - if ( isSelected ) { - // Timeout is necessary for the focus to be effective - setTimeout( () => element?.focus(), 0 ); - } + input?.addEventListener( 'focus', handleFocus ); return () => { - element?.removeEventListener( 'focus', onFocus ); + input?.removeEventListener( 'focus', handleFocus ); }; - }, [ isSelected, labelRef ] ); - - const supportsSplitting = supportsParagraphSplitting(); - const type = name.replace( 'jetpack/field-option-', '' ); - const classes = clsx( 'jetpack-field-option', `field-option-${ type }` ); + }, [ blockProps.id ] ); return ( -
+
setAttributes( { label: val } ) } - onReplace={ onReplace } onRemove={ handleDelete } + onReplace={ onReplace } preserveWhiteSpace={ false } withoutInteractiveFormatting - ref={ labelRef } { ...( supportsSplitting ? {} : { onSplit: handleSplit } ) } />
diff --git a/projects/packages/forms/src/blocks/contact-form/components/jetpack-field-textarea.js b/projects/packages/forms/src/blocks/contact-form/components/jetpack-field-textarea.js index b616f37be6d9c..9363cb66e43a3 100644 --- a/projects/packages/forms/src/blocks/contact-form/components/jetpack-field-textarea.js +++ b/projects/packages/forms/src/blocks/contact-form/components/jetpack-field-textarea.js @@ -1,3 +1,4 @@ +import { useBlockProps } from '@wordpress/block-editor'; import { compose } from '@wordpress/compose'; import { useEffect } from '@wordpress/element'; import clsx from 'clsx'; @@ -21,12 +22,15 @@ const JetpackFieldTextarea = props => { placeholder, width, } = props; + const formStyle = useFormStyle( clientId ); const { blockStyle, fieldStyle } = useJetpackFieldStyles( attributes ); - - const classes = clsx( 'jetpack-field jetpack-field-textarea', { - 'is-selected': isSelected, - 'has-placeholder': ! isEmpty( placeholder ), + const blockProps = useBlockProps( { + className: clsx( 'jetpack-field jetpack-field-textarea', { + 'is-selected': isSelected, + 'has-placeholder': ! isEmpty( placeholder ), + } ), + style: blockStyle, } ); useEffect( () => { @@ -38,7 +42,7 @@ const JetpackFieldTextarea = props => { return ( <> -
+
{ const { blockStyle, fieldStyle } = useJetpackFieldStyles( attributes ); const formStyle = useFormStyle( clientId ); - - const classes = clsx( 'jetpack-field', { - 'is-selected': isSelected, - 'has-placeholder': ! isEmpty( placeholder ), + const blockProps = useBlockProps( { + className: clsx( 'jetpack-field', { + 'is-selected': isSelected, + 'has-placeholder': ! isEmpty( placeholder ), + } ), + style: blockStyle, } ); return ( <> -
+
; + elt = ; + } else { + elt = ( + + ); } - return ( - - ); - } - - if ( ! hasInnerBlocks && registerBlockVariation ) { - return renderVariationPicker(); - } + } else if ( ! hasInnerBlocks && registerBlockVariation ) { + elt = renderVariationPicker(); + } else { + elt = ( + <> + + { ! attributes.formTitle && ( + + + { __( + 'Add a heading inside the form or before it to help everybody identify it.', + 'jetpack-forms' + ) } + { ' ' } + + ) } + + + + + { renderSubmissionSettings() } + + + + - return ( - <> - - { ! attributes.formTitle && ( - - - { __( - 'Add a heading inside the form or before it to help everybody identify it.', - 'jetpack-forms' + { isSalesForceExtensionEnabled && salesforceData?.sendToSalesforce && ( + + ) } + { ! ( isSimpleSite() || isAtomicSite() ) && ( + + { canUserInstallPlugins && ( + + + ) } - { ' ' } - - ) } - - - - - { renderSubmissionSettings() } - - - - + + + + + ) } + - { isSalesForceExtensionEnabled && salesforceData?.sendToSalesforce && ( - + - ) } - { ! ( isSimpleSite() || isAtomicSite() ) && ( - - { canUserInstallPlugins && ( - - - - ) } - - - - - ) } - +
+ + ); + } -
- -
- - ); + return
{ elt }
; } ); diff --git a/projects/packages/forms/src/blocks/contact-form/editor.scss b/projects/packages/forms/src/blocks/contact-form/editor.scss index 55e98b23939b2..31f6d919b2456 100644 --- a/projects/packages/forms/src/blocks/contact-form/editor.scss +++ b/projects/packages/forms/src/blocks/contact-form/editor.scss @@ -41,14 +41,14 @@ } } - > .block-editor-inner-blocks > .block-editor-block-list__layout { + .block-editor-inner-blocks .block-editor-block-list__layout { display: flex; flex-wrap: wrap; justify-content: flex-start; flex-direction: row; gap: var(--wp--style--block-gap, 1.5rem); - > .wp-block { + .wp-block { flex: 0 0 100%; margin: 0; @@ -593,7 +593,7 @@ .jetpack-contact-form { padding: 16px; - > .block-editor-inner-blocks > .block-editor-block-list__layout { + .block-editor-inner-blocks .block-editor-block-list__layout { margin: 0; } } diff --git a/projects/packages/forms/src/blocks/contact-form/index.js b/projects/packages/forms/src/blocks/contact-form/index.js index be342b30eb823..5fbabeea63cfa 100644 --- a/projects/packages/forms/src/blocks/contact-form/index.js +++ b/projects/packages/forms/src/blocks/contact-form/index.js @@ -43,6 +43,7 @@ const icon = renderMaterialIcon( ); export const settings = { + apiVersion: 3, title: __( 'Form', 'jetpack-forms' ), description: __( 'Create forms to collect data from site visitors and manage their responses.', diff --git a/projects/packages/forms/src/blocks/contact-form/util/block-icons.js b/projects/packages/forms/src/blocks/contact-form/util/block-icons.js index b4401b5fa229e..c2f176002e749 100644 --- a/projects/packages/forms/src/blocks/contact-form/util/block-icons.js +++ b/projects/packages/forms/src/blocks/contact-form/util/block-icons.js @@ -12,7 +12,7 @@ const COLOR_JETPACK = PALETTE[ 'Jetpack Green 40' ]; * * Green in the Jetpack context, otherwise black for Simple sites or Atomic sites. * - * @returns {string} HEX color for block editor icons + * @return {string} HEX color for block editor icons */ export function getIconColor() { if ( isAtomicSite() || isSimpleSite() ) { diff --git a/projects/packages/forms/src/blocks/contact-form/util/block-support.js b/projects/packages/forms/src/blocks/contact-form/util/block-support.js index 932e8e5ba3bc3..6e129601f7b2e 100644 --- a/projects/packages/forms/src/blocks/contact-form/util/block-support.js +++ b/projects/packages/forms/src/blocks/contact-form/util/block-support.js @@ -3,7 +3,7 @@ import { hasBlockSupport } from '@wordpress/blocks'; /** * Check if Gutenberg supports splitting paragraphs. * - * @returns {boolean} Whether Gutenberg supports splitting paragraphs. + * @return {boolean} Whether Gutenberg supports splitting paragraphs. */ export function supportsParagraphSplitting() { return hasBlockSupport( 'core/paragraph', 'splitting', false ); diff --git a/projects/packages/forms/src/blocks/contact-form/util/caret.js b/projects/packages/forms/src/blocks/contact-form/util/caret.js index 74cb11552290f..253f0498d235d 100644 --- a/projects/packages/forms/src/blocks/contact-form/util/caret.js +++ b/projects/packages/forms/src/blocks/contact-form/util/caret.js @@ -3,7 +3,7 @@ * From https://gist.github.com/loilo/f873a88631e660c59a1d5ab757ca9b1e * * @param {HTMLElement} target - Contenteditable element of which to get the caret position - * @returns {number} The caret position + * @return {number} The caret position */ export const getCaretPosition = target => { const sel = target.ownerDocument.defaultView.getSelection(); @@ -20,3 +20,24 @@ export const getCaretPosition = target => { return preCaretRange.toString().length; }; + +/** + * Move the caret position in an active contenteditable element to the end + * + * @param {HTMLElement} target - Contenteditable element of which to move the caret + */ +export const moveCaretToEnd = target => { + if ( 'undefined' === typeof window ) { + return; + } + + // Add the contenteditable element to a new selection and collapse it to the end + const range = document.createRange(); + range.selectNodeContents( target ); + range.collapse( false ); + + // Clear the window selection object and add the new selection + const selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange( range ); +}; diff --git a/projects/packages/forms/src/blocks/contact-form/util/plugin-management.js b/projects/packages/forms/src/blocks/contact-form/util/plugin-management.js index cb69803d47e85..566c0b80e7619 100644 --- a/projects/packages/forms/src/blocks/contact-form/util/plugin-management.js +++ b/projects/packages/forms/src/blocks/contact-form/util/plugin-management.js @@ -4,7 +4,7 @@ import apiFetch from '@wordpress/api-fetch'; /** * Returns a list of all active plugins on the site. * - * @returns {Promise} Resolves to a list of plugins, or reject if not retrievable (like on a wpcom simple site or a site running an older version of WP) + * @return {Promise} Resolves to a list of plugins, or reject if not retrievable (like on a wpcom simple site or a site running an older version of WP) */ export async function getPlugins() { // Bail early on WordPress.com Simple sites. @@ -26,7 +26,7 @@ export async function getPlugins() { * Install and activate a plugin from the WordPress.org plugin directory. * * @param {string} slug - The slug of the plugin we want to activate. - * @returns {Promise} Resolves to true if the plugin has been successfully activated, or reject. + * @return {Promise} Resolves to true if the plugin has been successfully activated, or reject. */ export async function installAndActivatePlugin( slug ) { // Bail early on WordPress.com Simple sites. @@ -54,7 +54,7 @@ export async function installAndActivatePlugin( slug ) { * Activate a plugin from the WordPress.org plugin directory. * * @param {string} pluginFile - The plugin long slug (slug/index-file, without the .php suffix) we want to activate. - * @returns {Promise} Resolves to true if the plugin has been successfully activated, or reject. + * @return {Promise} Resolves to true if the plugin has been successfully activated, or reject. */ export async function activatePlugin( pluginFile ) { // Bail early on WordPress.com Simple sites. diff --git a/projects/packages/forms/src/blocks/contact-form/util/register-jetpack-block.js b/projects/packages/forms/src/blocks/contact-form/util/register-jetpack-block.js index b37c4576a9404..7cb638afda301 100644 --- a/projects/packages/forms/src/blocks/contact-form/util/register-jetpack-block.js +++ b/projects/packages/forms/src/blocks/contact-form/util/register-jetpack-block.js @@ -9,11 +9,11 @@ import { addFilter } from '@wordpress/hooks'; /** * Registers a gutenberg block if the availability requirements are met. * - * @param {string} name - The block's name. - * @param {object} settings - The block's settings. - * @param {object} childBlocks - The block's child blocks. - * @param {boolean} prefix - Should this block be prefixed with `jetpack/`? - * @returns {object|boolean} Either false if the block is not available, or the results of `registerBlockType` + * @param {string} name - The block's name. + * @param {object} settings - The block's settings. + * @param {object} childBlocks - The block's child blocks. + * @param {boolean} prefix - Should this block be prefixed with `jetpack/`? + * @return {object|boolean} Either false if the block is not available, or the results of `registerBlockType` */ export default function registerJetpackBlock( name, settings, childBlocks = [], prefix = true ) { const { available, details, unavailableReason } = getJetpackExtensionAvailability( name ); diff --git a/projects/packages/forms/src/class-jetpack-forms.php b/projects/packages/forms/src/class-jetpack-forms.php index d1f66f12a7f6d..718faa4df98df 100644 --- a/projects/packages/forms/src/class-jetpack-forms.php +++ b/projects/packages/forms/src/class-jetpack-forms.php @@ -15,7 +15,7 @@ */ class Jetpack_Forms { - const PACKAGE_VERSION = '0.32.9-alpha'; + const PACKAGE_VERSION = '0.32.11'; /** * Load the contact form module. diff --git a/projects/packages/forms/src/contact-form/images/blank-screen-akismet.png b/projects/packages/forms/src/contact-form/images/blank-screen-akismet.png index a4ba1e2d68b34..29cfe93ac954c 100644 Binary files a/projects/packages/forms/src/contact-form/images/blank-screen-akismet.png and b/projects/packages/forms/src/contact-form/images/blank-screen-akismet.png differ diff --git a/projects/packages/forms/src/contact-form/images/blank-screen-button.png b/projects/packages/forms/src/contact-form/images/blank-screen-button.png index 58dfa26b6c96f..47d2fc0449ec0 100644 Binary files a/projects/packages/forms/src/contact-form/images/blank-screen-button.png and b/projects/packages/forms/src/contact-form/images/blank-screen-button.png differ diff --git a/projects/packages/forms/src/contact-form/images/grunion-form-2x.png b/projects/packages/forms/src/contact-form/images/grunion-form-2x.png index 824d85a316c69..20c28754ca24e 100644 Binary files a/projects/packages/forms/src/contact-form/images/grunion-form-2x.png and b/projects/packages/forms/src/contact-form/images/grunion-form-2x.png differ diff --git a/projects/packages/forms/src/contact-form/images/grunion-form.png b/projects/packages/forms/src/contact-form/images/grunion-form.png index f4a0cc1d64f87..35e0b6ae6c1b1 100644 Binary files a/projects/packages/forms/src/contact-form/images/grunion-form.png and b/projects/packages/forms/src/contact-form/images/grunion-form.png differ diff --git a/projects/packages/forms/src/contact-form/images/grunion-remove-field-2x.png b/projects/packages/forms/src/contact-form/images/grunion-remove-field-2x.png index bfbca5edfde9b..261de1e22bd50 100644 Binary files a/projects/packages/forms/src/contact-form/images/grunion-remove-field-2x.png and b/projects/packages/forms/src/contact-form/images/grunion-remove-field-2x.png differ diff --git a/projects/packages/forms/src/contact-form/images/grunion-remove-field-hover-2x.png b/projects/packages/forms/src/contact-form/images/grunion-remove-field-hover-2x.png index dca39da947524..c870243518067 100644 Binary files a/projects/packages/forms/src/contact-form/images/grunion-remove-field-hover-2x.png and b/projects/packages/forms/src/contact-form/images/grunion-remove-field-hover-2x.png differ diff --git a/projects/packages/forms/src/contact-form/images/grunion-remove-option-2x.png b/projects/packages/forms/src/contact-form/images/grunion-remove-option-2x.png index 4272442c51396..2ea0273f0d6a1 100644 Binary files a/projects/packages/forms/src/contact-form/images/grunion-remove-option-2x.png and b/projects/packages/forms/src/contact-form/images/grunion-remove-option-2x.png differ diff --git a/projects/packages/forms/src/contact-form/images/grunion-remove-option-hover-2x.png b/projects/packages/forms/src/contact-form/images/grunion-remove-option-hover-2x.png index 210de1b315e95..74f2d392a1b1b 100644 Binary files a/projects/packages/forms/src/contact-form/images/grunion-remove-option-hover-2x.png and b/projects/packages/forms/src/contact-form/images/grunion-remove-option-hover-2x.png differ diff --git a/projects/packages/forms/src/contact-form/images/grunion-remove-option-hover.gif b/projects/packages/forms/src/contact-form/images/grunion-remove-option-hover.gif index 9098b0656b758..e7b24f78823f3 100644 Binary files a/projects/packages/forms/src/contact-form/images/grunion-remove-option-hover.gif and b/projects/packages/forms/src/contact-form/images/grunion-remove-option-hover.gif differ diff --git a/projects/packages/forms/src/contact-form/images/grunion-remove-option.gif b/projects/packages/forms/src/contact-form/images/grunion-remove-option.gif index ec4916634a0db..d9637bf6e5ab4 100644 Binary files a/projects/packages/forms/src/contact-form/images/grunion-remove-option.gif and b/projects/packages/forms/src/contact-form/images/grunion-remove-option.gif differ diff --git a/projects/packages/forms/src/contact-form/images/twitter-dark.png b/projects/packages/forms/src/contact-form/images/twitter-dark.png index 0bab6b4f8b7ad..7582bd7f2dfe2 100644 Binary files a/projects/packages/forms/src/contact-form/images/twitter-dark.png and b/projects/packages/forms/src/contact-form/images/twitter-dark.png differ diff --git a/projects/packages/forms/src/dashboard/components/switch-transition/index.js b/projects/packages/forms/src/dashboard/components/switch-transition/index.js index 9f8fe81a9b632..f202ea046bd5a 100644 --- a/projects/packages/forms/src/dashboard/components/switch-transition/index.js +++ b/projects/packages/forms/src/dashboard/components/switch-transition/index.js @@ -9,12 +9,12 @@ import { CSSTransition, TransitionGroup } from 'react-transition-group'; * the old and the current version of the component, which adds some complexity. * This component aims to encapsulate that and provide a straight forward interface for switch transtions. * - * @param {object} props - Props passed down to the wrapper div. - * @param {string} props.activeViewKey - Identifier for the currently active view. - * @param {Array} props.children - Children. - * @param {number} props.duration - Duration of the transition. - * @param {object} ref - Reference to the currently active wrapper element. - * @returns {Element} React element. + * @param {object} props - Props passed down to the wrapper div. + * @param {string} props.activeViewKey - Identifier for the currently active view. + * @param {Array} props.children - Children. + * @param {number} props.duration - Duration of the transition. + * @param {object} ref - Reference to the currently active wrapper element. + * @return {Element} React element. */ const SwitchTransition = ( { activeViewKey, children, duration, ...props }, ref ) => { const [ viewKey, setViewKey ] = useState( activeViewKey ); diff --git a/projects/packages/forms/src/dashboard/data/responses.js b/projects/packages/forms/src/dashboard/data/responses.js index ed6cffb3da74b..cec436af09865 100644 --- a/projects/packages/forms/src/dashboard/data/responses.js +++ b/projects/packages/forms/src/dashboard/data/responses.js @@ -13,7 +13,7 @@ import { isNil, mapValues, omitBy, pick } from 'lodash'; * @param {string} query.status - Post status. * @param {number} query.limit - Maximum results limit. * @param {number} query.offset - Offset for results paging. - * @returns {Promise} Request promise. + * @return {Promise} Request promise. */ export const fetchResponses = query => { const queryString = new URLSearchParams( @@ -34,9 +34,9 @@ export const fetchResponses = query => { /** * Performs a bulk action on responses. * - * @param {Array} responseIds - The list of responses to be updated. - * @param {string} action - The action to be executed. - * @returns {Promise} Request promise. + * @param {Array} responseIds - The list of responses to be updated. + * @param {string} action - The action to be executed. + * @return {Promise} Request promise. */ export const doBulkAction = ( responseIds, action ) => { return apiFetch( { diff --git a/projects/packages/forms/src/dashboard/inbox/bulk-actions-menu.js b/projects/packages/forms/src/dashboard/inbox/bulk-actions-menu.js index 1862eb4b76fad..1c602fd4876d1 100644 --- a/projects/packages/forms/src/dashboard/inbox/bulk-actions-menu.js +++ b/projects/packages/forms/src/dashboard/inbox/bulk-actions-menu.js @@ -19,7 +19,7 @@ import { useFeedbackQuery } from './use-feedback-query'; * Custom temporary handler for check-for-spam action based on grunion_check_for_spam. * * @param {number} offset - Offset for the query. - * @returns {Promise} Promise that resolves once checking for spam has finished. + * @return {Promise} Promise that resolves once checking for spam has finished. */ const checkForSpam = ( offset = 0 ) => { const limit = 100; diff --git a/projects/packages/forms/src/dashboard/inbox/export-modal/util.js b/projects/packages/forms/src/dashboard/inbox/export-modal/util.js index b41ef0a178824..c90103247fe59 100644 --- a/projects/packages/forms/src/dashboard/inbox/export-modal/util.js +++ b/projects/packages/forms/src/dashboard/inbox/export-modal/util.js @@ -3,11 +3,11 @@ import { config } from '../../'; /** * Makes an export request. * - * @param {string} action - Action name. - * @param {string} nonceName - Nonce name. - * @param {object} query - Query parameters. - * @param {Array} selection - Selected IDs. - * @returns {Promise} - Request promise. + * @param {string} action - Action name. + * @param {string} nonceName - Nonce name. + * @param {object} query - Query parameters. + * @param {Array} selection - Selected IDs. + * @return {Promise} - Request promise. */ export const exportResponses = ( action, nonceName, query, selection ) => { const data = new FormData(); diff --git a/projects/packages/forms/src/dashboard/state/actions.js b/projects/packages/forms/src/dashboard/state/actions.js index a0966fca5a6e7..5f95e6450467c 100644 --- a/projects/packages/forms/src/dashboard/state/actions.js +++ b/projects/packages/forms/src/dashboard/state/actions.js @@ -18,7 +18,7 @@ import { * * @param {Function} apply - The function to apply the dispatch to. * @param {Array} args - Arguments to be passed onto the function. - * @returns {object} Action object. + * @return {object} Action object. */ export const dispatchAsync = ( apply, args = [] ) => ( { type: ASYNC_ROUTINE_DISPATCH, @@ -29,11 +29,11 @@ export const dispatchAsync = ( apply, args = [] ) => ( { /** * Handles the entire flow for fetching responses asynchronously. * - * @param {object} query - Query. - * @param {object} options - Options. + * @param {object} query - Query. + * @param {object} options - Options. * @param {boolean} options.append - Whether to append the responses to the existing set or replace it. Defaults to false. - * @yields {object} Action object. - * @returns {object} Action object. + * @yield {object} Action object. + * @return {object} Action object. */ export function* fetchResponses( query, options = {} ) { yield { type: RESPONSES_FETCH, append: options.append, query }; @@ -60,9 +60,9 @@ export function* fetchResponses( query, options = {} ) { /** * Removes the given responses from the current set. * - * @param {Array} responseIds - Response IDs to remove. - * @param {string} status - Current of the responses to be removed. - * @returns {object} Action object. + * @param {Array} responseIds - Response IDs to remove. + * @param {string} status - Current of the responses to be removed. + * @return {object} Action object. */ export const removeResponses = ( responseIds, status ) => ( { type: RESPONSES_REMOVE, @@ -73,8 +73,8 @@ export const removeResponses = ( responseIds, status ) => ( { /** * Updates the currently selected responses. * - * @param {Array} selectedResponses - Selected responses. - * @returns {object} Action object. + * @param {Array} selectedResponses - Selected responses. + * @return {object} Action object. */ export const selectResponses = selectedResponses => ( { type: RESPONSES_SELECTION_SET, @@ -85,7 +85,7 @@ export const selectResponses = selectedResponses => ( { * Set the application loading state. * * @param {boolean} loading - The loading state. - * @returns {object} Action object. + * @return {object} Action object. */ export const setLoading = loading => ( { type: RESPONSES_LOADING_SET, @@ -96,7 +96,7 @@ export const setLoading = loading => ( { * Add to current tab total numbers. * * @param {object} tabTotals - Totals to add. - * @returns {object} Action object, + * @return {object} Action object, */ export const addTabTotals = tabTotals => ( { type: RESPONSES_TAB_TOTALS_ADD, diff --git a/projects/packages/forms/tools/webpack.config.dashboard.js b/projects/packages/forms/tools/webpack.config.dashboard.js index c5103a03c2a33..62d220bb5de85 100644 --- a/projects/packages/forms/tools/webpack.config.dashboard.js +++ b/projects/packages/forms/tools/webpack.config.dashboard.js @@ -8,12 +8,8 @@ const jetpackWebpackConfig = require( '@automattic/jetpack-webpack-config/webpac module.exports = { mode: jetpackWebpackConfig.mode, entry: { - [ 'jetpack-forms-dashboard' ]: path.join( __dirname, '..', 'src/dashboard/index.js' ), - [ 'jetpack-forms-dashboard.wpcom' ]: path.join( - __dirname, - '..', - 'src/dashboard/style.wpcom.scss' - ), + 'jetpack-forms-dashboard': path.join( __dirname, '..', 'src/dashboard/index.js' ), + 'jetpack-forms-dashboard.wpcom': path.join( __dirname, '..', 'src/dashboard/style.wpcom.scss' ), }, output: { ...jetpackWebpackConfig.output, diff --git a/projects/packages/google-analytics/CHANGELOG.md b/projects/packages/google-analytics/CHANGELOG.md index d3fac1bf8509d..f7432529f9d67 100644 --- a/projects/packages/google-analytics/CHANGELOG.md +++ b/projects/packages/google-analytics/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.3] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## [0.2.2] - 2024-07-01 ### Fixed - Fix the 'missing array key' notice. [#38111] @@ -23,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Copy the code from the Jetpack module into the package. [#37184] - Migrate unit tests from the Jetpack module. [#37246] +[0.2.3]: https://github.com/Automattic/jetpack-google-analytics/compare/v0.2.2...v0.2.3 [0.2.2]: https://github.com/Automattic/jetpack-google-analytics/compare/v0.2.1...v0.2.2 [0.2.1]: https://github.com/Automattic/jetpack-google-analytics/compare/v0.2.0...v0.2.1 [0.2.0]: https://github.com/Automattic/jetpack-google-analytics/compare/v0.1.0...v0.2.0 diff --git a/projects/packages/google-analytics/composer.json b/projects/packages/google-analytics/composer.json index 0c3966e0d2e42..c66cd4d920a6f 100644 --- a/projects/packages/google-analytics/composer.json +++ b/projects/packages/google-analytics/composer.json @@ -8,7 +8,7 @@ "automattic/jetpack-status": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "^0.4.2" }, diff --git a/projects/packages/google-analytics/package.json b/projects/packages/google-analytics/package.json index 2534b897be0cc..75c1b1e2b8baa 100644 --- a/projects/packages/google-analytics/package.json +++ b/projects/packages/google-analytics/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-google-analytics", - "version": "0.2.2", + "version": "0.2.3", "description": "Set up Google Analytics without touching a line of code.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/google-analytics/#readme", "bugs": { diff --git a/projects/packages/google-analytics/src/class-ga-manager.php b/projects/packages/google-analytics/src/class-ga-manager.php index acc204bc361ba..46be2075d06f7 100644 --- a/projects/packages/google-analytics/src/class-ga-manager.php +++ b/projects/packages/google-analytics/src/class-ga-manager.php @@ -18,7 +18,7 @@ */ class GA_Manager { - const PACKAGE_VERSION = '0.2.2'; + const PACKAGE_VERSION = '0.2.3'; /** * Jetpack_Google_Analytics singleton instance. diff --git a/projects/packages/masterbar/changelog/renovate-wordpress-monorepo b/projects/packages/ignorefile/changelog/renovate-yoast-phpunit-polyfills-1.x similarity index 100% rename from projects/packages/masterbar/changelog/renovate-wordpress-monorepo rename to projects/packages/ignorefile/changelog/renovate-yoast-phpunit-polyfills-1.x diff --git a/projects/packages/ignorefile/changelog/try-no-version-bumps-in-trunk b/projects/packages/ignorefile/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..91efe85c55e06 --- /dev/null +++ b/projects/packages/ignorefile/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/packages/ignorefile/composer.json b/projects/packages/ignorefile/composer.json index 456311fb0aec6..3b0a837703bd4 100644 --- a/projects/packages/ignorefile/composer.json +++ b/projects/packages/ignorefile/composer.json @@ -8,7 +8,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "autoload": { "classmap": [ @@ -41,7 +41,7 @@ }, "autotagger": true, "branch-alias": { - "dev-trunk": "2.1.x-dev" + "dev-trunk": "2.0.x-dev" } } } diff --git a/projects/packages/image-cdn/CHANGELOG.md b/projects/packages/image-cdn/CHANGELOG.md index 475b4acc096e0..b658e82aba942 100644 --- a/projects/packages/image-cdn/CHANGELOG.md +++ b/projects/packages/image-cdn/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.4.7] - 2024-08-29 +### Changed +- Rely on WordPress HTML API to parse HTML instead of Regex [#32700] + +## [0.4.6] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + +## [0.4.5] - 2024-08-19 +### Fixed +- Lossless image optimization for images (should improve performance with no visible changes). [#38750] + ## [0.4.4] - 2024-08-05 ### Changed - Do not serve media from Amazon CDN from Jetpack's CDN. [#38682] @@ -106,6 +118,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add image CDN package. [#29561] +[0.4.7]: https://github.com/Automattic/jetpack-image-cdn/compare/v0.4.6...v0.4.7 +[0.4.6]: https://github.com/Automattic/jetpack-image-cdn/compare/v0.4.5...v0.4.6 +[0.4.5]: https://github.com/Automattic/jetpack-image-cdn/compare/v0.4.4...v0.4.5 [0.4.4]: https://github.com/Automattic/jetpack-image-cdn/compare/v0.4.3...v0.4.4 [0.4.3]: https://github.com/Automattic/jetpack-image-cdn/compare/v0.4.2...v0.4.3 [0.4.2]: https://github.com/Automattic/jetpack-image-cdn/compare/v0.4.1...v0.4.2 diff --git a/projects/packages/image-cdn/composer.json b/projects/packages/image-cdn/composer.json index 03daecc74b696..54e1336945dbe 100644 --- a/projects/packages/image-cdn/composer.json +++ b/projects/packages/image-cdn/composer.json @@ -10,7 +10,7 @@ }, "require-dev": { "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "suggest": { diff --git a/projects/packages/image-cdn/src/class-image-cdn.php b/projects/packages/image-cdn/src/class-image-cdn.php index 2b9108b7ed17a..13921df4355a9 100644 --- a/projects/packages/image-cdn/src/class-image-cdn.php +++ b/projects/packages/image-cdn/src/class-image-cdn.php @@ -12,7 +12,7 @@ */ final class Image_CDN { - const PACKAGE_VERSION = '0.4.4'; + const PACKAGE_VERSION = '0.4.7'; /** * Singleton. @@ -333,297 +333,360 @@ public static function parse_dimensions_from_filename( $src ) { * @return string */ public static function filter_the_content( $content ) { - $images = self::parse_images_from_html( $content ); + static $image_tags = array( 'IMG', 'AMP-IMG', 'AMP-ANIM' ); + $content_width = null; + $image_sizes = null; + $upload_dir = null; + $processor = new \WP_HTML_Tag_Processor( $content ); + $nearest_preceding_href = null; + + // Visit every image-containing tag in the document. + while ( $processor->next_tag( array( 'tag_closers' => 'visit' ) ) ) { + /* + * When an image is wrapped by an A element, the goal is to modify + * both elements. Thus it's important to track links that may be + * opened before reaching any image. In normative HTML this detection + * is reliable enough, but it could be confused in cases where other + * tags implicitly close the A. If this additional reliability is + * required, replace the Tag Processor with the HTML Processor. + */ + if ( 'A' === $processor->get_tag() ) { + // If this is a closing tag the attribute will be `null`. + $nearest_preceding_href = $processor->get_attribute( 'href' ); + $processor->set_bookmark( 'link' ); + continue; + } - if ( ! empty( $images ) ) { - $content_width = Image_CDN_Core::get_jetpack_content_width(); + /* + * Only examine tags that are considered an image. If encountering + * a closing tag then this is not the image being sought. + */ + if ( $processor->is_tag_closer() || ! in_array( $processor->get_tag(), $image_tags, true ) ) { + continue; + } - $image_sizes = self::image_sizes(); + $processor->set_bookmark( 'image' ); - $upload_dir = wp_get_upload_dir(); + /* + * At this point a target image has been found. Initialize the + * shared data and then process each image as it appears. + */ + if ( null === $content_width ) { + $content_width = Image_CDN_Core::get_jetpack_content_width(); + $image_sizes = self::image_sizes(); + $upload_dir = wp_get_upload_dir(); + } - foreach ( $images[0] as $index => $tag ) { - // Default to resize, though fit may be used in certain cases where a dimension cannot be ascertained. - $transform = 'resize'; + /* + * To preserve legacy behaviors for filtering by third-party plugins, + * create a normalized HTML string representing the tag. This will + * present all attributes as double-quoted attributes and include at + * most one copy of each attribute, escaping all values appropriately. + */ + $tag_name = strtolower( $processor->get_tag() ); + $tag = new \WP_HTML_Tag_Processor( "<{$tag_name}>" ); + $tag->next_tag(); + foreach ( $processor->get_attribute_names_with_prefix( '' ) ?? array() as $name ) { + $tag->set_attribute( $name, $processor->get_attribute( $name ) ); + } + $tag = $tag->get_updated_html(); - // Start with a clean attachment ID each time. - $attachment_id = false; + // Default to resize, though fit may be used in certain cases where a dimension cannot be ascertained. + $transform = 'resize'; - // Flag if we need to munge a fullsize URL. - $fullsize_url = false; + // Flag if we need to munge a fullsize URL. + $fullsize_url = false; - // Identify image source. - $src_orig = $images['img_url'][ $index ]; - $src = $src_orig; + // Identify image source. + $src_orig = $processor->get_attribute( 'src' ); + $src = $src_orig; - /** - * Allow specific images to be skipped by Photon. - * - * @module photon - * - * @since 2.0.3 - * - * @param bool false Should Photon ignore this image. Default to false. - * @param string $src Image URL. - * @param string|array|null $tag Image Tag (Image HTML output) or array of image details for srcset. - */ - if ( apply_filters( 'jetpack_photon_skip_image', false, $src, $tag ) ) { - continue; - } - - // Support Automattic's Lazy Load plugin. - // Can't modify $tag yet as we need unadulterated version later. - if ( preg_match( '#data-lazy-src=["\'](.+?)["\']#i', $images['img_tag'][ $index ], $lazy_load_src ) ) { - $placeholder_src_orig = $src; - $placeholder_src = $placeholder_src_orig; - $src_orig = $lazy_load_src[1]; - $src = $src_orig; - } elseif ( preg_match( '#data-lazy-original=["\'](.+?)["\']#i', $images['img_tag'][ $index ], $lazy_load_src ) ) { - $placeholder_src_orig = $src; - $placeholder_src = $placeholder_src_orig; - $src_orig = $lazy_load_src[1]; - $src = $src_orig; - } - - // Check if image URL should be used with Photon. - if ( self::validate_image_url( $src ) ) { - // Find the width and height attributes. - $width = false; - $height = false; - - // First, check the image tag. Note we only check for pixel sizes now; HTML4 percentages have never been correctly - // supported, so we stopped pretending to support them in JP 9.1.0. - if ( preg_match( '#[\s"\']width=["\']?([\d%]+)["\']?#i', $images['img_tag'][ $index ], $width_string ) ) { - $width = str_contains( $width_string[1], '%' ) ? false : $width_string[1]; - } + /** + * Allow specific images to be skipped by Photon. + * + * @module photon + * + * @since 2.0.3 + * + * @param bool false Should Photon ignore this image. Default to false. + * @param string $src Image URL. + * @param string|array|null $tag Image Tag (Image HTML output) or array of image details for srcset. + */ + if ( apply_filters( 'jetpack_photon_skip_image', false, $src, $tag ) ) { + continue; + } - if ( preg_match( '#[\s"\']height=["\']?([\d%]+)["\']?#i', $images['img_tag'][ $index ], $height_string ) ) { - $height = str_contains( $height_string[1], '%' ) ? false : $height_string[1]; - } + $data_lazy_src = $processor->get_attribute( 'data-lazy-src' ); + $data_lazy_original = $processor->get_attribute( 'data-lazy-original' ); - // Detect WP registered image size from HTML class. - if ( preg_match( '#class=["\']?[^"\']*size-([^"\'\s]+)[^"\']*["\']?#i', $images['img_tag'][ $index ], $size ) ) { - $size = array_pop( $size ); + $source_type = 'src'; + $chosen_data_src = null; - if ( false === $width && false === $height && 'full' !== $size && array_key_exists( $size, $image_sizes ) ) { - $width = (int) $image_sizes[ $size ]['width']; - $height = (int) $image_sizes[ $size ]['height']; - $transform = $image_sizes[ $size ]['crop'] ? 'resize' : 'fit'; - } - } else { - unset( $size ); - } + // Prefer a URL from the `data-lazy-src` attribute. + if ( null === $chosen_data_src && is_string( $data_lazy_src ) && ! empty( $data_lazy_src ) ) { + $source_type = 'data-lazy-src'; + $chosen_data_src = $data_lazy_src; + } - // WP Attachment ID, if uploaded to this site. - if ( - preg_match( '#class=["\']?[^"\']*wp-image-([\d]+)[^"\']*["\']?#i', $images['img_tag'][ $index ], $attachment_id ) && - str_starts_with( $src, $upload_dir['baseurl'] ) && - /** - * Filter whether an image using an attachment ID in its class has to be uploaded to the local site to go through Photon. - * - * @module photon - * - * @since 2.0.3 - * - * @param bool false Was the image uploaded to the local site. Default to false. - * @param array $args { - * Array of image details. - * - * @type $src Image URL. - * @type tag Image tag (Image HTML output). - * @type $images Array of information about the image. - * @type $index Image index. - * } - */ - apply_filters( 'jetpack_photon_image_is_local', false, compact( 'src', 'tag', 'images', 'index' ) ) - ) { - $attachment_id = (int) array_pop( $attachment_id ); - - if ( $attachment_id ) { - $attachment = get_post( $attachment_id ); - - // Basic check on returned post object. - if ( is_object( $attachment ) && ! is_wp_error( $attachment ) && 'attachment' === $attachment->post_type ) { - $src_per_wp = wp_get_attachment_image_src( $attachment_id, isset( $size ) ? $size : 'full' ); - - if ( self::validate_image_url( $src_per_wp[0] ) ) { - $src = $src_per_wp[0]; - $fullsize_url = true; - - // Prevent image distortion if a detected dimension exceeds the image's natural dimensions. - if ( ( false !== $width && $width > $src_per_wp[1] ) || ( false !== $height && $height > $src_per_wp[2] ) ) { - $width = false === $width ? false : min( $width, $src_per_wp[1] ); - $height = false === $height ? false : min( $height, $src_per_wp[2] ); - } - - // If no width and height are found, max out at source image's natural dimensions. - // Otherwise, respect registered image sizes' cropping setting. - if ( false === $width && false === $height ) { - $width = $src_per_wp[1]; - $height = $src_per_wp[2]; - $transform = 'fit'; - } elseif ( isset( $size ) && array_key_exists( $size, $image_sizes ) && isset( $image_sizes[ $size ]['crop'] ) ) { - $transform = (bool) $image_sizes[ $size ]['crop'] ? 'resize' : 'fit'; - } - } - } else { - unset( $attachment_id ); - unset( $attachment ); - } - } - } + // Fall back to a URL from the `data-lazy-original` attribute. + if ( null === $chosen_data_src && is_string( $data_lazy_original ) && ! empty( $data_lazy_original ) ) { + $source_type = 'data-lazy-original'; + $chosen_data_src = $data_lazy_original; + } - // If image tag lacks width and height arguments, try to determine from strings WP appends to resized image filenames. - if ( false === $width && false === $height ) { - list( $width, $height ) = self::parse_dimensions_from_filename( $src ); - } + // Update the src if one was provided in the `data-lazy-` attributes. + if ( 'src' !== $source_type ) { + $placeholder_src_orig = $src; + $placeholder_src = $placeholder_src_orig; + $src_orig = $chosen_data_src; + $src = $src_orig; + } - $width_orig = $width; - $height_orig = $height; - $transform_orig = $transform; + // Check if image URL should be used with Photon. + if ( self::validate_image_url( $src ) ) { + $width = $processor->get_attribute( 'width' ); + $height = $processor->get_attribute( 'height' ); + + // First, check the image tag. Note we only check for pixel sizes now; HTML4 percentages have never been correctly + // supported, so we stopped pretending to support them in JP 9.1.0. + if ( ! is_string( $width ) || str_contains( $width, '%' ) ) { + $width = false; + } - // If width is available, constrain to $content_width. - if ( false !== $width && is_numeric( $content_width ) && $width > $content_width ) { - if ( false !== $height ) { - $height = round( ( $content_width * $height ) / $width ); - } - $width = $content_width; - } + if ( ! is_string( $height ) || str_contains( $height, '%' ) ) { + $height = false; + } - // Set a width if none is found and $content_width is available. - // If width is set in this manner and height is available, use `fit` instead of `resize` to prevent skewing. - if ( false === $width && is_numeric( $content_width ) ) { - $width = (int) $content_width; + $needs_sizing = false === $width && false === $height; + $size = null; - if ( false !== $height ) { - $transform = 'fit'; + if ( $needs_sizing ) { + // Find the first CSS class listed with a prefix of `size-`, e.g. `size-full-width` + foreach ( $processor->class_list() ?? array() as $class_name ) { + if ( str_starts_with( $class_name, 'size-' ) ) { + $size = substr( $class_name, strlen( 'size-' ) ); + break; } } + } - // Detect if image source is for a custom-cropped thumbnail and prevent further URL manipulation. - if ( ! $fullsize_url && preg_match_all( '#-e[a-z0-9]+(-\d+x\d+)?\.(' . implode( '|', self::$extensions ) . '){1}$#i', basename( $src ), $filename ) ) { - $fullsize_url = true; - } - - // Build URL, first maybe removing WP's resized string so we pass the original image to Photon. - if ( ! $fullsize_url && str_starts_with( $src, $upload_dir['baseurl'] ) ) { - $src = self::strip_image_dimensions_maybe( $src ); - } - - // Build array of Photon args and expose to filter before passing to Photon URL function. - $args = array(); + if ( $needs_sizing && 'full' !== $size && is_string( $size ) && isset( $image_sizes[ $size ] ) && is_array( $image_sizes[ $size ] ) ) { + $width = (int) $image_sizes[ $size ]['width']; + $height = (int) $image_sizes[ $size ]['height']; + $transform = $image_sizes[ $size ]['crop'] ? 'resize' : 'fit'; + } else { + unset( $size ); + } - if ( false !== $width && false !== $height ) { - $args[ $transform ] = $width . ',' . $height; - } elseif ( false !== $width ) { - $args['w'] = $width; - } elseif ( false !== $height ) { - $args['h'] = $height; + // WP Attachment ID, if uploaded to this site. + $attachment_id = null; + foreach ( $processor->class_list() ?? array() as $class_name ) { + if ( str_starts_with( $class_name, 'wp-image-' ) ) { + $attachment_id = substr( $class_name, strlen( 'wp-image-' ) ); + break; } + } + // These values have not been used for a very long time, but removing them could break something. + $images = array(); + $index = 0; + if ( + $attachment_id && + preg_match( '#^[1-9][0-9]*$#', $attachment_id ) && + is_array( $upload_dir ) && + str_starts_with( $src, $upload_dir['baseurl'] ) && /** - * Filter the array of Photon arguments added to an image when it goes through Photon. - * By default, only includes width and height values. - * - * @see https://developer.wordpress.com/docs/photon/api/ + * Filter whether an image using an attachment ID in its class has to be uploaded to the local site to go through Photon. * * @module photon * - * @since 2.0.0 + * @since 2.0.3 * - * @param array $args Array of Photon Arguments. - * @param array $details { - * Array of image details. + * @param bool false Was the image uploaded to the local site. Default to false. + * @param array $args { + * Array of image details. * - * @type string $tag Image tag (Image HTML output). - * @type string $src Image URL. - * @type string $src_orig Original Image URL. - * @type int|false $width Image width. - * @type int|false $height Image height. - * @type int|false $width_orig Original image width before constrained by content_width. - * @type int|false $height_orig Original Image height before constrained by content_width. - * @type string $transform Transform. - * @type string $transform_orig Original transform before constrained by content_width. + * @type $src Image URL. + * @type tag Image tag (Image HTML output). * } */ - $args = apply_filters( 'jetpack_photon_post_image_args', $args, compact( 'tag', 'src', 'src_orig', 'width', 'height', 'width_orig', 'height_orig', 'transform', 'transform_orig' ) ); + apply_filters( 'jetpack_photon_image_is_local', false, compact( 'src', 'tag', 'images', 'index' ) ) + ) { + $attachment_id = (int) $attachment_id; + $attachment = get_post( $attachment_id ); + + // Basic check on returned post object. + if ( is_object( $attachment ) && ! is_wp_error( $attachment ) && 'attachment' === $attachment->post_type ) { + $src_per_wp = wp_get_attachment_image_src( $attachment_id, isset( $size ) ? $size : 'full' ); + + if ( self::validate_image_url( $src_per_wp[0] ) ) { + $src = $src_per_wp[0]; + $fullsize_url = true; + + // Prevent image distortion if a detected dimension exceeds the image's natural dimensions. + if ( ( false !== $width && $width > $src_per_wp[1] ) || ( false !== $height && $height > $src_per_wp[2] ) ) { + $width = false === $width ? false : min( $width, $src_per_wp[1] ); + $height = false === $height ? false : min( $height, $src_per_wp[2] ); + } - $photon_url = Image_CDN_Core::cdn_url( $src, $args ); + // If no width and height are found, max out at source image's natural dimensions. + // Otherwise, respect registered image sizes' cropping setting. + if ( false === $width && false === $height ) { + $width = $src_per_wp[1]; + $height = $src_per_wp[2]; + $transform = 'fit'; + } elseif ( isset( $size ) && is_array( $image_sizes ) && array_key_exists( $size, $image_sizes ) && isset( $image_sizes[ $size ]['crop'] ) ) { + $transform = $image_sizes[ $size ]['crop'] ? 'resize' : 'fit'; + } + } + } else { + unset( $attachment_id ); + unset( $attachment ); + } + } - // Modify image tag if Photon function provides a URL - // Ensure changes are only applied to the current image by copying and modifying the matched tag, then replacing the entire tag with our modified version. - if ( $src !== $photon_url ) { - $new_tag = $tag; + // If image tag lacks width and height arguments, try to determine from strings WP appends to resized image filenames. + if ( false === $width && false === $height ) { + list( $width, $height ) = self::parse_dimensions_from_filename( $src ); + } - // If present, replace the link href with a Photoned URL for the full-size image. - if ( ! empty( $images['link_url'][ $index ] ) && self::validate_image_url( $images['link_url'][ $index ] ) ) { - $new_tag = preg_replace( '#(href=["|\'])' . preg_quote( $images['link_url'][ $index ], '#' ) . '(["|\'])#i', '\1' . Image_CDN_Core::cdn_url( $images['link_url'][ $index ] ) . '\2', $new_tag, 1 ); - } + $width_orig = $width; + $height_orig = $height; + $transform_orig = $transform; - // Supplant the original source value with our Photon URL. - $photon_url = esc_url( $photon_url ); - $new_tag = str_replace( $src_orig, $photon_url, $new_tag ); + // If width is available, constrain to $content_width. + if ( false !== $width && is_numeric( $content_width ) && $width > $content_width ) { + if ( false !== $height ) { + $height = round( ( $content_width * $height ) / $width ); + } + $width = $content_width; + } - // If Lazy Load is in use, pass placeholder image through Photon. - if ( isset( $placeholder_src ) && self::validate_image_url( $placeholder_src ) ) { - $placeholder_src = Image_CDN_Core::cdn_url( $placeholder_src ); + // Set a width if none is found and $content_width is available. + // If width is set in this manner and height is available, use `fit` instead of `resize` to prevent skewing. + if ( false === $width && is_numeric( $content_width ) ) { + $width = (int) $content_width; - if ( $placeholder_src !== $placeholder_src_orig ) { - $new_tag = str_replace( $placeholder_src_orig, esc_url( $placeholder_src ), $new_tag ); - } + if ( false !== $height ) { + $transform = 'fit'; + } + } - unset( $placeholder_src ); - } + // Detect if image source is for a custom-cropped thumbnail and prevent further URL manipulation. + if ( ! $fullsize_url && preg_match_all( '#-e[a-z0-9]+(-\d+x\d+)?\.(' . implode( '|', self::$extensions ) . '){1}$#i', basename( $src ), $filename ) ) { + $fullsize_url = true; + } - // If we are not transforming the image with resize, fit, or letterbox (lb), then we should remove - // the width and height arguments (including HTML4 percentages) from the image to prevent distortion. - // Even if $args['w'] and $args['h'] are present, Photon does not crop to those dimensions. Instead, - // it appears to favor height. - // - // If we are transforming the image via one of those methods, let's update the width and height attributes. - if ( empty( $args['resize'] ) && empty( $args['fit'] ) && empty( $args['lb'] ) ) { - $new_tag = preg_replace( '#(?<=\s)(width|height)=["\']?[\d%]+["\']?\s?#i', '', $new_tag ); - } else { - $resize_args = isset( $args['resize'] ) ? $args['resize'] : false; - if ( false === $resize_args ) { - $resize_args = ( ! $resize_args && isset( $args['fit'] ) ) - ? $args['fit'] - : false; - } - if ( false === $resize_args ) { - $resize_args = ( ! $resize_args && isset( $args['lb'] ) ) - ? $args['lb'] - : false; - } + // Build URL, first maybe removing WP's resized string so we pass the original image to Photon. + if ( ! $fullsize_url && is_array( $upload_dir ) && str_starts_with( $src, $upload_dir['baseurl'] ) ) { + $src = self::strip_image_dimensions_maybe( $src ); + } + + // Build array of Photon args and expose to filter before passing to Photon URL function. + $args = array(); + + if ( false !== $width && false !== $height ) { + $args[ $transform ] = $width . ',' . $height; + } elseif ( false !== $width ) { + $args['w'] = $width; + } elseif ( false !== $height ) { + $args['h'] = $height; + } + + /** + * Filter the array of Photon arguments added to an image when it goes through Photon. + * By default, only includes width and height values. + * + * @see https://developer.wordpress.com/docs/photon/api/ + * + * @module photon + * + * @since 2.0.0 + * @since 0.4.7 Passes image tag name instead of full HTML of tag. + * + * @param array $args Array of Photon Arguments. + * @param array $details { + * Array of image details. + * + * @type string $tag Image tag (Image HTML output). + * @type string $src Image URL. + * @type string $src_orig Original Image URL. + * @type int|false $width Image width. + * @type int|false $height Image height. + * @type int|false $width_orig Original image width before constrained by content_width. + * @type int|false $height_orig Original Image height before constrained by content_width. + * @type string $transform Transform. + * @type string $transform_orig Original transform before constrained by content_width. + * } + */ + $args = apply_filters( 'jetpack_photon_post_image_args', $args, compact( 'tag', 'src', 'src_orig', 'width', 'height', 'width_orig', 'height_orig', 'transform', 'transform_orig' ) ); + + $photon_url = Image_CDN_Core::cdn_url( $src, $args ); + + // Modify image tag if Photon function provides a URL + // Ensure changes are only applied to the current image by copying and modifying the matched tag, then replacing the entire tag with our modified version. + if ( $src !== $photon_url ) { + // If present, replace the link href with a Photoned URL for the full-size image. + if ( is_string( $nearest_preceding_href ) && self::validate_image_url( $nearest_preceding_href ) ) { + $processor->seek( 'link' ); + $processor->set_attribute( 'href', Image_CDN_Core::cdn_url( $nearest_preceding_href ) ); + $processor->seek( 'image' ); + } + + // Supplant the original source value with our Photon URL. + $processor->set_attribute( 'src', $photon_url ); - $resize_args = array_map( 'trim', explode( ',', $resize_args ) ); + // If Lazy Load is in use, pass placeholder image through Photon. + if ( isset( $placeholder_src ) && self::validate_image_url( $placeholder_src ) ) { + $placeholder_src = Image_CDN_Core::cdn_url( $placeholder_src ); - // (?<=\s) - Ensure width or height attribute is preceded by a space - // (width=["\']?) - Matches, and captures, width=, width=", or width=' - // [\d%]+ - Matches 1 or more digits or percent signs - // (["\']?) - Matches, and captures, ", ', or empty string - // \s - Ensures there's a space after the attribute - $new_tag = preg_replace( '#(?<=\s)(width=["\']?)[\d%]+(["\']?)\s?#i', sprintf( '${1}%d${2} ', $resize_args[0] ), $new_tag ); - $new_tag = preg_replace( '#(?<=\s)(height=["\']?)[\d%]+(["\']?)\s?#i', sprintf( '${1}%d${2} ', $resize_args[1] ), $new_tag ); + if ( $placeholder_src !== $placeholder_src_orig ) { + $processor->set_attribute( $source_type, $placeholder_src ); } - // Tag an image for dimension checking. - if ( ! self::is_amp_endpoint() ) { - $new_tag = preg_replace( '#(\s?/)?>(\s*)?$#i', ' data-recalc-dims="1"\1>\2', $new_tag ); + unset( $placeholder_src ); + } + + // If we are not transforming the image with resize, fit, or letterbox (lb), then we should remove + // the width and height arguments (including HTML4 percentages) from the image to prevent distortion. + // Even if $args['w'] and $args['h'] are present, Photon does not crop to those dimensions. Instead, + // it appears to favor height. + // + // If we are transforming the image via one of those methods, let's update the width and height attributes. + if ( empty( $args['resize'] ) && empty( $args['fit'] ) && empty( $args['lb'] ) ) { + $processor->remove_attribute( 'width' ); + $processor->remove_attribute( 'height' ); + } else { + $resize_args = isset( $args['resize'] ) ? $args['resize'] : false; + if ( false === $resize_args ) { + $resize_args = ( ! $resize_args && isset( $args['fit'] ) ) + ? $args['fit'] + : false; + } + if ( false === $resize_args ) { + $resize_args = ( ! $resize_args && isset( $args['lb'] ) ) + ? $args['lb'] + : false; } - // Replace original tag with modified version. - $content = str_replace( $tag, $new_tag, $content ); + list( $resize_width, $resize_height ) = explode( ',', $resize_args ); + $processor->set_attribute( 'width', trim( $resize_width ) ); + $processor->set_attribute( 'height', trim( $resize_height ) ); } - } elseif ( preg_match( '#^http(s)?://i[\d]{1}.wp.com#', $src ) && ! empty( $images['link_url'][ $index ] ) && self::validate_image_url( $images['link_url'][ $index ] ) ) { - $new_tag = preg_replace( '#(href=["\'])' . preg_quote( $images['link_url'][ $index ], '#' ) . '(["\'])#i', '\1' . Image_CDN_Core::cdn_url( $images['link_url'][ $index ] ) . '\2', $tag, 1 ); - $content = str_replace( $tag, $new_tag, $content ); + // Tag an image for dimension checking. + if ( ! self::is_amp_endpoint() ) { + $processor->set_attribute( 'data-recalc-dims', '1' ); + } } + } elseif ( preg_match( '#^http(s)?://i[\d]{1}.wp.com#', $src ) && is_string( $nearest_preceding_href ) && self::validate_image_url( $nearest_preceding_href ) ) { + $processor->seek( 'link' ); + $processor->set_attribute( 'href', Image_CDN_Core::cdn_url( $nearest_preceding_href ) ); + $processor->seek( 'image' ); } } - return $content; + return $processor->get_updated_html(); } /** diff --git a/projects/packages/image-cdn/tests/php/sample-content/a-tags-with-hash-href.html b/projects/packages/image-cdn/tests/php/sample-content/a-tags-with-hash-href.html index 4b2c58ea0ce9e..266fdcebd587a 100644 --- a/projects/packages/image-cdn/tests/php/sample-content/a-tags-with-hash-href.html +++ b/projects/packages/image-cdn/tests/php/sample-content/a-tags-with-hash-href.html @@ -1,5 +1,5 @@ --RESULTS-- - + diff --git a/projects/packages/image-cdn/tests/php/sample-content/test-image-medium.png b/projects/packages/image-cdn/tests/php/sample-content/test-image-medium.png index 5c890bf297a79..2053dedfcec2e 100644 Binary files a/projects/packages/image-cdn/tests/php/sample-content/test-image-medium.png and b/projects/packages/image-cdn/tests/php/sample-content/test-image-medium.png differ diff --git a/projects/packages/import/CHANGELOG.md b/projects/packages/import/CHANGELOG.md index 4c8b15fd317bb..270e99dcf3f44 100644 --- a/projects/packages/import/CHANGELOG.md +++ b/projects/packages/import/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.8.7] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + ## [0.8.6] - 2024-05-27 ### Changed - Update dependencies. @@ -102,6 +106,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixed various imported resources hierarchies [#29012] +[0.8.7]: https://github.com/Automattic/jetpack-import/compare/v0.8.6...v0.8.7 [0.8.6]: https://github.com/Automattic/jetpack-import/compare/v0.8.5...v0.8.6 [0.8.5]: https://github.com/Automattic/jetpack-import/compare/v0.8.4...v0.8.5 [0.8.4]: https://github.com/Automattic/jetpack-import/compare/v0.8.3...v0.8.4 diff --git a/projects/packages/import/composer.json b/projects/packages/import/composer.json index 5ddfc94897a29..78114bfb80b81 100644 --- a/projects/packages/import/composer.json +++ b/projects/packages/import/composer.json @@ -9,7 +9,7 @@ "automattic/jetpack-sync": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master" }, diff --git a/projects/packages/import/package.json b/projects/packages/import/package.json index 60fe7babbd37e..5c5a161fd5e41 100644 --- a/projects/packages/import/package.json +++ b/projects/packages/import/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-import", - "version": "0.8.6", + "version": "0.8.7", "description": "Set of REST API routes used in WPCOM Unified Importer.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/import/#readme", "bugs": { diff --git a/projects/packages/import/src/class-main.php b/projects/packages/import/src/class-main.php index f5b1d181df378..df51421d127c5 100644 --- a/projects/packages/import/src/class-main.php +++ b/projects/packages/import/src/class-main.php @@ -20,7 +20,7 @@ class Main { * * @var string */ - const PACKAGE_VERSION = '0.8.6'; + const PACKAGE_VERSION = '0.8.7'; /** * A list of all the routes. diff --git a/projects/packages/ip/CHANGELOG.md b/projects/packages/ip/CHANGELOG.md index 812a12817d8e0..808b30b8c0937 100644 --- a/projects/packages/ip/CHANGELOG.md +++ b/projects/packages/ip/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.3] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## [0.2.2] - 2024-03-12 ### Changed - Internal updates. @@ -47,6 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add jetpack-ip package functionality [#28846] - Initialized the package. [#28765] +[0.2.3]: https://github.com/automattic/jetpack-ip/compare/v0.2.2...v0.2.3 [0.2.2]: https://github.com/automattic/jetpack-ip/compare/v0.2.1...v0.2.2 [0.2.1]: https://github.com/automattic/jetpack-ip/compare/v0.2.0...v0.2.1 [0.2.0]: https://github.com/automattic/jetpack-ip/compare/v0.1.6...v0.2.0 diff --git a/projects/packages/ip/composer.json b/projects/packages/ip/composer.json index 81689efee2a9a..453e0e795615a 100644 --- a/projects/packages/ip/composer.json +++ b/projects/packages/ip/composer.json @@ -8,7 +8,7 @@ }, "require-dev": { "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "suggest": { diff --git a/projects/packages/ip/src/class-utils.php b/projects/packages/ip/src/class-utils.php index 53dd3323bbfff..a062d7754f7e1 100644 --- a/projects/packages/ip/src/class-utils.php +++ b/projects/packages/ip/src/class-utils.php @@ -12,7 +12,7 @@ */ class Utils { - const PACKAGE_VERSION = '0.2.2'; + const PACKAGE_VERSION = '0.2.3'; /** * Get the current user's IP address. diff --git a/projects/packages/jetpack-mu-wpcom/.eslintignore b/projects/packages/jetpack-mu-wpcom/.eslintignore new file mode 100644 index 0000000000000..6a0ddf86aeb10 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/.eslintignore @@ -0,0 +1 @@ +src/features/newspack-blocks/synced-newspack-blocks diff --git a/projects/packages/jetpack-mu-wpcom/.gitattributes b/projects/packages/jetpack-mu-wpcom/.gitattributes index bb39b0ced174e..f24c7138ab785 100644 --- a/projects/packages/jetpack-mu-wpcom/.gitattributes +++ b/projects/packages/jetpack-mu-wpcom/.gitattributes @@ -7,7 +7,6 @@ package.json export-ignore # Remember to end all directories with `/**` to properly tag every file. # /src/js/example.min.js production-include src/build/** production-include -src/features/newspack-blocks/synced-newspack-blocks/** production-include # Files to exclude from the mirror repo, but included in the monorepo. # Remember to end all directories with `/**` to properly tag every file. @@ -17,3 +16,4 @@ phpunit.xml.dist production-exclude .phpcs.dir.xml production-exclude tests/** production-exclude .phpcsignore production-exclude +bin/** production-exclude diff --git a/projects/packages/jetpack-mu-wpcom/.gitignore b/projects/packages/jetpack-mu-wpcom/.gitignore index 4a17a341d86cd..b8c2e07945268 100644 --- a/projects/packages/jetpack-mu-wpcom/.gitignore +++ b/projects/packages/jetpack-mu-wpcom/.gitignore @@ -5,4 +5,3 @@ node_modules/ wordpress/ playwright-report/ src/features/help-center/languages/ -src/features/newspack-blocks/synced-newspack-blocks diff --git a/projects/packages/jetpack-mu-wpcom/.phan/baseline.php b/projects/packages/jetpack-mu-wpcom/.phan/baseline.php index e945e3cc89b32..bb58e6850074b 100644 --- a/projects/packages/jetpack-mu-wpcom/.phan/baseline.php +++ b/projects/packages/jetpack-mu-wpcom/.phan/baseline.php @@ -9,31 +9,46 @@ */ return [ // # Issue statistics: - // PhanTypeMismatchArgument : 15+ occurrences + // PhanTypeMismatchArgument : 35+ occurrences + // PhanPluginDuplicateConditionalNullCoalescing : 20+ occurrences + // PhanUndeclaredClassMethod : 20+ occurrences // PhanTypeMismatchArgumentProbablyReal : 15+ occurrences - // PhanPluginDuplicateConditionalNullCoalescing : 8 occurrences - // PhanTypeMismatchReturn : 6 occurrences + // PhanTypeMismatchReturnProbablyReal : 10+ occurrences + // PhanUndeclaredFunction : 10+ occurrences + // PhanTypeMismatchReturn : 8 occurrences + // PhanUndeclaredConstant : 7 occurrences + // PhanTypeArraySuspiciousNullable : 6 occurrences // PhanNoopNew : 5 occurrences - // PhanTypeMismatchReturnProbablyReal : 4 occurrences + // PhanParamTooMany : 4 occurrences + // PhanUnextractableAnnotationSuffix : 4 occurrences + // PhanDeprecatedProperty : 3 occurrences + // PhanPluginDuplicateExpressionAssignmentOperation : 3 occurrences // PhanTypePossiblyInvalidDimOffset : 3 occurrences - // PhanUndeclaredClassMethod : 3 occurrences + // PhanTypeSuspiciousNonTraversableForeach : 3 occurrences + // PhanUndeclaredClassReference : 3 occurrences + // PhanUndeclaredGlobalVariable : 3 occurrences // PhanEmptyFQSENInCallable : 2 occurrences - // PhanParamTooMany : 2 occurrences + // PhanPluginMixedKeyNoKey : 2 occurrences // PhanTypeArraySuspicious : 2 occurrences - // PhanTypeArraySuspiciousNullable : 2 occurrences // PhanTypeMismatchArgumentInternal : 2 occurrences // PhanTypeMismatchDefault : 2 occurrences // PhanTypeMissingReturn : 2 occurrences - // PhanUndeclaredFunction : 2 occurrences // PhanDeprecatedFunction : 1 occurrence // PhanImpossibleTypeComparison : 1 occurrence // PhanNonClassMethodCall : 1 occurrence // PhanNoopArrayAccess : 1 occurrence + // PhanPluginRedundantAssignment : 1 occurrence // PhanPluginSimplifyExpressionBool : 1 occurrence + // PhanPossiblyUndeclaredVariable : 1 occurrence // PhanRedefineFunction : 1 occurrence // PhanRedundantCondition : 1 occurrence // PhanTypeComparisonToArray : 1 occurrence + // PhanTypeInvalidLeftOperandOfBitwiseOp : 1 occurrence + // PhanTypeInvalidRightOperandOfBitwiseOp : 1 occurrence + // PhanTypeMismatchArgumentNullable : 1 occurrence + // PhanTypeMismatchArgumentNullableInternal : 1 occurrence // PhanTypeMismatchDimFetch : 1 occurrence + // PhanTypeMismatchProperty : 1 occurrence // PhanTypeMismatchReturnNullable : 1 occurrence // PhanTypeNonVarPassByRef : 1 occurrence // PhanTypeVoidArgument : 1 occurrence @@ -53,6 +68,14 @@ 'src/features/launchpad/launchpad.php' => ['PhanTypeArraySuspiciousNullable', 'PhanTypeMismatchArgument', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnProbablyReal'], 'src/features/marketplace-products-updater/class-marketplace-products-updater.php' => ['PhanTypeMismatchDimFetch', 'PhanTypeMismatchReturn'], 'src/features/media/heif-support.php' => ['PhanPluginSimplifyExpressionBool'], + 'src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/view.php' => ['PhanParamTooMany', 'PhanPluginDuplicateConditionalNullCoalescing', 'PhanPossiblyUndeclaredVariable', 'PhanTypeMismatchArgument', 'PhanTypeMismatchReturnProbablyReal'], + 'src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/class-wp-rest-newspack-articles-controller.php' => ['PhanTypeArraySuspiciousNullable'], + 'src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/templates/article.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredGlobalVariable'], + 'src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/templates/articles-list.php' => ['PhanUndeclaredGlobalVariable'], + 'src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/templates/articles-loop.php' => ['PhanUndeclaredGlobalVariable'], + 'src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/view.php' => ['PhanPluginDuplicateExpressionAssignmentOperation', 'PhanTypeArraySuspiciousNullable', 'PhanTypeMismatchArgumentNullableInternal', 'PhanTypeMismatchReturnProbablyReal', 'PhanUndeclaredClassMethod'], + 'src/features/newspack-blocks/synced-newspack-blocks/class-newspack-blocks-api.php' => ['PhanParamTooMany', 'PhanTypeMismatchArgument', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnProbablyReal', 'PhanUndeclaredClassMethod', 'PhanUndeclaredFunction', 'PhanUnextractableAnnotationSuffix'], + 'src/features/newspack-blocks/synced-newspack-blocks/class-newspack-blocks.php' => ['PhanDeprecatedProperty', 'PhanPluginDuplicateConditionalNullCoalescing', 'PhanPluginDuplicateExpressionAssignmentOperation', 'PhanPluginMixedKeyNoKey', 'PhanPluginRedundantAssignment', 'PhanTypeInvalidLeftOperandOfBitwiseOp', 'PhanTypeInvalidRightOperandOfBitwiseOp', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchProperty', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnProbablyReal', 'PhanTypeSuspiciousNonTraversableForeach', 'PhanUndeclaredClassMethod', 'PhanUndeclaredClassReference', 'PhanUndeclaredConstant', 'PhanUndeclaredFunction'], 'src/features/verbum-comments/class-verbum-comments.php' => ['PhanImpossibleTypeComparison', 'PhanNoopNew', 'PhanParamTooMany', 'PhanTypeMismatchArgumentProbablyReal', 'PhanUndeclaredFunction'], 'src/features/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-launchpad.php' => ['PhanPluginDuplicateConditionalNullCoalescing'], 'src/features/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-site-migration-migrate-guru-key.php' => ['PhanUndeclaredClassMethod'], diff --git a/projects/packages/jetpack-mu-wpcom/.phan/config.php b/projects/packages/jetpack-mu-wpcom/.phan/config.php index d2fb4ef5f636c..1c6422d32b63f 100644 --- a/projects/packages/jetpack-mu-wpcom/.phan/config.php +++ b/projects/packages/jetpack-mu-wpcom/.phan/config.php @@ -33,9 +33,6 @@ // This file breaks analysis, Phan gets lost recursing in trying to figure out some types. // @todo Add type declarations so Phan won't have to do it itself. Or update to a modern less lib. 'src/features/custom-css/custom-css/preprocessors/lessc.inc.php', - - // The synced newspack blocks files break analysis. - 'src/features/newspack-blocks/synced-newspack-blocks', ), ) ); diff --git a/projects/packages/jetpack-mu-wpcom/CHANGELOG.md b/projects/packages/jetpack-mu-wpcom/CHANGELOG.md index 9b068f4031d40..58d84015410e0 100644 --- a/projects/packages/jetpack-mu-wpcom/CHANGELOG.md +++ b/projects/packages/jetpack-mu-wpcom/CHANGELOG.md @@ -5,6 +5,57 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [5.59.0] - 2024-08-26 +### Added +- Auto open Upload Theme dialog if query parameter is present [#39045] +- Fixup project versions. [#38931] + +### Changed +- MU WPCOM: Fix Post Publish Modal checkbox alignment [#38990] + +### Fixed +- Bump package version [#39056] +- MU WPCOM: Fix the coming soon isn't configured correctly if the settings changes from Coming Soon -> Private -> Coming Soon [#39010] + +## [5.58.0] - 2024-08-23 +### Added +- Sync Calypso locale to Atomic Classic [#39009] + +### Changed +- Jetpack-mu-wpcom admin bar: move the Reader menu item to the secondary admin bar group. [#38976] +- Replace language selector with a link to WPCOM [#39013] +- Updated package dependencies. [#39004] + +### Fixed +- Admin bar: fix icon colors on site frontend [#39014] +- Ensure theme update icon is hidden correctly [#38957] +- Inconsistent Color Scheme when previewing on Simple Default [#39048] + +## [5.57.1] - 2024-08-21 +### Changed +- Site Level User Profile: expose all relevant fields on profile.php [#38949] + +### Fixed +- Help Center: show disconnected version on frontend [#38941] +- Revert recent SVG image optimizations. [#38981] + +## [5.57.0] - 2024-08-19 +### Added +- Social Links: Requiring feature from Classic Theme Helper package instead of Jetpack module. [#38730] + +### Changed +- Gutenberg: Include links to support docs for recent blocks. [#38794] +- Keep the synced-newspack-blocks folder instead of pulling on every install. [#38873] +- Replace the link of the additional CSS. [#38951] +- Re-tangle first/last/display name, website, and bio fields in profile.php. [#38854] +- Temporarily point to wpcalypso.wordpress.com for testing purposes. [#38903] +- Updated package dependencies. [#38662] +- Whem Atomic users log out of wp-admin they are also logged out of WPCOM. [#38850] + +### Fixed +- Help Center: Don't load english translations. [#38912] +- Lossless image optimization for images (should improve performance with no visible changes). [#38750] + ## [5.56.0] - 2024-08-13 ### Changed - WPCOM Block Description Links: add links for embed variations [#38834] @@ -1138,6 +1189,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Testing initial package release. +[5.59.0]: https://github.com/Automattic/jetpack-mu-wpcom/compare/v5.58.0...v5.59.0 +[5.58.0]: https://github.com/Automattic/jetpack-mu-wpcom/compare/v5.57.1...v5.58.0 +[5.57.1]: https://github.com/Automattic/jetpack-mu-wpcom/compare/v5.57.0...v5.57.1 +[5.57.0]: https://github.com/Automattic/jetpack-mu-wpcom/compare/v5.56.0...v5.57.0 [5.56.0]: https://github.com/Automattic/jetpack-mu-wpcom/compare/v5.55.0...v5.56.0 [5.55.0]: https://github.com/Automattic/jetpack-mu-wpcom/compare/v5.54.3...v5.55.0 [5.54.3]: https://github.com/Automattic/jetpack-mu-wpcom/compare/v5.54.2...v5.54.3 diff --git a/projects/packages/jetpack-mu-wpcom/bin/sync-newspack-blocks-formatter.js b/projects/packages/jetpack-mu-wpcom/bin/sync-newspack-blocks-formatter.js index 46fbbff4156d4..2f1b818dcb694 100644 --- a/projects/packages/jetpack-mu-wpcom/bin/sync-newspack-blocks-formatter.js +++ b/projects/packages/jetpack-mu-wpcom/bin/sync-newspack-blocks-formatter.js @@ -32,7 +32,7 @@ module.exports = function transformer( file, api ) { /** * Whether the node is a function call with the specific name * - * @param node - The AST node + * @param node - The AST node * @param functionName - The function name we want to check */ function isFunctionCallWithName( node, functionName ) { diff --git a/projects/packages/jetpack-mu-wpcom/changelog/add-more-eslint-rules b/projects/packages/jetpack-mu-wpcom/changelog/add-more-eslint-rules new file mode 100644 index 0000000000000..2b32cb03e644c --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/changelog/add-more-eslint-rules @@ -0,0 +1,5 @@ +Significance: patch +Type: fixed +Comment: Fix new eslint sniffs. Should be no change in functionality. + + diff --git a/projects/packages/jetpack-mu-wpcom/changelog/add-require-social-links-classic-theme-helper-package b/projects/packages/jetpack-mu-wpcom/changelog/add-require-social-links-classic-theme-helper-package deleted file mode 100644 index 99c5a34195c63..0000000000000 --- a/projects/packages/jetpack-mu-wpcom/changelog/add-require-social-links-classic-theme-helper-package +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: added - -Social Links: Requiring feature from Classic Theme Helper package instead of Jetpack module. diff --git a/projects/packages/jetpack-mu-wpcom/changelog/fix-howdy-link b/projects/packages/jetpack-mu-wpcom/changelog/fix-howdy-link new file mode 100644 index 0000000000000..3a3cd46e55a08 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/changelog/fix-howdy-link @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Always rewrite profile.php to /me on Default sites diff --git a/projects/packages/jetpack-mu-wpcom/changelog/help-center-fix-language-script b/projects/packages/jetpack-mu-wpcom/changelog/help-center-fix-language-script deleted file mode 100644 index 82c277ac0b18f..0000000000000 --- a/projects/packages/jetpack-mu-wpcom/changelog/help-center-fix-language-script +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fixed - -Help Center: don't load english translations diff --git a/projects/packages/jetpack-mu-wpcom/changelog/logout-wpcom b/projects/packages/jetpack-mu-wpcom/changelog/logout-wpcom deleted file mode 100644 index 209bffcc0a489..0000000000000 --- a/projects/packages/jetpack-mu-wpcom/changelog/logout-wpcom +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: changed - -Whem Atomic users log out of wp-admin they are also logged out of WPCOM diff --git a/projects/plugins/boost/changelog/add-mj-protect-card-auto-firewall-status b/projects/packages/jetpack-mu-wpcom/changelog/remove-custom-css-warnings similarity index 55% rename from projects/plugins/boost/changelog/add-mj-protect-card-auto-firewall-status rename to projects/packages/jetpack-mu-wpcom/changelog/remove-custom-css-warnings index 66603f18e7ca1..1f01d21832950 100644 --- a/projects/plugins/boost/changelog/add-mj-protect-card-auto-firewall-status +++ b/projects/packages/jetpack-mu-wpcom/changelog/remove-custom-css-warnings @@ -1,5 +1,5 @@ Significance: patch Type: changed -Comment: update lock file +Comment: Remove Phan comment diff --git a/projects/packages/jetpack-mu-wpcom/changelog/renovate-lock-file-maintenance b/projects/packages/jetpack-mu-wpcom/changelog/renovate-lock-file-maintenance deleted file mode 100644 index 3109d07526368..0000000000000 --- a/projects/packages/jetpack-mu-wpcom/changelog/renovate-lock-file-maintenance +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: changed -Comment: Update Phan baseline. - - diff --git a/projects/packages/my-jetpack/changelog/renovate-storybook-monorepo b/projects/packages/jetpack-mu-wpcom/changelog/renovate-npm-webpack-vulnerability similarity index 100% rename from projects/packages/my-jetpack/changelog/renovate-storybook-monorepo rename to projects/packages/jetpack-mu-wpcom/changelog/renovate-npm-webpack-vulnerability diff --git a/projects/packages/jetpack-mu-wpcom/changelog/retangle-name-fields b/projects/packages/jetpack-mu-wpcom/changelog/retangle-name-fields deleted file mode 100644 index f1fc920f6f13a..0000000000000 --- a/projects/packages/jetpack-mu-wpcom/changelog/retangle-name-fields +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: changed - -Re-tangle first/last/display name, website, and bio fields in profile.php diff --git a/projects/packages/jetpack-mu-wpcom/changelog/try-no-version-bumps-in-trunk b/projects/packages/jetpack-mu-wpcom/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..91efe85c55e06 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/packages/jetpack-mu-wpcom/changelog/update-jetpack-13.7-backport b/projects/packages/jetpack-mu-wpcom/changelog/update-jetpack-13.7-backport new file mode 100644 index 0000000000000..5822a8c421194 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/changelog/update-jetpack-13.7-backport @@ -0,0 +1,5 @@ +Significance: patch +Type: fixed +Comment: Updated versions. + + diff --git a/projects/packages/jetpack-mu-wpcom/changelog/update-newspack-blocks b/projects/packages/jetpack-mu-wpcom/changelog/update-newspack-blocks new file mode 100644 index 0000000000000..6a7f4b1b00f8d --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/changelog/update-newspack-blocks @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Newspack blocks: Updated from 3.5 to 4.0.1 diff --git a/projects/packages/jetpack-mu-wpcom/changelog/update-site-level-user-profile-links b/projects/packages/jetpack-mu-wpcom/changelog/update-site-level-user-profile-links deleted file mode 100644 index 02136300371cb..0000000000000 --- a/projects/packages/jetpack-mu-wpcom/changelog/update-site-level-user-profile-links +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: changed - -Temporarily point to wpcalypso.wordpress.com for testing purposes. diff --git a/projects/packages/jetpack-mu-wpcom/composer.json b/projects/packages/jetpack-mu-wpcom/composer.json index 267db520aeb94..85ee876360b48 100644 --- a/projects/packages/jetpack-mu-wpcom/composer.json +++ b/projects/packages/jetpack-mu-wpcom/composer.json @@ -20,7 +20,7 @@ "scssphp/scssphp": "1.12.0" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "0.4.2" }, @@ -62,7 +62,7 @@ }, "autotagger": true, "branch-alias": { - "dev-trunk": "5.57.x-dev" + "dev-trunk": "5.59.x-dev" }, "textdomain": "jetpack-mu-wpcom", "version-constants": { diff --git a/projects/packages/jetpack-mu-wpcom/package.json b/projects/packages/jetpack-mu-wpcom/package.json index ecdd18fc46ff2..48fb888c0042b 100644 --- a/projects/packages/jetpack-mu-wpcom/package.json +++ b/projects/packages/jetpack-mu-wpcom/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-mu-wpcom", - "version": "5.57.0-alpha", + "version": "5.59.0", "description": "Enhances your site with features powered by WordPress.com", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/jetpack-mu-wpcom/#readme", "bugs": { @@ -19,12 +19,11 @@ "build-js": "pnpm clean && webpack", "build-production": "echo 'Not implemented.'", "build-production-js": "NODE_ENV=production BABEL_ENV=production pnpm build-js", - "postinstall": "pnpm run sync:newspack-blocks", "lint": "eslint --ext .js,.jsx,.cjs,.mjs,.ts,.tsx .", "clean": "rm -rf src/build/", "watch": "pnpm run build-production-js && pnpm webpack watch", "e2e-tests": "playwright test --config src/features/verbum-comments/playwright.config.ts", - "sync:newspack-blocks": "./bin/sync-newspack-blocks.sh --release=v3.5.0" + "sync:newspack-blocks": "./bin/sync-newspack-blocks.sh" }, "optionalDependencies": { "react": "^18.2.0", @@ -44,7 +43,7 @@ "sass": "1.64.1", "sass-loader": "12.4.0", "typescript": "^5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "dependencies": { diff --git a/projects/packages/jetpack-mu-wpcom/src/class-jetpack-mu-wpcom.php b/projects/packages/jetpack-mu-wpcom/src/class-jetpack-mu-wpcom.php index f2f4a6d46f2fa..4144312a48b3c 100644 --- a/projects/packages/jetpack-mu-wpcom/src/class-jetpack-mu-wpcom.php +++ b/projects/packages/jetpack-mu-wpcom/src/class-jetpack-mu-wpcom.php @@ -9,11 +9,13 @@ namespace Automattic\Jetpack; +define( 'WPCOM_ADMIN_BAR_UNIFICATION', true ); + /** * Jetpack_Mu_Wpcom main class. */ class Jetpack_Mu_Wpcom { - const PACKAGE_VERSION = '5.57.0-alpha'; + const PACKAGE_VERSION = '5.59.0'; const PKG_DIR = __DIR__ . '/../'; const BASE_DIR = __DIR__ . '/'; const BASE_FILE = __FILE__; @@ -109,8 +111,6 @@ public static function load_features() { require_once __DIR__ . '/features/wpcom-block-editor/class-jetpack-wpcom-block-editor.php'; require_once __DIR__ . '/features/wpcom-block-editor/functions.editor-type.php'; require_once __DIR__ . '/features/wpcom-logout/wpcom-logout.php'; - require_once __DIR__ . '/features/wpcom-profile-settings/profile-settings-link-to-wpcom.php'; - require_once __DIR__ . '/features/wpcom-profile-settings/profile-settings-notices.php'; require_once __DIR__ . '/features/wpcom-themes/wpcom-theme-fixes.php'; // Initializers, if needed. @@ -143,7 +143,10 @@ public static function load_wpcom_user_features() { require_once __DIR__ . '/features/wpcom-admin-interface/wpcom-admin-interface.php'; require_once __DIR__ . '/features/wpcom-admin-menu/wpcom-admin-menu.php'; require_once __DIR__ . '/features/wpcom-command-palette/wpcom-command-palette.php'; + require_once __DIR__ . '/features/wpcom-locale/sync-locale-from-calypso-to-atomic.php'; require_once __DIR__ . '/features/wpcom-plugins/wpcom-plugins.php'; + require_once __DIR__ . '/features/wpcom-profile-settings/profile-settings-link-to-wpcom.php'; + require_once __DIR__ . '/features/wpcom-profile-settings/profile-settings-notices.php'; require_once __DIR__ . '/features/wpcom-sidebar-notice/wpcom-sidebar-notice.php'; require_once __DIR__ . '/features/wpcom-site-management-widget/class-wpcom-site-management-widget.php'; require_once __DIR__ . '/features/wpcom-themes/wpcom-themes.php'; diff --git a/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/hooks/use-has-selected-payment-block-once.js b/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/hooks/use-has-selected-payment-block-once.js index f8060b9a2d232..2927393b14c3c 100644 --- a/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/hooks/use-has-selected-payment-block-once.js +++ b/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/hooks/use-has-selected-payment-block-once.js @@ -8,7 +8,7 @@ import { useState, useEffect } from '@wordpress/element'; * or jetpack/recurring-payments. * Selecting a block whose direct parent has 'payments' in the name also counts. * This is to account for clicking inside the button in a payments block, for example. - * @returns {boolean} Has the user selected a payments block (or a direct descendant) at least once? + * @return {boolean} Has the user selected a payments block (or a direct descendant) at least once? */ const useHasSelectedPaymentBlockOnce = () => { const [ hasSelectedPaymentsOnce, setHasSelectedPaymentsOnce ] = useState( false ); diff --git a/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/hooks/use-keydown-handler.ts b/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/hooks/use-keydown-handler.ts index 6ea129fe08f2e..1cdf93219b40e 100644 --- a/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/hooks/use-keydown-handler.ts +++ b/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/hooks/use-keydown-handler.ts @@ -20,13 +20,22 @@ const useKeydownHandler = ( { onEscape, onArrowRight, onArrowLeft }: Props ): vo switch ( event.key ) { case 'Escape': - onEscape && ( onEscape(), ( handled = true ) ); + if ( onEscape ) { + onEscape(); + handled = true; + } break; case 'ArrowRight': - onArrowRight && ( onArrowRight(), ( handled = true ) ); + if ( onArrowRight ) { + onArrowRight(); + handled = true; + } break; case 'ArrowLeft': - onArrowLeft && ( onArrowLeft(), ( handled = true ) ); + if ( onArrowLeft ) { + onArrowLeft(); + handled = true; + } break; default: break; diff --git a/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/utils/index.ts b/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/utils/index.ts index 3f00a820d1703..f9fdc9cdda385 100644 --- a/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/utils/index.ts +++ b/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/utils/index.ts @@ -3,7 +3,7 @@ import debugFactory from 'debug'; /** * Helper to convert CSV of `classes` to an array. * @param classes - String or array of classes to format. - * @returns Array of classes + * @return Array of classes */ export function classParser( classes?: string | string[] ): string[] | null { if ( classes?.length ) { diff --git a/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/utils/live-resize-modifier.tsx b/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/utils/live-resize-modifier.tsx index ab1a14cf8568b..63047ac65f2b2 100644 --- a/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/utils/live-resize-modifier.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/common/tour-kit/utils/live-resize-modifier.tsx @@ -38,11 +38,11 @@ type liveResizeModifierFactory = ( * The Popper modifier queues an asynchronous update on the Popper instance whenever either of the * Observers trigger its callback. * - * @param config - The config. + * @param config - The config. * @param config.rootElementSelector - The selector of the root element. - * @param config.mutation - Whether to mutate. - * @param config.resize - Whether to resize. - * @returns custom Popper modifier. + * @param config.mutation - Whether to mutate. + * @param config.resize - Whether to resize. + * @return custom Popper modifier. */ export const liveResizeModifier: liveResizeModifierFactory = ( { rootElementSelector, mutation = false, resize = false }: LiveResizeConfiguration = { @@ -53,9 +53,7 @@ export const liveResizeModifier: liveResizeModifierFactory = ( name: 'liveResizeModifier', enabled: true, phase: 'main', - fn: () => { - return; - }, + fn: () => {}, effect: arg0 => { try { const { state, instance } = arg0 as ModifierArgumentsWithObserversProp; // augment types here because we are mutating the properties on the argument that is passed in diff --git a/projects/packages/jetpack-mu-wpcom/src/features/admin-color-schemes/admin-color-schemes.php b/projects/packages/jetpack-mu-wpcom/src/features/admin-color-schemes/admin-color-schemes.php index 2f4e6849bdf77..d2e7e49692bae 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/admin-color-schemes/admin-color-schemes.php +++ b/projects/packages/jetpack-mu-wpcom/src/features/admin-color-schemes/admin-color-schemes.php @@ -11,6 +11,6 @@ // @TODO Ideally we should remove this feature entirely and update Jetpack_Mu_Wpcom::load_features to initialize // Masterbar for both WoA and Simple sites. // This would require removing the relevant Masterbar code on WPCOM and rely on the package only. -if ( get_option( 'wpcom_admin_interface' ) === 'wp-admin' && ( new Host() )->is_wpcom_simple() ) { +if ( ( new Host() )->is_wpcom_simple() ) { new Admin_Color_Schemes(); } diff --git a/projects/packages/jetpack-mu-wpcom/src/features/block-inserter-modifications/src/contextual-tip.js b/projects/packages/jetpack-mu-wpcom/src/features/block-inserter-modifications/src/contextual-tip.js index 76c61ce2a4c84..76bb0d696d843 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/block-inserter-modifications/src/contextual-tip.js +++ b/projects/packages/jetpack-mu-wpcom/src/features/block-inserter-modifications/src/contextual-tip.js @@ -7,9 +7,9 @@ import tipsList from './list'; /** * Create the contextual tip. * - * @param {object} props - The function props. - * @param {string} props.searchTerm - Search term text. - * @param {boolean} props.random - Whether to choose a random tooltip on multiple matches. + * @param {object} props - The function props. + * @param {string} props.searchTerm - Search term text. + * @param {boolean} props.random - Whether to choose a random tooltip on multiple matches. * @param {Function} props.canUserCreate - Function to check user permission. */ function ContextualTip( { searchTerm, random = false, canUserCreate } ) { diff --git a/projects/packages/jetpack-mu-wpcom/src/features/block-inserter-modifications/src/tip-link.js b/projects/packages/jetpack-mu-wpcom/src/features/block-inserter-modifications/src/tip-link.js index 2af8179856831..da71674594f02 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/block-inserter-modifications/src/tip-link.js +++ b/projects/packages/jetpack-mu-wpcom/src/features/block-inserter-modifications/src/tip-link.js @@ -5,9 +5,9 @@ const isEditorIFramed = inIframe(); /** * Create the link for the contextual tip. * - * @param {object} props - The function props. - * @param {string} props.children - The tip content. - * @param {string} props.section - The tip context section. + * @param {object} props - The function props. + * @param {string} props.children - The tip content. + * @param {string} props.section - The tip context section. */ export default function ( { children, section } ) { const { hostname } = window.location; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/block-inserter-modifications/src/utils.js b/projects/packages/jetpack-mu-wpcom/src/features/block-inserter-modifications/src/utils.js index 49e946ef6eaff..5ba9ee34de76b 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/block-inserter-modifications/src/utils.js +++ b/projects/packages/jetpack-mu-wpcom/src/features/block-inserter-modifications/src/utils.js @@ -1,6 +1,6 @@ /** * Detect if the editor is already iFramed. - * @returns {boolean} `True` is the editor is iFramed. Otherwise, `False`. + * @return {boolean} `True` is the editor is iFramed. Otherwise, `False`. */ export const inIframe = () => { try { diff --git a/projects/packages/jetpack-mu-wpcom/src/features/coming-soon/coming-soon.php b/projects/packages/jetpack-mu-wpcom/src/features/coming-soon/coming-soon.php index a88675032b222..8391adba2de59 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/coming-soon/coming-soon.php +++ b/projects/packages/jetpack-mu-wpcom/src/features/coming-soon/coming-soon.php @@ -171,6 +171,9 @@ function add_public_coming_soon_to_settings_endpoint_get( $options ) { function add_public_coming_soon_to_settings_endpoint_post( $input, $unfiltered_input ) { if ( is_array( $unfiltered_input ) && array_key_exists( 'wpcom_public_coming_soon', $unfiltered_input ) ) { $input['wpcom_public_coming_soon'] = (int) $unfiltered_input['wpcom_public_coming_soon']; + + // Avoid updating the value of the `wpcom_public_coming_soon` if the request wants to change the option. + remove_action( 'update_option_blog_public', __NAMESPACE__ . '\disable_coming_soon_on_privacy_change', 10 ); } return $input; } diff --git a/projects/packages/jetpack-mu-wpcom/src/features/custom-css/custom-css.php b/projects/packages/jetpack-mu-wpcom/src/features/custom-css/custom-css.php index bb7ef3b786e84..eda09f550b0e1 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/custom-css/custom-css.php +++ b/projects/packages/jetpack-mu-wpcom/src/features/custom-css/custom-css.php @@ -1,7 +1,6 @@ is_block_editor() && $can_edit_posts; + } + /** * Returns the URL for the Help Center redirect. * Used for the Help Center when disconnected. */ public function get_help_center_url() { - $help_url = 'https://wordpress.com/help'; + $help_url = 'https://wordpress.com/help?help-center=home'; - if ( ! $this->is_jetpack_disconnected() ) { - return false; + if ( $this->is_jetpack_disconnected() || $this->is_loading_on_frontend() ) { + return $help_url; } - return $help_url; + return false; } + /** * Get the asset via file-system on wpcom and via network on Atomic sites. * @@ -376,6 +394,10 @@ private static function download_asset( $filepath, $parse_json = true ) { * Add icon to WP-ADMIN admin bar. */ public function enqueue_wp_admin_scripts() { + if ( $this->is_wc_admin_home_page() ) { + return; + } + require_once ABSPATH . 'wp-admin/includes/screen.php'; $can_edit_posts = current_user_can( 'edit_posts' ) && is_user_member_of_blog(); @@ -385,17 +407,17 @@ public function enqueue_wp_admin_scripts() { // 1. On wp-admin // 2. On the front end of the site if the current user can edit posts // 3. On the front end of the site and the theme is not P2 + // 4. If it is the frontend we show the disconnected version of the help center. if ( ! is_admin() && ( ! $can_edit_posts || $is_p2 ) ) { return; + } elseif ( $this->is_loading_on_frontend() ) { + $variant = 'wp-admin-disconnected'; + } elseif ( $this->is_block_editor() ) { + $variant = 'gutenberg' . ( $this->is_jetpack_disconnected() ? '-disconnected' : '' ); + } else { + $variant = 'wp-admin' . ( $this->is_jetpack_disconnected() ? '-disconnected' : '' ); } - if ( $this->is_wc_admin_home_page() ) { - return; - } - - $variant = $this->is_block_editor() ? 'gutenberg' : 'wp-admin'; - $variant .= $this->is_jetpack_disconnected() ? '-disconnected' : ''; - $asset_file = self::download_asset( 'widgets.wp.com/help-center/help-center-' . $variant . '.asset.json' ); if ( ! $asset_file ) { return; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/jetpack-global-styles/src/dom-updater.js b/projects/packages/jetpack-mu-wpcom/src/features/jetpack-global-styles/src/dom-updater.js index cef284ca2cf91..a6f960680ad7b 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/jetpack-global-styles/src/dom-updater.js +++ b/projects/packages/jetpack-mu-wpcom/src/features/jetpack-global-styles/src/dom-updater.js @@ -4,7 +4,7 @@ import { isEmpty, isEqual } from 'lodash'; /** * DOM updater - * @param {string[]} options - A list of option names to keep track of. + * @param {string[]} options - A list of option names to keep track of. * @param {Function} getOptionValue - A function that given an option name as a string, returns the current option value. */ export default ( options, getOptionValue ) => { diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/README.md b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/README.md index 8e5e8295c9961..a4cc12220990b 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/README.md +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/README.md @@ -36,10 +36,17 @@ Once your changes land on the Newspack side, coordinate with the team (over issu While being in `projects/packages/jetpack-mu-wpcom` directory, you can run: ``` -pnpm run sync:newspack-blocks +pnpm run sync:newspack-blocks --release= ``` -This will pull the code from the release and integrate it into this repository. Please review changes, make sure to update `NEWSPACK_BLOCKS__VERSION` in [index.php](./index.php) and commit. +This will pull the code from the release and integrate it into this repository. Please: + 1. Review changes + 2. Keep the PHPCS config if still necessary + 3. Ensure [htmlentities uses ENT_COMPAT](https://github.com/Automattic/jetpack/pull/38873/commits/16f57e6f01b6eed98a19cd0299261ce5ac075b8e) + 4. Update the phan baseline with `jetpack phan --update-baseline packages/jetpack-mu-wpcom` + 4. Update `NEWSPACK_BLOCKS__VERSION` in [index.php](./index.php) + 5. Ensure that the blocks `block.json` has `"textdomain": "jetpack-mu-wpcom"` + 6. Commit. ### Local development diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/index.php b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/index.php index 2e2e00fe77ca9..83bbe4855c5d9 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/index.php +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/index.php @@ -11,6 +11,7 @@ define( 'NEWSPACK_BLOCKS__BLOCKS_DIRECTORY', Jetpack_Mu_Wpcom::BASE_DIR . 'build/' ); define( 'NEWSPACK_BLOCKS__PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); +define( 'NEWSPACK_BLOCKS__VERSION', '4.0.1' ); require_once __DIR__ . '/../../utils.php'; require_once __DIR__ . '/synced-newspack-blocks/class-newspack-blocks.php'; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/.phpcs.dir.xml b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/.phpcs.dir.xml new file mode 100644 index 0000000000000..c49f51983d12d --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/.phpcs.dir.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/create-swiper.js b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/create-swiper.js new file mode 100644 index 0000000000000..151b9a0000201 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/create-swiper.js @@ -0,0 +1,236 @@ +/** + * External dependencies + */ +import { speak } from '@wordpress/a11y'; +import { escapeHTML } from '@wordpress/escape-html'; +import { __, sprintf } from '@wordpress/i18n'; +// eslint-disable-next-line import/no-unresolved +import Swiper from 'swiper/bundle'; +// eslint-disable-next-line import/no-unresolved +import 'swiper/css/bundle'; + +const autoplayClassName = 'wp-block-newspack-blocks-carousel__autoplay-playing'; + +/** + * A helper for IE11-compatible iteration over NodeList elements. + * + * @param {object} nodeList - List of nodes to be iterated over. + * @param {Function} cb - Invoked for each iteratee. + */ +function forEachNode( nodeList, cb ) { + /** + * Calls Array.prototype.forEach for IE11 compatibility. + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/NodeList + */ + Array.prototype.forEach.call( nodeList, cb ); +} + +/** + * Modifies attributes on slide HTML to make it accessible. + * + * @param {HTMLElement} slide - Slide DOM element + */ +function activateSlide( slide ) { + if ( slide ) { + slide.setAttribute( 'aria-hidden', 'false' ); + forEachNode( slide.querySelectorAll( 'a' ), el => el.removeAttribute( 'tabindex' ) ); + } +} + +/** + * Modifies attributes on slide HTML to make it accessible. + * + * @param {HTMLElement} slide - Slide DOM element + */ +function deactivateSlide( slide ) { + if ( slide ) { + slide.setAttribute( 'aria-hidden', 'true' ); + forEachNode( slide.querySelectorAll( 'a' ), el => el.setAttribute( 'tabindex', '-1' ) ); + } +} + +/** + * Creates a Swiper instance with predefined config used by the Articles + * Carousel block in both front-end and editor. + * + * @param {object} els - Swiper elements + * @param {Element} els.block - Block element + * @param {Element} els.container - Swiper container element + * @param {Element} els.next - Next button element + * @param {Element} els.prev - Previous button element + * @param {Element} els.play - Play button element + * @param {Element} els.pause - Pause button element + * @param {Element} els.pagination - Pagination element + * @param {Object} config - Swiper config + * @return {Object} Swiper instance + */ +export default function createSwiper( els, config = {} ) { + const isVisible = 0 < els.container.offsetWidth && 0 < els.container.offsetHeight; + + // Don't initialize if the swiper is hidden on initial mount. + if ( ! isVisible ) { + return false; + } + + const swiper = new Swiper( els.container, { + /** + * Remove the messages, as we're announcing the slide content and number. + * These messages are overwriting the slide announcement. + */ + a11y: false, + autoplay: !! config.autoplay && { + delay: config.delay, + disableOnInteraction: false, + }, + effect: 'slide', + grabCursor: true, + init: false, + initialSlide: config.initialSlide || 0, + loop: true, + navigation: { + nextEl: els.next, + prevEl: els.prev, + }, + pagination: { + bulletElement: 'button', + clickable: true, + el: els.pagination, + type: 'bullets', + renderBullet: ( index, className ) => { + // Use a custom render, as Swiper's render is inaccessible. + return ``; + }, + }, + watchSlidesProgress: config.slidesPerView > 1, + preventClicksPropagation: false, // Necessary for normal block interactions. + releaseFormElements: false, + setWrapperSize: true, + slidesPerView: config.slidesPerView, + spaceBetween: 16, + touchStartPreventDefault: false, + breakpoints: { + 320: { + slidesPerView: 1, + }, + 782: { + slidesPerView: config.slidesPerView > 1 ? 2 : 1, + }, + 1168: { + slidesPerView: config.slidesPerView, + }, + }, + on: { + init() { + forEachNode( this.wrapperEl.querySelectorAll( '.swiper-slide' ), slide => + deactivateSlide( slide ) + ); + + setAspectRatio.call( this ); // Set the aspect ratio on init. + activateSlide( this.slides[ this.activeIndex ] ); // Set-up our active slide. + }, + + slideChange() { + const currentSlide = this.slides[ this.activeIndex ]; + + deactivateSlide( this.slides[ this.previousIndex ] ); + + activateSlide( currentSlide ); + + /** + * If we're autoplaying, don't announce the slide change, as that would + * be supremely annoying. + */ + if ( ! this.autoplay?.running ) { + // Announce the contents of the slide. + const currentImage = currentSlide.querySelector( 'img' ); + const alt = currentImage ? currentImage?.alt : false; + + const slideInfo = sprintf( + /* translators: 1: current slide number and 2: total number of slides */ + __( 'Slide %1$s of %2$s', 'jetpack-mu-wpcom' ), + this.realIndex + 1, + this.pagination?.bullets?.length || 0 + ); + + speak( + escapeHTML( + `${ currentSlide.innerText }, + ${ + alt + ? /* translators: the title of the image. */ sprintf( + __( 'Image: %s, ', 'jetpack-mu-wpcom' ), + alt + ) + : '' + } + ${ slideInfo }` + ), + 'assertive' + ); + } + }, + }, + } ); + + /** + * Forces an aspect ratio for each slide. + */ + function setAspectRatio() { + const { aspectRatio } = config; + const slides = Array.from( this.slides ); + + slides.forEach( slide => { + slide.style.height = `${ slide.clientWidth * aspectRatio }px`; + } ); + } + + swiper.on( 'imagesReady', setAspectRatio ); + swiper.on( 'resize', setAspectRatio ); + + if ( config.autoplay ) { + /** + * Handles the Pause button click. + */ + function handlePauseButtonClick() { + swiper.autoplay.stop(); + els.play.focus(); // Move focus to the play button. + } + + /** + * Handles the Play button click. + */ + function handlePlayButtonClick() { + swiper.autoplay.start(); + els.pause.focus(); // Move focus to the pause button. + } + + swiper.on( 'init', function () { + els.play.addEventListener( 'click', handlePlayButtonClick ); + els.pause.addEventListener( 'click', handlePauseButtonClick ); + } ); + + swiper.on( 'autoplayStart', function () { + els.block.classList.add( autoplayClassName ); // Hide play & show pause button. + speak( __( 'Playing', 'jetpack-mu-wpcom' ), 'assertive' ); + } ); + + swiper.on( 'autoplayStop', function () { + els.block.classList.remove( autoplayClassName ); // Hide pause & show play button. + speak( __( 'Paused', 'jetpack-mu-wpcom' ), 'assertive' ); + } ); + + swiper.on( 'beforeDestroy', function () { + els.play.removeEventListener( 'click', handlePlayButtonClick ); + els.pause.removeEventListener( 'click', handlePauseButtonClick ); + } ); + } + + swiper.init(); + + return swiper; +} diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/edit.js b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/edit.js new file mode 100644 index 0000000000000..c4a066ae61f1f --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/edit.js @@ -0,0 +1,580 @@ +/* eslint-disable jsx-a11y/anchor-is-valid, jsx-a11y/anchor-has-content, jsx-a11y/click-events-have-key-events, jsx-a11y/interactive-supports-focus */ + +/** + * External dependencies + */ + +/** + * WordPress dependencies + */ +import { InspectorControls } from '@wordpress/block-editor'; +// eslint-disable-next-line @wordpress/no-unsafe-wp-apis +import { + BaseControl, + Button, + ButtonGroup, + PanelBody, + PanelRow, + Placeholder, + RangeControl, + Spinner, + ToggleControl, +} from '@wordpress/components'; +import { compose } from '@wordpress/compose'; +import { withDispatch, withSelect } from '@wordpress/data'; +import { dateI18n, __experimentalGetSettings } from '@wordpress/date'; +import { Component, createRef, Fragment, RawHTML } from '@wordpress/element'; +import { decodeEntities } from '@wordpress/html-entities'; +import { __ } from '@wordpress/i18n'; +import classnames from 'classnames'; +import { isEqual } from 'lodash'; + +/** + * Internal dependencies + */ +import { PostTypesPanel, PostStatusesPanel } from '../../components/editor-panels'; +import QueryControls from '../../components/query-controls'; +import { + formatAvatars, + formatByline, + formatSponsorLogos, + formatSponsorByline, + getPostStatusLabel, +} from '../../shared/js/utils'; +// Use same posts store as Homepage Posts block. +import { postsBlockSelector, postsBlockDispatch, shouldReflow } from '../homepage-articles/utils'; +import createSwiper from './create-swiper'; + +// Max number of slides that can be shown at once. +const MAX_NUMBER_OF_SLIDES = 6; + +class Edit extends Component { + constructor( props ) { + super( props ); + + this.btnPlayRef = createRef(); + this.btnPauseRef = createRef(); + this.btnNextRef = createRef(); + this.btnPrevRef = createRef(); + this.carouselRef = createRef(); + this.paginationRef = createRef(); + + this.state = { + swiperInitialized: false, + }; + } + + componentDidMount() { + this.initializeSwiper( 0 ); + this.props.triggerReflow(); + } + + componentDidUpdate( prevProps ) { + const isVisible = + 0 < this.carouselRef.current.offsetWidth && 0 < this.carouselRef.current.offsetHeight; + + // Bail early if the component is hidden. + if ( ! isVisible ) { + return false; + } + + // If the swiper hasn't been initialized yet, initialize it. + if ( ! this.state.swiperInitialized ) { + return this.initializeSwiper( 0 ); + } + + if ( shouldReflow( prevProps, this.props ) ) { + this.props.triggerReflow(); + } + + const { attributes, latestPosts } = this.props; + + if ( + ! isEqual( prevProps.latestPosts, latestPosts ) || + ! isEqual( prevProps.attributes, attributes ) + ) { + let initialSlide = 0; + + if ( this.swiperInstance ) { + if ( latestPosts && this.swiperInstance.realIndex < latestPosts.length ) { + initialSlide = this.swiperInstance.realIndex; + } + this.setState( { swiperInitialized: false } ); + this.swiperInstance.destroy( true, true ); + } + + this.initializeSwiper( initialSlide ); + } + } + + componentWillUnmount() { + this.props.triggerReflow(); + } + + initializeSwiper( initialSlide ) { + const { latestPosts } = this.props; + + if ( latestPosts && latestPosts.length ) { + const { aspectRatio, autoplay, delay, slidesPerView } = this.props.attributes; + const swiperInstance = createSwiper( + { + block: this.carouselRef.current, // Editor uses the same wrapper for block and swiper container. + container: this.carouselRef.current, + next: this.btnNextRef.current, + prev: this.btnPrevRef.current, + play: this.btnPlayRef.current, + pause: this.btnPauseRef.current, + pagination: this.paginationRef.current, + }, + { + aspectRatio, + autoplay, + delay: delay * 1000, + initialSlide, + slidesPerView: slidesPerView <= latestPosts.length ? slidesPerView : latestPosts.length, + } + ); + + // Swiper won't be initialized unless the component is visible in the viewport. + if ( swiperInstance ) { + this.swiperInstance = swiperInstance; + this.setState( { swiperInitialized: true } ); + } + } + } + + render() { + const { attributes, className, setAttributes, latestPosts, isUIDisabled } = this.props; + const { + aspectRatio, + authors, + autoplay, + categories, + includeSubcategories, + customTaxonomies, + delay, + hideControls, + imageFit, + postsToShow, + postType, + showCategory, + showDate, + showAuthor, + showAvatar, + showCaption, + showCredit, + showTitle, + slidesPerView, + specificMode, + specificPosts, + tags, + } = attributes; + const classes = classnames( + className, + 'wp-block-newspack-blocks-carousel', // Default to make styles work for third-party consumers. + 'wpnbpc', // Shortened version of the default classname. + 'slides-per-view-' + slidesPerView, + 'swiper', + { + 'wp-block-newspack-blocks-carousel__autoplay-playing': autoplay, + 'newspack-block--disabled': isUIDisabled, + 'hide-controls': hideControls, + } + ); + const dateFormat = __experimentalGetSettings().formats.date; + const hasNoPosts = latestPosts && ! latestPosts.length; + const hasOnePost = latestPosts && latestPosts.length === 1; + const maxPosts = latestPosts ? Math.min( postsToShow, latestPosts.length ) : postsToShow; + const aspectRatioOptions = [ + { + value: 1, + label: /* translators: label for square aspect ratio option */ __( + 'Square', + 'jetpack-mu-wpcom' + ), + shortName: /* translators: abbreviation for 1:1 aspect ratio */ __( + '1:1', + 'jetpack-mu-wpcom' + ), + }, + { + value: 0.75, + label: /* translators: label for 4:3 aspect ratio option */ __( '4:3', 'jetpack-mu-wpcom' ), + shortName: /* translators: abbreviation for 4:3 aspect ratio */ __( + '4:3', + 'jetpack-mu-wpcom' + ), + }, + { + value: 0.5625, + label: /* translators: label for 16:9 aspect ratio option */ __( + '16:9', + 'jetpack-mu-wpcom' + ), + shortName: /* translators: abbreviation for 16:9 aspect ratio */ __( + '16:9', + 'jetpack-mu-wpcom' + ), + }, + { + value: 4 / 3, + label: /* translators: label for 3:4 aspect ratio option */ __( '3:4', 'jetpack-mu-wpcom' ), + shortName: /* translators: abbreviation for 3:4 aspect ratio */ __( + '3:4', + 'jetpack-mu-wpcom' + ), + }, + { + value: 16 / 9, + label: /* translators: label for 9:16 aspect ratio option */ __( + '9:16', + 'jetpack-mu-wpcom' + ), + shortName: /* translators: abbreviation for 9:16 aspect ratio */ __( + '9:16', + 'jetpack-mu-wpcom' + ), + }, + ]; + + return ( + ( +
+ { hasNoPosts && ( + +
+ { __( 'Sorry, no posts were found.', 'jetpack-mu-wpcom' ) } +
+
+ ) } + { ( ! this.state.swiperInitialized || ! latestPosts ) && ( + } className="component-placeholder__align-center" /> + ) } + { latestPosts && ( + + { autoplay && ( + + + ); + } ) } + + + + + + + + + + + + { + setAttributes( { hideControls: _hideControls } ); + } } + /> + { + setAttributes( { autoplay: _autoplay } ); + } } + /> + { autoplay && ( + { + setAttributes( { delay: _delay } ); + } } + min={ 1 } + max={ 20 } + /> + ) } + { latestPosts && 1 < latestPosts.length && ( + { + setAttributes( { slidesPerView: _slidesPerView } ); + } } + min={ 1 } + max={ + specificMode + ? Math.min( MAX_NUMBER_OF_SLIDES, latestPosts.length ) + : Math.min( MAX_NUMBER_OF_SLIDES, maxPosts ) + } + /> + ) } + + + + setAttributes( { showTitle: ! showTitle } ) } + /> + + + setAttributes( { showDate: ! showDate } ) } + /> + + + setAttributes( { showCategory: ! showCategory } ) } + /> + + + setAttributes( { showAuthor: ! showAuthor } ) } + /> + + { showAuthor && ( + + setAttributes( { showAvatar: ! showAvatar } ) } + /> + + ) } + + setAttributes( { showCaption: ! showCaption } ) } + /> + + + setAttributes( { showCredit: ! showCredit } ) } + /> + + + + + + ) + ); + } +} + +export default compose( [ withSelect( postsBlockSelector ), withDispatch( postsBlockDispatch ) ] )( + Edit +); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/editor.js b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/editor.js new file mode 100644 index 0000000000000..ed4f2816371ba --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/editor.js @@ -0,0 +1,7 @@ +/** + * Internal dependencies + */ +import { registerBlockType } from '@wordpress/blocks'; +import { name, settings } from '.'; + +registerBlockType( `newspack-blocks/${ name }`, settings ); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/editor.scss b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/editor.scss new file mode 100644 index 0000000000000..4cb2594373e8d --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/editor.scss @@ -0,0 +1,40 @@ +@use "../../shared/sass/placeholder"; + +.wp-block-newspack-blocks-carousel { + .swiper-wrapper { + height: auto; + pointer-events: none; + } + .entry-title { + color: white; + } + a { + color: inherit; + + &:active, + &:focus, + &:hover { + color: rgba(255, 255, 255, 0.75); + } + } + .post-thumbnail img { + display: block; + } + &__placeholder { + height: 100%; + } + .swiper-pagination-bullet.swiper-pagination-bullet-active { + opacity: 1; + width: 24px; + } + &.hide-controls { + button { + display: none; + visibility: hidden; + } + } +} +.editor-block-list__layout .editor-block-list__block .wpnbpc .entry-title a, +.editor-block-list__layout .editor-block-list__block .wpnbpc .entry-meta .byline a { + color: inherit; +} diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/index.js b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/index.js new file mode 100644 index 0000000000000..37b562d71a759 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/index.js @@ -0,0 +1,149 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import edit from './edit'; + +/** + * Style dependencies - will load in editor + */ +import './view.scss'; +import './editor.scss'; + +export const name = 'carousel'; +export const title = __( 'Post Carousel', 'jetpack-mu-wpcom' ); + +export const icon = ( + + + + +); + +export const settings = { + title, + icon: { + src: icon, + foreground: '#36f', + }, + category: 'newspack', + keywords: [ + __( 'posts', 'jetpack-mu-wpcom' ), + __( 'slideshow', 'jetpack-mu-wpcom' ), + __( 'carousel', 'jetpack-mu-wpcom' ), + ], + description: __( 'A carousel of posts.', 'jetpack-mu-wpcom' ), + attributes: { + className: { + type: 'string', + }, + imageFit: { + type: 'string', + default: 'cover', + }, + autoplay: { + type: 'boolean', + default: false, + }, + delay: { + type: 'number', + default: 5, + }, + postsToShow: { + type: 'integer', + default: 3, + }, + authors: { + type: 'array', + }, + categories: { + type: 'array', + }, + includeSubcategories: { + type: 'boolean', + default: true, + }, + tags: { + type: 'array', + }, + customTaxonomies: { + type: 'array', + }, + showDate: { + type: 'boolean', + default: true, + }, + showAuthor: { + type: 'boolean', + default: true, + }, + showAvatar: { + type: 'boolean', + default: true, + }, + showCaption: { + type: 'boolean', + default: false, + }, + showCredit: { + type: 'boolean', + default: false, + }, + showCategory: { + type: 'boolean', + default: false, + }, + showTitle: { + type: 'boolean', + default: true, + }, + postType: { + type: 'array', + default: [ 'post' ], + items: { + type: 'string', + }, + }, + specificMode: { + type: 'boolean', + default: false, + }, + specificPosts: { + type: 'array', + default: [], + items: { type: 'integer' }, + }, + slidesPerView: { + type: 'number', + default: 1, + }, + hideControls: { + type: 'boolean', + default: false, + }, + aspectRatio: { + type: 'number', + default: 0.75, + }, + includedPostStatuses: { + type: 'array', + default: [ 'publish' ], + items: { type: 'string' }, + }, + }, + supports: { + html: false, + align: [ 'center', 'wide', 'full' ], + }, + edit, + save: () => null, // to use view.php +}; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/view.js b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/view.js new file mode 100644 index 0000000000000..34b621a5c1d29 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/view.js @@ -0,0 +1,51 @@ +/** + * WordPress dependencies + */ +import domReady from '@wordpress/dom-ready'; + +/** + * Internal dependencies + */ +import createSwiper from './create-swiper'; +import './view.scss'; + +if ( typeof window !== 'undefined' ) { + domReady( () => { + const blocksArray = Array.from( + document.querySelectorAll( '.wp-block-newspack-blocks-carousel' ) + ); + blocksArray.forEach( block => { + // Initialize Swiper only when the carousel becomes visible. + const observer = new IntersectionObserver( + entries => { + entries.forEach( entry => { + if ( entry.isIntersecting ) { + const slidesPerView = parseInt( block.dataset.slidesPerView ); + const slideCount = parseInt( block.dataset.slideCount ); + createSwiper( + { + block, + container: block.querySelector( '.swiper' ), + prev: block.querySelector( '.swiper-button-prev' ), + next: block.querySelector( '.swiper-button-next' ), + pagination: block.querySelector( '.swiper-pagination-bullets' ), + pause: block.querySelector( '.swiper-button-pause' ), + play: block.querySelector( '.swiper-button-play' ), + }, + { + aspectRatio: parseFloat( block.dataset.aspectRatio ), + autoplay: !! parseInt( block.dataset.autoplay ), + delay: parseInt( block.dataset.autoplay_delay ) * 1000, + slidesPerView: slidesPerView <= slideCount ? slidesPerView : slideCount, + spaceBetween: 16, + } + ); + } + } ); + }, + { threshold: 0.25 } + ); + observer.observe( block ); + } ); + } ); +} diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/view.php b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/view.php new file mode 100644 index 0000000000000..87000f1e301fd --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/view.php @@ -0,0 +1,408 @@ +have_posts() ) { + return; + } + + $counter = 0; + + ob_start(); + if ( $article_query->have_posts() ) : + while ( $article_query->have_posts() ) : + $article_query->the_post(); + $post_id = get_the_ID(); + $authors = Newspack_Blocks::prepare_authors(); + $newspack_blocks_post_id[ $post_id ] = true; + + $article_classes = array( + 'post-has-image', + 'swiper-slide', + ); + + // Add classes based on the post's assigned categories and tags. + $article_classes[] = Newspack_Blocks::get_term_classes( $post_id ); + + // Get sponsors for this post. + $sponsors = Newspack_Blocks::get_all_sponsors( $post_id ); + + ++$counter; + $has_featured_image = has_post_thumbnail(); + $post_type = get_post_type(); + $post_link = Newspack_Blocks::get_post_link( $post_id ); + + // Support Newspack Listings hide author/publish date options. + $hide_author = apply_filters( 'newspack_listings_hide_author', false ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + $hide_publish_date = apply_filters( 'newspack_listings_hide_publish_date', false ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + $show_author = $attributes['showAuthor'] && ! $hide_author; + $show_date = $attributes['showDate'] && ! $hide_publish_date; + $show_caption = $attributes['showCaption']; + $show_credit = $attributes['showCredit']; + + // Validate the value of the "image fit" attribute. + $image_fits = array( 'cover', 'contain' ); + $image_fit = in_array( $attributes['imageFit'], $image_fits, true ) ? $attributes['imageFit'] : $image_fits[0]; + ?> + +
+ +
+ + + +
+ + +
+ + + ', '' ); + } + ?> + + + +
+ ', + absint( $x ), + esc_attr( $aria_label ), + 0 === $x ? 'selected' : '' + ); + } + + $slides_per_view = absint( $attributes['slidesPerView'] ?? 1 ); + $aspect_ratio = floatval( $attributes['aspectRatio'] ?? 0.75 ); + + $selector = sprintf( + '
%2$s
', + $attributes['hideControls'] ? 'aria-hidden="true"' : '', + implode( '', $buttons ) + ); + $navigation = 1 === $counter ? '' : sprintf( + '', + esc_attr__( 'Previous Slide', 'jetpack-mu-wpcom' ), + esc_attr__( 'Next Slide', 'jetpack-mu-wpcom' ), + $attributes['hideControls'] ? 'aria-hidden="true"' : '' + ); + $carousel = sprintf( + '
%s
%s
', + $slides, + $navigation + ); + $autoplay_ui = $autoplay ? newspack_blocks_carousel_block_autoplay_ui( $newspack_blocks_carousel_id ) : ''; + + $data_attributes = array( + 'data-current-post-id=' . $post_id, + 'data-slides-per-view=' . esc_attr( $slides_per_view ), + 'data-slide-count=' . $counter, + 'data-aspect-ratio=' . esc_attr( $aspect_ratio ), + ); + + if ( $autoplay ) { + $data_attributes[] = 'data-autoplay=1'; + $data_attributes[] = sprintf( 'data-autoplay_delay=%s', esc_attr( $delay ) ); + } + Newspack_Blocks::enqueue_view_assets( 'carousel' ); + if ( 1 === $counter ) { + $selector = ''; + } + return sprintf( + '', + esc_attr( $classes ), + absint( $newspack_blocks_carousel_id ), + esc_attr( implode( ' ', $data_attributes ) ), + $autoplay_ui, + $carousel, + $selector + ); +} + +/** + * Generate autoplay play/pause UI. + * + * @return string Autoplay UI markup. + */ +function newspack_blocks_carousel_block_autoplay_ui() { + return sprintf( + '', + esc_attr__( 'Pause Slideshow', 'jetpack-mu-wpcom' ), + esc_attr__( 'Play Slideshow', 'jetpack-mu-wpcom' ) + ); +} + +/** + * Registers the `newspack-blocks/carousel` block on server. + */ +function newspack_blocks_register_carousel() { + register_block_type( + apply_filters( 'newspack_blocks_block_name', 'newspack-blocks/carousel' ), + apply_filters( + 'newspack_blocks_block_args', + array( + 'attributes' => array( + 'className' => array( + 'type' => 'string', + ), + 'postsToShow' => array( + 'type' => 'integer', + 'default' => 3, + ), + 'authors' => array( + 'type' => 'array', + 'default' => array(), + 'items' => array( + 'type' => 'integer', + ), + ), + 'categories' => array( + 'type' => 'array', + 'default' => array(), + 'items' => array( + 'type' => 'integer', + ), + ), + 'tags' => array( + 'type' => 'array', + 'default' => array(), + 'items' => array( + 'type' => 'integer', + ), + ), + 'customTaxonomies' => array( + 'type' => 'array', + 'default' => array(), + 'items' => array( + 'type' => 'object', + 'properties' => array( + 'slug' => array( + 'type' => 'string', + ), + 'terms' => array( + 'type' => 'array', + 'items' => array( + 'type' => 'integer', + ), + ), + ), + ), + ), + 'autoplay' => array( + 'type' => 'boolean', + 'default' => false, + ), + 'delay' => array( + 'type' => 'integer', + 'default' => 5, + ), + 'showAuthor' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'showAvatar' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'showCaption' => array( + 'type' => 'boolean', + 'default' => false, + ), + 'showCredit' => array( + 'type' => 'boolean', + 'default' => false, + ), + 'showCategory' => array( + 'type' => 'boolean', + 'default' => false, + ), + 'showDate' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'imageFit' => array( + 'type' => 'string', + 'default' => 'cover', + ), + 'showTitle' => array( + 'type' => 'boolean', + 'default' => true, + ), + 'slidesPerView' => array( + 'type' => 'number', + 'default' => 1, + ), + 'hideControls' => array( + 'type' => 'boolean', + 'default' => false, + ), + 'aspectRatio' => array( + 'type' => 'number', + 'default' => 0.75, + ), + ), + 'render_callback' => 'newspack_blocks_render_block_carousel', + 'supports' => array(), + ), + 'carousel' + ) + ); +} +add_action( 'init', 'newspack_blocks_register_carousel' ); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/view.scss b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/view.scss new file mode 100644 index 0000000000000..4679e48722ee0 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/carousel/view.scss @@ -0,0 +1,386 @@ +@use "../../shared/sass/variables"; +@use "../../shared/sass/mixins"; +@use "../../shared/sass/colors"; +@use "../../shared/sass/preview"; + +.wp-block-newspack-blocks-carousel { + position: relative; + margin-top: 0; + + article { + max-width: 100%; + padding: 0; + position: relative; + margin-bottom: 0; + word-break: break-word; + overflow-wrap: break-word; + a { + color: #fff; + + &:active, + &:focus, + &:hover { + color: rgba(255, 255, 255, 0.75); + } + } + .entry-title { + font-size: 1.2em; + + a { + /* autoprefixer: off */ + -webkit-box-orient: vertical; + /* autoprefixer: on */ + display: -webkit-box; + -webkit-line-clamp: 3; + max-height: 3.5625em; + overflow: hidden; + text-overflow: ellipsis; + } + } + .avatar { + height: 1.8em; + width: 1.8em; + } + + @include mixins.media( tablet ) { + .entry-title { + font-size: 1.6em; + } + .avatar { + height: 40px; + width: 40px; + } + } + .entry-wrapper { + bottom: 0; + background-color: rgba(black, 0.5); + color: white; + left: 0; + padding: 1.5em; + position: absolute; + right: 0; + } + .entry-meta { + color: #fff; + margin-bottom: 0; + font-size: 0.8em; + + a { + color: #fff; + font-weight: bold; + text-decoration: none; + + &:active, + &:focus, + &:hover { + color: rgba(255, 255, 255, 0.75); + } + } + } + + .entry-caption { + margin-top: var(--wp--preset--spacing--00, var(--wp--preset--spacing--20, 0.5rem)); + width: 100%; + + figcaption { + color: #fff; + font-size: var(--wp--preset--font-size--x-small, var(--newspack-theme-font-size-sm, 0.8em)); + line-height: var(--wp--custom--line-height--x-small, var(--newspack-theme-font-line-height-body, 1.6)); + + a { + font-weight: 400; + text-decoration: underline; + } + } + } + } + .post-thumbnail { + margin: 0; + height: 100%; + width: 100%; + padding: 0; + position: relative; + a, + img { + display: block; + height: 100%; + object-fit: cover; + width: 100%; + + &.image-fit-contain { + object-fit: contain; + } + } + } + &__placeholder { + height: 420px; + background: colors.$color__background-screen; + } + .swiper-initialized .wp-block-newspack-blocks-carousel__placeholder { + height: 100%; + } + p { + white-space: normal; + } + .swiper-pagination-bullets { + align-items: flex-end; + bottom: 0; + display: flex; + flex-wrap: wrap; + height: calc(1.5em + 12px); + justify-content: center; + padding: 0; + position: relative; + } + .swiper-pagination-bullet { + background: black; + border-radius: 6px; + display: inline-block; + height: 12px; + margin: 0 4px; + opacity: 0.5; + padding: 0; + transition: box-shadow 250ms, opacity 250ms, width 250ms; + width: 12px; + &:focus { + box-shadow: 0 0 0 2px white, 0 0 0 4px black; + outline: 0; + } + &.swiper-pagination-bullet-active, + &[selected] { + opacity: 1; + outline: 0; + width: 24px; + } + + span { + @include mixins.visuallyHidden; + } + } + .swiper-button { + background-color: rgba(black, 0.5); + background-position: center; + background-repeat: no-repeat; + background-size: 24px; + border: 0; + border-radius: 4px; + box-shadow: none; + cursor: pointer; + height: 48px; + margin: 0; + padding: 0; + transition: background-color 250ms, box-shadow 250ms; + width: 48px; + &:focus, + &:hover { + background-color: rgba(black, 0.75); + } + &:focus { + box-shadow: inset 0 0 0 2px rgba(black, 0.75), inset 0 0 0 4px white; + outline: 0; + } + } + .swiper-button-next, + .swiper-button-prev { + left: 1.5em; + display: none; + right: auto; + margin-top: -24px; + + @include mixins.media( mobile ) { + display: block; + } + } + .swiper-button-prev::after, + .swiper-rtl .swiper-button-next::after { + content: none; + } + .swiper-button-next::after, + .swiper-rtl .swiper-button-prev::after { + content: none; + } + .swiper-button-next { + background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M5.88%204.12L13.76%2012l-7.88%207.88L8%2022l10-10L8%202z'%20fill='white'/%3E%3Cpath%20fill='none'%20d='M0 0h24v24H0z'/%3E%3C/svg%3E"); + left: auto; + right: 1.5em; + } + .swiper-button-prev { + background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M18%204.12L10.12%2012%2018%2019.88%2015.88%2022l-10-10%2010-10z'%20fill='white'/%3E%3Cpath%20fill='none'%20d='M0 0h24v24H0z'/%3E%3C/svg%3E"); + } + .swiper-button-pause, + .swiper-button-play { + background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M6%2019h4V5H6v14zm8-14v14h4V5h-4z'%20fill='white'/%3E%3Cpath%20d='M0%200h24v24H0z'%20fill='none'/%3E%3C/svg%3E"); + display: none; + margin-top: 0; + position: absolute; + right: 1.5em; + top: 1.5em; + transform: none; + z-index: 9; + } + .swiper-button-play { + background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M8%205v14l11-7z'%20fill='white'/%3E%3Cpath%20d='M0 0h24v24H0z'%20fill='none'/%3E%3C/svg%3E"); + } + + /* Swiper Slide */ + .swiper-slide { + height: auto; + max-height: 75vh; + } + + /* Image styles */ + figcaption { + font-size: variables.$font__size-xxs; + } + + /* Headings */ + .entry-title { + margin: 0 0 0.25em; + a { + color: #fff; + text-decoration: none; + } + } + + /* Article meta */ + .entry-meta { + display: flex; + flex-wrap: wrap; + align-items: center; + margin-top: 0.5em; + .byline:not(:last-child) { + margin-right: 1.5em; + } + } + .cat-links { + color: #fff; + font-size: 0.6em; + font-weight: bold; + margin: 0 0 0.5em; + + &.sponsor-label { + align-items: center; + + .flag + a { + margin-left: 0.5em; + } + } + + a { + text-decoration: none; + } + } + .avatar { + border-radius: 100%; + display: block; + margin-right: 0.5em; + } + + &.wp-block-newspack-blocks-carousel__autoplay-playing .swiper-button-pause, + .swiper-button-play { + display: block; + } + &.wp-block-newspack-blocks-carousel__autoplay-playing .swiper-button-play, + .swiper-button-pause { + display: none; + } + + // Make sure Jetpack Content Options don't affect the block. + .posted-on, + .cat-links, + .tags-links, + .byline, + .author-avatar { + clip: auto; + height: auto; + position: relative; + width: auto; + } + + // If hideControls is enabled, visually hide the UI elements. + &.hide-controls { + button { + display: none; + visibility: hidden; + } + } + + &.slides-per-view-2 article { + .entry-title { + @include mixins.media( tablet ) { + font-size: 1.4em; + } + } + } + + &.slides-per-view-3 article, + &.slides-per-view-4 article { + .entry-title { + @include mixins.media( tablet ) { + font-size: 1.2em; + } + @include mixins.media( desktop ) { + font-size: 1em; + } + } + .entry-meta { + @include mixins.media( tablet ) { + font-size: 0.7em; + } + } + } + + &.slides-per-view-5 article, + &.slides-per-view-6 article { + .entry-wrapper { + @include mixins.media( desktop ) { + padding: 1em; + } + } + .entry-title { + @include mixins.media( tablet ) { + font-size: 1.2em; + } + @include mixins.media( desktop ) { + font-size: 0.9em; + + a { + -webkit-line-clamp: 2; + } + } + } + .entry-meta { + @include mixins.media( tablet ) { + font-size: 0.7em; + } + } + } +} + +/* stylelint-disable selector-type-no-unknown */ +.wpnbpc { + .entry-sponsors { + align-items: center; + display: inline-flex; + flex-wrap: wrap; + gap: 0.5em; + width: 100%; + + &.plus-author { + font-size: 0.9em; + + &:not(:last-child) { + margin-bottom: 0.5rem; + } + } + } + + .sponsor-logos { + align-items: center; + display: inline-flex; + flex-wrap: wrap; + gap: 0.5em; + line-height: 1; + } +} +/* stylelint-enable */ diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/block.json b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/block.json new file mode 100644 index 0000000000000..55143540cbf39 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/block.json @@ -0,0 +1,243 @@ +{ + "name": "homepage-articles", + "category": "newspack", + "textdomain": "jetpack-mu-wpcom", + "attributes": { + "className": { + "type": "string", + "default": "" + }, + "showExcerpt": { + "type": "boolean", + "default": true + }, + "excerptLength": { + "type": "number", + "default": 55 + }, + "showReadMore": { + "type": "boolean", + "default": false + }, + "readMoreLabel": { + "type": "string", + "default": "Keep reading" + }, + "showDate": { + "type": "boolean", + "default": true + }, + "showImage": { + "type": "boolean", + "default": true + }, + "showCaption": { + "type": "boolean", + "default": false + }, + "showCredit": { + "type": "boolean", + "default": false + }, + "disableImageLazyLoad": { + "type": "boolean", + "default": false + }, + "fetchPriority": { + "type": "string", + "default": "" + }, + "imageShape": { + "type": "string", + "default": "landscape" + }, + "minHeight": { + "type": "integer", + "default": 0 + }, + "moreButton": { + "type": "boolean", + "default": false + }, + "moreButtonText": { + "type": "string", + "default": "" + }, + "showAuthor": { + "type": "boolean", + "default": true + }, + "showAvatar": { + "type": "boolean", + "default": true + }, + "showCategory": { + "type": "boolean", + "default": false + }, + "postLayout": { + "type": "string", + "default": "list" + }, + "columns": { + "type": "integer", + "default": 3 + }, + "colGap": { + "type": "integer", + "default": 3 + }, + "postsToShow": { + "type": "integer", + "default": 3 + }, + "mediaPosition": { + "type": "string", + "default": "top" + }, + "authors": { + "type": "array", + "default": [], + "items": { + "type": "integer" + } + }, + "categories": { + "type": "array", + "default": [], + "items": { + "type": "integer" + } + }, + "includeSubcategories": { + "type": "boolean", + "default": true + }, + "tags": { + "type": "array", + "default": [], + "items": { + "type": "integer" + } + }, + "customTaxonomies": { + "type": "array", + "default": [], + "items": { + "type": "object", + "properties": { + "slug": { + "type": "string" + }, + "terms": { + "type": "array", + "items": { + "type": "integer" + } + } + } + } + }, + "tagExclusions": { + "type": "array", + "default": [], + "items": { + "type": "integer" + } + }, + "categoryExclusions": { + "type": "array", + "default": [], + "items": { + "type": "integer" + } + }, + "customTaxonomyExclusions": { + "type": "array", + "default": [], + "items": { + "type": "object", + "properties": { + "slug": { + "type": "string" + }, + "terms": { + "type": "array", + "items": { + "type": "integer" + } + } + } + } + }, + "specificPosts": { + "type": "array", + "default": [], + "items": { + "type": "integer" + } + }, + "typeScale": { + "type": "integer", + "default": 4 + }, + "imageScale": { + "type": "integer", + "default": 3 + }, + "mobileStack": { + "type": "boolean", + "default": false + }, + "sectionHeader": { + "type": "string", + "default": "" + }, + "specificMode": { + "type": "boolean", + "default": false + }, + "textColor": { + "type": "string", + "default": "" + }, + "customTextColor": { + "type": "string", + "default": "" + }, + "singleMode": { + "type": "boolean", + "default": false + }, + "showSubtitle": { + "type": "boolean", + "default": false + }, + "postType": { + "type": "array", + "default": [ + "post" + ], + "items": { + "type": "string" + } + }, + "textAlign": { + "type": "string", + "default": "left" + }, + "includedPostStatuses": { + "type": "array", + "default": [ + "publish" + ], + "items": { + "type": "string" + } + }, + "deduplicate": { + "type": "boolean", + "default": true + } + } +} diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/class-wp-rest-newspack-articles-controller.php b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/class-wp-rest-newspack-articles-controller.php new file mode 100644 index 0000000000000..d35a74895283f --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/class-wp-rest-newspack-articles-controller.php @@ -0,0 +1,239 @@ +namespace = 'newspack-blocks/v1'; + } + + /** + * Registers the necessary REST API routes. + * + * @access public + */ + public function register_routes() { + // Endpoint to get articles on the front-end. + register_rest_route( + $this->namespace, + '/articles', + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_items' ), + 'args' => $this->get_attribute_schema(), + 'permission_callback' => '__return_true', + ), + ) + ); + + // Endpoint to get articles in the editor, in regular/query mode. + register_rest_route( + $this->namespace, + '/newspack-blocks-posts', + array( + 'methods' => \WP_REST_Server::READABLE, + 'callback' => array( 'Newspack_Blocks_API', 'posts_endpoint' ), + 'args' => array_merge( + $this->get_attribute_schema(), + array( + 'exclude' => array( // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude + 'type' => 'array', + 'items' => array( + 'type' => 'integer', + ), + 'default' => array(), + ), + 'include' => array( + 'type' => 'array', + 'items' => array( + 'type' => 'integer', + ), + 'default' => array(), + ), + ) + ), + 'permission_callback' => function () { + return current_user_can( 'edit_posts' ); + }, + ) + ); + + // Endpoint to get articles in the editor, in specific posts mode. + register_rest_route( + $this->namespace, + '/newspack-blocks-specific-posts', + array( + 'methods' => \WP_REST_Server::READABLE, + 'callback' => array( 'Newspack_Blocks_API', 'specific_posts_endpoint' ), + 'args' => array( + 'search' => array( + 'sanitize_callback' => 'sanitize_text_field', + ), + 'postsToShow' => array( + 'sanitize_callback' => 'absint', + ), + 'postType' => array( + 'type' => 'array', + 'items' => array( + 'type' => 'string', + ), + 'default' => array(), + ), + ), + 'permission_callback' => function () { + return current_user_can( 'edit_posts' ); + }, + ) + ); + + // Endpoint to get styles in the editor. + register_rest_route( + $this->namespace, + '/homepage-articles-css', + array( + 'methods' => \WP_REST_Server::READABLE, + 'callback' => array( 'Newspack_Blocks_API', 'css_endpoint' ), + 'permission_callback' => function () { + return current_user_can( 'edit_posts' ); + }, + ) + ); + } + + /** + * Returns a list of rendered posts. + * + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response + */ + public function get_items( $request ) { + $page = $request->get_param( 'page' ) ?? 1; + $exclude_ids = $request->get_param( 'exclude_ids' ) ?? array(); + $next_page = $page + 1; + $attributes = wp_parse_args( + $request->get_params() ?? array(), + wp_list_pluck( $this->get_attribute_schema(), 'default' ) + ); + + $article_query_args = Newspack_Blocks::build_articles_query( $attributes, apply_filters( 'newspack_blocks_block_name', 'newspack-blocks/homepage-articles' ) ); + + // If using exclude_ids, don't worry about pagination. Just get the next postsToShow number of results without the excluded posts. Otherwise, use standard WP pagination. + $query = ! empty( $exclude_ids ) ? + array_merge( + $article_query_args, + array( + 'post__not_in' => $exclude_ids, // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in + ) + ) : + array_merge( + $article_query_args, + array( + 'paged' => $page, + ) + ); + + // Run Query. + $article_query = new WP_Query( $query ); + + // Defaults. + $items = array(); + $ids = array(); + $next_url = ''; + + Newspack_Blocks::filter_excerpt( $attributes ); + + // The Loop. + while ( $article_query->have_posts() ) { + $article_query->the_post(); + $html = Newspack_Blocks::template_inc( + __DIR__ . '/templates/article.php', + array( + 'attributes' => $attributes, + ) + ); + + $items[]['html'] = $html; + $ids[] = get_the_ID(); + } + + Newspack_Blocks::remove_excerpt_filter(); + + // Provide next URL if there are more pages. + $show_next_button = ! empty( $exclude_ids ) ? $article_query->max_num_pages > 1 : $article_query->max_num_pages > $next_page; + if ( $show_next_button ) { + $next_url = add_query_arg( + array_merge( + array_map( + function ( $attribute ) { + return false === $attribute ? '0' : $attribute; + }, + $attributes + ), + array( + 'exclude_ids' => false, + 'page' => $next_page, + ) + ), + rest_url( '/newspack-blocks/v1/articles' ) + ); + } + + return rest_ensure_response( + array( + 'items' => $items, + 'ids' => $ids, + 'next' => $next_url, + ) + ); + } + + /** + * Sets up and returns attribute schema. + * + * @return array + */ + public function get_attribute_schema() { + if ( empty( $this->attribute_schema ) ) { + $block_json = json_decode( + file_get_contents( __DIR__ . '/block.json' ), // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents + true + ); + + $this->attribute_schema = array_merge( + $block_json['attributes'], + array( + 'exclude_ids' => array( + 'type' => 'array', + 'default' => array(), + 'items' => array( + 'type' => 'integer', + ), + ), + ) + ); + } + return $this->attribute_schema; + } +} diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/edit.tsx b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/edit.tsx new file mode 100644 index 0000000000000..f0b03e754c1d1 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/edit.tsx @@ -0,0 +1,834 @@ +/* eslint-disable jsx-a11y/anchor-is-valid, @typescript-eslint/no-explicit-any */ + +/** + * Internal dependencies + */ + +/** + * External dependencies + */ + +/** + * WordPress dependencies + */ +import { + BlockControls, + InspectorControls, + PanelColorSettings, + RichText, + withColors, + AlignmentControl, +} from '@wordpress/block-editor'; +import { + Button, + ButtonGroup, + PanelBody, + PanelRow, + RangeControl, + Toolbar, + ToggleControl, + TextControl, + Placeholder, + Spinner, + BaseControl, + Path, + SVG, +} from '@wordpress/components'; +import { compose } from '@wordpress/compose'; +import { withDispatch, withSelect } from '@wordpress/data'; +import { Component, Fragment, RawHTML } from '@wordpress/element'; +import { decodeEntities } from '@wordpress/html-entities'; +import { __ } from '@wordpress/i18n'; +import { + Icon, + formatListBullets, + fullscreen, + grid, + image, + postFeaturedImage, + pullLeft, + pullRight, +} from '@wordpress/icons'; +import classNames from 'classnames'; +import { PostTypesPanel, PostStatusesPanel } from '../../components/editor-panels'; +import QueryControls from '../../components/query-controls'; +import { + formatAvatars, + formatByline, + formatSponsorLogos, + formatSponsorByline, + getPostStatusLabel, +} from '../../shared/js/utils'; +import { postsBlockSelector, postsBlockDispatch, isBlogPrivate, shouldReflow } from './utils'; + +let IS_SUBTITLE_SUPPORTED_IN_THEME: boolean; +if ( + typeof window === 'object' && + window.newspack_blocks_data && + window.newspack_blocks_data.post_subtitle +) { + IS_SUBTITLE_SUPPORTED_IN_THEME = true; +} + +const landscapeIcon = ( + + + +); + +const portraitIcon = ( + + + +); + +const squareIcon = ( + + + +); + +class Edit extends Component< HomepageArticlesProps > { + renderPost = ( post: Post ) => { + const { attributes, isUIDisabled } = this.props; + const { + showImage, + imageShape, + mediaPosition, + minHeight, + showCaption, + showCredit, + showExcerpt, + showReadMore, + readMoreLabel, + showSubtitle, + showAuthor, + showAvatar, + showDate, + showCategory, + sectionHeader, + } = attributes; + + const styles = { + minHeight: + ( mediaPosition === 'behind' && + showImage && + post.newspack_featured_image_src && + minHeight + 'vh' ) || + undefined, + paddingTop: + ( mediaPosition === 'behind' && + showImage && + post.newspack_featured_image_src && + minHeight / 5 + 'vh' ) || + undefined, + }; + + const postClasses = classNames( + { + 'post-has-image': post.newspack_featured_image_src, + 'newspack-block--disabled': isUIDisabled, + }, + post.newspack_article_classes + ); + + const postTitle = this.titleForPost( post ); + return ( +
+ { getPostStatusLabel( post ) } + { showImage && post.newspack_featured_image_src && ( +
+ + { imageShape === 'landscape' && ( + + ) } + { imageShape === 'portrait' && ( + + ) } + { imageShape === 'square' && ( + + ) } + { imageShape === 'uncropped' && ( + + ) } + + { ( showCaption || showCredit ) && ( +
+ ) } +
+ ) } + +
+ { ( post.newspack_post_sponsors || + ( showCategory && 0 < post.newspack_category_info.length ) ) && ( +
+ { post.newspack_post_sponsors && ( + { post.newspack_post_sponsors[ 0 ].flag } + ) } + { showCategory && + ( ! post.newspack_post_sponsors || post.newspack_sponsors_show_categories ) && ( + { decodeEntities( post.newspack_category_info ) } + ) } +
+ ) } + { RichText.isEmpty( sectionHeader ) ? ( +

+ { postTitle } +

+ ) : ( +

+ { postTitle } +

+ ) } + { IS_SUBTITLE_SUPPORTED_IN_THEME && showSubtitle && ( + + { post.meta.newspack_post_subtitle || '' } + + ) } + { showExcerpt && ( + + { post.excerpt.rendered } + + ) } + { showReadMore && post.post_link && ( + + { readMoreLabel } + + ) } +
+ { post.newspack_post_sponsors && ( + + { formatSponsorLogos( post.newspack_post_sponsors ) } + { formatSponsorByline( post.newspack_post_sponsors ) } + + ) } + + { showAuthor && + ! post.newspack_listings_hide_author && + showAvatar && + ( ! post.newspack_post_sponsors || post.newspack_sponsors_show_author ) && + formatAvatars( post.newspack_author_info ) } + + { showAuthor && + ! post.newspack_listings_hide_author && + ( ! post.newspack_post_sponsors || post.newspack_sponsors_show_author ) && + formatByline( post.newspack_author_info ) } + + { showDate && ! post.newspack_listings_hide_publish_date && ( + + ) } + { post.article_meta_footer ? { post.article_meta_footer } : null } +
+
+
+ ); + }; + + titleForPost = ( post: Post ) => { + if ( ! post.title ) { + return ''; + } + if ( typeof post.title === 'object' && post.title.rendered ) { + return decodeEntities( post.title.rendered.trim() ); + } + }; + + renderInspectorControls = () => { + const { attributes, setAttributes, textColor, setTextColor } = this.props; + + const { + authors, + specificPosts, + postsToShow, + categories, + includeSubcategories, + customTaxonomies, + columns, + colGap, + postType, + showImage, + showCaption, + showCredit, + imageScale, + mobileStack, + minHeight, + moreButton, + showExcerpt, + showReadMore, + readMoreLabel, + excerptLength, + showSubtitle, + typeScale, + showDate, + showAuthor, + showAvatar, + showCategory, + postLayout, + mediaPosition, + specificMode, + tags, + tagExclusions, + categoryExclusions, + customTaxonomyExclusions, + } = attributes; + + const imageSizeOptions = [ + { + value: 1, + label: /* translators: label for small size option */ __( 'Small', 'jetpack-mu-wpcom' ), + shortName: /* translators: abbreviation for small size */ __( 'S', 'jetpack-mu-wpcom' ), + }, + { + value: 2, + label: /* translators: label for medium size option */ __( 'Medium', 'jetpack-mu-wpcom' ), + shortName: /* translators: abbreviation for medium size */ __( 'M', 'jetpack-mu-wpcom' ), + }, + { + value: 3, + label: /* translators: label for large size option */ __( 'Large', 'jetpack-mu-wpcom' ), + shortName: /* translators: abbreviation for large size */ __( 'L', 'jetpack-mu-wpcom' ), + }, + { + value: 4, + label: /* translators: label for extra large size option */ __( + 'Extra Large', + 'jetpack-mu-wpcom' + ), + shortName: /* translators: abbreviation for extra large size */ __( + 'XL', + 'jetpack-mu-wpcom' + ), + }, + ]; + + const colGapOptions = [ + { + value: 1, + label: /* translators: label for small size option */ __( 'Small', 'jetpack-mu-wpcom' ), + shortName: /* translators: abbreviation for small size */ __( 'S', 'jetpack-mu-wpcom' ), + }, + { + value: 2, + label: /* translators: label for medium size option */ __( 'Medium', 'jetpack-mu-wpcom' ), + shortName: /* translators: abbreviation for medium size */ __( 'M', 'jetpack-mu-wpcom' ), + }, + { + value: 3, + label: /* translators: label for large size option */ __( 'Large', 'jetpack-mu-wpcom' ), + shortName: /* translators: abbreviation for large size */ __( 'L', 'jetpack-mu-wpcom' ), + }, + ]; + + const handleAttributeChange = ( key: HomepageArticlesAttributesKey ) => ( value: any ) => + setAttributes( { [ key ]: value } ); + + return ( + + + + setAttributes( { postsToShow: _postsToShow || 1 } ) + } + specificMode={ specificMode } + onSpecificModeChange={ handleAttributeChange( 'specificMode' ) } + specificPosts={ specificPosts } + onSpecificPostsChange={ handleAttributeChange( 'specificPosts' ) } + authors={ authors } + onAuthorsChange={ handleAttributeChange( 'authors' ) } + categories={ categories } + onCategoriesChange={ handleAttributeChange( 'categories' ) } + includeSubcategories={ includeSubcategories } + onIncludeSubcategoriesChange={ handleAttributeChange( 'includeSubcategories' ) } + tags={ tags } + onTagsChange={ handleAttributeChange( 'tags' ) } + onCustomTaxonomiesChange={ handleAttributeChange( 'customTaxonomies' ) } + customTaxonomies={ customTaxonomies } + tagExclusions={ tagExclusions } + onTagExclusionsChange={ handleAttributeChange( 'tagExclusions' ) } + categoryExclusions={ categoryExclusions } + onCategoryExclusionsChange={ handleAttributeChange( 'categoryExclusions' ) } + customTaxonomyExclusions={ customTaxonomyExclusions } + onCustomTaxonomyExclusionsChange={ handleAttributeChange( 'customTaxonomyExclusions' ) } + postType={ postType } + /> + { postLayout === 'grid' && ( + + + + + + + { colGapOptions.map( option => { + const isCurrent = colGap === option.value; + return ( + + ); + } ) } + + + + + ) } + { ! specificMode && isBlogPrivate() ? ( + /* + * Hide the "Load more posts" button option on private sites. + * + * Client-side fetching from a private WP.com blog requires authentication, + * which is not provided in the current implementation. + * See https://github.com/Automattic/newspack-blocks/issues/306. + */ + + { __( + 'This blog is private, therefore the "Load more posts" feature is not active.', + 'jetpack-mu-wpcom' + ) } + + ) : ( + ! specificMode && ( + setAttributes( { moreButton: ! moreButton } ) } + /> + ) + ) } + setAttributes( { deduplicate: ! value } ) } + className="newspack-blocks-deduplication-toggle" + /> + + + + setAttributes( { showImage: ! showImage } ) } + /> + + + { showImage && ( + <> + + setAttributes( { showCaption: ! showCaption } ) } + /> + + + setAttributes( { showCredit: ! showCredit } ) } + /> + + + ) } + + { showImage && mediaPosition !== 'top' && mediaPosition !== 'behind' && ( + + + setAttributes( { mobileStack: ! mobileStack } ) } + /> + + + + + { imageSizeOptions.map( option => { + const isCurrent = imageScale === option.value; + return ( + + ); + } ) } + + + + + ) } + + { showImage && mediaPosition === 'behind' && ( + setAttributes( { minHeight: _minHeight } ) } + min={ 0 } + max={ 100 } + required + /> + ) } + + + { IS_SUBTITLE_SUPPORTED_IN_THEME && ( + + setAttributes( { showSubtitle: ! showSubtitle } ) } + /> + + ) } + + setAttributes( { showExcerpt: ! showExcerpt } ) } + /> + + { showExcerpt && ( + setAttributes( { excerptLength: value } ) } + min={ 10 } + max={ 100 } + /> + ) } + setAttributes( { showReadMore: ! showReadMore } ) } + /> + { showReadMore && ( + setAttributes( { readMoreLabel: value } ) } + /> + ) } + setAttributes( { typeScale: _typeScale } ) } + min={ 1 } + max={ 10 } + required + /> + + + + + setAttributes( { showDate: ! showDate } ) } + /> + + + setAttributes( { showCategory: ! showCategory } ) } + /> + + + setAttributes( { showAuthor: ! showAuthor } ) } + /> + + { showAuthor && ( + + setAttributes( { showAvatar: ! showAvatar } ) } + /> + + ) } + + + + + ); + }; + + componentDidMount() { + this.props.triggerReflow(); + } + componentDidUpdate( props: HomepageArticlesProps ) { + if ( shouldReflow( props, this.props ) ) { + this.props.triggerReflow(); + } + } + componentWillUnmount() { + this.props.triggerReflow(); + } + + render() { + /** + * Constants + */ + + const { attributes, className, setAttributes, isSelected, latestPosts, textColor, error } = + this.props; + + const { + showImage, + imageShape, + postLayout, + mediaPosition, + moreButton, + moreButtonText, + columns, + colGap, + typeScale, + imageScale, + mobileStack, + sectionHeader, + showCaption, + showCategory, + specificMode, + textAlign, + } = attributes; + + const classes = classNames( className, { + 'is-grid': postLayout === 'grid', + 'show-image': showImage, + [ `columns-${ columns }` ]: postLayout === 'grid', + [ `colgap-${ colGap }` ]: postLayout === 'grid', + [ `ts-${ typeScale }` ]: typeScale, + [ `image-align${ mediaPosition }` ]: showImage, + [ `is-${ imageScale }` ]: showImage, + 'mobile-stack': mobileStack, + [ `is-${ imageShape }` ]: showImage, + 'has-text-color': textColor.color !== '', + 'show-caption': showCaption, + 'show-category': showCategory, + [ `has-text-align-${ textAlign }` ]: textAlign, + wpnbha: true, + } ); + + const blockControls = [ + { + icon: , + title: __( 'List View', 'jetpack-mu-wpcom' ), + onClick: () => setAttributes( { postLayout: 'list' } ), + isActive: postLayout === 'list', + }, + { + icon: , + title: __( 'Grid View', 'jetpack-mu-wpcom' ), + onClick: () => setAttributes( { postLayout: 'grid' } ), + isActive: postLayout === 'grid', + }, + ]; + + const blockControlsImages = [ + { + icon: , + title: __( 'Show media on top', 'jetpack-mu-wpcom' ), + isActive: mediaPosition === 'top', + onClick: () => setAttributes( { mediaPosition: 'top' } ), + }, + { + icon: , + title: __( 'Show media on left', 'jetpack-mu-wpcom' ), + isActive: mediaPosition === 'left', + onClick: () => setAttributes( { mediaPosition: 'left' } ), + }, + { + icon: , + title: __( 'Show media on right', 'jetpack-mu-wpcom' ), + isActive: mediaPosition === 'right', + onClick: () => setAttributes( { mediaPosition: 'right' } ), + }, + { + icon: , + title: __( 'Show media behind', 'jetpack-mu-wpcom' ), + isActive: mediaPosition === 'behind', + onClick: () => setAttributes( { mediaPosition: 'behind' } ), + }, + ]; + + const blockControlsImageShape = [ + { + icon: landscapeIcon, + title: __( 'Landscape Image Shape', 'jetpack-mu-wpcom' ), + isActive: imageShape === 'landscape', + onClick: () => setAttributes( { imageShape: 'landscape' } ), + }, + { + icon: portraitIcon, + title: __( 'portrait Image Shape', 'jetpack-mu-wpcom' ), + isActive: imageShape === 'portrait', + onClick: () => setAttributes( { imageShape: 'portrait' } ), + }, + { + icon: squareIcon, + title: __( 'Square Image Shape', 'jetpack-mu-wpcom' ), + isActive: imageShape === 'square', + onClick: () => setAttributes( { imageShape: 'square' } ), + }, + { + icon: , + title: __( 'Uncropped', 'jetpack-mu-wpcom' ), + isActive: imageShape === 'uncropped', + onClick: () => setAttributes( { imageShape: 'uncropped' } ), + }, + ]; + + return ( + +
+
+ { latestPosts && ( ! RichText.isEmpty( sectionHeader ) || isSelected ) && ( + setAttributes( { sectionHeader: value } ) } + placeholder={ __( 'Write header…', 'jetpack-mu-wpcom' ) } + value={ sectionHeader } + tagName="h2" + className="article-section-title" + /> + ) } + { latestPosts && ! latestPosts.length && ( + { __( 'Sorry, no posts were found.', 'jetpack-mu-wpcom' ) } + ) } + { ! latestPosts && ! error && ( + } className="component-placeholder__align-center" /> + ) } + { ! latestPosts && error && ( + + { error } + + ) } + + { latestPosts && latestPosts.map( post => this.renderPost( post ) ) } +
+
+ + { ! specificMode && latestPosts && moreButton && ! isBlogPrivate() && ( + /* + * The "More" button option is hidden for private sites, so we should + * also hide the button in case it was previously enabled. + */ +
+
+ setAttributes( { moreButtonText: value } ) } + className="wp-block-button__link" + allowedFormats={ [] } + /> +
+
+ ) } + + + + { + setAttributes( { textAlign: nextAlign } ); + } } + /> + + + { showImage && } + { showImage && } + + { this.renderInspectorControls() } +
+ ); + } +} + +export default compose( [ + withColors( { textColor: 'color' } ), + withSelect( postsBlockSelector ), + withDispatch( postsBlockDispatch ), +] as any )( Edit ); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/editor.js b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/editor.js new file mode 100644 index 0000000000000..860e8f74385d3 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/editor.js @@ -0,0 +1,27 @@ +/** + * WordPress dependencies + */ +import apiFetch from '@wordpress/api-fetch'; +import { registerBlockType } from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { name as carouselBlockName } from '../carousel'; +import { registerQueryStore } from './store'; +import { settings, name } from '.'; + +const BLOCK_NAME = `newspack-blocks/${ name }`; + +registerBlockType( BLOCK_NAME, settings ); +registerQueryStore( [ BLOCK_NAME, `newspack-blocks/${ carouselBlockName }` ] ); + +// Fetch CSS and insert it in a style tag. +apiFetch( { + path: '/newspack-blocks/v1/homepage-articles-css', +} ).then( css => { + const style = document.createElement( 'style' ); + style.innerHTML = css; + style.id = 'newspack-blocks-homepage-articles-styles'; + document.head.appendChild( style ); +} ); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/editor.scss b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/editor.scss new file mode 100644 index 0000000000000..f4641de9b2a97 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/editor.scss @@ -0,0 +1,64 @@ +@use "../../shared/sass/variables"; +@use "../../shared/sass/placeholder"; +@use "../../shared/sass/colors"; +@use "../../shared/sass/mixins"; + +.wpnbha { + article .entry-title { + margin: 0 0 0.25em; + } + + @include mixins.media( tablet ) { + &.ts-4 article .entry-title { + font-size: 1.6em; + } + } + + .editor-rich-text { + width: 100%; + } + + /* Article meta */ + .cat-links { + font-size: variables.$font__size-xs; + } + + span.avatar { + display: inline-block; + margin-right: 0.5em; + div { + display: inline; + } + } + + /* Article excerpt */ + .excerpt-contain p { + margin: 0.5em 0; + } + + +} + +.editor-styles-wrapper.wpnbha__wp-block-button__wrapper { + background-color: transparent; +} + +.newspack-block { + &--error.components-placeholder { + color: colors.$color__error; + } + &--disabled { + position: relative; + &::after { + content: ""; + position: absolute; + z-index: 2; + width: 100%; + height: 100%; + top: 0; + left: 0; + background-color: #fff; + opacity: 0.6; + } + } +} diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/index.js b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/index.js new file mode 100644 index 0000000000000..40a778cacb801 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/index.js @@ -0,0 +1,109 @@ +/** + * WordPress dependencies + */ +import { createBlock } from '@wordpress/blocks'; +import { Path, SVG } from '@wordpress/components'; +import { applyFilters } from '@wordpress/hooks'; +import { __, _x } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import edit from './edit'; + +/** + * Style dependencies - will load in editor + */ +import './editor.scss'; +import './view.scss'; +import metadata from './block.json'; +const { name, attributes, category } = metadata; + +// Name must be exported separately. +export { name }; + +export const title = __( 'Homepage Posts', 'jetpack-mu-wpcom' ); + +export const icon = ( + + + + + +); + +export const settings = { + title, + icon: { + src: icon, + foreground: '#36f', + }, + attributes, + category, + keywords: [ + __( 'posts', 'jetpack-mu-wpcom' ), + __( 'articles', 'jetpack-mu-wpcom' ), + __( 'latest', 'jetpack-mu-wpcom' ), + ], + description: __( 'A block for displaying homepage posts.', 'jetpack-mu-wpcom' ), + styles: [ + { name: 'default', label: _x( 'Default', 'block style', 'jetpack-mu-wpcom' ), isDefault: true }, + { name: 'borders', label: _x( 'Borders', 'block style', 'jetpack-mu-wpcom' ) }, + ], + supports: { + html: false, + align: [ 'wide', 'full' ], + default: '', + }, + edit, + save: () => null, // to use view.php + transforms: { + from: [ + { + type: 'block', + blocks: [ 'core/latest-posts' ], + transform: ( { + displayPostContent, + displayPostDate, + postLayout, + columns, + postsToShow, + categories, + } ) => { + return createBlock( + applyFilters( 'blocks.transforms_from_name', 'newspack-blocks/homepage-articles' ), + { + showExcerpt: displayPostContent, + showDate: displayPostDate, + postLayout, + columns, + postsToShow, + showAuthor: false, + categories: categories ? [ categories ] : [], + } + ); + }, + }, + ], + to: [ + { + type: 'block', + blocks: [ 'core/latest-posts' ], + transform: ( { showExcerpt, showDate, postLayout, columns, postsToShow, categories } ) => { + return createBlock( 'core/latest-posts', { + displayPostContent: showExcerpt, + displayPostDate: showDate, + postLayout, + columns, + postsToShow, + categories: categories[ 0 ] || '', + } ); + }, + }, + ], + }, +}; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/store.js b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/store.js new file mode 100644 index 0000000000000..c3a009931f936 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/store.js @@ -0,0 +1,201 @@ +/** + * External dependencies + */ +import apiFetch from '@wordpress/api-fetch'; +import { register, select } from '@wordpress/data'; +import { addQueryArgs } from '@wordpress/url'; +import { set } from 'lodash'; +import { createStore, applyMiddleware } from 'redux'; +import createSagaMiddleware from 'redux-saga'; +import { call, put, takeLatest, delay } from 'redux-saga/effects'; + +/** + * WordPress dependencies + */ + +/** + * Internal dependencies + */ +import metadata from './block.json'; +import { getBlockQueries, sanitizePostList } from './utils'; + +const { name } = metadata; +export const STORE_NAMESPACE = `newspack-blocks/${ name }`; + +const initialState = { + // Map of returned posts to block clientIds. + postsByBlock: {}, + errorsByBlock: {}, +}; + +// Generic redux action creators, not @wordpress/data actions. +const actions = { + reflow: () => { + reduxStore.dispatch( { + type: 'REFLOW', + } ); + }, +}; + +// Generic redux selectors, not @wordpress/data selectors. +const selectors = { + getPosts( { clientId } ) { + return reduxStore.getState().postsByBlock[ clientId ]; + }, + getError( { clientId } ) { + return reduxStore.getState().errorsByBlock[ clientId ]; + }, + isUIDisabled() { + return reduxStore.getState().isUIDisabled; + }, +}; + +const reducer = ( state = initialState, action ) => { + switch ( action.type ) { + case 'DISABLE_UI': + return set( state, 'isUIDisabled', true ); + case 'ENABLE_UI': + return set( state, 'isUIDisabled', false ); + case 'UPDATE_BLOCK_POSTS': + return set( state, [ 'postsByBlock', action.clientId ], action.posts ); + case 'UPDATE_BLOCK_ERROR': + return set( state, [ 'errorsByBlock', action.clientId ], action.error ); + } + return state; +}; + +// create the saga middleware +const sagaMiddleware = createSagaMiddleware(); +// mount it on the Store +const reduxStore = createStore( reducer, applyMiddleware( sagaMiddleware ) ); + +const genericStore = { + getSelectors() { + return selectors; + }, + getActions() { + return actions; + }, + ...reduxStore, +}; + +/** + * A cache for posts queries. + */ +const POSTS_QUERIES_CACHE = {}; +const createCacheKey = JSON.stringify; + +/** + * Get posts for a single block. + * + * @yield + * @param {object} block - an object with a postsQuery and a clientId + */ +function* getPostsForBlock( block ) { + const cacheKey = createCacheKey( block.postsQuery ); + const restUrl = window.newspack_blocks_data.posts_rest_url; + let posts = POSTS_QUERIES_CACHE[ cacheKey ]; + if ( posts === undefined ) { + const url = addQueryArgs( restUrl, { + ...block.postsQuery, + // `context=edit` is needed, so that custom REST fields are returned. + context: 'edit', + } ); + posts = yield call( apiFetch, { url } ); + POSTS_QUERIES_CACHE[ cacheKey ] = posts; + } + + const postsIds = posts.map( post => post.id ); + yield put( { type: 'UPDATE_BLOCK_POSTS', clientId: block.clientId, posts } ); + return postsIds; +} + +/** + * Whether a block uses deduplication. + * + * @param {string} clientId + * + * @return {boolean} whether the block uses deduplication + */ +function shouldDeduplicate( clientId ) { + const { getBlock } = select( 'core/block-editor' ); + const block = getBlock( clientId ); + return block?.attributes?.deduplicate; +} + +const createFetchPostsSaga = blockNames => { + /** + * "worker" Saga: will be fired on REFLOW actions + * + * @yield + */ + function* fetchPosts() { + // debounce by 300ms + yield delay( 300 ); + + const { getBlocks } = select( 'core/block-editor' ); + const { getCurrentPostId } = select( 'core/editor' ); + + yield put( { type: 'DISABLE_UI' } ); + + // Ensure innerBlocks are populated for widget area blocks. + // See https://github.com/WordPress/gutenberg/issues/32607#issuecomment-890728216. + const blocks = getBlocks().map( block => { + const innerBlocks = select( 'core/block-editor' ).getBlocks( block.clientId ); + return { + ...block, + innerBlocks, + }; + } ); + + const blockQueries = getBlockQueries( blocks, blockNames ); + + // Use requested specific posts ids as the starting state of exclusion list. + const specificPostsId = blockQueries.reduce( ( acc, { clientId, postsQuery } ) => { + if ( shouldDeduplicate( clientId ) && postsQuery.include ) { + acc = [ ...acc, ...postsQuery.include ]; + } + return acc; + }, [] ); + + let exclude = sanitizePostList( [ ...specificPostsId, getCurrentPostId() ] ); + while ( blockQueries.length ) { + const nextBlock = blockQueries.shift(); + const deduplicate = shouldDeduplicate( nextBlock.clientId ); + if ( deduplicate ) { + nextBlock.postsQuery.exclude = exclude; + } + let fetchedPostIds = []; + try { + fetchedPostIds = yield call( getPostsForBlock, nextBlock ); + } catch ( e ) { + yield put( { type: 'UPDATE_BLOCK_ERROR', clientId: nextBlock.clientId, error: e.message } ); + } + if ( deduplicate ) { + exclude = [ ...exclude, ...fetchedPostIds ]; + } + } + + yield put( { type: 'ENABLE_UI' } ); + } + + /** + * Starts fetchPosts on each dispatched `REFLOW` action. + * + * fetchPosts will wait 300ms before fetching. Thanks to takeLatest, + * if new reflow happens during this time, the reflow from before + * will be cancelled. + * + * @yield + */ + return function* fetchPostsSaga() { + yield takeLatest( 'REFLOW', fetchPosts ); + }; +}; + +export const registerQueryStore = blockNames => { + register( { name: STORE_NAMESPACE, instantiate: () => genericStore } ); + + // Run the saga ✨ + sagaMiddleware.run( createFetchPostsSaga( blockNames ) ); +}; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/templates/article.php b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/templates/article.php new file mode 100644 index 0000000000000..2a0f2e109f2e0 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/templates/article.php @@ -0,0 +1,254 @@ + true, + 'alt' => trim( wp_strip_all_tags( get_the_title( $post_id ) ) ), + ); + + // This global will be used by the newspack_blocks_filter_hpb_srcset filter. + global $newspack_blocks_hpb_rendering_context; + $newspack_blocks_hpb_rendering_context = array( 'attrs' => $attributes ); + + // Disable lazy loading by using an arbitraty `loading` attribute other than `lazy`. + // Empty string or `false` would still result in `lazy`. + if ( $attributes['disableImageLazyLoad'] ) { + $thumbnail_args['loading'] = 'none'; + } + if ( $attributes['fetchPriority'] && in_array( $attributes['fetchPriority'], array( 'high', 'low', 'auto' ), true ) ) { + $thumbnail_args['fetchpriority'] = $attributes['fetchPriority']; + } + + // Support Newspack Listings hide author/publish date options. + $hide_author = apply_filters( 'newspack_listings_hide_author', false ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + $hide_publish_date = apply_filters( 'newspack_listings_hide_publish_date', false ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + $show_author = $attributes['showAuthor'] && ! $hide_author; + $show_date = $attributes['showDate'] && ! $hide_publish_date; + ?> + +
+ style="" + + > + + +
+ + + + + + + +
+ + +
+ + + + ', '' ); + } else { + the_title( '

', '

' ); + } + } elseif ( ! $post_link ) { + // Don't link the title if the post lacks a valid URL. + the_title( '

', '

' ); + } else { + the_title( '

', '

' ); + } + ?> + +
+ true, + 'strong' => true, + 'i' => true, + 'em' => true, + 'mark' => true, + 'u' => true, + 'small' => true, + 'sub' => true, + 'sup' => true, + 'a' => array( + 'href' => true, + 'target' => true, + 'rel' => true, + ), + ); + + echo wptexturize( wp_kses( $subtitle, $allowed_tags ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + ?> +
+ + + + + + + + +
+
+ + $data['attributes'], // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + 'article_query' => $data['article_query'], // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + ) + ); + }, + $data // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable +); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/templates/articles-loop.php b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/templates/articles-loop.php new file mode 100644 index 0000000000000..385f079362f89 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/templates/articles-loop.php @@ -0,0 +1,35 @@ +have_posts() ) { + $article_query->the_post(); + if ( Newspack_Blocks::should_deduplicate_block( $attributes ) ) { + $newspack_blocks_post_id[ get_the_ID() ] = true; + } + echo Newspack_Blocks::template_inc( __DIR__ . '/article.php', array( 'attributes' => $attributes ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } + + Newspack_Blocks::remove_excerpt_filter(); + + do_action( 'newspack_blocks_homepage_posts_after_render' ); + wp_reset_postdata(); + }, + $data // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable +); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/utils.ts b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/utils.ts new file mode 100644 index 0000000000000..cfeb040771de9 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/utils.ts @@ -0,0 +1,283 @@ +/** + * External dependencies + */ +import { dispatch as wpDataDispatch } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; +import { times, isEqual, isNull, isUndefined, pick, pickBy } from 'lodash'; + +/** + * WordPress dependencies + */ +import { STORE_NAMESPACE } from './store'; + +/** + * Based global WP.com blog_public option, checks whether current blog is + * private or not. + */ +export const isBlogPrivate = (): boolean => + typeof window === 'object' && + window.wpcomGutenberg && + Number( window.wpcomGutenberg.blogPublic ) === -1; + +/** + * Block attributes which influence posts query + */ +const POST_QUERY_ATTRIBUTES = [ + 'postsToShow', + 'authors', + 'categories', + 'includeSubcategories', + 'excerptLength', + 'tags', + 'customTaxonomies', + 'showExcerpt', + 'specificPosts', + 'specificMode', + 'tagExclusions', + 'categoryExclusions', + 'customTaxonomyExclusions', + 'postType', + 'includedPostStatuses', + 'deduplicate', + 'showCaption', + 'showCredit', +]; + +/** + * Does the props change necessitate a reflow? + * A reflow should happen if: + * 1. Query-changing attributes of a block change + * 2. The top-level blocks order changes. A Homepage Articles + * block might be nested somewhere. + * @param prevProps + * @param props + */ +export const shouldReflow = ( + prevProps: HomepageArticlesProps, + props: HomepageArticlesProps +): boolean => + ! isEqual( + pick( prevProps.attributes, POST_QUERY_ATTRIBUTES ), + pick( props.attributes, POST_QUERY_ATTRIBUTES ) + ) || ! isEqual( prevProps.topBlocksClientIdsInOrder, props.topBlocksClientIdsInOrder ); + +/** + * Builds query criteria from given attributes. + * @param attributes + */ +export const queryCriteriaFromAttributes = ( attributes: Block[ 'attributes' ] ): PostsQuery => { + const { + postsToShow, + authors, + categories, + includeSubcategories, + excerptLength, + postType, + showExcerpt, + showCaption, + showCredit, + tags, + customTaxonomies, + specificPosts = [], + specificMode, + tagExclusions, + categoryExclusions, + customTaxonomyExclusions, + includedPostStatuses, + } = pick( attributes, POST_QUERY_ATTRIBUTES ); + + const cleanPosts = sanitizePostList( specificPosts ); + const isSpecificPostModeActive = specificMode && cleanPosts && cleanPosts.length; + const criteria: PostsQuery = pickBy( + isSpecificPostModeActive + ? { + include: cleanPosts, + postsToShow: specificPosts.length, + postType, + } + : { + postsToShow, + categories: validateAttributeCollection( categories ), + includeSubcategories, + authors: validateAttributeCollection( authors ), + tags: validateAttributeCollection( tags ), + tagExclusions: validateAttributeCollection( tagExclusions ), + categoryExclusions: validateAttributeCollection( categoryExclusions ), + customTaxonomyExclusions, + customTaxonomies, + postType, + includedPostStatuses, + }, + ( value: unknown ) => ! isUndefined( value ) + ); + criteria.excerptLength = excerptLength; + criteria.showExcerpt = showExcerpt; + criteria.showCaption = showCaption; + criteria.showCredit = showCredit; + return criteria; +}; + +export const sanitizePostList = ( postList: HomepageArticlesAttributes[ 'specificPosts' ] ) => + postList.map( id => parseInt( id ) ).filter( id => id > 0 ); + +export const validateAttributeCollection = ( attr: Array< number > ) => + pickBy( attr, ( value: unknown ) => ! isUndefined( value ) && ! isNull( value ) ); + +/** + * Each eligible block's attributes can be used to create a posts query. + * This function is recursively traversing an array of blocks and creating an aray + * of {postsQuery, clientId} objects. + * The eligible blocks are identified by block name, passed in the second argument. + * @param blocks + * @param blockNames + */ +export const getBlockQueries = ( + blocks: Block[], + blockNames: Block[ 'name' ][] +): { postsQuery: PostsQuery; clientId: Block[ 'clientId' ] }[] => + blocks.flatMap( ( block: Block ) => { + const homepageArticleBlocks = []; + if ( blockNames.indexOf( block.name ) >= 0 ) { + const postsQuery = queryCriteriaFromAttributes( block.attributes ); + homepageArticleBlocks.push( { postsQuery, clientId: block.clientId } ); + } + return homepageArticleBlocks.concat( getBlockQueries( block.innerBlocks, blockNames ) ); + } ); + +export const getEditorBlocksIds = ( blocks: Block[] ): Block[ 'clientId' ][] => + blocks.flatMap( ( block: Block ) => { + const homepageArticleBlocks = []; + homepageArticleBlocks.push( block.clientId ); + return homepageArticleBlocks.concat( getEditorBlocksIds( block.innerBlocks ) ); + } ); + +const PREVIEW_IMAGE_BASE = window.newspack_blocks_data.assets_path; +const generatePreviewPost = ( id: PostId ) => { + const now = new Date(); + now.setHours( 12, 0, 0, 0 ); + return { + author: 1, + content: { + rendered: '

' + __( 'The post content.', 'jetpack-mu-wpcom' ) + '

', + }, + date: now.toISOString(), + date_formatted: now.toLocaleString(), + article_meta_footer: '', + excerpt: { + rendered: '

' + __( 'The post excerpt.', 'jetpack-mu-wpcom' ) + '

', + }, + post_link: '/', + featured_media: '1', + id, + post_type: 'post', + meta: { + newspack_post_subtitle: __( 'Post Subtitle', 'jetpack-mu-wpcom' ), + }, + title: { + rendered: __( 'Post Title', 'jetpack-mu-wpcom' ), + }, + newspack_article_classes: 'type-post', + newspack_author_info: [ + { + display_name: __( 'Author Name', 'jetpack-mu-wpcom' ), + avatar: `
`, + id: 1, + author_link: '/', + }, + ], + newspack_category_info: __( 'Category', 'jetpack-mu-wpcom' ), + newspack_featured_image_caption: __( 'Featured image caption', 'jetpack-mu-wpcom' ), + newspack_featured_image_src: { + large: `${ PREVIEW_IMAGE_BASE }/newspack-1024x536.jpg`, + landscape: `${ PREVIEW_IMAGE_BASE }/newspack-800x600.jpg`, + portrait: `${ PREVIEW_IMAGE_BASE }/newspack-600x800.jpg`, + square: `${ PREVIEW_IMAGE_BASE }/newspack-800x800.jpg`, + uncropped: `${ PREVIEW_IMAGE_BASE }/newspack-1024x536.jpg`, + }, + newspack_has_custom_excerpt: false, + newspack_sponsors_show_categories: false, + newspack_sponsors_show_author: false, + }; +}; + +const getPreviewPosts = ( attributes: HomepageArticlesAttributes ) => + times( attributes.postsToShow, generatePreviewPost ); + +type Select = ( namespace: string ) => { + // core/blocks-editor + getBlocks: ( clientId?: string ) => Block[]; + // core/editor + getEditedPostAttribute: ( attribute: string ) => Block[]; + // core + getPostTypes: ( query: object ) => null | PostType[]; + // STORE_NAMESPACE - TODO: move these to src/blocks/homepage-articles/store.js once it's TS + getPosts: ( query: object ) => Post[]; + getError: ( config: { clientId: Block[ 'clientId' ] } ) => undefined | string; + isUIDisabled: () => boolean; +}; + +/** + * wordpress/data selector for blocks using this custom store. + * @param select + * @param root0 + * @param root0.clientId + * @param root0.attributes + */ +export const postsBlockSelector = ( + select: Select, + { + clientId, + attributes, + }: { clientId: Block[ 'clientId' ]; attributes: HomepageArticlesAttributes } +): HomepageArticlesPropsFromDataSelector => { + const { getBlocks } = select( 'core/block-editor' ); + const { getEditedPostAttribute } = select( 'core/editor' ); + + const editorBlocks = getEditedPostAttribute( 'blocks' ) || []; + const allEditorBlocks = []; + + for ( const block of editorBlocks ) { + // Get pattern blocks as well. + if ( block.name === 'core/block' ) { + allEditorBlocks.push( ...getBlocks( block.clientId ) ); + } else { + allEditorBlocks.push( block ); + } + } + + const editorBlocksIds = getEditorBlocksIds( allEditorBlocks ); + const blocks = getBlocks(); + const isWidgetEditor = blocks.some( block => block.name === 'core/widget-area' ); + + // The block might be rendered in the block styles preview, not in the editor. + const isEditorBlock = + editorBlocksIds.length === 0 || editorBlocksIds.indexOf( clientId ) >= 0 || isWidgetEditor; + + const { getPosts, getError, isUIDisabled } = select( STORE_NAMESPACE ); + const props = { + isEditorBlock, + isUIDisabled: isUIDisabled(), + error: getError( { clientId } ), + topBlocksClientIdsInOrder: blocks.map( block => block.clientId ), + latestPosts: isEditorBlock ? getPosts( { clientId } ) : getPreviewPosts( attributes ), // For block preview, display static content. + }; + + return props; +}; + +/** + * wordpress/data dispatch for blocks using this custom store. + * @param dispatch + * @param root0 + * @param root0.isEditorBlock + */ +export const postsBlockDispatch = ( + dispatch: typeof wpDataDispatch, + { isEditorBlock }: { isEditorBlock: boolean } +) => { + return { + // Only editor blocks can trigger reflows. + // @ts-ignore It's a string. + triggerReflow: isEditorBlock ? dispatch( STORE_NAMESPACE ).reflow : () => undefined, + }; +}; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/view.js b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/view.js new file mode 100644 index 0000000000000..92dabb4c5f45b --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/view.js @@ -0,0 +1,210 @@ +/** + * VIEW + * JavaScript used on front of site. + */ + +/** + * Style dependencies + */ +import './view.scss'; + +const fetchRetryCount = 3; + +/** + * Load More Button Handling + * + * Calls Array.prototype.forEach for IE11 compatibility. + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/NodeList + */ +Array.prototype.forEach.call( + document.querySelectorAll( '.wp-block-newspack-blocks-homepage-articles.has-more-button' ), + buildLoadMoreHandler +); + +/** + * Builds a function to handle clicks on the load more button. + * Creates internal state via closure to ensure all state is + * isolated to a single Block + button instance. + * + * @param {HTMLElement} blockWrapperEl - the button that was clicked + */ +function buildLoadMoreHandler( blockWrapperEl ) { + const btnEl = blockWrapperEl.querySelector( '[data-next]' ); + if ( ! btnEl ) { + return; + } + const postsContainerEl = blockWrapperEl.querySelector( '[data-posts]' ); + + // Set initial state flags. + let isFetching = false; + let isEndOfData = false; + + btnEl.addEventListener( 'click', () => { + // Early return if still fetching or no more posts to render. + if ( isFetching || isEndOfData ) { + return false; + } + + isFetching = true; + + blockWrapperEl.classList.remove( 'is-error' ); + blockWrapperEl.classList.add( 'is-loading' ); + + // Set currently rendered posts' IDs as a query param (e.g. exclude_ids=1,2,3) + const requestURL = + btnEl.getAttribute( 'data-next' ) + '&exclude_ids=' + getRenderedPostsIds().join( ',' ); + + fetchWithRetry( { url: requestURL, onSuccess, onError }, fetchRetryCount ); + + /** + * @param {object} data - Post data + */ + function onSuccess( data ) { + // Validate received data. + if ( ! isPostsDataValid( data ) ) { + return onError(); + } + + if ( data.items.length ) { + // Render posts' HTML from string. + const postsHTML = data.items.map( item => item.html ).join( '' ); + postsContainerEl.insertAdjacentHTML( 'beforeend', postsHTML ); + } + + if ( data.next ) { + // Save next URL as button's attribute. + btnEl.setAttribute( 'data-next', data.next ); + } + + if ( ! data.items.length || ! data.next ) { + isEndOfData = true; + blockWrapperEl.classList.remove( 'has-more-button' ); + } + + isFetching = false; + + blockWrapperEl.classList.remove( 'is-loading' ); + } + + /** + * Handle fetching error + */ + function onError() { + isFetching = false; + + blockWrapperEl.classList.remove( 'is-loading' ); + blockWrapperEl.classList.add( 'is-error' ); + } + } ); +} + +/** + * Returns unique IDs for posts that are currently in the DOM. + */ +function getRenderedPostsIds() { + const postEls = document.querySelectorAll( "[class^='wp-block-newspack-blocks'] [data-post-id]" ); + const postIds = Array.from( postEls ).map( el => el.getAttribute( 'data-post-id' ) ); + + postIds.push( + document.querySelector( 'div[data-current-post-id]' ).getAttribute( 'data-current-post-id' ) + ); + + return [ ...new Set( postIds ) ]; // Make values unique with Set +} + +/** + * Wrapper for XMLHttpRequest that performs given number of retries when error + * occurs. + * + * @param {object} options - XMLHttpRequest options + * @param {number} n - retry count before throwing + */ +function fetchWithRetry( options, n ) { + const xhr = new XMLHttpRequest(); + + xhr.onreadystatechange = () => { + // Return if the request is completed. + if ( xhr.readyState !== 4 ) { + return; + } + + // Call onSuccess with parsed JSON if the request is successful. + if ( xhr.status >= 200 && xhr.status < 300 ) { + const data = JSON.parse( xhr.responseText ); + + return options.onSuccess( data ); + } + + // Call onError if the request has failed n + 1 times (or if n is undefined). + if ( ! n ) { + return options.onError(); + } + + // Retry fetching if request has failed and n > 0. + return fetchWithRetry( options, n - 1 ); + }; + + xhr.open( 'GET', options.url ); + xhr.send(); +} + +/** + * Validates the "Load more" posts endpoint schema: + * { + * "type": "object", + * "properties": { + * "items": { + * "type": "array", + * "items": { + * "type": "object", + * "properties": { + * "html": { + * "type": "string" + * } + * }, + * "required": ["html"] + * }, + * "required": ["items"] + * }, + * "next": { + * "type": ["string", "null"] + * } + * }, + * "required": ["items", "next"] + * } + * + * @param {object} data - posts endpoint payload + */ +function isPostsDataValid( data ) { + let isValid = false; + + if ( + data && + hasOwnProp( data, 'items' ) && + Array.isArray( data.items ) && + hasOwnProp( data, 'next' ) && + typeof data.next === 'string' + ) { + isValid = true; + + if ( + data.items.length && + ! ( hasOwnProp( data.items[ 0 ], 'html' ) && typeof data.items[ 0 ].html === 'string' ) + ) { + isValid = false; + } + } + + return isValid; +} + +/** + * Checks if object has own property. + * + * @param {object} obj - Object + * @param {string} prop - Property to check + */ +function hasOwnProp( obj, prop ) { + return Object.prototype.hasOwnProperty.call( obj, prop ); +} diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/view.php b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/view.php new file mode 100644 index 0000000000000..8e540d87bd481 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/view.php @@ -0,0 +1,535 @@ +template; + } + if ( stripos( $newspack_blocks_hpb_current_theme, 'newspack' ) === false ) { + // Bail if not using a Newspack theme – assumptions about the site content width can't be made then. + return $sizes; + } + $max_width = newspack_blocks_hpb_maximum_image_width(); + if ( 0 !== $max_width ) { + // >=782px is the desktop size – set width as computed. + $sizes = '(min-width: 782px) ' . $max_width . 'px'; + // Between 600-782px is the tablet size – all columns will collapse to two-column layout + // (assuming 5% padding on each side and between columns). + $sizes .= ', (min-width: 600px) 42.5vw'; + // <=600px is the mobile size – columns will stack to full width + // (assumming 5% side padding on each side). + $sizes .= ', 90vw'; + } + return $sizes; +} + +/** + * Retrieve Homepage Articles blocks from blocks, recursively. + * + * @param array $blocks The blocks to search. + * @param string $block_name The block name to search for. + */ +function newspack_blocks_retrieve_homepage_articles_blocks( $blocks, $block_name ) { + $ha_blocks = array(); + foreach ( $blocks as $block ) { + if ( $block_name === $block['blockName'] ) { + $ha_blocks = array_merge( $ha_blocks, array( $block ) ); + } + if ( is_array( $block['innerBlocks'] ) ) { + $ha_blocks = array_merge( $ha_blocks, newspack_blocks_retrieve_homepage_articles_blocks( $block['innerBlocks'], $block_name ) ); + } + } + return $ha_blocks; +} + +/** + * Collect all attributes' values used in a set of blocks. + * + * @param array $blocks The blocks to search. + */ +function newspack_blocks_collect_all_attribute_values( $blocks ) { + $result = array(); + + foreach ( $blocks as $block ) { + foreach ( $block as $key => $value ) { + if ( ! isset( $result[ $key ] ) ) { + $result[ $key ] = array(); + } + if ( ! in_array( $value, $result[ $key ], true ) ) { + $result[ $key ][] = $value; + } + } + } + + return $result; +} + +/** + * Output a CSS string based on attributes used in a set of blocks. + * This is to mitigate CLS. Any CSS that might cause CLS should be output here, + * inline and before the blocks are printed. + * + * @param array $attrs The attributes used in the blocks. + */ +function newspack_blocks_get_homepage_articles_css_string( $attrs ) { + $entry_title_type_scale = array( + '0.7em', + '0.9em', + '1em', + '1.2em', + '1.4em', + '1.7em', + '2em', + '2.2em', + '2.4em', + '2.6em', + ); + + ob_start(); + ?> + .wpnbha article .entry-title { + font-size: 1.2em; + } + .wpnbha .entry-meta { + display: flex; + flex-wrap: wrap; + align-items: center; + margin-top: 0.5em; + } + .wpnbha article .entry-meta { + font-size: 0.8em; + } + .wpnbha article .avatar { + height: 25px; + width: 25px; + } + .wpnbha .post-thumbnail{ + margin: 0; + margin-bottom: 0.25em; + } + .wpnbha .post-thumbnail img { + height: auto; + width: 100%; + } + .wpnbha .post-thumbnail figcaption { + margin-bottom: 0.5em; + } + .wpnbha p { + margin: 0.5em 0; + } + + + have_posts() ) { + return; + } + + // Gather all Homepage Articles blocks on the page and output only the needed CSS. + // This CSS will be printed along with the first found block markup. + global $newspack_blocks_hpb_all_blocks; + $inline_style_html = ''; + if ( ! is_array( $newspack_blocks_hpb_all_blocks ) ) { + $newspack_blocks_hpb_all_blocks = newspack_blocks_retrieve_homepage_articles_blocks( + parse_blocks( get_the_content() ), + $block_name + ); + $all_used_attrs = newspack_blocks_collect_all_attribute_values( array_column( $newspack_blocks_hpb_all_blocks, 'attrs' ) ); + $css_string = newspack_blocks_get_homepage_articles_css_string( $all_used_attrs ); + ob_start(); + ?> + + 2, + ) + ), + rest_url( '/newspack-blocks/v1/articles' ) + ); + + $page = $article_query->paged ?? 1; + + $has_more_pages = ( ++$page ) <= $article_query->max_num_pages; + + /** + * Hide the "More" button on private sites. + * + * Client-side fetching from a private WP.com blog requires authentication, + * which is not provided in the current implementation. + * See https://github.com/Automattic/newspack-blocks/issues/306. + */ + $is_blog_private = (int) get_option( 'blog_public' ) === -1; + + $has_more_button = ! $is_blog_private && $has_more_pages && (bool) $attributes['moreButton']; + + if ( $has_more_button ) { + $classes .= ' has-more-button'; + } + + ob_start(); + + ?> +
+ +
+ +

+ +

+ + $articles_rest_url, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + 'article_query' => $article_query, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + 'attributes' => $attributes, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + ) + ); + ?> +
+ + +

+ +

+ + + +
+ $block['attributes'], + 'render_callback' => 'newspack_blocks_render_block_homepage_articles', + 'supports' => array(), + ), + $block['name'] + ) + ); +} +add_action( 'init', 'newspack_blocks_register_homepage_articles' ); + +/** + * Renders author avatar markup. + * + * @param array $author_info Author info array. + * + * @return string Returns formatted Avatar markup + */ +function newspack_blocks_format_avatars( $author_info ) { + $elements = array_map( + function ( $author ) { + return sprintf( + '%s', + esc_url( $author->url ), + wp_kses( + $author->avatar, + Newspack_Blocks::get_sanitized_image_attributes() + ) + ); + }, + $author_info + ); + + return implode( '', $elements ); +} + +/** + * Renders byline markup. + * + * @param array $author_info Author info array. + * + * @return string Returns byline markup. + */ +function newspack_blocks_format_byline( $author_info ) { + $index = -1; + $elements = array_merge( + array( + '' . esc_html_x( 'by', 'post author', 'jetpack-mu-wpcom' ) . ' ', + ), + array_reduce( + $author_info, + function ( $accumulator, $author ) use ( $author_info, &$index ) { + $index++; + $penultimate = count( $author_info ) - 2; + return array_merge( + $accumulator, + array( + sprintf( + /* translators: 1: author link. 2: author name. 3. variable seperator (comma, 'and', or empty) */ + '%2$s', + esc_url( $author->url ), + esc_html( $author->display_name ) + ), + ( $index < $penultimate ) ? ', ' : '', + ( count( $author_info ) > 1 && $penultimate === $index ) ? esc_html_x( ' and ', 'post author', 'jetpack-mu-wpcom' ) : '', + ) + ); + }, + array() + ) + ); + + return implode( '', $elements ); +} + +/** + * Renders category markup plus filter. + * + * @param string $post_id Post ID. + */ +function newspack_blocks_format_categories( $post_id ) { + $category = false; + // Use Yoast primary category if set. + if ( class_exists( 'WPSEO_Primary_Term' ) ) { + $primary_term = new WPSEO_Primary_Term( 'category', $post_id ); + $category_id = $primary_term->get_primary_term(); + if ( $category_id ) { + $category = get_term( $category_id ); + } + } + if ( ! $category ) { + $categories_list = get_the_category(); + if ( ! empty( $categories_list ) ) { + $category = $categories_list[0]; + } + } + + if ( ! is_a( $category, 'WP_Term' ) ) { + return ''; + } + + $category_link = get_category_link( $category->term_id ); + $category_formatted = esc_html( $category->name ); + + if ( ! empty( $category_link ) ) { + $category_formatted = '' . $category_formatted . ''; + } + + return apply_filters( 'newspack_blocks_categories', $category_formatted ); +} diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/view.scss b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/view.scss new file mode 100644 index 0000000000000..136a6bcf2ffba --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/blocks/homepage-articles/view.scss @@ -0,0 +1,759 @@ +@use "../../shared/sass/variables"; +@use "../../shared/sass/mixins"; +@use "../../shared/sass/preview"; + +:root { + --wpnbha-col-gap: 1em; +} + +@include mixins.media( mobile ) { + :root { + --wpnbha-col-gap: 16px; + } +} + +@include mixins.media( tablet ) { + :root { + --wpnbha-col-gap: 32px; + } +} + +.colgap-2 { + @include mixins.media( mobile ) { + --wpnbha-col-gap: 16px; + } +} + +.colgap-1 { + @include mixins.media( mobile ) { + --wpnbha-col-gap: 8px; + } +} + +.wpnbha { + margin-bottom: 1em; + + article { + min-width: 0; // fixes column width on certain themes + margin-bottom: 1.5em; + word-break: break-word; + overflow-wrap: break-word; + position: relative; + + &:last-of-type { + margin-bottom: 0; + } + } + + /* Section header */ + .article-section-title { + font-size: variables.$font__size-sm; + margin-bottom: 0.5em; + width: 100%; // make sure this isn't caught up in the flex styles. + + mark { + background-color: transparent; + } + } + + /* Column styles */ + &.is-grid { + > div { + display: flex; + flex-flow: row wrap; + justify-content: flex-start; + gap: var(--wpnbha-col-gap); + padding: 0; + list-style: none; + } + + article { + flex-basis: 100%; + margin-bottom: 0; + } + + .article-section-title { + margin-bottom: calc(1em - var(--wpnbha-col-gap)); + } + } + + @include mixins.media( mobile ) { + // width of column - ( column gap / number of columns * number of gaps ) + &.columns-3 article, + &.columns-6 article { + flex-basis: calc(33.33% - ( var(--wpnbha-col-gap) / 3 * 2 ) - 0.1px); + } + + &.is-style-borders.columns-3 article, + &.is-style-borders.columns-6 article { + flex-basis: calc(33.33% - ( 2 * var(--wpnbha-col-gap) / 3 * 2 ) - 1.1px); + } + + &.columns-2 article, + &.columns-4 article, + &.columns-5 article { + flex-basis: calc(50% - ( var(--wpnbha-col-gap) / 2 ) - 0.1px); + } + + &.is-style-borders.columns-2 article, + &.is-style-borders.columns-4 article, + &.is-style-borders.columns-5 article { + flex-basis: calc(50% - ( 2 * var(--wpnbha-col-gap) / 2 ) - 1.1px); + } + + &.columns-5 article:last-of-type, + &.is-style-borders.columns-5 article:last-of-type { + flex-basis: 100%; + } + } + + @include mixins.media( tablet ) { + &.columns-4 article { + flex-basis: calc(25% - ( var(--wpnbha-col-gap) / 4 * 3 ) - 0.1px); + } + + &.is-style-borders.columns-4 article { + flex-basis: calc(25% - ( 2 * var(--wpnbha-col-gap) / 4 * 3 ) - 1.1px); + } + + &.columns-5 article, + &.columns-5 article:last-of-type { + flex-basis: calc(20% - ( var(--wpnbha-col-gap) / 5 * 4 ) - 0.1px); + } + + &.is-style-borders.columns-5 article, + &.is-style-borders.columns-5 article:last-of-type { + flex-basis: calc(20% - ( 2 * var(--wpnbha-col-gap) / 5 * 4 ) - 1.1px); + } + + &.columns-6 article { + flex-basis: calc(16.6666% - ( var(--wpnbha-col-gap) / 6 * 5 ) - 0.1px); + } + + &.is-style-borders.columns-6 article { + flex-basis: calc(16.6666% - ( 2 * var(--wpnbha-col-gap) / 6 * 5 ) - 1.1px); + } + } + + /* Image styles */ + + figcaption { + font-size: variables.$font__size-xxs; + } + + &.image-alignleft, + &.image-alignright { + .post-has-image { + display: flex; + + .post-thumbnail { + flex-basis: 33%; + } + .entry-wrapper { + flex-basis: 67%; + } + } + + &.mobile-stack .post-has-image { + display: block; + } + + @include mixins.media( mobile ) { + &.mobile-stack .post-has-image { + display: flex; + } + } + + // Image scale + @include mixins.media( mobile ) { + &.is-4 { + .post-thumbnail { + flex-basis: 75%; + } + .entry-wrapper { + flex-basis: 25%; + } + } + + &.is-3 { + .post-thumbnail, + .entry-wrapper { + flex-basis: 50%; + } + } + + // is-2 matches the mobile default above + } + + &.is-1 { + .post-thumbnail { + flex-basis: 25%; + } + .entry-wrapper { + flex-basis: 75%; + } + } + } + + &.image-alignleft .post-thumbnail { + margin-right: 1em; + } + + &.image-alignright { + .post-thumbnail { + margin-left: 1em; + } + + .entry-wrapper { + order: -1; + } + } + + &.mobile-stack { + &.image-alignleft, + &.image-alignright { + .post-thumbnail { + margin-left: 0; + margin-right: 0; + } + } + } + + @include mixins.media( mobile ) { + &.mobile-stack.image-alignleft .post-thumbnail { + margin-right: 1em; + } + + &.mobile-stack.image-alignright .post-thumbnail { + margin-left: 1em; + } + } + + /* Headings */ + .entry-title { + margin: 0 0 0.25em; + a { + color: inherit; + text-decoration: none; + } + } + + .entry-meta { + .byline:not(:last-child) { + margin-right: 1.5em; + } + + .updated { + display: none; + + &.published { + display: block; + } + } + } + + .avatar { + border-radius: 100%; + display: block; + margin-right: 0.5em; + } + + &.has-text-color { + .article-section-title, + .entry-title, + .entry-title a, + .entry-title a:visited, + .entry-meta, + .entry-meta a, + .entry-meta .byline a, + .entry-meta .byline a:visited, + .cat-links, + .cat-links a, + .cat-links a:visited, + figcaption { + color: inherit; + } + .entry-meta span:not(.avatar) { + opacity: 0.8; + } + } + + &.image-alignbehind { + .post-has-image { + display: flex; + align-items: flex-end; + position: relative; + + .post-thumbnail { + inset: 0; + margin: 0; + overflow: hidden; + position: absolute; + + img { + height: 100% !important; + object-fit: cover !important; + margin: 0 !important; + max-width: 1000% !important; + width: 100% !important; + } + + &::after { + background: rgba(0, 0, 0, 0.5); + content: ""; + inset: 0; + position: absolute; + z-index: 1; + } + } + + .entry-wrapper { + padding: 2rem 1rem; + position: relative; + width: 100%; + z-index: 2; + + @include mixins.media( desktop ) { + padding: 2rem 1.5rem; + } + } + + .entry-wrapper, + .entry-title a, + .entry-meta, + .entry-meta .byline a, + .cat-links a { + color: #fff; + } + } + + figcaption { + bottom: 1em; + /* autoprefixer: ignore next */ + -webkit-box-orient: vertical; + color: rgba(white, 0.9); + display: -webkit-box; + font-style: italic; + left: 0; + -webkit-line-clamp: 1; + margin: 0; + max-height: 1.6em; + overflow: hidden; + padding: 0 1rem; + position: absolute; + right: 0; + text-align: right; + text-overflow: ellipsis; + z-index: 3; + + a, + a:visited { + color: #fff; + } + + @include mixins.media( desktop ) { + padding: 0 1.5rem; + } + } + } + + /* "More" button & related elements styles */ + button, + .loading, + .error { + display: none; + } + + > button { + margin-top: 1em; + position: relative; + } + + &.has-more-button { + button { + display: block; + } + } + + &.has-more-button.is-loading { + button { + pointer-events: none; + } + .label { + visibility: hidden; + } + .loading { + display: block; + } + } + + .loading { + animation: linear 900ms infinite wpnbha-loading-animation; + border-color: currentcolor currentcolor transparent transparent; + border-radius: 50%; + border-style: solid; + border-width: 1.5px; + height: 18px; + left: 50%; + margin-left: -9px; + margin-top: -9px; + position: absolute; + top: 50%; + transform: rotate(0deg); + width: 18px; + } + + &.has-more-button.is-error { + button, + .error { + display: block; + } + } + + // Make sure Jetpack Content Options don't affect the block. + .posted-on, + .cat-links, + .tags-links, + .byline, + .author-avatar { + clip: auto; + height: auto; + position: relative; + width: auto; + } + + // Ensure centre alignment when selected. + &.has-text-align-center { + .cat-links, + .entry-meta, + .entry-sponsors { + justify-content: center; + } + + &.image-alignbehind figcaption, + figcaption { + text-align: inherit; + } + } + + // Ensure right alignment when selected. + &.has-text-align-right { + .cat-links, + .entry-meta, + .entry-sponsors, + .sponsor-logos { + justify-content: flex-end; + text-align: right; + } + + figcaption { + text-align: inherit; + } + + .entry-date:not(:first-child) { + margin-left: 1.5em; + } + + .entry-meta .byline:not(:last-child) { + margin: 0; + } + } + + /* Article meta */ + .cat-links { + display: flex; + flex-wrap: wrap; + font-size: variables.$font__size-xxs; + font-weight: bold; + margin: 0 0 0.5em; + + &.sponsor-label { + align-items: center; + display: flex; + gap: 0.5em; + } + + a { + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } + } + + .entry-sponsors { + align-items: center; + display: inline-flex; + flex-wrap: wrap; + gap: 0.25em; + width: 100%; + + &.plus-author { + font-size: 0.9em; + + &:not(:last-child) { + margin-bottom: 0.5rem; + } + } + } + + .sponsor-logos { + align-items: center; + display: inline-flex; + flex-wrap: wrap; + gap: 0.5em; + line-height: 1; + } +} + +/* + Some really rough font sizing. + */ +/* stylelint-disable no-duplicate-selectors */ +.wpnbha { + article { + @include mixins.media( tablet ) { + .entry-title { + font-size: 1.6em; + } + .avatar { + height: 40px; + width: 40px; + } + } + } + + &.ts-10, + &.ts-9, + &.ts-8 { + @include mixins.media( tablet ) { + article .avatar { + height: 2.4em; + width: 2.4em; + } + } + } + + &.ts-10 article { + @include mixins.media( tablet ) { + .entry-title { + font-size: 3.6em; + } + } + @include mixins.media( desktop ) { + .entry-title { + font-size: 4.8em; + } + } + } + + &.ts-9 article { + @include mixins.media( tablet ) { + .entry-title { + font-size: 3.4em; + } + } + @include mixins.media( desktop ) { + .entry-title { + font-size: 4.2em; + } + } + } + + &.ts-8 article { + @include mixins.media( tablet ) { + .entry-title { + font-size: 3em; + } + } + @include mixins.media( desktop ) { + .entry-title { + font-size: 3.6em; + } + } + } + + &.ts-7 article { + @include mixins.media( tablet ) { + .entry-title { + font-size: 2.4em; + } + .avatar { + height: 48px; + width: 48px; + } + } + @include mixins.media( desktop ) { + .entry-title { + font-size: 3em; + } + } + } + + &.ts-6 article { + @include mixins.media( tablet ) { + .entry-title { + font-size: 2em; + } + .avatar { + height: 44px; + width: 44px; + } + } + @include mixins.media( desktop ) { + .entry-title { + font-size: 2.4em; + } + } + } + + &.ts-5 article { + @include mixins.media( tablet ) { + .entry-title { + font-size: 1.8em; + } + .avatar { + height: 40px; + width: 40px; + } + } + @include mixins.media( desktop ) { + .entry-title { + font-size: 2em; + } + } + } + + /* Type Scale 4: default */ + + &.ts-3 article { + @include mixins.media( tablet ) { + .entry-title { + font-size: 1.2em; + } + + .entry-meta { + font-size: 0.7em; + } + + .avatar { + height: 32px; + width: 32px; + } + } + } + + &.ts-2 article, + &.ts-1 article { + @include mixins.media( tablet ) { + .entry-wrapper p, + .entry-wrapper .more-link, + .entry-meta, + .newspack-post-subtitle { + font-size: 0.7em; + } + } + } + + &.ts-2 article { + @include mixins.media( tablet ) { + .entry-title { + font-size: 0.9em; + } + + .avatar { + height: 28px; + width: 28px; + } + } + } + + &.ts-1 article { + @include mixins.media( tablet ) { + .entry-title { + font-size: 0.7em; + } + + .avatar { + height: 24px; + width: 24px; + } + } + } +} +/* stylelint-enable */ + +/* Block styles */ + +.wpnbha.is-style-borders { + article { + border: solid rgba(0, 0, 0, 0.2); + border-width: 0 0 1px; + box-sizing: content-box; + padding-bottom: 1em; + + &:last-of-type { + &:not(:first-of-type) { + border-bottom: 0; + padding-right: 0; + } + } + } + + @include mixins.media( mobile ) { + &.is-grid article { + border-width: 0; + padding-right: 0; + } + + &.columns-2, + &.columns-4, + &.columns-5 { + article:nth-of-type(odd):not(:last-of-type) { + border-width: 0 1px 0 0; + padding-right: var(--wpnbha-col-gap); + } + } + + &.columns-3, + &.columns-6 { + article { + &:nth-of-type(3n + 1):not(:last-of-type), + &:nth-of-type(3n + 2):not(:last-of-type) { + border-width: 0 1px 0 0; + padding-right: var(--wpnbha-col-gap); + } + } + } + } + + @include mixins.media( tablet ) { + &.is-grid { + article { + border-width: 0 1px 0 0; + padding-right: var(--wpnbha-col-gap); + } + } + + &.is-grid article:last-of-type, + &.columns-1 article, + &.columns-2 article:nth-of-type(2n), + &.columns-3 article:nth-of-type(3n), + &.columns-4 article:nth-of-type(4n), + &.columns-5 article:nth-of-type(5n), + &.columns-6 article:nth-of-type(6n) { + border: 0; + padding-right: 0; + } + } +} + +@keyframes wpnbha-loading-animation { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/class-newspack-blocks-api.php b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/class-newspack-blocks-api.php new file mode 100644 index 0000000000000..2d1a428d213fe --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/class-newspack-blocks-api.php @@ -0,0 +1,405 @@ +ID, $author->user_nicename ); + } + $author_data[] = array( + /* Get the author name */ + 'display_name' => esc_html( $author->display_name ), + /* Get the author avatar */ + 'avatar' => wp_kses_post( $author_avatar ), + /* Get the author ID */ + 'id' => $author->ID, + /* Get the author Link */ + 'author_link' => $author_link, + ); + } + else : + $author_data[] = array( + /* Get the author name */ + 'display_name' => get_the_author_meta( 'display_name', $object_info['author'] ), + /* Get the author avatar */ + 'avatar' => get_avatar( $object_info['author'], 48 ), + /* Get the author ID */ + 'id' => $object_info['author'], + /* Get the author Link */ + 'author_link' => get_author_posts_url( $object_info['author'] ), + ); + endif; + + /* Return the author data */ + return $author_data; + } + + /** + * Get primary category for the rest field. + * + * @param array $object_info The object info. + * @return string Category name. + */ + public static function newspack_blocks_get_primary_category( $object_info ) { + $category = false; + + // Use Yoast primary category if set. + if ( class_exists( 'WPSEO_Primary_Term' ) ) { + $primary_term = new WPSEO_Primary_Term( 'category', $object_info['id'] ); + $category_id = $primary_term->get_primary_term(); + if ( $category_id ) { + $category = get_term( $category_id ); + } + } + + if ( ! $category ) { + $categories_list = get_the_category( $object_info['id'] ); + if ( ! empty( $categories_list ) ) { + $category = $categories_list[0]; + } + } + + if ( ! $category ) { + return ''; + } + + $linked_category = '' . $category->name . ''; + + return apply_filters( 'newspack_blocks_categories', $linked_category ); + } + + /** + * Get a list of category, tag classes for the rest field. + * + * @param array $object_info The object info. + * @return string classes from assigned categories and tags. + */ + public static function newspack_blocks_get_cat_tag_classes( $object_info ) { + return Newspack_Blocks::get_term_classes( $object_info['id'] ); + } + + /** + * Get all sponsor information for the rest field. + * + * @param array $object_info The object info. + * @return array sponsor information. + */ + public static function newspack_blocks_sponsor_info( $object_info ) { + $sponsors = Newspack_Blocks::get_all_sponsors( + $object_info['id'], + 'native', + 'post', + array( + 'maxwidth' => 80, + 'maxheight' => 40, + ) + ); + if ( ! empty( $sponsors ) ) { + $sponsor_info = array(); + foreach ( $sponsors as $sponsor ) { + $sponsor_info_item = array( + 'flag' => $sponsor['sponsor_flag'], + 'sponsor_name' => $sponsor['sponsor_name'], + 'sponsor_url' => $sponsor['sponsor_url'], + 'byline_prefix' => $sponsor['sponsor_byline'], + 'id' => $sponsor['sponsor_id'], + 'scope' => $sponsor['sponsor_scope'], + ); + if ( ! empty( $sponsor['sponsor_logo'] ) ) { + $sponsor_info_item['src'] = $sponsor['sponsor_logo']['src']; + $sponsor_info_item['img_width'] = $sponsor['sponsor_logo']['img_width']; + $sponsor_info_item['img_height'] = $sponsor['sponsor_logo']['img_height']; + } + $sponsor_info[] = $sponsor_info_item; + } + return $sponsor_info; + } + + return false; + } + + /** + * Pass whether there is a custom excerpt to the editor. + * + * @param array $object_info The object info. + * @return boolean custom excerpt status. + */ + public static function newspack_blocks_has_custom_excerpt( $object_info ) { + $post_has_custom_excerpt = has_excerpt( $object_info['id'] ); + return $post_has_custom_excerpt; + } + + /** + * Register the video-playlist endpoint. + */ + public static function register_video_playlist_endpoint() { + register_rest_route( + 'newspack-blocks/v1', + '/video-playlist', + array( + 'methods' => 'GET', + 'callback' => array( 'Newspack_Blocks_API', 'video_playlist_endpoint' ), + 'permission_callback' => function () { + return current_user_can( 'edit_posts' ); + }, + ) + ); + } + + /** + * Process requests to the video-playlist endpoint. + * + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response. + */ + public static function video_playlist_endpoint( $request ) { + $args = $request->get_params(); + return new \WP_REST_Response( newspack_blocks_get_video_playlist( $args ), 200 ); + } + + /** + * Posts endpoint + * + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response. + */ + public static function posts_endpoint( $request ) { + $attributes = $request->get_params(); + $args = Newspack_Blocks::build_articles_query( $attributes, apply_filters( 'newspack_blocks_block_name', 'newspack-blocks/homepage-articles' ) ); + + if ( $attributes['exclude'] && count( $attributes['exclude'] ) ) { + $args['post__not_in'] = $attributes['exclude']; // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in + } + + if ( $attributes['include'] && count( $attributes['include'] ) ) { + $args['post__in'] = $attributes['include']; + $args['orderby'] = 'post__in'; + $args['order'] = 'ASC'; + } + + if ( isset( $attributes['showExcerpt'], $attributes['excerptLength'] ) ) { + $block_attributes = array( + 'showExcerpt' => $attributes['showExcerpt'], + 'excerptLength' => $attributes['excerptLength'], + ); + Newspack_Blocks::filter_excerpt( $block_attributes ); + } + + $query = new WP_Query( $args ); + $posts = array(); + + foreach ( $query->posts as $post ) { + $GLOBALS['post'] = $post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + setup_postdata( $post ); + + // phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + $excerpt = apply_filters( 'get_the_excerpt', $post->post_excerpt, $post ); + $excerpt = apply_filters( 'the_excerpt', $excerpt ); + $content = apply_filters( 'the_content', $post->post_content ); + // phpcs:enable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + + $meta = new WP_REST_Post_Meta_Fields( 'post' ); + $data = array( + 'author' => (int) $post->post_author, + 'content' => array( + 'rendered' => post_password_required( $post ) ? '' : $content, + ), + 'date' => Newspack_Blocks::get_displayed_post_date( $post ), + 'date_formatted' => Newspack_Blocks::get_formatted_displayed_post_date( $post ), + 'article_meta_footer' => Newspack_Blocks::get_article_meta_footer( $post ), + 'excerpt' => array( + 'rendered' => post_password_required( $post ) ? '' : $excerpt, + ), + 'featured_media' => (int) get_post_thumbnail_id( $post->ID ), + 'id' => $post->ID, + 'meta' => $meta->get_value( $post->ID, $request ), + 'title' => array( + 'rendered' => get_the_title( $post->ID ), + ), + ); + + $sponsors = Newspack_Blocks::get_all_sponsors( $post->ID ); + $add_ons = array( + 'newspack_article_classes' => Newspack_Blocks::get_term_classes( $data['id'] ), + 'newspack_author_info' => self::newspack_blocks_get_author_info( $data ), + 'newspack_category_info' => self::newspack_blocks_get_primary_category( $data ), + 'newspack_featured_image_caption' => Newspack_Blocks::get_image_caption( $data['featured_media'], $attributes['showCaption'], $attributes['showCredit'] ), + 'newspack_featured_image_src' => self::newspack_blocks_get_image_src( $data ), + 'newspack_has_custom_excerpt' => self::newspack_blocks_has_custom_excerpt( $data ), + 'newspack_post_sponsors' => self::newspack_blocks_sponsor_info( $data ), + 'newspack_sponsors_show_author' => Newspack_Blocks::newspack_display_sponsors_and_authors( $sponsors ), + 'newspack_sponsors_show_categories' => Newspack_Blocks::newspack_display_sponsors_and_categories( $sponsors ), + 'post_status' => $post->post_status, + 'post_type' => $post->post_type, + 'post_link' => Newspack_Blocks::get_post_link( $post->ID ), + ); + + // Support Newspack Listings hide author/publish date options. + if ( class_exists( 'Newspack_Listings\Core' ) ) { + $add_ons['newspack_listings_hide_author'] = apply_filters( 'newspack_listings_hide_author', false ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + $add_ons['newspack_listings_hide_publish_date'] = apply_filters( 'newspack_listings_hide_publish_date', false ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + } + + $posts[] = array_merge( $data, $add_ons ); + } + + Newspack_Blocks::remove_excerpt_filter(); + + return new \WP_REST_Response( $posts ); + } + + /** + * Lookup individual posts by title only. + * + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response. + */ + public static function specific_posts_endpoint( $request ) { + $params = $request->get_params(); + if ( empty( $params['search'] ) ) { + return new \WP_REST_Response( array() ); + } + add_filter( 'posts_where', array( 'Newspack_Blocks_API', 'add_post_title_wildcard_search' ), 10, 2 ); + + $args = array( + 'post_status' => 'publish', + 'title_wildcard_search' => esc_sql( $params['search'] ), + 'posts_per_page' => $params['postsToShow'], + ); + + if ( $params['postType'] && count( $params['postType'] ) ) { + $args['post_type'] = $params['postType']; + } else { + $args['post_type'] = 'post'; + } + + $query = new WP_Query( $args ); + remove_filter( 'posts_where', array( 'Newspack_Blocks_API', 'add_post_title_wildcard_search' ), 10, 2 ); + return new \WP_REST_Response( + array_map( + function ( $post ) { + return array( + 'id' => $post->ID, + 'title' => $post->post_title, + ); + }, + $query->posts + ), + 200 + ); + } + + /** + * Add title wildcard search to post lookup query. + * + * @param String $where Where clause. + * @param WP_Query $query The query. + */ + public static function add_post_title_wildcard_search( $where, $query ) { + $search = ! empty( $query->query['title_wildcard_search'] ) ? $query->query['title_wildcard_search'] : null; + $where .= ' AND post_title LIKE "%' . $search . '%" '; + return $where; + } + + /** + * Return CSS for the Homepage Articles block, when rendered in the editor. + * + * @return WP_REST_Response. + */ + public static function css_endpoint() { + return newspack_blocks_get_homepage_articles_css_string( + array( + 'typeScale' => range( 1, 10 ), + 'showSubtitle' => array( 1 ), + ) + ); + } +} + +add_action( 'rest_api_init', array( 'Newspack_Blocks_API', 'register_video_playlist_endpoint' ) ); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/class-newspack-blocks.php b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/class-newspack-blocks.php new file mode 100644 index 0000000000000..2685df500ef0f --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/class-newspack-blocks.php @@ -0,0 +1,1647 @@ + 'newspack-blocks-donate-modal-checkout', + 'modal-checkout-block' => 'newspack-blocks-donate-modal-checkout-block', + 'frequency-based' => 'newspack-blocks-donate-frequency-based', + 'tiers-based' => 'newspack-blocks-donate-tiers-based', + ); + + /** + * Regex pattern we can use to search for and remove custom SQL statements. + * Custom statements added by this class are wrapped by `newspack-blocks` comments. + */ + const SQL_PATTERN = '/\/\* newspack-blocks \*\/(.|\n)*\/\* \/newspack-blocks \*\//'; + + /** + * Class property to store user IDs and CAP guest author names for building + * custom SQL statements. In order to allow a single WP_Query to filter by + * both WP users and CAP guest authors (a taxonomy), we need to directly + * modify the JOIN and WHERE clauses in the SQL query. + * + * If this property is false, then the custom statements will be stripped + * from all SQL clauses. If it's an array with `authors` and `coauthors` + * keys, the custom statements will be added to the SQL query. + * + * Example array: + * [ + * 'authors' => [], // Array of numeric WP user IDs. + * 'coauthors' => [], // Array of CAP guest author name slugs. + * ] + * + * @var boolean|array + */ + protected static $filter_clauses = false; + + /** + * Add hooks and filters. + */ + public static function init() { + add_action( 'after_setup_theme', array( __CLASS__, 'add_image_sizes' ) ); + add_post_type_support( 'post', 'newspack_blocks' ); + add_post_type_support( 'page', 'newspack_blocks' ); + add_action( 'jetpack_register_gutenberg_extensions', array( __CLASS__, 'disable_jetpack_donate' ), 99 ); + add_filter( 'the_content', array( __CLASS__, 'hide_post_content_when_iframe_block_is_fullscreen' ) ); + add_filter( 'posts_clauses', array( __CLASS__, 'filter_posts_clauses_when_co_authors' ), 999, 2 ); + add_filter( 'posts_groupby', array( __CLASS__, 'group_by_post_id_filter' ), 999 ); + + /** + * Disable NextGEN's `C_NextGen_Shortcode_Manager`. + * + * The way it currently parses `the_content` conflicts with the REST API + * request to save a post containing a Homepage Posts block. This is due to + * how it uses output buffering through `ob_start()` on REST requests. + * + * @link https://plugins.trac.wordpress.org/browser/nextgen-gallery/tags/3.23/non_pope/class.nextgen_shortcode_manager.php#L193. + */ + if ( ! defined( 'NGG_DISABLE_SHORTCODE_MANAGER' ) ) { + define( 'NGG_DISABLE_SHORTCODE_MANAGER', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound + } + } + + /** + * Hide the post content when it contains an iframe block that is set to fullscreen mode. + * + * @param string $content post content from the_content hook. + * @return string the post content. + */ + public static function hide_post_content_when_iframe_block_is_fullscreen( $content ) { + if ( has_block( 'newspack-blocks/iframe' ) ) { + $blocks = parse_blocks( get_post()->post_content ); + + foreach ( $blocks as $block ) { + if ( 'newspack-blocks/iframe' === $block['blockName'] + && is_array( $block['attrs'] ) + && array_key_exists( 'isFullScreen', $block['attrs'] ) + && $block['attrs']['isFullScreen'] + ) { + // we don't need the post content since the iframe will be fullscreen. + $content = render_block( $block ); + + add_filter( + 'body_class', + function ( $classes ) { + $classes[] = 'newspack-post-with-fullscreen-iframe'; + return $classes; + } + ); + + // we don't need to show Newspack popups since the iframe will take over them. + add_filter( 'newspack_popups_assess_has_disabled_popups', '__return_true' ); + } + } + } + + return $content; + } + + /** + * Gather dependencies and paths needed for script enqueuing. + * + * @param string $script_path Path to the script relative to plugin root. + * + * @return array Associative array including dependency array, version, and web path to the script. Returns false if script doesn't exist. + */ + public static function script_enqueue_helper( $script_path ) { + $local_path = NEWSPACK_BLOCKS__PLUGIN_DIR . $script_path; + if ( ! file_exists( $local_path ) ) { + return false; + } + + $path_info = pathinfo( $local_path ); + $asset_path = $path_info['dirname'] . '/' . $path_info['filename'] . '.asset.php'; + $script_data = file_exists( $asset_path ) + ? require $asset_path + : array( + 'dependencies' => array( 'wp-a11y', 'wp-escape-html', 'wp-i18n', 'wp-polyfill' ), + 'version' => filemtime( $local_path ), + ); + + $script_data['script_path'] = plugins_url( $script_path, NEWSPACK_BLOCKS__PLUGIN_FILE ); + return $script_data; + } + + /** + * Enqueue placeholder blocks assets. + */ + public static function enqueue_placeholder_blocks_assets() { + $script_data = self::script_enqueue_helper( NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . 'placeholder_blocks.js' ); + if ( $script_data ) { + wp_enqueue_script( + 'newspack-blocks-placeholder-blocks', + $script_data['script_path'], + $script_data['dependencies'], + $script_data['version'], + true + ); + wp_set_script_translations( + 'newspack-blocks-placeholder-blocks', + 'jetpack-mu-wpcom', + plugin_dir_path( NEWSPACK_BLOCKS__PLUGIN_FILE ) . 'languages' + ); + } + } + + /** + * Gets the list of custom taxonomies that will be available for filtering in the blocks + * + * @return array Array of custom taxonomies where each taxonomy is an array with slug and label keys. + */ + public static function get_custom_taxonomies() { + $custom_taxonomies = array_map( + function ( $tax ) { + if ( ! empty( array_intersect( array( 'post', 'page' ), $tax->object_type ) ) ) { + return array( + 'slug' => $tax->name, + 'label' => $tax->label, + ); + } + }, + get_taxonomies( + array( + 'public' => true, + '_builtin' => false, + 'show_in_rest' => true, + ), + 'objects' + ) + ); + $custom_taxonomies = array_values( + array_filter( + $custom_taxonomies, + function ( $tax ) { + return ! empty( $tax ); + } + ) + ); + + /** + * Filters the custom taxonomies that will be available in the Home Page block. + * + * By default, on the top of category and tags, will display any public taxonomy applied to post or pages + * + * @param array $custom_taxonomies Array of custom taxonomies where each taxonomy is an array with slug and label keys. + */ + return apply_filters( 'newspack_blocks_home_page_block_custom_taxonomies', $custom_taxonomies ); + } + + /** + * Check if the Name Your Price extension is available. + * + * @return bool True if available, false if not. + */ + public static function can_use_name_your_price() { + // If the donation platform is NRH, the Donate block should behave as if Name Your Price is available. + if ( method_exists( 'Newspack\Donations', 'is_platform_nrh' ) && \Newspack\Donations::is_platform_nrh() ) { + return true; + } + return class_exists( 'WC_Name_Your_Price_Helpers' ); + } + + /** + * Enqueue block scripts and styles for editor. + */ + public static function enqueue_block_editor_assets() { + $script_data = static::script_enqueue_helper( NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . 'editor.js' ); + + if ( $script_data ) { + wp_enqueue_script( + 'newspack-blocks-editor', + $script_data['script_path'], + $script_data['dependencies'], + $script_data['version'], + true + ); + + $localized_data = array( + 'patterns' => self::get_patterns_for_post_type( get_post_type() ), + 'posts_rest_url' => rest_url( 'newspack-blocks/v1/newspack-blocks-posts' ), + 'specific_posts_rest_url' => rest_url( 'newspack-blocks/v1/newspack-blocks-specific-posts' ), + 'authors_rest_url' => rest_url( 'newspack-blocks/v1/authors' ), + 'assets_path' => plugins_url( '/src/assets', NEWSPACK_BLOCKS__PLUGIN_FILE ), + 'post_subtitle' => get_theme_support( 'post-subtitle' ), + 'iframe_accepted_file_mimes' => WP_REST_Newspack_Iframe_Controller::iframe_accepted_file_mimes(), + 'iframe_can_upload_archives' => WP_REST_Newspack_Iframe_Controller::can_upload_archives(), + 'supports_recaptcha' => class_exists( 'Newspack\Recaptcha' ), + 'has_recaptcha' => class_exists( 'Newspack\Recaptcha' ) && \Newspack\Recaptcha::can_use_captcha(), + 'recaptcha_url' => admin_url( 'admin.php?page=newspack-connections-wizard' ), + 'custom_taxonomies' => self::get_custom_taxonomies(), + 'can_use_name_your_price' => self::can_use_name_your_price(), + 'tier_amounts_template' => self::get_formatted_amount(), + ); + + if ( class_exists( 'WP_REST_Newspack_Author_List_Controller' ) ) { + $localized_data['can_use_cap'] = class_exists( 'CoAuthors_Guest_Authors' ); + $author_list_controller = new WP_REST_Newspack_Author_List_Controller(); + $localized_data['editable_roles'] = $author_list_controller->get_editable_roles(); + } + + if ( class_exists( '\Newspack\Authors_Custom_Fields' ) ) { + $localized_data['author_custom_fields'] = \Newspack\Authors_Custom_Fields::get_custom_fields(); + } + + wp_localize_script( + 'newspack-blocks-editor', + 'newspack_blocks_data', + $localized_data + ); + + wp_set_script_translations( + 'newspack-blocks-editor', + 'jetpack-mu-wpcom', + plugin_dir_path( NEWSPACK_BLOCKS__PLUGIN_FILE ) . 'languages' + ); + } + + $editor_style = plugins_url( NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . 'editor.css', NEWSPACK_BLOCKS__PLUGIN_FILE ); + + wp_enqueue_style( + 'newspack-blocks-editor', + $editor_style, + array(), + NEWSPACK_BLOCKS__VERSION + ); + } + + /** + * Enqueue block scripts and styles for view. + */ + public static function manage_view_scripts() { + if ( is_admin() ) { + // In editor environment, do nothing. + return; + } + $src_directory = NEWSPACK_BLOCKS__PLUGIN_DIR . 'src/blocks/'; + $dist_directory = NEWSPACK_BLOCKS__PLUGIN_DIR . 'dist/'; + $iterator = new DirectoryIterator( $src_directory ); + foreach ( $iterator as $block_directory ) { + if ( ! $block_directory->isDir() || $block_directory->isDot() ) { + continue; + } + $type = $block_directory->getFilename(); + + /* If view.php is found, include it and use for block rendering. */ + $view_php_path = $src_directory . $type . '/view.php'; + + if ( file_exists( $view_php_path ) ) { + include_once $view_php_path; + continue; + } + + /* If view.php is missing but view Javascript file is found, do generic view asset loading. */ + $view_js_path = $dist_directory . $type . '/view.js'; + if ( file_exists( $view_js_path ) ) { + register_block_type( + "newspack-blocks/{$type}", + array( + 'render_callback' => function ( $attributes, $content ) use ( $type ) { + self::enqueue_view_assets( $type ); + return $content; + }, + ) + ); + } + } + } + + /** + * Enqueue block styles stylesheet. + */ + public static function enqueue_block_styles_assets() { + $style_path = NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . 'block_styles' . ( is_rtl() ? '.rtl' : '' ) . '.css'; + if ( file_exists( NEWSPACK_BLOCKS__PLUGIN_DIR . $style_path ) ) { + wp_enqueue_style( + 'newspack-blocks-block-styles-stylesheet', + plugins_url( $style_path, NEWSPACK_BLOCKS__PLUGIN_FILE ), + array(), + NEWSPACK_BLOCKS__VERSION + ); + } + } + + /** + * Enqueue view scripts and styles for a single block. + * + * @param string $type The block's type. + */ + public static function enqueue_view_assets( $type ) { + $style_path = apply_filters( + 'newspack_blocks_enqueue_view_assets', + NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . $type . '/view' . ( is_rtl() ? '.rtl' : '' ) . '.css', + $type, + is_rtl() + ); + + if ( file_exists( NEWSPACK_BLOCKS__PLUGIN_DIR . $style_path ) ) { + wp_enqueue_style( + "newspack-blocks-{$type}", + plugins_url( $style_path, NEWSPACK_BLOCKS__PLUGIN_FILE ), + array(), + NEWSPACK_BLOCKS__VERSION + ); + } + $script_data = static::script_enqueue_helper( NEWSPACK_BLOCKS__BLOCKS_DIRECTORY . $type . '/view.js' ); + if ( $script_data ) { + wp_enqueue_script( + "newspack-blocks-{$type}", + $script_data['script_path'], + $script_data['dependencies'], + $script_data['version'], + true + ); + } + } + + /** + * Utility to assemble the class for a server-side rendered block. + * + * @param string $type The block type. + * @param array $attributes Block attributes. + * @param array $extra Additional classes to be added to the class list. + * + * @return string Class list separated by spaces. + */ + public static function block_classes( $type, $attributes = array(), $extra = array() ) { + $classes = array( "wp-block-newspack-blocks-{$type}" ); + + if ( ! empty( $attributes['align'] ) ) { + $classes[] = 'align' . $attributes['align']; + } + if ( isset( $attributes['className'] ) ) { + array_push( $classes, $attributes['className'] ); + } + if ( is_array( $extra ) && ! empty( $extra ) ) { + $classes = array_merge( $classes, $extra ); + } + if ( ! empty( $attributes['hideControls'] ) ) { + $classes[] = 'hide-controls'; + } + + return implode( ' ', $classes ); + } + + /** + * Return the most appropriate thumbnail size to display. + * + * @param string $orientation The block's orientation settings: landscape|portrait|square. + * + * @return string Returns the thumbnail key to use. + */ + public static function image_size_for_orientation( $orientation = 'landscape' ) { + $sizes = array( + 'landscape' => array( + 'large' => array( + 1200, + 900, + ), + 'medium' => array( + 800, + 600, + ), + 'intermediate' => array( + 600, + 450, + ), + 'small' => array( + 400, + 300, + ), + 'tiny' => array( + 200, + 150, + ), + ), + 'portrait' => array( + 'large' => array( + 900, + 1200, + ), + 'medium' => array( + 600, + 800, + ), + 'intermediate' => array( + 450, + 600, + ), + 'small' => array( + 300, + 400, + ), + 'tiny' => array( + 150, + 200, + ), + ), + 'square' => array( + 'large' => array( + 1200, + 1200, + ), + 'medium' => array( + 800, + 800, + ), + 'intermediate' => array( + 600, + 600, + ), + 'small' => array( + 400, + 400, + ), + 'tiny' => array( + 200, + 200, + ), + ), + ); + + if ( isset( $sizes[ $orientation ] ) ) { + foreach ( $sizes[ $orientation ] as $key => $dimensions ) { + $attachment = wp_get_attachment_image_src( + get_post_thumbnail_id( get_the_ID() ), + 'newspack-article-block-' . $orientation . '-' . $key + ); + if ( ! empty( $attachment ) && $dimensions[0] === $attachment[1] && $dimensions[1] === $attachment[2] ) { + return 'newspack-article-block-' . $orientation . '-' . $key; + } + } + } + + return 'large'; + } + + /** + * Registers image sizes required for Newspack Blocks. + */ + public static function add_image_sizes() { + add_image_size( 'newspack-article-block-landscape-large', 1200, 900, true ); + add_image_size( 'newspack-article-block-portrait-large', 900, 1200, true ); + add_image_size( 'newspack-article-block-square-large', 1200, 1200, true ); + + add_image_size( 'newspack-article-block-landscape-medium', 800, 600, true ); + add_image_size( 'newspack-article-block-portrait-medium', 600, 800, true ); + add_image_size( 'newspack-article-block-square-medium', 800, 800, true ); + + add_image_size( 'newspack-article-block-landscape-intermediate', 600, 450, true ); + add_image_size( 'newspack-article-block-portrait-intermediate', 450, 600, true ); + add_image_size( 'newspack-article-block-square-intermediate', 600, 600, true ); + + add_image_size( 'newspack-article-block-landscape-small', 400, 300, true ); + add_image_size( 'newspack-article-block-portrait-small', 300, 400, true ); + add_image_size( 'newspack-article-block-square-small', 400, 400, true ); + + add_image_size( 'newspack-article-block-landscape-tiny', 200, 150, true ); + add_image_size( 'newspack-article-block-portrait-tiny', 150, 200, true ); + add_image_size( 'newspack-article-block-square-tiny', 200, 200, true ); + + add_image_size( 'newspack-article-block-uncropped', 1200, 9999, false ); + } + + /** + * Whether the block should be included in the deduplication logic. + * + * @param array $attributes Block attributes. + * + * @return bool + */ + public static function should_deduplicate_block( $attributes ) { + /** + * Filters whether to use deduplication while rendering the given block. + * + * @param bool $deduplicate Whether to deduplicate. + * @param array $attributes The block attributes. + */ + return apply_filters( 'newspack_blocks_should_deduplicate', $attributes['deduplicate'] ?? true, $attributes ); + } + + /** + * Get all "specificPosts" ids from given blocks. + * + * @param array $blocks An array of blocks. + * @param string $block_name Name of the block requesting the query. + * + * @return array All "specificPosts" ids from all eligible blocks. + */ + private static function get_specific_posts_from_blocks( $blocks, $block_name ) { + $specific_posts = array(); + foreach ( $blocks as $block ) { + if ( ! empty( $block['innerBlocks'] ) ) { + $specific_posts = array_merge( + $specific_posts, + self::get_specific_posts_from_blocks( $block['innerBlocks'], $block_name ) + ); + continue; + } + if ( + $block_name === $block['blockName'] && + self::should_deduplicate_block( $block['attrs'] ) && + ! empty( $block['attrs']['specificMode'] ) && + ! empty( $block['attrs']['specificPosts'] ) + ) { + $specific_posts = array_merge( + $specific_posts, + $block['attrs']['specificPosts'] + ); + } + } + return $specific_posts; + } + + /** + * Builds and returns query args based on block attributes. + * + * @param array $attributes An array of block attributes. + * @param array $block_name Name of the block requesting the query. + * + * @return array + */ + public static function build_articles_query( $attributes, $block_name ) { + // Reset author/CAP guest author SQL statements by default. + self::$filter_clauses = false; + + global $newspack_blocks_post_id; + if ( ! $newspack_blocks_post_id ) { + $newspack_blocks_post_id = array(); + } + + // Get all blocks and gather specificPosts ids of all eligible blocks. + global $newspack_blocks_all_specific_posts_ids; + if ( ! is_array( $newspack_blocks_all_specific_posts_ids ) ) { + $blocks = parse_blocks( get_the_content() ); + $newspack_blocks_all_specific_posts_ids = self::get_specific_posts_from_blocks( $blocks, $block_name ); + } + + $post_type = isset( $attributes['postType'] ) ? $attributes['postType'] : array( 'post' ); + $included_post_statuses = array( 'publish' ); + if ( current_user_can( 'edit_others_posts' ) && isset( $attributes['includedPostStatuses'] ) ) { + $included_post_statuses = $attributes['includedPostStatuses']; + } + $authors = isset( $attributes['authors'] ) ? $attributes['authors'] : array(); + $categories = isset( $attributes['categories'] ) ? $attributes['categories'] : array(); + $include_subcategories = isset( $attributes['includeSubcategories'] ) ? intval( $attributes['includeSubcategories'] ) : false; + $tags = isset( $attributes['tags'] ) ? $attributes['tags'] : array(); + $custom_taxonomies = isset( $attributes['customTaxonomies'] ) ? $attributes['customTaxonomies'] : array(); + $tag_exclusions = isset( $attributes['tagExclusions'] ) ? $attributes['tagExclusions'] : array(); + $category_exclusions = isset( $attributes['categoryExclusions'] ) ? $attributes['categoryExclusions'] : array(); + $custom_taxonomy_exclusions = isset( $attributes['customTaxonomyExclusions'] ) ? $attributes['customTaxonomyExclusions'] : array(); + $specific_posts = isset( $attributes['specificPosts'] ) ? $attributes['specificPosts'] : array(); + $posts_to_show = intval( $attributes['postsToShow'] ); + $specific_mode = isset( $attributes['specificMode'] ) ? intval( $attributes['specificMode'] ) : false; + $args = array( + 'post_type' => $post_type, + 'post_status' => $included_post_statuses, + 'suppress_filters' => false, + 'ignore_sticky_posts' => true, + 'has_password' => false, + 'is_newspack_query' => true, + ); + if ( $specific_mode && $specific_posts ) { + $args['posts_per_page'] = count( $specific_posts ); + $args['post__in'] = $specific_posts; + $args['orderby'] = 'post__in'; + } else { + $args['posts_per_page'] = $posts_to_show; + if ( ! self::should_deduplicate_block( $attributes ) ) { + $args['post__not_in'] = array( get_the_ID() ); // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in + } else { + if ( count( $newspack_blocks_all_specific_posts_ids ) ) { + $args['post__not_in'] = $newspack_blocks_all_specific_posts_ids; // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in + } + $current_post_id = get_the_ID(); + $args['post__not_in'] = array_merge( // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in + $args['post__not_in'] ?? array(), + array_keys( $newspack_blocks_post_id ), + is_singular() && $current_post_id ? array( $current_post_id ) : array() + ); + } + if ( $categories && count( $categories ) ) { + if ( 1 === $include_subcategories ) { + $children = array(); + foreach ( $categories as $parent ) { + $children = array_merge( $children, get_categories( array( 'child_of' => $parent ) ) ); + foreach ( $children as $child ) { + $categories[] = $child->term_id; + } + } + } + $args['category__in'] = $categories; + } + if ( $tags && count( $tags ) ) { + $args['tag__in'] = $tags; + } + if ( $tag_exclusions && count( $tag_exclusions ) ) { + $args['tag__not_in'] = $tag_exclusions; + } + if ( $category_exclusions && count( $category_exclusions ) ) { + $args['category__not_in'] = $category_exclusions; + } + if ( ! empty( $custom_taxonomies ) ) { + foreach ( $custom_taxonomies as $taxonomy ) { + if ( ! empty( $taxonomy['slug'] ) && ! empty( $taxonomy['terms'] ) ) { + $args['tax_query'][] = array( + 'taxonomy' => $taxonomy['slug'], + 'field' => 'term_id', + 'terms' => $taxonomy['terms'], + 'include_children' => false, + ); + } + } + } + if ( $custom_taxonomy_exclusions && count( $custom_taxonomy_exclusions ) ) { + foreach ( $custom_taxonomy_exclusions as $exclusion ) { + $args['tax_query'][] = array( + 'field' => 'term_id', + 'include_children' => false, + 'operator' => 'NOT IN', + 'taxonomy' => $exclusion['slug'], + 'terms' => $exclusion['terms'], + ); + } + } + + $is_co_authors_plus_active = class_exists( 'CoAuthors_Guest_Authors' ); + + if ( $authors && count( $authors ) ) { + $co_authors_names = array(); + $author_names = array(); + $author_emails = array(); + + if ( $is_co_authors_plus_active ) { + $co_authors_guest_authors = new CoAuthors_Guest_Authors(); + + foreach ( $authors as $index => $author_id ) { + // If the given ID is a guest author. + $co_author = $co_authors_guest_authors->get_guest_author_by( 'id', $author_id ); + if ( $co_author ) { + if ( ! empty( $co_author->linked_account ) ) { + $linked_account = get_user_by( 'login', $co_author->linked_account ); + if ( $linked_account ) { + $authors[] = $linked_account->ID; + } + } + $co_authors_names[] = $co_author->user_nicename; + unset( $authors[ $index ] ); + } else { + // If the given ID is linked to a guest author. + $authors_controller = new WP_REST_Newspack_Authors_Controller(); + $author_data = get_userdata( $author_id ); + if ( $author_data ) { + $linked_guest_author = $authors_controller->get_linked_guest_author( $author_data->user_login ); + if ( $linked_guest_author ) { + $guest_author_name = sanitize_title( $linked_guest_author->post_title ); + if ( ! in_array( $guest_author_name, $co_authors_names, true ) ) { + $co_authors_names[] = $guest_author_name; + unset( $authors[ $index ] ); + } + } else { + $author_names[] = $author_data->user_login; + $author_emails[] = $author_data->user_email; + } + } + } + } + } + + // Reset numeric indexes. + $authors = array_values( $authors ); + if ( empty( $authors ) && count( $co_authors_names ) ) { + // Look for co-authors posts. + $args['tax_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query + array( + 'field' => 'name', + 'taxonomy' => 'author', + 'terms' => $co_authors_names, + ), + ); + } elseif ( empty( $co_authors_names ) && count( $authors ) ) { + $args['author__in'] = $authors; + + if ( $is_co_authors_plus_active ) { + // Don't get any posts that are attributed to other CAP guest authors. + $args['tax_query'] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query + array( + 'relation' => 'OR', + array( + 'taxonomy' => 'author', + 'operator' => 'NOT EXISTS', + ), + array( + 'field' => 'name', + 'taxonomy' => 'author', + 'terms' => $author_names, + ), + array( + 'field' => 'name', + 'taxonomy' => 'author', + 'terms' => $author_emails, + ), + ), + ); + } + } else { + // The query contains both WP users and CAP guest authors. We need to filter the SQL query. + self::$filter_clauses = array( + 'authors' => $authors, + 'coauthors' => $co_authors_names, + ); + } + } + } + + /** + * Customize the WP_Query arguments to fetch post articles before the actual query is executed. + * + * The filter is called after the build_articles_query() function is called by a Newspack block to + * build the WP_Query arguments based on the given attributes and block requesting the query. + * + * @param array $args WP_Query arguments as created by build_articles_query() + * @param array $attributes The attributes initial passed to build_articles_query() + * @param string $block_name The name of the requesting block to create the query args for + */ + return apply_filters( 'newspack_blocks_build_articles_query', $args, $attributes, $block_name ); + } + + /** + * Loads a template with given data in scope. + * + * @param string $template full Path to the template to be included. + * @param array $data Data to be passed into the template to be included. + * @return string + */ + public static function template_inc( $template, $data = array() ) { //phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable, Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed + if ( ! strpos( $template, '.php' ) ) { + $template = $template . '.php'; + } + if ( ! is_file( $template ) ) { + return ''; + } + ob_start(); + include $template; + $contents = ob_get_contents(); + ob_end_clean(); + return $contents; + } + + /** + * Prepare an array of authors, taking presence of CoAuthors Plus into account. + * + * @return array Array of WP_User objects. + */ + public static function prepare_authors() { + if ( function_exists( 'coauthors_posts_links' ) && ! empty( get_coauthors() ) ) { + $authors = get_coauthors(); + foreach ( $authors as $author ) { + $author->avatar = coauthors_get_avatar( $author, 48 ); + $author->url = get_author_posts_url( $author->ID, $author->user_nicename ); + } + return $authors; + } + $id = get_the_author_meta( 'ID' ); + return array( + (object) array( + 'ID' => $id, + 'avatar' => get_avatar( $id, 48 ), + 'url' => get_author_posts_url( $id ), + 'user_nicename' => get_the_author(), + 'display_name' => get_the_author_meta( 'display_name' ), + ), + ); + } + + /** + * Prepare a list of classes based on assigned tags, categories, post formats and types. + * + * @param string $post_id Post ID. + * @return string CSS classes. + */ + public static function get_term_classes( $post_id ) { + $classes = array(); + + $tags = get_the_terms( $post_id, 'post_tag' ); + if ( ! empty( $tags ) ) { + foreach ( $tags as $tag ) { + $classes[] = 'tag-' . $tag->slug; + } + } + + $categories = get_the_terms( $post_id, 'category' ); + if ( ! empty( $categories ) ) { + foreach ( $categories as $cat ) { + $classes[] = 'category-' . $cat->slug; + } + } + + foreach ( self::get_custom_taxonomies() as $tax ) { + $terms = get_the_terms( $post_id, $tax['slug'] ); + if ( ! empty( $terms ) ) { + foreach ( $terms as $term ) { + $classes[] = $term->taxonomy . '-' . $term->slug; + } + } + } + + $post_type = get_post_type( $post_id ); + if ( false !== $post_type ) { + $classes[] = 'type-' . $post_type; + } + + /** + * Filter the array of class names before applying them to the HTML. + * + * @param array $classes Array of term class names. + * + * @return array Filtered array of term class names. + */ + $classes = apply_filters( 'newspack_blocks_term_classes', $classes ); + + return implode( ' ', $classes ); + } + + /** + * Get patterns for post type. + * + * @param string $post_type Post type. + * @return array Array of patterns. + */ + public static function get_patterns_for_post_type( $post_type = null ) { + $patterns = apply_filters( 'newspack_blocks_patterns', array(), $post_type ); + $categorized = array(); + $clean = array(); + foreach ( $patterns as $pattern ) { + if ( ! isset( $pattern['image'] ) || ! $pattern['image'] ) { + continue; + } + $category = isset( $pattern['category'] ) ? $pattern['category'] : __( 'Common', 'jetpack-mu-wpcom' ); + if ( ! isset( $categorized[ $category ] ) ) { + $categorized[ $category ] = array(); + } + $categorized[ $category ][] = $pattern; + } + $categories = array_keys( $categorized ); + sort( $categories ); + foreach ( $categories as $category ) { + $clean[] = array( + 'title' => $category, + 'items' => $categorized[ $category ], + ); + } + return $clean; + } + + /** + * Function to check if plugin is enabled, and if there are sponsors. + * + * @see https://github.com/Automattic/newspack-sponsors/blob/8ebf72ec4fe744bca405a1f6fe8cd5bce3a29e6a/includes/newspack-sponsors-theme-helpers.php#L35 + * + * @param int|null $id ID of the post or archive term to get sponsors for. + * If not provided, we will try to guess based on context. + * @param string|null $scope Scope of the sponsors to get. Can be 'native' or + * 'underwritten'. If provided, only sponsors with the + * matching scope will be returned. If not, all sponsors + * will be returned regardless of scope. + * @param string|null $type Type of the $id given: 'post' or 'archive'. If not + * provided, we will try to guess based on context. + * @param array $logo_options Optional array of logo options. Valid options: + * maxwidth: max width of the logo image, in pixels. + * maxheight: max height of the logo image, in pixels. + * @return array Array of sponsors. + */ + public static function get_all_sponsors( $id = null, $scope = 'native', $type = 'post', $logo_options = array( + 'maxwidth' => 80, + 'maxheight' => 40, + ) ) { + if ( function_exists( '\Newspack_Sponsors\get_sponsors_for_post' ) ) { + if ( is_singular() ) { + $scope_override = get_post_meta( $id, 'newspack_sponsor_sponsorship_scope', true ); + + // Scope override: if post is set to display as native-sponsored, return all sponsors. + if ( 'native' === $scope_override ) { + $scope = null; + } + + // Scope override: if post is set to display as underwritten, return nothing. + if ( 'underwritten' === $scope_override ) { + return array(); + } + } + + return \Newspack_Sponsors\get_all_sponsors( $id, $scope, $type, $logo_options ); // phpcs:ignore PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ns_separatorFound + } + + return false; + } + + /** + * Function to return sponsor 'flag' from first sponsor. + * + * @param array $sponsors Array of sponsors. + * @param string $id Post ID. + * @return string|boolean Sponsor flag label, or false if none found. + */ + public static function get_sponsor_label( $sponsors = null, $id = null ) { + if ( null === $sponsors && ! empty( $id ) ) { + $sponsors = self::get_all_sponsors( $id ); + } + + if ( ! empty( $sponsors ) ) { + $sponsor_flag = $sponsors[0]['sponsor_flag']; + return $sponsor_flag; + } + + return false; + } + + /** + * Outputs the sponsor byline markup for the theme. + * + * @param array $sponsors Array of sponsors. + * @param string $id Post ID. + * @return array|boolean Array of Sponsor byline information, or false if none found. + */ + public static function get_sponsor_byline( $sponsors = null, $id = null ) { + if ( null === $sponsors & ! empty( $id ) ) { + $sponsors = self::get_all_sponsors( $id ); + } + + if ( ! empty( $sponsors ) ) { + $sponsor_count = count( $sponsors ); + $i = 1; + $sponsor_list = array(); + + foreach ( $sponsors as $sponsor ) { + ++$i; + if ( $sponsor_count === $i ) : + /* translators: separates last two sponsor names; needs a space on either side. */ + $sep = esc_html__( ' and ', 'jetpack-mu-wpcom' ); + elseif ( $sponsor_count > $i ) : + /* translators: separates all but the last two sponsor names; needs a space at the end. */ + $sep = esc_html__( ', ', 'jetpack-mu-wpcom' ); + else : + $sep = ''; + endif; + + $sponsor_list[] = array( + 'byline' => $sponsor['sponsor_byline'], + 'url' => $sponsor['sponsor_url'], + 'name' => $sponsor['sponsor_name'], + 'sep' => $sep, + ); + } + return $sponsor_list; + } + + return false; + } + + /** + * Outputs set of sponsor logos with links. + * + * @param array $sponsors Array of sponsors. + * @param string $id Post ID. + * @return array Array of sponsor logo images, or false if none found. + */ + public static function get_sponsor_logos( $sponsors = null, $id = null ) { + if ( null === $sponsors && ! empty( $id ) ) { + $sponsors = self::get_all_sponsors( + $id, + 'native', + 'post', + array( + 'maxwidth' => 80, + 'maxheight' => 40, + ) + ); + } + + if ( ! empty( $sponsors ) ) { + $sponsor_logos = array(); + foreach ( $sponsors as $sponsor ) { + if ( ! empty( $sponsor['sponsor_logo'] ) ) : + $sponsor_logos[] = array( + 'url' => $sponsor['sponsor_url'], + 'src' => esc_url( $sponsor['sponsor_logo']['src'] ), + 'alt' => esc_attr( $sponsor['sponsor_name'] ), + 'width' => esc_attr( $sponsor['sponsor_logo']['img_width'] ), + 'height' => esc_attr( $sponsor['sponsor_logo']['img_height'] ), + ); + endif; + } + + return $sponsor_logos; + } + + return false; + } + + /** + * If at least one native sponsor is set to display both sponsors and authors, show the authors. + * + * @param array $sponsors Array of sponsors. + * + * @return boolean True if we should display both sponsors and categories, false if we should display only sponsors. + */ + public static function newspack_display_sponsors_and_authors( $sponsors ) { + if ( function_exists( '\Newspack_Sponsors\newspack_display_sponsors_and_authors' ) ) { + return \Newspack_Sponsors\newspack_display_sponsors_and_authors( $sponsors ); + } + return false; + } + + /** + * If at least one native sponsor is set to display both sponsors and categories, show the categories. + * + * @param array $sponsors Array of sponsors. + * + * @return boolean True if we should display both sponsors and categories, false if we should display only sponsors. + */ + public static function newspack_display_sponsors_and_categories( $sponsors ) { + if ( function_exists( '\Newspack_Sponsors\newspack_display_sponsors_and_categories' ) ) { + return \Newspack_Sponsors\newspack_display_sponsors_and_categories( $sponsors ); + } + return false; + } + + /** + * Closure for excerpt filtering that can be added and removed. + * + * @var Closure + */ + public static $newspack_blocks_excerpt_closure = null; + + /** + * Closure for excerpt length filtering that can be added and removed. + * + * @var Closure + * @deprecated + */ + public static $newspack_blocks_excerpt_length_closure = null; + + /** + * Function to override WooCommerce Membership's Excerpt Length filter. + * + * @return string Current post's original excerpt. + */ + public static function remove_wc_memberships_excerpt_limit() { + $excerpt = get_the_excerpt( get_the_id() ); + return $excerpt; + } + + /** + * Filter for excerpt length. + * + * @param array $attributes The block's attributes. + */ + public static function filter_excerpt( $attributes ) { + if ( empty( $attributes['excerptLength'] ) || ! $attributes['showExcerpt'] ) { + return; + } + + self::$newspack_blocks_excerpt_closure = function ( $text = '', $post = null ) use ( $attributes ) { + // If we have a manually entered excerpt, use that and allow some tags. + if ( ! empty( $post->post_excerpt ) ) { + $excerpt = $post->post_excerpt; + $allowed_tags = ',,,,,
    ,
      ,
    1. ,

      ,

      ,

      ,

      ,

      ,
      ,,,

      '; + } else { + // If we don't, built an excerpt but allow no tags. + $excerpt = $post->post_content; + $allowed_tags = ''; + } + + // Recreate logic from wp_trim_excerpt (https://developer.wordpress.org/reference/functions/wp_trim_excerpt/). + $excerpt = strip_shortcodes( $excerpt ); + $excerpt = excerpt_remove_blocks( $excerpt ); + $excerpt = wpautop( $excerpt ); + $excerpt = str_replace( ']]>', ']]>', $excerpt ); + + // Strip HTML tags except for the explicitly allowed tags. + $excerpt = strip_tags( $excerpt, $allowed_tags ); // phpcs:ignore WordPressVIPMinimum.Functions.StripTags.StripTagsTwoParameters + + // Get excerpt length. If not provided a valid length, use the default excerpt length. + if ( empty( $attributes['excerptLength'] ) || ! is_numeric( $attributes['excerptLength'] ) ) { + $excerpt_length = 55; + } else { + $excerpt_length = $attributes['excerptLength']; + } + + // Set excerpt length (https://core.trac.wordpress.org/ticket/29533#comment:3). + $excerpt = force_balance_tags( html_entity_decode( wp_trim_words( htmlentities( $excerpt, ENT_COMPAT ), $excerpt_length, static::more_excerpt() ), ENT_COMPAT ) ); + + return $excerpt; + }; + add_filter( 'get_the_excerpt', self::$newspack_blocks_excerpt_closure, 11, 2 ); + } + + /** + * Remove excerpt filter after Homepage Posts block loop. + */ + public static function remove_excerpt_filter() { + if ( static::$newspack_blocks_excerpt_closure ) { + remove_filter( 'get_the_excerpt', static::$newspack_blocks_excerpt_closure, 11 ); + } + } + + /** + * Filter for excerpt length. + * + * @deprecated + * @param array $attributes The block's attributes. + */ + public static function filter_excerpt_length( $attributes ) { + // If showing excerpt, filter the length using the block attribute. + if ( isset( $attributes['excerptLength'] ) && $attributes['showExcerpt'] ) { + self::$newspack_blocks_excerpt_length_closure = add_filter( + 'excerpt_length', + function () use ( $attributes ) { + if ( $attributes['excerptLength'] ) { + return $attributes['excerptLength']; + } + return 55; + }, + 999 + ); + add_filter( 'wc_memberships_trimmed_restricted_excerpt', array( 'Newspack_Blocks', 'remove_wc_memberships_excerpt_limit' ), 999 ); + } + } + + /** + * Remove excerpt length filter after Homepage Posts block loop. + * + * @deprecated + */ + public static function remove_excerpt_length_filter() { + if ( self::$newspack_blocks_excerpt_length_closure ) { + remove_filter( + 'excerpt_length', + self::$newspack_blocks_excerpt_length_closure, + 999 + ); + remove_filter( 'wc_memberships_trimmed_restricted_excerpt', array( 'Newspack_Blocks', 'remove_wc_memberships_excerpt_limit' ) ); + } + } + + /** + * Return a excerpt more replacement when using the 'Read More' link. + */ + public static function more_excerpt() { + return '…'; + } + + /** + * Filter for excerpt ellipsis. + * + * @deprecated + * @param array $attributes The block's attributes. + */ + public static function filter_excerpt_more( $attributes ) { + // If showing the 'Read More' link, modify the ellipsis. + if ( $attributes['showReadMore'] ) { + add_filter( 'excerpt_more', array( __CLASS__, 'more_excerpt' ), 999 ); + } + } + + /** + * Remove excerpt ellipsis filter after Homepage Posts block loop. + * + * @deprecated + */ + public static function remove_excerpt_more_filter() { + remove_filter( 'excerpt_more', array( __CLASS__, 'more_excerpt' ), 999 ); + } + + /** + * Filter posts by authors and co-authors. If the query is filtering posts + * by both WP users and CAP guest authors, the SQL clauses must be modified + * directly so that the filtering can happen with a single SQL query. + * + * @param string[] $clauses Associative array of the clauses for the query. + * @param WP_Query $query The WP_Query instance (passed by reference). + */ + public static function filter_posts_clauses_when_co_authors( $clauses, $query ) { + // Remove any lingering custom SQL statements. + $clauses['join'] = preg_replace( self::SQL_PATTERN, '', $clauses['join'] ); + $clauses['where'] = preg_replace( self::SQL_PATTERN, '', $clauses['where'] ); + $is_newspack_query = isset( $query->query_vars['is_newspack_query'] ) && $query->query_vars['is_newspack_query']; + + // If the query isn't coming from this plugin, or $filter_clauses lacks expected data. + if ( + ! $is_newspack_query || + ! self::$filter_clauses || + ! isset( self::$filter_clauses['authors'] ) || + ! isset( self::$filter_clauses['coauthors'] ) + ) { + return $clauses; + } + + global $wpdb; + + $authors_ids = self::$filter_clauses['authors']; + $co_authors_names = self::$filter_clauses['coauthors']; + + // co-author tax query. + $tax_query = array( + array( + 'taxonomy' => 'author', + 'field' => 'name', + 'terms' => $co_authors_names, + ), + ); + + // Generate the tax query SQL. + $tax_query = new WP_Tax_Query( $tax_query ); + $tax_query = $tax_query->get_sql( $wpdb->posts, 'ID' ); + + // Generate the author query SQL. + $csv = implode( ',', wp_parse_id_list( (array) $authors_ids ) ); + $author_names = array_reduce( + $authors_ids, + function ( $acc, $author_id ) { + $author_data = get_userdata( $author_id ); + if ( $author_data ) { + $acc[] = $author_data->user_login; + } + return $acc; + }, + array() + ); + + // If getting only WP users, we don't want to get posts attributed to CAP guest authors not linked to the given WP users. + $exclude = new WP_Tax_Query( + array( + 'relation' => 'OR', + array( + 'taxonomy' => 'author', + 'operator' => 'NOT EXISTS', + ), + array( + 'field' => 'name', + 'taxonomy' => 'author', + 'terms' => $author_names, + ), + ) + ); + $exclude = $exclude->get_sql( $wpdb->posts, 'ID' ); + $exclude = $exclude['where']; + $authors = " ( {$wpdb->posts}.post_author IN ( $csv ) $exclude ) "; + + // Make sure the authors are set, the tax query is valid (doesn't contain 0 = 1). + if ( false === strpos( $tax_query['where'], ' 0 = 1' ) ) { + // Append to the current join parts. The JOIN statment only needs to exist in the clause once. + if ( false === strpos( $clauses['join'], $tax_query['join'] ) ) { + $clauses['join'] .= '/* newspack-blocks */ ' . $tax_query['join'] . ' /* /newspack-blocks */'; + } + + $clauses['where'] .= sprintf( + // The tax query SQL comes prepended with AND. + '%s AND ( %s ( 1=1 %s ) ) %s', + '/* newspack-blocks */', + empty( $authors_ids ) ? '' : $authors . ' OR', + $tax_query['where'], + '/* /newspack-blocks */' + ); + } + return $clauses; + } + + /** + * Group by post ID filter, used when we join taxonomies while getting posts. + * + * @param string $groupby The GROUP BY clause of the query. + * @return string The filtered GROUP BY clause. + */ + public static function group_by_post_id_filter( $groupby ) { + global $wpdb; + + if ( self::$filter_clauses ) { + return "{$wpdb->posts}.ID "; + } + + return $groupby; + } + + /** + * Utility to get the link for the given post ID. If the post has an external URL meta value, use that. + * Otherwise, use the permalink. But if the post type doesn't have a public singular view, don't link. + * + * @param int $post_id Post ID for which to get the link. Will default to current post if none given. + * @return string|boolean The URL for the post, or false if it can't be linked to. + */ + public static function get_post_link( $post_id = null ) { + if ( null === $post_id ) { + $post_id = get_the_ID(); + } + + $post_type = get_post_type( $post_id ); + $sponsor_url = get_post_meta( $post_id, 'newspack_sponsor_url', true ); + $supporter_url = get_post_meta( $post_id, 'newspack_supporter_url', true ); + $external_url = ! empty( $sponsor_url ) ? $sponsor_url : $supporter_url; + $post_type_info = get_post_type_object( $post_type ); + $link = ! empty( $external_url ) ? $external_url : get_permalink(); + $should_have_link = ! empty( $post_type_info->public ) || ! empty( $external_url ); // False if a sponsor or supporter without an external URL. + + return $should_have_link ? $link : false; + } + + /** + * Sanitize SVG markup for front-end display. + * + * @param string $svg SVG markup to sanitize. + * @return string Sanitized markup. + */ + public static function sanitize_svg( $svg = '' ) { + $allowed_html = array( + 'svg' => array( + 'xmlns' => array(), + 'fill' => array(), + 'viewbox' => array(), + 'role' => array(), + 'aria-hidden' => array(), + 'focusable' => array(), + 'height' => array(), + 'width' => array(), + ), + 'path' => array( + 'd' => array(), + 'fill' => array(), + ), + ); + + return wp_kses( $svg, $allowed_html ); + } + + /** + * Disable Jetpack's donate block when using Newspack donations. + */ + public static function disable_jetpack_donate() { + // Do nothing if Jetpack's blocks or Newspack aren't being used. + if ( ! class_exists( 'Jetpack_Gutenberg' ) || ! class_exists( 'Newspack' ) ) { + return; + } + + // Allow Jetpack donations if Newspack donations isn't set up. + $donate_settings = Newspack\Donations::get_donation_settings(); + if ( is_wp_error( $donate_settings ) ) { + return; + } + + // Tell Jetpack to mark the donations feature as unavailable. + Jetpack_Gutenberg::set_extension_unavailable( + 'jetpack/donations', + esc_html__( 'Jetpack donations is disabled in favour of Newspack donations.', 'jetpack-mu-wpcom' ) + ); + } + + /** + * Loads a template with given data in scope. + * + * @param string $template Name of the template to be included. + * @param array $data Data to be passed into the template to be included. + * @param string $path (Optional) Path to the folder containing the template. + * @return string + */ + public static function template_include( $template, $data = array(), $path = NEWSPACK_BLOCKS__PLUGIN_DIR . 'src/templates/' ) { + if ( ! strpos( $template, '.php' ) ) { + $template = $template . '.php'; + } + $path .= $template; + if ( ! is_file( $path ) ) { + return ''; + } + ob_start(); + include $path; + $contents = ob_get_contents(); + ob_end_clean(); + return $contents; + } + + /** + * Get post status label. + */ + public static function get_post_status_label() { + $post_status = get_post_status(); + $post_statuses_labels = array( + 'draft' => __( 'Draft', 'jetpack-mu-wpcom' ), + 'future' => __( 'Scheduled', 'jetpack-mu-wpcom' ), + ); + if ( 'publish' !== $post_status ) { + ob_start(); + ?> +

      + $l2 ) { + $contrast_ratio = (int) ( ( $l1 + 0.05 ) / ( $l2 + 0.05 ) ); + } else { + $contrast_ratio = (int) ( ( $l2 + 0.05 ) / ( $l1 + 0.05 ) ); + } + if ( $contrast_ratio > 5 ) { + // If contrast is more than 5, return black color. + return 'black'; + } else { + // if not, return white color. + return 'white'; + } + } + + /** + * Get an array of allowed HTML attributes for sanitizing image markup. + * For use with wp_kses: https://developer.wordpress.org/reference/functions/wp_kses/ + * + * @return array + */ + public static function get_sanitized_image_attributes() { + return array( + 'img' => array( + 'alt' => true, + 'class' => true, + 'data-*' => true, + 'decoding' => true, + 'height' => true, + 'loading' => true, + 'sizes' => true, + 'src' => true, + 'srcset' => true, + 'width' => true, + ), + 'noscript' => array(), + 'a' => array( + 'href' => true, + ), + ); + } + + /** + * Get post date to be displayed. + * + * @param WP_Post $post Post object. + * @return string Date string. + */ + public static function get_displayed_post_date( $post = null ) { + if ( $post === null ) { + $post = get_post(); + } + return apply_filters( 'newspack_blocks_displayed_post_date', mysql_to_rfc3339( $post->post_date ), $post ); + } + + /** + * Get post date to be displayed, formatted. + * + * @param WP_Post $post Post object. + * @return string Formatted date. + */ + public static function get_formatted_displayed_post_date( $post = null ) { + if ( $post === null ) { + $post = get_post(); + } + $date = self::get_displayed_post_date( $post ); + $date = new DateTime( $date ); + $date_format = get_option( 'date_format' ); + $date_formatted = date_i18n( $date_format, $date->getTimestamp() ); + return apply_filters( 'newspack_blocks_formatted_displayed_post_date', $date_formatted, $post ); + } + + /** + * Get article meta footer. + * + * @param WP_Post $post Post object. + */ + public static function get_article_meta_footer( $post = null ) { + if ( $post === null ) { + $post = get_post(); + } + $meta_footer = apply_filters( 'newspack_blocks_article_meta_footer', '', $post ); + if ( strlen( $meta_footer ) > 0 ) { + return '' . $meta_footer; + } + } + + /** + * Get a formatted HTML string containing amount and frequency of a donation. + * + * @param float $amount Amount. + * @param string $frequency Frequency. + * @param bool $hide_once_label Whether to hide the "once" label. + * + * @return string + */ + public static function get_formatted_amount( $amount = 0, $frequency = 'day', $hide_once_label = false ) { + if ( ! function_exists( 'wc_price' ) || ( method_exists( 'Newspack\Donations', 'is_platform_wc' ) && ! \Newspack\Donations::is_platform_wc() ) ) { + if ( 0 === $amount ) { + return false; + } + + // Translators: %s is the %s is the frequency. + $frequency_string = 'once' === $frequency ? $frequency : sprintf( __( 'per %s', 'jetpack-mu-wpcom' ), $frequency ); + $formatter = new NumberFormatter( \get_locale(), NumberFormatter::CURRENCY ); + $formatted_price = '' . $formatter->formatCurrency( $amount, 'USD' ) . ' ' . $frequency_string . ''; + return str_replace( '.00', '', $formatted_price ); + } + if ( ! function_exists( 'wcs_price_string' ) ) { + return \wc_price( $amount ); + } + $price_args = array( + 'recurring_amount' => $amount, + 'subscription_period' => 'once' === $frequency ? 'day' : $frequency, + ); + $wc_formatted_amount = \wcs_price_string( $price_args ); + + // A '0' value means we want a placeholder string to replace in the editor. + if ( 0 === $amount ) { + preg_match( '/<\/span>(.*)<\/bdi>/', $wc_formatted_amount, $matches ); + if ( ! empty( $matches[1] ) ) { + $wc_formatted_amount = str_replace( $matches[1], 'AMOUNT_PLACEHOLDER', $wc_formatted_amount ); + } + } + + // A 'day' frequency means we want a placeholder string to replace in the editor. + if ( 'day' === $frequency ) { + $wc_formatted_amount = preg_replace( '/ \/ ?.*/', 'FREQUENCY_PLACEHOLDER', $wc_formatted_amount ); + } elseif ( 'once' === $frequency ) { + $once_label = $hide_once_label ? '' : __( ' once', 'jetpack-mu-wpcom' ); + $wc_formatted_amount = preg_replace( '/ \/ ?.*/', $once_label, $wc_formatted_amount ); + } + $wc_formatted_amount = str_replace( ' / ', __( ' per ', 'jetpack-mu-wpcom' ), $wc_formatted_amount ); + + return '' . $wc_formatted_amount . ''; + } + + /** + * Get an image caption, optionally with credit appended. + * + * @param int $attachment_id Attachment ID of the image. + * @param bool $include_caption Whether to include the caption. + * @param bool $include_credit Whether to include the credit. + * + * @return string + */ + public static function get_image_caption( $attachment_id = null, $include_caption = true, $include_credit = false ) { + if ( ! $attachment_id || ( ! $include_caption && ! $include_credit ) ) { + return ''; + } + + $caption = $include_caption ? wp_get_attachment_caption( $attachment_id ) : ''; + $credit = ''; + + if ( $include_credit && method_exists( 'Newspack\Newspack_Image_Credits', 'get_media_credit_string' ) ) { + $credit = \Newspack\Newspack_Image_Credits::get_media_credit_string( $attachment_id ); + } + + $full_caption = trim( $caption . ' ' . $credit ); + if ( empty( $full_caption ) ) { + return ''; + } + + $combined_caption = sprintf( + '%2$s', + ! empty( $credit ) ? ' class="has-credit"' : '', + $full_caption + ); + + return $combined_caption; + } +} +Newspack_Blocks::init(); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/components/autocomplete-tokenfield.js b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/components/autocomplete-tokenfield.js new file mode 100644 index 0000000000000..08dd060acf04f --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/components/autocomplete-tokenfield.js @@ -0,0 +1,192 @@ +/** + * External dependencies + */ +import { FormTokenField, Spinner } from '@wordpress/components'; +import { Component } from '@wordpress/element'; +import { debounce } from 'lodash'; + +/** + * WordPress dependencies + */ + +/** + * Internal dependencies + */ +import './autocomplete-tokenfield.scss'; + +/** + * An multi-selecting, api-driven autocomplete input suitable for use in block attributes. + */ +class AutocompleteTokenField extends Component { + constructor( props ) { + super( props ); + this.state = { + suggestions: [], + validValues: {}, + loading: this.isFetchingInfoOnLoad(), + }; + + this.debouncedUpdateSuggestions = debounce( this.updateSuggestions, 500 ); + } + + /** + * If the component has tokens passed in props, it should fetch info after it mounts. + */ + isFetchingInfoOnLoad = () => { + const { tokens, fetchSavedInfo } = this.props; + return Boolean( tokens.length && fetchSavedInfo ); + }; + + /** + * When the component loads, fetch information about the tokens so we can populate + * the tokens with the correct labels. + */ + componentDidMount() { + if ( this.isFetchingInfoOnLoad() ) { + const { tokens, fetchSavedInfo } = this.props; + + fetchSavedInfo( tokens ).then( results => { + const { validValues } = this.state; + + results.forEach( suggestion => { + validValues[ suggestion.value ] = suggestion.label; + } ); + + this.setState( { validValues, loading: false } ); + } ); + } + } + + /** + * Clean up any unfinished autocomplete api call requests. + */ + componentWillUnmount() { + delete this.suggestionsRequest; + this.debouncedUpdateSuggestions.cancel(); + } + + /** + * Get a list of labels for input values. + * + * @param {Array} values - Array of values (ids, etc.). + * @return {Array} array of valid labels corresponding to the values. + */ + getLabelsForValues( values ) { + const { validValues } = this.state; + return values.reduce( + ( accumulator, value ) => + validValues[ value ] ? [ ...accumulator, validValues[ value ] ] : accumulator, + [] + ); + } + + /** + * Get a list of values for input labels. + * + * @param {Array} labels - Array of labels from the tokens. + * @return {Array} Array of valid values corresponding to the labels. + */ + getValuesForLabels( labels ) { + const { validValues } = this.state; + + return ( + labels + .map( label => Object.keys( validValues ).find( key => validValues[ key ] === label ) ) + // It's possible the submitted label doesn't have a corresponding value, so we filter out any undefined values. + .filter( value => !! value ) + ); + } + + /** + * Refresh the autocomplete dropdown. + * + * @param {string} input - Input to fetch suggestions for + */ + updateSuggestions( input ) { + const { fetchSuggestions } = this.props; + if ( ! fetchSuggestions ) { + return; + } + + this.setState( { loading: true }, () => { + const request = fetchSuggestions( input ); + request + .then( suggestions => { + // A fetch Promise doesn't have an abort option. It's mimicked by + // comparing the request reference in on the instance, which is + // reset or deleted on subsequent requests or unmounting. + if ( this.suggestionsRequest !== request ) { + return; + } + + const { validValues } = this.state; + const currentSuggestions = []; + + suggestions.forEach( suggestion => { + const trimmedSuggestionLabel = suggestion.label.trim(); + const duplicatedSuggestionIndex = currentSuggestions.indexOf( trimmedSuggestionLabel ); + if ( duplicatedSuggestionIndex >= 0 ) { + suggestion.label = `${ trimmedSuggestionLabel } (${ suggestion.value })`; + } + currentSuggestions.push( trimmedSuggestionLabel ); + validValues[ suggestion.value ] = trimmedSuggestionLabel; + } ); + + this.setState( { suggestions: currentSuggestions, validValues, loading: false } ); + } ) + .catch( () => { + if ( this.suggestionsRequest === request ) { + this.setState( { + loading: false, + } ); + } + } ); + + this.suggestionsRequest = request; + } ); + } + + /** + * When a token is selected, we need to convert the string label into a recognized value suitable for saving as an attribute. + * + * @param {Array} tokenStrings - An array of token label strings. + */ + handleOnChange( tokenStrings ) { + const { onChange } = this.props; + onChange( this.getValuesForLabels( tokenStrings ) ); + } + + /** + * To populate the tokens, we need to convert the values into a human-readable label. + * + * @return {Array} An array of token label strings. + */ + getTokens() { + const { tokens } = this.props; + return this.getLabelsForValues( tokens ); + } + + /** + * Render. + */ + render() { + const { help, label = '' } = this.props; + const { suggestions, loading } = this.state; + + return ( +
      + this.handleOnChange( tokens ) } + onInputChange={ input => this.debouncedUpdateSuggestions( input ) } + label={ label } + /> + { loading && } + { help &&

      { help }

      } +
      + ); + } +} + +export default AutocompleteTokenField; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/components/autocomplete-tokenfield.scss b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/components/autocomplete-tokenfield.scss new file mode 100644 index 0000000000000..5e1da1a9fd527 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/components/autocomplete-tokenfield.scss @@ -0,0 +1,18 @@ +.autocomplete-tokenfield { + position: relative; + + .components-spinner { + position: absolute; + top: 2em; + right: 0; + } + + /* Workaround for hard-coded help text in FormTokenField. */ + .components-form-token-field > .components-form-token-field__help { + display: none; + } + + .autocomplete-tokenfield__help { + font-style: italic; + } +} diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/components/editor-panels.js b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/components/editor-panels.js new file mode 100644 index 0000000000000..23aea7ec02195 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/components/editor-panels.js @@ -0,0 +1,84 @@ +/** + * WordPress dependencies + */ +import { Spinner, CheckboxControl, PanelBody, PanelRow } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; + +const CheckboxesGroup = ( { options, values, onChange } ) => { + if ( ! Array.isArray( options ) ) { + return ; + } + return options.map( ( { name, slug } ) => ( + + -1 } + onChange={ value => { + const cleanPostType = [ ...new Set( values ) ]; + if ( value && cleanPostType.indexOf( slug ) === -1 ) { + cleanPostType.push( slug ); + } else if ( ! value && cleanPostType.indexOf( slug ) > -1 ) { + cleanPostType.splice( cleanPostType.indexOf( slug ), 1 ); + } + onChange( cleanPostType ); + } } + /> + + ) ); +}; + +export const PostTypesPanel = ( { attributes, setAttributes } ) => { + const { availablePostTypes } = useSelect( select => { + const { getPostTypes } = select( 'core' ); + const listingsLabel = __( 'Listings', 'jetpack-mu-wpcom' ); + return { + availablePostTypes: getPostTypes( { per_page: -1 } ) + ?.filter( ( { supports: { newspack_blocks: newspackBlocks } } ) => newspackBlocks ) + ?.map( postType => { + // Disambiguate the "Listings" post types. + if ( + postType.slug.indexOf( 'newspack_lst' ) === 0 && + postType.slug !== 'newspack_lst_generic' && + postType.name.indexOf( listingsLabel ) === -1 + ) { + postType.name = `${ postType.name } ${ listingsLabel }`; + } + return postType; + } ), + }; + } ); + + return ( + + setAttributes( { postType } ) } + /> + + ); +}; + +export const PostStatusesPanel = ( { attributes, setAttributes } ) => { + return ( + + + + { __( + 'Selection here has effect only for editors, regular users will only see published posts.', + 'jetpack-mu-wpcom' + ) } + + + setAttributes( { includedPostStatuses } ) } + /> + + ); +}; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/components/query-controls.js b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/components/query-controls.js new file mode 100644 index 0000000000000..8541c8cfe3f98 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/components/query-controls.js @@ -0,0 +1,408 @@ +/** + * WordPress dependencies + */ +import apiFetch from '@wordpress/api-fetch'; +import { Button, QueryControls as BasicQueryControls, ToggleControl } from '@wordpress/components'; +import { Component } from '@wordpress/element'; +import { decodeEntities } from '@wordpress/html-entities'; +import { __, sprintf } from '@wordpress/i18n'; +import { addQueryArgs } from '@wordpress/url'; + +/** + * Internal dependencies. + */ +import AutocompleteTokenField from './autocomplete-tokenfield'; + +const getCategoryTitle = category => + decodeEntities( category.name ) || __( '(no title)', 'jetpack-mu-wpcom' ); + +const getTermTitle = term => decodeEntities( term.name ) || __( '(no title)', 'jetpack-mu-wpcom' ); + +class QueryControls extends Component { + state = { + showAdvancedFilters: false, + }; + + fetchPostSuggestions = search => { + const { postType } = this.props; + const restUrl = window.newspack_blocks_data.specific_posts_rest_url; + return apiFetch( { + url: addQueryArgs( restUrl, { + search, + postsToShow: 20, + _fields: 'id,title', + type: 'post', + postType, + } ), + } ).then( function ( posts ) { + const result = posts.map( post => ( { + value: post.id, + label: decodeEntities( post.title ) || __( '(no title)', 'jetpack-mu-wpcom' ), + } ) ); + return result; + } ); + }; + fetchSavedPosts = postIDs => { + const { postType } = this.props; + const restUrl = window.newspack_blocks_data.posts_rest_url; + return apiFetch( { + url: addQueryArgs( restUrl, { + // These params use the block query parameters (see Newspack_Blocks::build_articles_query). + postsToShow: 100, + include: postIDs.join( ',' ), + _fields: 'id,title', + postType, + } ), + } ).then( function ( posts ) { + return posts.map( post => ( { + value: post.id, + label: decodeEntities( post.title.rendered ) || __( '(no title)', 'jetpack-mu-wpcom' ), + } ) ); + } ); + }; + + fetchAuthorSuggestions = search => { + const restUrl = window.newspack_blocks_data.authors_rest_url; + return apiFetch( { + url: addQueryArgs( restUrl, { + search, + per_page: 20, + fields: 'id,name', + } ), + } ).then( function ( users ) { + return users.map( user => ( { + value: user.id, + label: decodeEntities( user.name ) || __( '(no name)', 'jetpack-mu-wpcom' ), + } ) ); + } ); + }; + fetchSavedAuthors = userIDs => { + const restUrl = window.newspack_blocks_data.authors_rest_url; + return apiFetch( { + url: addQueryArgs( restUrl, { + per_page: 100, + include: userIDs.join( ',' ), + fields: 'id,name', + } ), + } ).then( function ( users ) { + return users.map( user => ( { + value: user.id, + label: decodeEntities( user.name ) || __( '(no name)', 'jetpack-mu-wpcom' ), + } ) ); + } ); + }; + + fetchCategorySuggestions = search => { + return apiFetch( { + path: addQueryArgs( '/wp/v2/categories', { + search, + per_page: 20, + _fields: 'id,name,parent', + orderby: 'count', + order: 'desc', + } ), + } ).then( categories => + Promise.all( + categories.map( category => { + if ( category.parent > 0 ) { + return apiFetch( { + path: addQueryArgs( `/wp/v2/categories/${ category.parent }`, { + _fields: 'name', + } ), + } ).then( parentCategory => ( { + value: category.id, + label: `${ getCategoryTitle( category ) } – ${ getCategoryTitle( parentCategory ) }`, + } ) ); + } + return Promise.resolve( { + value: category.id, + label: getCategoryTitle( category ), + } ); + } ) + ) + ); + }; + fetchSavedCategories = categoryIDs => { + return apiFetch( { + path: addQueryArgs( '/wp/v2/categories', { + per_page: 100, + _fields: 'id,name', + include: categoryIDs.join( ',' ), + } ), + } ).then( function ( categories ) { + return categories.map( category => ( { + value: category.id, + label: decodeEntities( category.name ) || __( '(no title)', 'jetpack-mu-wpcom' ), + } ) ); + } ); + }; + + fetchTagSuggestions = search => { + return apiFetch( { + path: addQueryArgs( '/wp/v2/tags', { + search, + per_page: 20, + _fields: 'id,name', + orderby: 'count', + order: 'desc', + } ), + } ).then( function ( tags ) { + return tags.map( tag => ( { + value: tag.id, + label: decodeEntities( tag.name ) || __( '(no title)', 'jetpack-mu-wpcom' ), + } ) ); + } ); + }; + fetchSavedTags = tagIDs => { + return apiFetch( { + path: addQueryArgs( '/wp/v2/tags', { + per_page: 100, + _fields: 'id,name', + include: tagIDs.join( ',' ), + } ), + } ).then( function ( tags ) { + return tags.map( tag => ( { + value: tag.id, + label: decodeEntities( tag.name ) || __( '(no title)', 'jetpack-mu-wpcom' ), + } ) ); + } ); + }; + + fetchCustomTaxonomiesSuggestions = ( taxSlug, search ) => { + return apiFetch( { + path: addQueryArgs( `/wp/v2/${ taxSlug }`, { + search, + per_page: 20, + _fields: 'id,name,parent', + orderby: 'count', + order: 'desc', + } ), + } ).then( terms => + Promise.all( + terms.map( term => { + if ( term.parent > 0 ) { + return apiFetch( { + path: addQueryArgs( `/wp/v2/${ taxSlug }/${ term.parent }`, { + _fields: 'name', + } ), + } ).then( parentTerm => ( { + value: term.id, + label: `${ getTermTitle( term ) } – ${ getTermTitle( parentTerm ) }`, + } ) ); + } + return Promise.resolve( { + value: term.id, + label: getTermTitle( term ), + } ); + } ) + ) + ); + }; + fetchSavedCustomTaxonomies = ( taxSlug, termIDs ) => { + return apiFetch( { + path: addQueryArgs( `/wp/v2/${ taxSlug }`, { + per_page: 100, + _fields: 'id,name', + include: termIDs.join( ',' ), + } ), + } ).then( function ( terms ) { + return terms.map( term => ( { + value: term.id, + label: decodeEntities( term.name ) || __( '(no title)', 'jetpack-mu-wpcom' ), + } ) ); + } ); + }; + + render = () => { + const { + specificMode, + onSpecificModeChange, + specificPosts, + onSpecificPostsChange, + authors, + onAuthorsChange, + categories, + onCategoriesChange, + includeSubcategories, + onIncludeSubcategoriesChange, + tags, + onTagsChange, + customTaxonomies, + onCustomTaxonomiesChange, + tagExclusions, + onTagExclusionsChange, + categoryExclusions, + onCategoryExclusionsChange, + customTaxonomyExclusions, + onCustomTaxonomyExclusionsChange, + enableSpecific, + } = this.props; + const { showAdvancedFilters } = this.state; + + const registeredCustomTaxonomies = window.newspack_blocks_data?.custom_taxonomies; + + const customTaxonomiesPrepareChange = ( taxArr, taxHandler, taxSlug, value ) => { + let newValue = taxArr.filter( tax => tax.slug !== taxSlug ); + newValue = [ ...newValue, { slug: taxSlug, terms: value } ]; + taxHandler( newValue ); + }; + + const getTermsOfCustomTaxonomy = ( taxArr, taxSlug ) => { + const tax = taxArr.find( taxObj => taxObj.slug === taxSlug ); + return tax ? tax.terms : []; + }; + + return (<> + { enableSpecific && ( + + ) } + { specificMode ? ( + + ) : ( + <> + + { onAuthorsChange && ( + + ) } + { onCategoriesChange && ( + + ) } + { onIncludeSubcategoriesChange && ( + + ) } + { onTagsChange && ( + + ) } + { onCustomTaxonomiesChange && + registeredCustomTaxonomies.map( tax => ( + { + customTaxonomiesPrepareChange( + customTaxonomies, + onCustomTaxonomiesChange, + tax.slug, + value + ); + } } + fetchSuggestions={ search => + this.fetchCustomTaxonomiesSuggestions( tax.slug, search ) + } + fetchSavedInfo={ termIds => this.fetchSavedCustomTaxonomies( tax.slug, termIds ) } + label={ tax.label } + /> + ) ) } + { onTagExclusionsChange && ( +

      + +

      + ) } + { showAdvancedFilters && ( + <> + { onTagExclusionsChange && ( + + ) } + { onCategoryExclusionsChange && ( + + ) } + { registeredCustomTaxonomies && + onCustomTaxonomyExclusionsChange && + registeredCustomTaxonomies.map( ( { label, slug } ) => ( + this.fetchSavedCustomTaxonomies( slug, termIds ) } + fetchSuggestions={ search => + this.fetchCustomTaxonomiesSuggestions( slug, search ) + } + key={ `${ slug }-exclusions-selector` } + label={ sprintf( + // translators: %s is the custom taxonomy label. + __( 'Excluded %s', 'jetpack-mu-wpcom' ), + label + ) } + onChange={ value => + customTaxonomiesPrepareChange( + customTaxonomyExclusions, + onCustomTaxonomyExclusionsChange, + slug, + value + ) + } + tokens={ getTermsOfCustomTaxonomy( customTaxonomyExclusions, slug ) } + /> + ) ) } + + ) } + + ) } + ); + }; +} + +QueryControls.defaultProps = { + enableSpecific: true, + specificPosts: [], + authors: [], + categories: [], + tags: [], + customTaxonomies: [], + tagExclusions: [], + customTaxonomyExclusions: [], +}; + +export default QueryControls; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/components/redirect-after-success.tsx b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/components/redirect-after-success.tsx new file mode 100644 index 0000000000000..68fcbc3deda53 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/components/redirect-after-success.tsx @@ -0,0 +1,50 @@ +/** + * WordPress dependencies + */ +import { TextControl, SelectControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +type Props = { + attributes: { + afterSuccessBehavior: string; + afterSuccessButtonLabel: string; + afterSuccessURL: string; + }; + setAttributes: ( attributes: Partial< Props[ 'attributes' ] > ) => void; +}; + +const RedirectAfterSuccess = ( { attributes, setAttributes }: Props ) => ( + <> + { + setAttributes( { afterSuccessBehavior: value.toString() } ); + } } + /> + setAttributes( { afterSuccessButtonLabel: value } ) } + /> + { attributes.afterSuccessBehavior === 'custom' && ( + setAttributes( { afterSuccessURL: value } ) } + /> + ) } + +); + +export default RedirectAfterSuccess; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/package.json b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/package.json new file mode 100644 index 0000000000000..fe0b1adffe4a3 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/package.json @@ -0,0 +1,69 @@ +{ + "name": "@automattic/newspack-blocks", + "version": "4.0.1", + "author": "Automattic", + "devDependencies": { + "@rushstack/eslint-patch": "^1.10.4", + "@testing-library/dom": "^10.4.0", + "@testing-library/user-event": "^14.5.2", + "@types/lodash": "^4.17.7", + "@wordpress/browserslist-config": "^6.0.0", + "eslint": "^8.57.0", + "fetch-mock-jest": "^1.5.1", + "html-entities": "^2.5.2", + "identity-obj-proxy": "^3.0.0", + "lint-staged": "^15.2.7", + "newspack-components": "^3.0.0", + "newspack-scripts": "^5.5.2", + "postcss-scss": "^4.0.9" + }, + "description": "=== Newspack Blocks === Contributors: (this should be a list of wordpress.org userid's) Donate link: https://example.com/ Tags: comments, spam Requires at least: 4.5 Tested up to: 5.1.1 Stable tag: 0.1.0 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html", + "dependencies": { + "classnames": "^2.5.1", + "redux": "^5.0.0", + "redux-saga": "^1.3.0", + "regenerator-runtime": "^0.14.1", + "swiper": "11.1.8" + }, + "scripts": { + "cm": "newspack-scripts commit", + "semantic-release": "newspack-scripts release --files=newspack-blocks.php", + "clean": "rm -rf dist", + "build": "npm run clean && newspack-scripts wp-scripts build", + "start": "npm ci --legacy-peer-deps && npm run watch", + "watch": "npm run clean && newspack-scripts wp-scripts start", + "test": "newspack-scripts test", + "lint": "npm run lint:scss && npm run lint:js", + "lint:js": "newspack-scripts wp-scripts lint-js '**/{src,includes}/**/*.{js,jsx,ts,tsx}'", + "lint:js:staged": "newspack-scripts wp-scripts lint-js --ext .js,.jsx,.ts,.tsx", + "fix:js": "newspack-scripts wp-scripts lint-js --fix '**/{src,includes}/**/*.{js,jsx,ts,tsx}'", + "format:js": "newspack-scripts wp-scripts format '**/{src,includes}/**/*.{js,jsx,ts,tsx}'", + "lint:php": "./vendor/bin/phpcs", + "lint:php:staged": "./vendor/bin/phpcs --filter=GitStaged", + "fix:php": "./vendor/bin/phpcbf", + "lint:scss": "newspack-scripts wp-scripts lint-style '**/{src,includes}/**/*.scss' --customSyntax postcss-scss", + "lint:scss:staged": "newspack-scripts wp-scripts lint-style --customSyntax postcss-scss", + "format:scss": "newspack-scripts wp-scripts lint-style '**/{src,includes}/**/*.scss' --customSyntax postcss-scss --fix", + "i18n": "NODE_ENV=production npm run build; bash ./bin/update-translations.sh", + "typescript:check": "newspack-scripts typescript-check", + "release": "npm run build && npm run semantic-release", + "release:archive": "rm -rf release && mkdir -p release && rsync -r . ./release/newspack-blocks --exclude-from='./.distignore' && cd release && zip -r newspack-blocks.zip newspack-blocks" + }, + "lint-staged": { + "*.scss": "npm run lint:scss:staged", + "*.(js|jsx)": "npm run lint:js:staged", + "*.(ts|tsx)": "npm run typescript:check", + "*.php": "npm run lint:php:staged" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Automattic/newspack-blocks.git" + }, + "license": "GPL-3.0-or-later", + "bugs": { + "url": "https://github.com/Automattic/newspack-blocks/issues" + }, + "overrides": { + "path-to-regexp": "1.7.0" + } +} diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/js/newspack-icon.js b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/js/newspack-icon.js new file mode 100644 index 0000000000000..0bafa319a34ee --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/js/newspack-icon.js @@ -0,0 +1,31 @@ +/** + * WordPress dependencies. + */ +import { Path, SVG } from '@wordpress/components'; + +/** + * External dependencies. + */ +import classnames from 'classnames'; + +const NewspackIcon = ( { size = 24, className } ) => ( + + + + +); + +export default NewspackIcon; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/js/utils.js b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/js/utils.js new file mode 100644 index 0000000000000..5e9fc61c99e05 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/js/utils.js @@ -0,0 +1,82 @@ +/** + * WordPress dependencies + */ +import { RawHTML, Fragment } from '@wordpress/element'; +import { _x, __ } from '@wordpress/i18n'; + +export const formatAvatars = authorInfo => + authorInfo.map( author => ( + +
      + { author.avatar } + + + ) ); + +export const formatByline = authorInfo => ( + + { _x( 'by', 'post author', 'jetpack-mu-wpcom' ) }{ ' ' } + { authorInfo.reduce( ( accumulator, author, index ) => { + return [ + ...accumulator, + + + { author.display_name } + + , + index < authorInfo.length - 2 && ', ', + authorInfo.length > 1 && + index === authorInfo.length - 2 && + _x( ' and ', 'post author', 'jetpack-mu-wpcom' ), + ]; + }, [] ) } + +); + +export const formatSponsorLogos = sponsorInfo => ( + + { sponsorInfo.map( sponsor => ( + + { sponsor.src && ( + + { + + ) } + + ) ) } + +); + +export const formatSponsorByline = sponsorInfo => ( + + { sponsorInfo[ 0 ].byline_prefix }{ ' ' } + { sponsorInfo.reduce( ( accumulator, sponsor, index ) => { + return [ + ...accumulator, + + { sponsor.sponsor_name } + , + index < sponsorInfo.length - 2 && ', ', + sponsorInfo.length > 1 && + index === sponsorInfo.length - 2 && + _x( ' and ', 'post author', 'jetpack-mu-wpcom' ), + ]; + }, [] ) } + +); + +export const getPostStatusLabel = ( post = {} ) => + post.post_status !== 'publish' ? ( +
      + { + { draft: __( 'Draft', 'jetpack-mu-wpcom' ), future: __( 'Scheduled', 'jetpack-mu-wpcom' ) }[ + post.post_status + ] + } +
      + ) : null; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/sass/_colors.scss b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/sass/_colors.scss new file mode 100644 index 0000000000000..ad799c3dd9df1 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/sass/_colors.scss @@ -0,0 +1,26 @@ +$color__primary: #36f; +$color__secondary: #555; +$color__background-body: #fff; +$color__background-input: #fff; +$color__background-screen: #f1f1f1; +$color__text-main: #111; +$color__text-light: #767676; +$color__text-input-focus: #111; +$color__border: #ccc; +$color__error: #d63638; +$color__success: #008a20; +$color__info: #dfdfdf; +$color__gray: #757575; +$color__gray-lighter: #f0f0f0; +$newspack-ui-color-neutral-0: #fff; +$newspack-ui-color-neutral-5: #f7f7f7; +$newspack-ui-color-neutral-10: #f0f0f0; +$newspack-ui-color-neutral-20: #e0e0e0; +$newspack-ui-color-neutral-30: #ddd; +$newspack-ui-color-neutral-40: #ccc; +$newspack-ui-color-neutral-50: #949494; +$newspack-ui-color-neutral-60: #6c6c6c; +$newspack-ui-color-neutral-70: #00000070; +$newspack-ui-color-neutral-80: #3e3e3e; +$newspack-ui-color-neutral-90: #1e1e1e; +$newspack-ui-color-neutral-100: #000; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/sass/_mixins.scss b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/sass/_mixins.scss new file mode 100644 index 0000000000000..83b939f27c073 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/sass/_mixins.scss @@ -0,0 +1,42 @@ +@use "./variables"; + +@mixin media( $res ) { + @if mobile == $res { + @media only screen and ( min-width: variables.$mobile_width ) { + @content; + } + } + + @if tabletonly == $res { + @media only screen and ( max-width: #{ variables.$tablet_width - 1 } ) { + @content; + } + } + + @if tablet == $res { + @media only screen and ( min-width: variables.$tablet_width ) { + @content; + } + } + + @if desktop == $res { + @media only screen and ( min-width: variables.$desktop_width ) { + @content; + } + } + + @if wide == $res { + @media only screen and ( min-width: variables.$wide_width ) { + @content; + } + } +} + +@mixin visuallyHidden { + position: absolute !important; + height: 1px; + width: 1px; + overflow: hidden; + clip: rect(1px, 1px, 1px, 1px); + white-space: nowrap; /* added line */ +} diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/sass/_placeholder.scss b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/sass/_placeholder.scss new file mode 100644 index 0000000000000..c3f50d1f3cfb9 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/sass/_placeholder.scss @@ -0,0 +1,5 @@ +.wp-block[data-type^="newspack-blocks/"] { + .component-placeholder__align-center { + align-items: center; + } +} diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/sass/_preview.scss b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/sass/_preview.scss new file mode 100644 index 0000000000000..ecfbf61f1f674 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/sass/_preview.scss @@ -0,0 +1,12 @@ +.newspack-preview-label { + position: absolute; + top: 5px; + left: 5px; + z-index: 1; + font-family: sans-serif; + font-size: 10px; + text-transform: uppercase; + background: #ffc000; + padding: 0 4px; + border-radius: 2px; +} diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/sass/_variables.scss b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/sass/_variables.scss new file mode 100644 index 0000000000000..88d0df56d569a --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/shared/sass/_variables.scss @@ -0,0 +1,26 @@ +$mobile_width: 600px; +$tablet_width: 782px; +$desktop_width: 1168px; +$wide_width: 1379px; + +$font__size_base: 20px; +$font__size-ratio: 1.125; + +$font__size-xxxs: 1em * 0.5; // 10px +$font__size-xxs: 1em * 0.6; // 12px +$font__size-xs: 1em * 0.7; // 14px +$font__size-sm: 1em * 0.8; // 16px +// $font__size_base: 1em * 1; // 20px +$font__size-md: 1em * 1.2; // 24px +$font__size-lg: 1em * 1.4; // 28px +$font__size-xl: 1em * 1.8; // 36px +$font__size-xxl: 1em * 2.2; // 44px +$font__size-xxxl: 1em * 2.8; // 56px +$font__size-xxxxl: 1em * 3.2; // 64px + +$font__line-height-body: 1.6; +$font__line-height-pre: 1.6; +$font__line-height-heading: 1.2; +$font__line-height-double: 2 * $font__line-height-heading; + +$color__border: #ccc; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/types/index.d.ts b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/types/index.d.ts new file mode 100644 index 0000000000000..8effbad8278f9 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/newspack-blocks/synced-newspack-blocks/types/index.d.ts @@ -0,0 +1,169 @@ +declare global { + interface Window { + wpcomGutenberg: { + blogPublic: string; + }; + newspack_blocks_data: { + assets_path: string; + supports_recaptcha: boolean; + has_recaptcha: boolean; + recaptcha_url: string; + post_subtitle: boolean; + can_use_name_your_price: boolean; + tier_amounts_template: string; + }; + grecaptcha: any; + newspackReaderActivation: { + on: Function; + off: Function; + setReaderEmail: Function; + setAuthenticated: Function; + refreshAuthentication: Function; + getReader: Function; + hasAuthLink: Function; + setAuthStrategy: Function; + getAuthStrategy: Function; + }; + } + + type PostId = number; + type CategoryId = number; + type TagId = number; + type Taxonomy = { slug: string; terms: number[] }[]; + type AuthorId = number; + + type PostType = { name: string; slug: string; supports: { newspack_blocks: boolean } }; + + // As used by Newspack_Blocks_API::posts_endpoint. + type PostsQuery = { + include?: PostId[]; + excerptLength?: number; + showExcerpt?: boolean; + showCaption?: boolean; + showCredit?: boolean; + }; + + type Block = { + name: string; + clientId: string; + attributes: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + [ key: string ]: any; + }; + innerBlocks: Block[]; + }; + + type Post = { + id: number; + title: { + rendered: string; + }; + post_type: string; + date: string; + date_formatted: string; + article_meta_footer: string; + excerpt: { + rendered: string; + }; + meta: { + newspack_post_subtitle: string; + }; + post_link: string; + newspack_author_info: { + id: number; + author_link: string; + avatar: string; + }[]; + newspack_article_classes: string; + newspack_featured_image_caption: string; + newspack_featured_image_src: { + large: string; + landscape: string; + portrait: string; + square: string; + uncropped: string; + }; + newspack_category_info: string; + newspack_sponsors_show_categories: boolean; + newspack_sponsors_show_author: boolean; + newspack_post_sponsors?: + | { + flag: string; + }[] + | false; + newspack_listings_hide_author?: boolean; + newspack_listings_hide_publish_date?: boolean; + }; + + type HomepageArticlesAttributes = { + postsToShow: number; + authors: AuthorId[]; + categories: CategoryId[]; + includeSubcategories: boolean; + excerptLength: number; + postType: PostType[]; + showImage: boolean; + showExcerpt: boolean; + tags: TagId[]; + customTaxonomies: Taxonomy[]; + specificPosts: string[]; + specificMode: boolean; + tagExclusions: TagId[]; + categoryExclusions: CategoryId[]; + customTaxonomyExclusions: Taxonomy[]; + className: string; + showExcerpt: boolean; + excerptLength: number; + showReadMore: boolean; + readMoreLabel: string; + showDate: boolean; + showImage: boolean; + showCaption: boolean; + showCredit: boolean; + disableImageLazyLoad: boolean; + fetchPriority: string; + imageShape: string; + minHeight: integer; + moreButton: boolean; + moreButtonText: string; + showAuthor: boolean; + showAvatar: boolean; + showCategory: boolean; + postLayout: string; + columns: integer; + colGap: integer; + postsToShow: integer; + mediaPosition: string; + showSubtitle: boolean; + sectionHeader: string; + imageScale: number; + mobileStack: boolean; + typeScale: number; + textAlign: string; + deduplicate: boolean; + }; + + type HomepageArticlesAttributesKey = keyof HomepageArticlesAttributes; + + type HomepageArticlesPropsFromDataSelector = { + topBlocksClientIdsInOrder: Block[ 'clientId' ][]; + latestPosts: Post[]; + isEditorBlock: boolean; + isUIDisabled: boolean; + error: undefined | string; + }; + + type HomepageArticlesProps = HomepageArticlesPropsFromDataSelector & { + attributes: HomepageArticlesAttributes; + setAttributes: ( attributes: Partial< HomepageArticlesAttributes > ) => void; + textColor: { + color: string; + }; + setTextColor: ( color: string ) => void; + triggerReflow: () => void; + className: string; + isSelected: boolean; + }; +} + +export {}; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/FrequencyToggle/index.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/FrequencyToggle/index.tsx index 21fa457afc39a..822b0a8a442e3 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/FrequencyToggle/index.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/FrequencyToggle/index.tsx @@ -17,12 +17,12 @@ type Option = { /** * Frequency toggle component. - * @param {FrequencyToggleProps} props - props - * @param {string} props.name - name of the radio group - * @param {Option[]} props.initialOptions - the options to pick one from - * @param {Function} props.onChange - callback when the selected option changes - * @param {Option[]} props.selectedOption - the currently selected option - * @param {boolean} props.disabled - whether the toggle is disabled + * @param {FrequencyToggleProps} props - props + * @param {string} props.name - name of the radio group + * @param {Option[]} props.initialOptions - the options to pick one from + * @param {Function} props.onChange - callback when the selected option changes + * @param {Option[]} props.selectedOption - the currently selected option + * @param {boolean} props.disabled - whether the toggle is disabled */ export function FrequencyToggle( { name = 'frequency-toggle', diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/email-frequency-group.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/email-frequency-group.tsx index d612f43431620..0377350606973 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/email-frequency-group.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/email-frequency-group.tsx @@ -20,7 +20,7 @@ interface EmailFrequencyGroupProps { * Runs a media query and returns its value when it changes. * * @param query - the media query to run. - * @returns return value of the media query. + * @return return value of the media query. */ export default function useMediaQuery( query: string ) { const [ match, setMatch ] = useState( window.matchMedia( query ).matches ); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-in.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-in.tsx index 6be546faa4d05..6021400b71c2b 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-in.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/components/logged-in.tsx @@ -10,7 +10,7 @@ import { NewPostsNotifications } from './new-posts-notifications'; /** * Replace the first occurrence of %s in a string with a parameter. - * @param s - string to replace + * @param s - string to replace * @param param - parameter to replace with */ function sprintf( s: string, param: string ) { diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/hooks/useSocialLogin.tsx b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/hooks/useSocialLogin.tsx index 9a1545b6d6e3d..97c47025de92c 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/hooks/useSocialLogin.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/hooks/useSocialLogin.tsx @@ -26,7 +26,7 @@ const addWordPressDomain = window.location.hostname.endsWith( '.wordpress.com' ) /** * Hook to retrieve user info from server, handle social login, and logout functionality. * - * @returns {object} login, loginWindowRef, logout - login is a function to open the social login popup, loginWindowRef is a reference to the login popup window, and logout is a function to logout the user. + * @return {object} login, loginWindowRef, logout - login is a function to open the social login popup, loginWindowRef is a reference to the login popup window, and logout is a function to logout the user. */ export default function useSocialLogin() { const [ loginWindowRef, setLoginWindowRef ] = useState< Window >(); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts index 4d9bf4bed18c5..8041dafa7ff2d 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts +++ b/projects/packages/jetpack-mu-wpcom/src/features/verbum-comments/src/utils.ts @@ -62,7 +62,7 @@ export function isFastConnection() { * Get how many times the user saw the subscription modal. * * @param {number} uid - The user ID associated with the subscription modal. - * @returns {number} - The number of times the user saw the subscription modal. + * @return {number} - The number of times the user saw the subscription modal. */ export function getSubscriptionModalViewCount( uid: number ) { const cookieName = 'verbum_subscription_modal_counter_' + uid; @@ -77,8 +77,8 @@ export function getSubscriptionModalViewCount( uid: number ) { * Set the view count for the subscription modal in a cookie. * * @param {number} count - The view count to be set. - * @param {number} uid - The user ID associated with the subscription modal. - * @returns {void} + * @param {number} uid - The user ID associated with the subscription modal. + * @return {void} */ export function setSubscriptionModalViewCount( count: number, uid: number ) { const cookieName = 'verbum_subscription_modal_counter_' + uid; @@ -89,8 +89,8 @@ export function setSubscriptionModalViewCount( count: number, uid: number ) { * and if the user already view this modal > 5 times. * * @param {boolean} alreadySubscribed - boolean - * @param {number} uid - The user ID associated with the subscription modal. - * @returns {string} - The string that will be used to determine if the modal should be shown. + * @param {number} uid - The user ID associated with the subscription modal. + * @return {string} - The string that will be used to determine if the modal should be shown. */ export function shouldShowSubscriptionModal( alreadySubscribed: boolean, uid: number ) { const { subscribeToBlog } = VerbumComments; @@ -118,8 +118,8 @@ export function shouldShowSubscriptionModal( alreadySubscribed: boolean, uid: nu * Wraps a textarea with a setter that calls onChange when the value changes. * * @param {HTMLTextAreaElement} textarea - the textarea to wrap. - * @param {event} onChange - the callback to call when .value is set. - * @returns {object} the textarea with a reactive .value setter. + * @param {event} onChange - the callback to call when .value is set. + * @return {object} the textarea with a reactive .value setter. */ export function makeReactiveTextArea( textarea: HTMLTextAreaElement, @@ -145,7 +145,7 @@ export function makeReactiveTextArea( * Used by the textarea and editor components. * * @param {string} html - The contents of the comment textarea. - * @returns {boolean} indicating if the editor content is empty. + * @return {boolean} indicating if the editor content is empty. */ export function isEmptyEditor( html: string ) { const parser = new DOMParser(); @@ -196,7 +196,7 @@ export const setUserInfoCookie = ( userData: UserInfo ) => { /** * Get the user info from the cookie. * - * @returns {UserInfo} the user info. + * @return {UserInfo} the user info. */ export const getUserInfoCookie = () => { let userData: UserInfo = { service: 'guest' }; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/class-wpcom-admin-bar.php b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/class-wpcom-admin-bar.php index 31c62ae02722d..76f2d0eb33c9c 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/class-wpcom-admin-bar.php +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/class-wpcom-admin-bar.php @@ -60,6 +60,17 @@ public function add_node( $args ) { return; } + if ( $args['id'] === 'my-account' ) { + if ( ! is_user_member_of_blog() || get_option( 'wpcom_admin_interface' ) !== 'wp-admin' ) { + $args['href'] = 'https://wordpress.com/me'; + + // Temporarily point to wpcalypso.wordpress.com for testing purposes. + if ( get_option( 'wpcom_site_level_user_profile' ) === '1' ) { + $args['href'] = 'https://wpcalypso.wordpress.com/me'; + } + } + } + $home_url = home_url( '/' ); $site_slug = wp_parse_url( $home_url, PHP_URL_HOST ); $href = str_replace( $home_url, '', $args['href'] ); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.php b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.php index 644c536dc242c..37d31e4b763f0 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.php +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.php @@ -10,8 +10,6 @@ use Automattic\Jetpack\Connection\Manager as Connection_Manager; use Automattic\Jetpack\Jetpack_Mu_Wpcom; -define( 'WPCOM_ADMIN_BAR_UNIFICATION', true ); - // The $icon-color variable for admin color schemes. // See: https://github.com/WordPress/wordpress-develop/blob/679cc0c4a261a77bd8fdb140cd9b0b2ff80ebf37/src/wp-admin/css/colors/_variables.scss#L9 // Only the ones different from the "fresh" scheme are listed. @@ -83,7 +81,7 @@ function wpcom_enqueue_admin_bar_assets() { ); } - $admin_color = get_user_option( 'admin_color' ); + $admin_color = is_admin() ? get_user_option( 'admin_color' ) : 'fresh'; $admin_icon_color = WPCOM_ADMIN_ICON_COLORS[ $admin_color ] ?? WPCOM_ADMIN_ICON_COLORS['fresh']; // Force the icon colors to have desktop color even on mobile viewport. @@ -144,18 +142,23 @@ function wpcom_replace_wp_logo_with_wpcom_all_sites_menu( $wp_admin_bar ) { * @param WP_Admin_Bar $wp_admin_bar The WP_Admin_Bar core object. */ function wpcom_add_reader_menu( $wp_admin_bar ) { - $wp_admin_bar->add_node( + $wp_admin_bar->add_menu( array( - 'id' => 'reader', - 'title' => __( 'Reader', 'jetpack-mu-wpcom' ), - 'href' => maybe_add_origin_site_id_to_url( 'https://wordpress.com/read' ), - 'meta' => array( + 'id' => 'reader', + 'title' => '' . + /* translators: Hidden accessibility text. */ + __( 'Reader', 'jetpack-mu-wpcom' ) . + '', + 'href' => maybe_add_origin_site_id_to_url( 'https://wordpress.com/read' ), + 'meta' => array( 'class' => 'wp-admin-bar-reader', ), + 'parent' => 'top-secondary', ) ); } -add_action( 'admin_bar_menu', 'wpcom_add_reader_menu', 15 ); +// Add the reader icon to the admin bar before the help center icon. +add_action( 'admin_bar_menu', 'wpcom_add_reader_menu', 11 ); /** * Points the (Profile) -> Edit Profile menu to /me when appropriate. diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.scss b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.scss index 4d99d56e1972e..bbeadbd5feca4 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.scss +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-admin-bar/wpcom-admin-bar.scss @@ -76,55 +76,6 @@ } } -/** - * Reader menu - */ -#wpadminbar .wp-admin-bar-reader { - a.ab-item { - display: flex; - align-items: center; - } - - a.ab-item:before { - content: ""; - width: 24px; - height: 20px; - margin-right: 8px; - background-color: currentColor; - mask-image: url('data:image/svg+xml,'); - mask-position: center; - mask-repeat: no-repeat; - } - - @media (max-width: 782px) { - & { - display: flex; - } - - & a.ab-item { - justify-content: center; - text-indent: 0; - font-size: 0; - width: 52px; - } - - & a.ab-item:before { - width: 36px; - height: 36px; - margin: 0 8px; - mask-size: contain; - } - } - @media (max-width: 480px) { - & a.ab-item { - width: 46px; - } - & a.ab-item:before { - margin: 0 5px; - } - } -} - #wpadminbar #wp-admin-bar-site-name { > .ab-item:before { /** @@ -174,16 +125,59 @@ } } + /* Reader menu item */ + #wp-admin-bar-reader { + .ab-item { + padding: 0px; + } + + .ab-icon { + display: flex; + align-items: center; + padding: 0 10px; + margin: 0; + height: 100%; + + &:before { + display: flex; + content: ""; + width: 24px; + height: 20px; + margin: 0px; + background-color: currentColor; + mask-image: url('data:image/svg+xml,'); + mask-position: center; + mask-repeat: no-repeat; + } + } + } + @media (max-width: 782px) { height: 45px; + #wp-admin-bar-reader { + display: block; + width: auto !important; + min-width: 52px; + padding: 0px; + + .ab-icon { + justify-content: center; + padding: 0px 10px; + + &:before { + width: 36px; + height: 36px; + margin: 0px; + mask-size: contain; + } + } + } + #wp-admin-bar-help-center { display: block !important; - width: 52px !important; + width: 49px !important; margin-right: 0 !important; - .ab-item { - width: 52px; - } } #wp-admin-bar-notes { @@ -214,6 +208,13 @@ } } @media (max-width: 480px) { + #wp-admin-bar-reader { + width: 46px; + + .ab-icon { + max-width: 40px; + } + } #wp-admin-bar-help-center { width: 46px !important; } diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-description-links/src/block-links-map.ts b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-description-links/src/block-links-map.ts index eae86bced0a92..f13ece843d2fb 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-description-links/src/block-links-map.ts +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-description-links/src/block-links-map.ts @@ -341,6 +341,18 @@ const blockInfoMapping: { [ key: string ]: { link: string; postId: number } } = link: 'https://wordpress.com/support/wordpress-editor/blocks/subscriber-login-block/', postId: 380451, }, + 'jetpack/blog-stats': { + link: 'https://wordpress.com/support/wordpress-editor/blocks/blog-stats-block/', + postId: 382010, + }, + 'jetpack/top-posts': { + link: 'https://wordpress.com/support/wordpress-editor/blocks/top-posts-pages-block/', + postId: 381536, + }, + 'jetpack/goodreads': { + link: 'https://wordpress.com/support/wordpress-editor/blocks/goodreads-block/', + postId: 382051, + }, }; export const blockInfoWithVariations: { diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-description-links/src/inline-support-link.tsx b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-description-links/src/inline-support-link.tsx index e6afd8ea29145..4aa6100f3e490 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-description-links/src/inline-support-link.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-description-links/src/inline-support-link.tsx @@ -17,11 +17,11 @@ interface Props { /** * Create the block description link. * - * @param {Props} props - The component props. + * @param {Props} props - The component props. * @param {string | ReactElement>} props.children - The component children. - * @param {string} props.title - Block title. - * @param {string} props.url - Support link URL. - * @param {number} props.postId - Post ID. + * @param {string} props.title - Block title. + * @param {string} props.url - Support link URL. + * @param {number} props.postId - Post ID. */ export default function DescriptionSupportLink( { children, diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/sharing-modal/inline-social-logo.tsx b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/sharing-modal/inline-social-logo.tsx index b3d72b5eae882..cf1900f2b5444 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/sharing-modal/inline-social-logo.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/sharing-modal/inline-social-logo.tsx @@ -18,7 +18,7 @@ interface Props { * * InlineSocialLogosSprite must be included on the page where this is used * @param props - The props of the component, - * @returns A Social Logo SVG + * @return A Social Logo SVG */ function InlineSocialLogo( props: Assign< React.SVGProps< SVGSVGElement >, Props > ) { const { size = 24, icon, className, ...otherProps } = props; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/sharing-modal/inline-social-logos-sprite.tsx b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/sharing-modal/inline-social-logos-sprite.tsx index c0c5e9388cdad..4068aba7fcd38 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/sharing-modal/inline-social-logos-sprite.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/sharing-modal/inline-social-logos-sprite.tsx @@ -2,7 +2,7 @@ * A hidden inline svg sprite of social logos. * * Sprite was coppied from https://wordpress.com/calypso/images/social-logos-d55401f99bb02ebd6cf4.svg - * @returns see above. + * @return see above. */ const InlineSocialLogosSprite = () => { return ( diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/sharing-modal/style.scss b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/sharing-modal/style.scss index c7738fc6fc0d5..56b6da442b79e 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/sharing-modal/style.scss +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/sharing-modal/style.scss @@ -112,6 +112,10 @@ .wpcom-block-editor-post-published-sharing-modal__checkbox-section { margin-top: 40px; color: var(--studio-gray-60); + + label { + display: flex; + } } .form-checkbox { margin-top: 1px; diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/welcome-modal/wpcom-nux.js b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/welcome-modal/wpcom-nux.js index 6fb72e578b66c..535833b504b64 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/welcome-modal/wpcom-nux.js +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/welcome-modal/wpcom-nux.js @@ -68,7 +68,7 @@ function WpcomNux() { /** * This function returns a collection of NUX slide data - * @returns { Array } a collection of props + * @return { Array } a collection of props */ function getWpcomNuxPages() { return [ @@ -113,13 +113,13 @@ function getWpcomNuxPages() { /** * Display the Nux page * - * @param props - The props of the component. - * @param props.pageNumber - The number of page. - * @param props.isLastPage - Whether the current page is the last one. + * @param props - The props of the component. + * @param props.pageNumber - The number of page. + * @param props.isLastPage - Whether the current page is the last one. * @param props.alignBottom - Whether to align bottom. - * @param props.heading - The text of heading. + * @param props.heading - The text of heading. * @param props.description - The text of description. - * @param props.imgSrc - The src of image. + * @param props.imgSrc - The src of image. */ function NuxPage( { pageNumber, isLastPage, alignBottom = false, heading, description, imgSrc } ) { useEffect( () => { diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/welcome-tour/tour-launch.jsx b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/welcome-tour/tour-launch.jsx index 1df746ef992b5..6789b4e5ed931 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/welcome-tour/tour-launch.jsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/welcome-tour/tour-launch.jsx @@ -80,7 +80,7 @@ function LaunchWpcomWelcomeTour() { /** * Display the welcome tour. * - * @param props - The props of the component. + * @param props - The props of the component. * @param props.siteIntent - The intent of the site. */ function WelcomeTour( { siteIntent } ) { diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/welcome-tour/use-tour-steps.tsx b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/welcome-tour/use-tour-steps.tsx index 6d0ad267c70c1..aefd0873a4a75 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/welcome-tour/use-tour-steps.tsx +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-block-editor-nux/src/welcome-tour/use-tour-steps.tsx @@ -68,11 +68,11 @@ function getTourAssets( key: string ): TourAsset | undefined { /** * Get the steps of the tour * - * @param localeSlug - The slug of the locale. + * @param localeSlug - The slug of the locale. * @param referencePositioning - The reference positioning. - * @param isSiteEditor - Whether is the site editor. - * @param themeName - The name of the theme. - * @param siteIntent - The intent of the current site. + * @param isSiteEditor - Whether is the site editor. + * @param themeName - The name of the theme. + * @param siteIntent - The intent of the current site. */ function useTourSteps( localeSlug: string, diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-blocks/event-countdown/edit.js b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-blocks/event-countdown/edit.js index 6c937f5921544..a3753fd9cfdf8 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-blocks/event-countdown/edit.js +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-blocks/event-countdown/edit.js @@ -12,10 +12,10 @@ const TIMEZONELESS_FORMAT = 'YYYY-MM-DDTHH:mm:ss'; /** * Assigns timezone to a date without altering it - * @param {string} date - a date in YYYY-MM-DDTHH:mm:ss format + * @param {string} date - a date in YYYY-MM-DDTHH:mm:ss format * @param {number} offset - the offset in hours * @param {string} format - the format of the date - * @returns {object} a moment instance + * @return {object} a moment instance */ function assignTimezone( date, offset, format = TIMEZONELESS_FORMAT ) { // passing the `true` flag to `utcOffset` keeps the date unaltered, only adds a tz diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-blocks/event-countdown/view.js b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-blocks/event-countdown/view.js index dc58638193102..d17346aa9b3a0 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-blocks/event-countdown/view.js +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-blocks/event-countdown/view.js @@ -50,9 +50,9 @@ domReady( function () { * Countdown element passed in as the dom node to search * within, supporting multiple events per page * - * @param ts - The timestamp of the countdown + * @param ts - The timestamp of the countdown * @param elem - The element of the countdown container - * @param id - The ID of the countdown + * @param id - The ID of the countdown */ function updateCountdown( ts, elem, id ) { const now = Date.now(); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-documentation-links/wpcom-documentation-links.ts b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-documentation-links/wpcom-documentation-links.ts index add37ecf5b3de..ee1c306b27205 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-documentation-links/wpcom-documentation-links.ts +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-documentation-links/wpcom-documentation-links.ts @@ -52,6 +52,9 @@ function overrideCoreDocumentationLinksToWpcom( translation: string, text: strin 'https://wordpress.org/documentation/article/styles-overview/': 'https://wordpress.com/support/using-styles/', + 'https://developer.wordpress.org/advanced-administration/wordpress/css/': + 'https://wordpress.com/support/editing-css/', + /** * Embed Block */ diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-global-styles/wpcom-global-styles-view.js b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-global-styles/wpcom-global-styles-view.js index cd1f47cb5d357..e0544227ad5cd 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-global-styles/wpcom-global-styles-view.js +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-global-styles/wpcom-global-styles-view.js @@ -6,7 +6,7 @@ import './wpcom-global-styles-view.scss'; /** * Records a Tracks click event. * @param button - {string} Identifier of the button that has been clicked. - * @param props - {object} Additional props to track. + * @param props - {object} Additional props to track. */ function recordEvent( button, props = {} ) { wpcomTrackEvent( 'wpcom_launchbar_button_click', { diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-locale/sync-locale-from-calypso-to-atomic.php b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-locale/sync-locale-from-calypso-to-atomic.php new file mode 100644 index 0000000000000..616be750d30a0 --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-locale/sync-locale-from-calypso-to-atomic.php @@ -0,0 +1,110 @@ +wp_locale ? $jetpack_locale_object->wp_locale : 'en_US'; + } + } + + if ( isset( $jetpack_locale ) ) { + return $jetpack_locale; + } + + return 'en_US'; +} + +/** + * Install locale if not yet available. + * + * @param string $locale The new locale slug. + */ +function _install_locale( $locale = '' ) { + if ( ! in_array( $locale, get_available_languages(), true ) + && ! empty( $locale ) && current_user_can( 'install_languages' ) ) { + + if ( ! function_exists( 'wp_download_language_pack' ) ) { + require_once ABSPATH . 'wp-admin/includes/translation-install.php'; + } + + if ( ! function_exists( 'request_filesystem_credentials' ) ) { + require_once ABSPATH . 'wp-admin/includes/file.php'; + } + + if ( wp_can_install_language_pack() ) { + wp_download_language_pack( $locale ); + load_default_textdomain( $locale ); + } + } +} + +/** + * Trigger reloading of all non-default textdomains if the user just changed + * their locale on WordPress.com. + * + * @param string $wpcom_locale The user's detected WordPress.com locale. + */ +function _unload_non_default_textdomains_on_wpcom_user_locale_switch( $wpcom_locale ) { + $user_switched_locale = get_user_locale() !== $wpcom_locale; + if ( ! $user_switched_locale ) { + return; + } + + global $l10n; + $loaded_textdomains = array_keys( $l10n ); + $non_default_textdomains = array_diff( $loaded_textdomains, array( 'default' ) ); + foreach ( $non_default_textdomains as $textdomain ) { + // Using $reloadable = true makes sure the correct locale's + // translations are loaded just-in-time. + unload_textdomain( $textdomain, true ); + } +} + +/** + * Handles the locale setup for Atomic sites. + * + * @param string $user_locale The user's locale. + */ +function wpcom_sync_locale_from_calypso_to_atomic( $user_locale ) { + $is_atomic_site = ( new Automattic\Jetpack\Status\Host() )->is_woa_site(); + if ( ! $is_atomic_site ) { + return; + } + + $user_id = get_current_user_id(); + $connection_manager = new Connection_Manager( 'jetpack' ); + if ( ! $connection_manager->is_user_connected( $user_id ) ) { + return; + } + $user_data = $connection_manager->get_connected_user_data( $user_id ); + $user_locale = $user_data['user_locale'] ?? ''; + + $jetpack_locale = _get_jetpack_locale( $user_locale ); + _install_locale( $jetpack_locale ); + _unload_non_default_textdomains_on_wpcom_user_locale_switch( $jetpack_locale ); + + if ( get_user_option( 'locale', $user_id ) !== $jetpack_locale ) { + update_user_option( $user_id, 'locale', $jetpack_locale, true ); + } +} +add_filter( 'init', 'wpcom_sync_locale_from_calypso_to_atomic' ); diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.php b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.php index b4f8c6b3b463f..2b950a10863d3 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.php +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.php @@ -8,16 +8,16 @@ use Automattic\Jetpack\Jetpack_Mu_Wpcom; /** - * Check if the site is a WordPress.com Simple site. + * Check if the site is a WordPress.com Atomic site. * * @return bool */ -function is_wpcom_simple() { +function is_woa_site() { if ( ! class_exists( 'Automattic\Jetpack\Status\Host' ) ) { return false; } $host = new Automattic\Jetpack\Status\Host(); - return $host->is_wpcom_simple(); + return $host->is_woa_site(); } /** @@ -33,7 +33,7 @@ function wpcom_profile_settings_add_links_to_wpcom() { true ); - $is_wpcom_simple = is_wpcom_simple(); + $is_wpcom_atomic_classic = is_woa_site() && get_option( 'wpcom_admin_interface' ) === 'wp-admin'; // Temporarily point to wpcalypso.wordpress.com for testing purposes. $wpcom_host = 'https://wordpress.com'; @@ -45,19 +45,23 @@ function wpcom_profile_settings_add_links_to_wpcom() { 'wpcom-profile-settings-link-to-wpcom', 'wpcomProfileSettingsLinkToWpcom', array( - 'synced' => array( + 'language' => array( + 'link' => esc_url( $wpcom_host . '/me/account' ), + 'text' => __( 'Your admin interface language is managed on WordPress.com Account settings', 'jetpack-mu-wpcom' ), + ), + 'synced' => array( 'link' => esc_url( $wpcom_host . '/me' ), 'text' => __( 'You can manage your profile on WordPress.com Profile settings (First / Last / Display Names, Website, and Biographical Info)', 'jetpack-mu-wpcom' ), ), - 'email' => array( + 'email' => array( 'link' => esc_url( $wpcom_host . '/me/account' ), 'text' => __( 'Your WordPress.com email is managed on WordPress.com Account settings', 'jetpack-mu-wpcom' ), ), - 'password' => array( + 'password' => array( 'link' => esc_url( $wpcom_host . '/me/security' ), 'text' => __( 'Your WordPress.com password is managed on WordPress.com Security settings', 'jetpack-mu-wpcom' ), ), - 'isWpcomSimple' => $is_wpcom_simple, + 'isWpcomAtomicClassic' => $is_wpcom_atomic_classic, ) ); } diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.ts b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.ts index 50d96c63d7af6..621c213633e06 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.ts +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/profile-settings-link-to-wpcom.ts @@ -1,8 +1,8 @@ /** - * Disable the email field on Simple sites. + * Disable the email field except on Atomic Classic sites. */ const wpcom_profile_settings_disable_email_field = () => { - if ( ! window.wpcomProfileSettingsLinkToWpcom?.isWpcomSimple ) { + if ( window.wpcomProfileSettingsLinkToWpcom?.isWpcomAtomicClassic ) { return; } const emailField = document.getElementById( 'email' ) as HTMLInputElement; @@ -18,18 +18,28 @@ const wpcom_profile_settings_disable_email_field = () => { * Add a link to the WordPress.com profile settings page. */ const wpcom_profile_settings_add_links_to_wpcom = () => { - const usernameSection = document.querySelector( '.user-user-login-wrap' )?.querySelector( 'td' ); - const emailSection = document.querySelector( '.user-email-wrap' )?.querySelector( 'td' ); - const newPasswordSection = document.getElementById( 'password' )?.querySelector( 'td' ); const userSessionSection = document.querySelector( '.user-sessions-wrap' ); - userSessionSection?.remove(); - // Simple sites cannot set a password in wp-admin. - if ( window.wpcomProfileSettingsLinkToWpcom?.isWpcomSimple && newPasswordSection ) { + // We cannot set a password in wp-admin except on Atomic Classic sites. + const newPasswordSection = document.getElementById( 'password' )?.querySelector( 'td' ); + if ( ! window.wpcomProfileSettingsLinkToWpcom?.isWpcomAtomicClassic && newPasswordSection ) { newPasswordSection.innerHTML = ''; } + const languageSection = document.querySelector( '.user-language-wrap' )?.querySelector( 'td' ); + const languageSelect = document.getElementById( 'locale' ); + const languageSettingsLink = window.wpcomProfileSettingsLinkToWpcom?.language?.link; + const languageSettingsLinkText = window.wpcomProfileSettingsLinkToWpcom?.language?.text; + if ( languageSettingsLink && languageSettingsLinkText ) { + const notice = document.createElement( 'p' ); + notice.className = 'description'; + notice.innerHTML = `${ languageSettingsLinkText }.`; + languageSection?.appendChild( notice ); + languageSelect?.remove(); + } + + const emailSection = document.querySelector( '.user-email-wrap' )?.querySelector( 'td' ); const emailSettingsLink = window.wpcomProfileSettingsLinkToWpcom?.email?.link; const emailSettingsLinkText = window.wpcomProfileSettingsLinkToWpcom?.email?.text; if ( emailSection && emailSettingsLink && emailSettingsLinkText ) { @@ -48,6 +58,7 @@ const wpcom_profile_settings_add_links_to_wpcom = () => { newPasswordSection.appendChild( notice ); } + const usernameSection = document.querySelector( '.user-user-login-wrap' )?.querySelector( 'td' ); const syncedSettingsLink = window.wpcomProfileSettingsLinkToWpcom?.synced?.link; const syncedSettingsLinkText = window.wpcomProfileSettingsLinkToWpcom?.synced?.text; if ( usernameSection && syncedSettingsLink && syncedSettingsLinkText ) { diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/types.d.ts b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/types.d.ts index f4b741a905177..a3d97189c251b 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/types.d.ts +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-profile-settings/types.d.ts @@ -1,6 +1,14 @@ declare global { interface Window { wpcomProfileSettingsLinkToWpcom: { + language: { + link: string; + text: string; + }; + synced: { + link: string; + text: string; + }; email: { link: string; text: string; @@ -9,7 +17,7 @@ declare global { link: string; text: string; }; - isWpcomSimple: boolean; + isWpcomAtomicClassic: boolean; }; } } diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-themes/css/ui-fixes.css b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-themes/css/ui-fixes.css index 8351acec39e25..cb8e78405ec23 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-themes/css/ui-fixes.css +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-themes/css/ui-fixes.css @@ -1,3 +1,7 @@ .theme-browser .button:visited { color: #fff; +} + +.theme-autoupdate .hidden { + display: none; } \ No newline at end of file diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-themes/wpcom-themes.php b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-themes/wpcom-themes.php index d8d25b497f141..6d6ede007345a 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-themes/wpcom-themes.php +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-themes/wpcom-themes.php @@ -70,3 +70,22 @@ function wpcom_themes_add_theme_showcase_menu() { ); } add_action( 'admin_menu', 'wpcom_themes_add_theme_showcase_menu' ); + +/** + * Automatically opens the "Upload Theme" dialog on the theme installation page based on a 'wpcom-upload' query parameter. + */ +function wpcom_auto_open_upload_theme() { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended + if ( isset( $_GET['wpcom-upload'] ) && $_GET['wpcom-upload'] === '1' ) { + if ( ! current_user_can( 'install_themes' ) ) { + return; + } + add_filter( + 'admin_body_class', + function ( $classes ) { + return $classes . ' show-upload-view '; + } + ); + } +} +add_action( 'load-theme-install.php', 'wpcom_auto_open_upload_theme' ); diff --git a/projects/packages/jitm/CHANGELOG.md b/projects/packages/jitm/CHANGELOG.md index 37930fb849039..13dcd5be77c4f 100644 --- a/projects/packages/jitm/CHANGELOG.md +++ b/projects/packages/jitm/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.1.19] - 2024-08-29 +### Changed +- Updated package dependencies. [#39111] + +## [3.1.18] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + +## [3.1.17] - 2024-08-19 +### Fixed +- Lossless image optimization for images (should improve performance with no visible changes). [#38750] + ## [3.1.16] - 2024-08-15 ### Changed - Updated package dependencies. [#38662] @@ -743,6 +755,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Update Jetpack to use new JITM package +[3.1.19]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.18...v3.1.19 +[3.1.18]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.17...v3.1.18 +[3.1.17]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.16...v3.1.17 [3.1.16]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.15...v3.1.16 [3.1.15]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.14...v3.1.15 [3.1.14]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.13...v3.1.14 diff --git a/projects/packages/jitm/composer.json b/projects/packages/jitm/composer.json index 9451806367164..9930839451dd2 100644 --- a/projects/packages/jitm/composer.json +++ b/projects/packages/jitm/composer.json @@ -15,7 +15,7 @@ }, "require-dev": { "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "suggest": { diff --git a/projects/packages/jitm/package.json b/projects/packages/jitm/package.json index 34d050daac44b..9ce31fd30b742 100644 --- a/projects/packages/jitm/package.json +++ b/projects/packages/jitm/package.json @@ -27,7 +27,7 @@ "@wordpress/browserslist-config": "6.5.0", "sass": "1.64.1", "sass-loader": "12.4.0", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" } } diff --git a/projects/packages/jitm/src/class-jitm.php b/projects/packages/jitm/src/class-jitm.php index 0141c3ca848d0..1e79af826c202 100644 --- a/projects/packages/jitm/src/class-jitm.php +++ b/projects/packages/jitm/src/class-jitm.php @@ -20,7 +20,7 @@ */ class JITM { - const PACKAGE_VERSION = '3.1.16'; + const PACKAGE_VERSION = '3.1.19'; /** * The configuration method that is called from the jetpack-config package. diff --git a/projects/packages/jitm/src/images/background.png b/projects/packages/jitm/src/images/background.png index c2d50e1b7c025..07ae0ef447c60 100644 Binary files a/projects/packages/jitm/src/images/background.png and b/projects/packages/jitm/src/images/background.png differ diff --git a/projects/packages/licensing/CHANGELOG.md b/projects/packages/licensing/CHANGELOG.md index 5990ffa32ec9f..71ea1cff01a8c 100644 --- a/projects/packages/licensing/CHANGELOG.md +++ b/projects/packages/licensing/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.7] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + +## [2.0.6] - 2024-08-19 +### Changed +- Internal updates. + ## [2.0.5] - 2024-04-22 ### Changed - Internal updates. @@ -272,6 +280,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Licensing: Add support for Jetpack licenses +[2.0.7]: https://github.com/Automattic/jetpack-licensing/compare/v2.0.6...v2.0.7 +[2.0.6]: https://github.com/Automattic/jetpack-licensing/compare/v2.0.5...v2.0.6 [2.0.5]: https://github.com/Automattic/jetpack-licensing/compare/v2.0.4...v2.0.5 [2.0.4]: https://github.com/Automattic/jetpack-licensing/compare/v2.0.3...v2.0.4 [2.0.3]: https://github.com/Automattic/jetpack-licensing/compare/v2.0.2...v2.0.3 diff --git a/projects/packages/licensing/changelog/renovate-lock-file-maintenance b/projects/packages/licensing/changelog/renovate-lock-file-maintenance deleted file mode 100644 index 3109d07526368..0000000000000 --- a/projects/packages/licensing/changelog/renovate-lock-file-maintenance +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: changed -Comment: Update Phan baseline. - - diff --git a/projects/packages/licensing/composer.json b/projects/packages/licensing/composer.json index cd45696a21b38..ca6ff1ed34f50 100644 --- a/projects/packages/licensing/composer.json +++ b/projects/packages/licensing/composer.json @@ -9,7 +9,7 @@ }, "require-dev": { "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "suggest": { diff --git a/projects/packages/logo/CHANGELOG.md b/projects/packages/logo/CHANGELOG.md index f5925e49e8cc9..79a55848c425a 100644 --- a/projects/packages/logo/CHANGELOG.md +++ b/projects/packages/logo/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.4] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## [2.0.3] - 2024-05-20 ### Changed - Replaced heredoc syntax with strings. [#37396] @@ -178,6 +182,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Packages: Add a basic Jetpack Logo package +[2.0.4]: https://github.com/Automattic/jetpack-logo/compare/v2.0.3...v2.0.4 [2.0.3]: https://github.com/Automattic/jetpack-logo/compare/v2.0.2...v2.0.3 [2.0.2]: https://github.com/Automattic/jetpack-logo/compare/v2.0.1...v2.0.2 [2.0.1]: https://github.com/Automattic/jetpack-logo/compare/v2.0.0...v2.0.1 diff --git a/projects/packages/logo/composer.json b/projects/packages/logo/composer.json index 7b28705077382..e68d8db3227a2 100644 --- a/projects/packages/logo/composer.json +++ b/projects/packages/logo/composer.json @@ -7,7 +7,7 @@ "php": ">=7.0" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "suggest": { diff --git a/projects/packages/masterbar/CHANGELOG.md b/projects/packages/masterbar/CHANGELOG.md index 1f59b8a0f5299..8caf2f036efd8 100644 --- a/projects/packages/masterbar/CHANGELOG.md +++ b/projects/packages/masterbar/CHANGELOG.md @@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.8.0] - 2024-08-23 +### Changed +- Remove locale sync [#39009] +- Updated package dependencies. [#39004] + +### Fixed +- Inconsistent Color Scheme when previewing on Simple Default [#39048] + +## [0.7.0] - 2024-08-21 +### Changed +- Site Level User Profile: expose all relevant fields on profile.php [#38949] + +### Fixed +- Revert recent SVG image optimizations. [#38981] + +## [0.6.1] - 2024-08-19 +### Changed +- Updated package dependencies. [#38662] + +### Fixed +- Lossless image optimization for images (should improve performance with no visible changes). [#38750] + ## [0.6.0] - 2024-07-29 ### Changed - Remove Browse sites from sidebar as it's on WordPress logo in masterbar [#38547] @@ -80,6 +102,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated package dependencies. [#37669] - Updated package dependencies. [#37706] +[0.8.0]: https://github.com/Automattic/jetpack-masterbar/compare/v0.7.0...v0.8.0 +[0.7.0]: https://github.com/Automattic/jetpack-masterbar/compare/v0.6.1...v0.7.0 +[0.6.1]: https://github.com/Automattic/jetpack-masterbar/compare/v0.6.0...v0.6.1 [0.6.0]: https://github.com/Automattic/jetpack-masterbar/compare/v0.5.0...v0.6.0 [0.5.0]: https://github.com/Automattic/jetpack-masterbar/compare/v0.4.0...v0.5.0 [0.4.0]: https://github.com/Automattic/jetpack-masterbar/compare/v0.3.1...v0.4.0 diff --git a/projects/js-packages/ai-client/changelog/force-a-release b/projects/packages/masterbar/changelog/remove-custom-css-warnings similarity index 58% rename from projects/js-packages/ai-client/changelog/force-a-release rename to projects/packages/masterbar/changelog/remove-custom-css-warnings index d4ad6c7cc3379..9c3045aab1360 100644 --- a/projects/js-packages/ai-client/changelog/force-a-release +++ b/projects/packages/masterbar/changelog/remove-custom-css-warnings @@ -1,4 +1,5 @@ Significance: patch Type: changed +Comment: Fix Phan issue + -Update dependencies. diff --git a/projects/packages/publicize/changelog/renovate-wordpress-monorepo b/projects/packages/masterbar/changelog/renovate-npm-webpack-vulnerability similarity index 100% rename from projects/packages/publicize/changelog/renovate-wordpress-monorepo rename to projects/packages/masterbar/changelog/renovate-npm-webpack-vulnerability diff --git a/projects/packages/masterbar/changelog/try-no-version-bumps-in-trunk b/projects/packages/masterbar/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..91efe85c55e06 --- /dev/null +++ b/projects/packages/masterbar/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/packages/masterbar/composer.json b/projects/packages/masterbar/composer.json index 6961045716711..fc64f44496214 100644 --- a/projects/packages/masterbar/composer.json +++ b/projects/packages/masterbar/composer.json @@ -17,7 +17,7 @@ }, "require-dev": { "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/patchwork-redefine-exit": "@dev", "automattic/wordbless": "dev-master" @@ -63,7 +63,7 @@ "extra": { "autotagger": true, "branch-alias": { - "dev-trunk": "0.6.x-dev" + "dev-trunk": "0.8.x-dev" }, "changelogger": { "link-template": "https://github.com/Automattic/jetpack-masterbar/compare/v${old}...v${new}" diff --git a/projects/packages/masterbar/package.json b/projects/packages/masterbar/package.json index d6a2358731837..542fc9fd1ab3a 100644 --- a/projects/packages/masterbar/package.json +++ b/projects/packages/masterbar/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-masterbar", - "version": "0.6.1-alpha", + "version": "0.8.0", "description": "The WordPress.com Toolbar feature replaces the default admin bar and offers quick links to the Reader, all your sites, your WordPress.com profile, and notifications.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/masterbar/#readme", "bugs": { @@ -42,7 +42,7 @@ "postcss-loader": "6.2.0", "sass": "1.64.1", "sass-loader": "12.4.0", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" } } diff --git a/projects/packages/masterbar/src/admin-color-schemes/class-admin-color-schemes.php b/projects/packages/masterbar/src/admin-color-schemes/class-admin-color-schemes.php index 42a9c0f32fa78..ffe8fd0f3f3af 100644 --- a/projects/packages/masterbar/src/admin-color-schemes/class-admin-color-schemes.php +++ b/projects/packages/masterbar/src/admin-color-schemes/class-admin-color-schemes.php @@ -32,10 +32,10 @@ public function __construct() { add_action( 'rest_api_init', array( $this, 'register_admin_color_meta' ) ); } - if ( ( defined( 'WPCOM_ADMIN_BAR_UNIFICATION' ) && WPCOM_ADMIN_BAR_UNIFICATION ) || get_option( 'wpcom_admin_interface' ) === 'wp-admin' ) { // Classic sites. + if ( ( defined( 'WPCOM_ADMIN_BAR_UNIFICATION' ) && WPCOM_ADMIN_BAR_UNIFICATION ) || get_option( 'wpcom_admin_interface' ) === 'wp-admin' ) { // Simple and Atomic sites. add_filter( 'css_do_concat', array( $this, 'disable_css_concat_for_color_schemes' ), 10, 2 ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_color_scheme_for_sidebar_notice' ) ); - } else { // Default and self-hosted sites. + } else { // self-hosted sites. add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_core_color_schemes_overrides' ) ); } } diff --git a/projects/packages/masterbar/src/admin-menu/class-atomic-admin-menu.php b/projects/packages/masterbar/src/admin-menu/class-atomic-admin-menu.php index 1bca10c709fd5..b163593062c98 100644 --- a/projects/packages/masterbar/src/admin-menu/class-atomic-admin-menu.php +++ b/projects/packages/masterbar/src/admin-menu/class-atomic-admin-menu.php @@ -137,10 +137,11 @@ public function add_users_menu() { // // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- Core should ideally document null for no-callback arg. https://core.trac.wordpress.org/ticket/52539. add_submenu_page( 'users.php', esc_attr__( 'Subscribers', 'jetpack-masterbar' ), __( 'Subscribers', 'jetpack-masterbar' ), 'list_users', 'https://wordpress.com/subscribers/' . $this->domain, null ); - // When the interface is not set to wp-admin, we replace the Profile submenu. - remove_submenu_page( 'users.php', 'profile.php' ); - // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- Core should ideally document null for no-callback arg. https://core.trac.wordpress.org/ticket/52539. - add_submenu_page( 'users.php', esc_attr__( 'My Profile', 'jetpack-masterbar' ), __( 'My Profile', 'jetpack-masterbar' ), 'read', 'https://wordpress.com/me/', null ); + if ( empty( get_option( 'wpcom_site_level_user_profile' ) ) ) { + remove_submenu_page( 'users.php', 'profile.php' ); + // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- Core should ideally document null for no-callback arg. https://core.trac.wordpress.org/ticket/52539. + add_submenu_page( 'users.php', esc_attr__( 'My Profile', 'jetpack-masterbar' ), __( 'My Profile', 'jetpack-masterbar' ), 'read', 'https://wordpress.com/me/', null ); + } } // Users who can't 'list_users' will see "Profile" menu & "Profile > Account Settings" as submenu. diff --git a/projects/packages/masterbar/src/admin-menu/load.php b/projects/packages/masterbar/src/admin-menu/load.php index 76322e7eb57e1..d7a78f363633f 100644 --- a/projects/packages/masterbar/src/admin-menu/load.php +++ b/projects/packages/masterbar/src/admin-menu/load.php @@ -64,6 +64,7 @@ function () { remove_action( 'customize_register', 'Automattic\Jetpack\Masterbar\register_css_nudge_control' ); + // @phan-suppress-next-line PhanUndeclaredClassInCallable remove_action( 'customize_register', array( 'Jetpack_Custom_CSS_Enhancements', 'customize_register' ) ); } } diff --git a/projects/packages/masterbar/src/class-main.php b/projects/packages/masterbar/src/class-main.php index 7254ab887e104..21427bea3a753 100644 --- a/projects/packages/masterbar/src/class-main.php +++ b/projects/packages/masterbar/src/class-main.php @@ -14,7 +14,7 @@ */ class Main { - const PACKAGE_VERSION = '0.6.1-alpha'; + const PACKAGE_VERSION = '0.8.0'; /** * Initializer. diff --git a/projects/packages/masterbar/src/masterbar/class-masterbar.php b/projects/packages/masterbar/src/masterbar/class-masterbar.php index cff37f0ecb106..a9c84085df0c5 100644 --- a/projects/packages/masterbar/src/masterbar/class-masterbar.php +++ b/projects/packages/masterbar/src/masterbar/class-masterbar.php @@ -135,13 +135,6 @@ public function __construct() { if ( isset( $this->user_data['use_wp_admin_links'] ) ) { update_user_option( $this->user_id, 'jetpack_admin_menu_link_destination', $this->user_data['use_wp_admin_links'] ? '1' : '0' ); } - // If Atomic, store and install user locale. - if ( $this->site_woa && 'wp-admin' !== get_option( 'wpcom_admin_interface' ) ) { - $this->user_locale = $this->get_jetpack_locale( $this->user_locale ); - $this->install_locale( $this->user_locale ); - $this->unload_non_default_textdomains_on_wpcom_user_locale_switch( $this->user_locale ); - update_user_option( $this->user_id, 'locale', $this->user_locale, true ); - } add_action( 'admin_bar_init', array( $this, 'init' ) ); diff --git a/projects/packages/masterbar/src/profile-edit/bootstrap.php b/projects/packages/masterbar/src/profile-edit/bootstrap.php index 11cf49b27a270..46ecee1904b85 100644 --- a/projects/packages/masterbar/src/profile-edit/bootstrap.php +++ b/projects/packages/masterbar/src/profile-edit/bootstrap.php @@ -9,7 +9,6 @@ use Automattic\Jetpack\Connection\Manager as Connection_Manager; -require_once __DIR__ . '/profile-edit.php'; require_once __DIR__ . '/class-wpcom-user-profile-fields-revert.php'; /** diff --git a/projects/packages/my-jetpack/.phan/baseline.php b/projects/packages/my-jetpack/.phan/baseline.php index 9158438791ca1..dd9d2bb32018e 100644 --- a/projects/packages/my-jetpack/.phan/baseline.php +++ b/projects/packages/my-jetpack/.phan/baseline.php @@ -24,11 +24,12 @@ // PhanTypeMismatchArgumentProbablyReal : 2 occurrences // PhanPluginMixedKeyNoKey : 1 occurrence // PhanTypeMismatchArgumentNullableInternal : 1 occurrence + // PhanUndeclaredClassMethod : 1 occurrence // Currently, file_suppressions and directory_suppressions are the only supported suppressions 'file_suppressions' => [ 'src/class-activitylog.php' => ['PhanTypeMismatchArgumentProbablyReal'], - 'src/class-initializer.php' => ['PhanImpossibleCondition', 'PhanNoopNew', 'PhanRedundantCondition', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnNullable'], + 'src/class-initializer.php' => ['PhanImpossibleCondition', 'PhanNoopNew', 'PhanRedundantCondition', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnNullable', 'PhanUndeclaredClassMethod'], 'src/class-jetpack-manage.php' => ['PhanTypeMismatchArgumentProbablyReal'], 'src/class-products.php' => ['PhanNonClassMethodCall'], 'src/class-rest-products.php' => ['PhanParamTooMany', 'PhanPluginMixedKeyNoKey', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnProbablyReal'], diff --git a/projects/packages/my-jetpack/CHANGELOG.md b/projects/packages/my-jetpack/CHANGELOG.md index 1e7f8cabdb19a..c26f3b6f70b69 100644 --- a/projects/packages/my-jetpack/CHANGELOG.md +++ b/projects/packages/my-jetpack/CHANGELOG.md @@ -5,6 +5,49 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [4.33.1] - 2024-08-29 +### Changed +- Admin menu: change order of Jetpack sub-menu items [#39095] +- My Jetpack: reflect tier filters properly on product class and UI. Fix little nuances with date constructor [#39074] +- Updated package dependencies. [#39111] + +### Fixed +- Don't consider user lifecycle status when repeating evaluation [#39069] +- My Jetpack: Fix the popover and active button of the Bboost card are overlapping [#39067] + +## [4.33.0] - 2024-08-26 +### Added +- Add context switching to videopress card from yearly views to monthly views [#38979] + +### Changed +- My Jetpack: AI product class to handle better disabling tiers [#38989] +- Updated package dependencies. [#39004] + +### Fixed +- allow user currency in My Jetpack pricing [#38977] +- Fix tooltip title for videopress card [#39030] + +## [4.32.4] - 2024-08-21 +### Changed +- Removed unnecessary WAF dependency in My Jetpack. [#38942] + +### Fixed +- Notification bubbles: avoid PHP warning when information is missing. [#38963] +- Revert recent SVG image optimizations. [#38981] + +## [4.32.3] - 2024-08-19 +### Added +- Add stat trends for videopress card. [#38868] +- Add tooltip to VideoPress card. [#38842] +- Add value to active card state on VideoPress My Jetpack card. [#38812] + +### Changed +- Updated package dependencies. [#38893] + +### Fixed +- Lossless image optimization for images (should improve performance with no visible changes). [#38750] +- My Jetpack: ensure product screens redirect to the correct post-checkout URLs. [#38704] + ## [4.32.2] - 2024-08-15 ### Changed - Updated package dependencies. [#38665] @@ -1636,6 +1679,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Created package +[4.33.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.33.0...4.33.1 +[4.33.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.32.4...4.33.0 +[4.32.4]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.32.3...4.32.4 +[4.32.3]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.32.2...4.32.3 [4.32.2]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.32.1...4.32.2 [4.32.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.32.0...4.32.1 [4.32.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.31.0...4.32.0 diff --git a/projects/packages/my-jetpack/_inc/admin.jsx b/projects/packages/my-jetpack/_inc/admin.jsx index eca4f0dc31915..7ccb559796a71 100644 --- a/projects/packages/my-jetpack/_inc/admin.jsx +++ b/projects/packages/my-jetpack/_inc/admin.jsx @@ -38,7 +38,7 @@ import './style.module.scss'; /** * Component to scroll window to top on route change. * - * @returns {null} Null. + * @return {null} Null. */ function ScrollToTop() { const location = useLocation(); diff --git a/projects/packages/my-jetpack/_inc/components/add-license-screen/index.jsx b/projects/packages/my-jetpack/_inc/components/add-license-screen/index.jsx index 380b8974da44c..9ba650d42a6cc 100644 --- a/projects/packages/my-jetpack/_inc/components/add-license-screen/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/add-license-screen/index.jsx @@ -17,7 +17,7 @@ import GoBackLink from '../go-back-link'; /** * The AddLicenseScreen component of the My Jetpack app. * - * @returns {object} The AddLicenseScreen component. + * @return {object} The AddLicenseScreen component. */ export default function AddLicenseScreen() { const { recordEvent } = useAnalytics(); diff --git a/projects/packages/my-jetpack/_inc/components/connected-product-card/index.tsx b/projects/packages/my-jetpack/_inc/components/connected-product-card/index.tsx index a46ab3b185b51..f1ca6373df03b 100644 --- a/projects/packages/my-jetpack/_inc/components/connected-product-card/index.tsx +++ b/projects/packages/my-jetpack/_inc/components/connected-product-card/index.tsx @@ -34,6 +34,7 @@ interface ConnectedProductCardProps { primaryActionOverride?: Record< string, AdditionalAction >; onMouseEnter?: () => void; onMouseLeave?: () => void; + customLoadTracks?: Record< Lowercase< string >, unknown >; } const ConnectedProductCard: FC< ConnectedProductCardProps > = ( { @@ -49,6 +50,7 @@ const ConnectedProductCard: FC< ConnectedProductCardProps > = ( { primaryActionOverride, onMouseEnter, onMouseLeave, + customLoadTracks, } ) => { const { isRegistered, isUserConnected } = useMyJetpackConnection(); const { recordEvent } = useAnalytics(); @@ -142,6 +144,7 @@ const ConnectedProductCard: FC< ConnectedProductCardProps > = ( { upgradeInInterstitial={ upgradeInInterstitial } onMouseEnter={ onMouseEnter } onMouseLeave={ onMouseLeave } + customLoadTracks={ customLoadTracks } > { children } diff --git a/projects/packages/my-jetpack/_inc/components/connection-screen/connect.png b/projects/packages/my-jetpack/_inc/components/connection-screen/connect.png index 66f8710ac0634..4779757259f45 100644 Binary files a/projects/packages/my-jetpack/_inc/components/connection-screen/connect.png and b/projects/packages/my-jetpack/_inc/components/connection-screen/connect.png differ diff --git a/projects/packages/my-jetpack/_inc/components/connections-section/index.jsx b/projects/packages/my-jetpack/_inc/components/connections-section/index.jsx index 126d2f5977c60..ffb1da1e64cd9 100644 --- a/projects/packages/my-jetpack/_inc/components/connections-section/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/connections-section/index.jsx @@ -8,7 +8,7 @@ import ConnectionStatusCard from '../connection-status-card'; /** * Plan section component. * - * @returns {object} ConnectionsSection React component. + * @return {object} ConnectionsSection React component. */ export default function ConnectionsSection() { const { apiRoot, apiNonce, topJetpackMenuItemUrl, connectedPlugins } = useMyJetpackConnection(); diff --git a/projects/packages/my-jetpack/_inc/components/go-back-link/index.js b/projects/packages/my-jetpack/_inc/components/go-back-link/index.js index 3eb499905798e..ee97389628066 100644 --- a/projects/packages/my-jetpack/_inc/components/go-back-link/index.js +++ b/projects/packages/my-jetpack/_inc/components/go-back-link/index.js @@ -7,10 +7,10 @@ import styles from './styles.module.scss'; /** * Simple component that renders a go back link * - * @param {object} props - Component props. + * @param {object} props - Component props. * @param {Function} props.onClick - A callback to execute on click - * @param {boolean} props.reload - Whether to reload the page after going back - * @returns {object} GoBackLink component. + * @param {boolean} props.reload - Whether to reload the page after going back + * @return {object} GoBackLink component. */ function GoBackLink( { onClick = () => {}, reload } ) { const to = reload ? '/?reload=true' : '/'; diff --git a/projects/packages/my-jetpack/_inc/components/golden-token/tooltip/index.jsx b/projects/packages/my-jetpack/_inc/components/golden-token/tooltip/index.jsx index 88c844ff0a174..fc8d06fa816e1 100644 --- a/projects/packages/my-jetpack/_inc/components/golden-token/tooltip/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/golden-token/tooltip/index.jsx @@ -14,10 +14,10 @@ import './style.global.scss'; * We created this one because is (at the time of writing) * hardcoded to only support Grid icons, and we're on a rather tight deadline. * - * @param {object} props - Component properties. + * @param {object} props - Component properties. * @param {string} props.productName - A product/plan name. - * @param {string} props.giftedDate - The date the product/plan was gifted. - * @returns {object} - A Golden Token Tooltip. + * @param {string} props.giftedDate - The date the product/plan was gifted. + * @return {object} - A Golden Token Tooltip. */ export function GoldenTokenTooltip( { productName, giftedDate } ) { const [ isVisible, setIsVisible ] = useState( false ); diff --git a/projects/packages/my-jetpack/_inc/components/idc-modal/index.js b/projects/packages/my-jetpack/_inc/components/idc-modal/index.js index 3424afa186288..75f61158b362c 100644 --- a/projects/packages/my-jetpack/_inc/components/idc-modal/index.js +++ b/projects/packages/my-jetpack/_inc/components/idc-modal/index.js @@ -5,7 +5,7 @@ import styles from './styles.module.scss'; /** * Wrapper for the IDC Screen to display it in a modal. * - * @returns {React.Component|null} The IDC Screen modal component. + * @return {React.Component|null} The IDC Screen modal component. */ function IDCModal() { const [ isOpen, setOpen ] = useState( true ); @@ -16,7 +16,7 @@ function IDCModal() { return null; } - if ( ! window.hasOwnProperty( 'JP_IDENTITY_CRISIS__INITIAL_STATE' ) ) { + if ( ! Object.hasOwn( window, 'JP_IDENTITY_CRISIS__INITIAL_STATE' ) ) { return null; } diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/info-tooltip/index.tsx b/projects/packages/my-jetpack/_inc/components/info-tooltip/index.tsx similarity index 91% rename from projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/info-tooltip/index.tsx rename to projects/packages/my-jetpack/_inc/components/info-tooltip/index.tsx index 27762e6871491..7f85c29b646ac 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/info-tooltip/index.tsx +++ b/projects/packages/my-jetpack/_inc/components/info-tooltip/index.tsx @@ -2,21 +2,23 @@ import { Gridicon } from '@automattic/jetpack-components'; import { Popover } from '@wordpress/components'; import { useViewportMatch } from '@wordpress/compose'; import { useState, useCallback, useRef } from 'react'; -import useAnalytics from '../../../../hooks/use-analytics'; +import useAnalytics from '../../hooks/use-analytics'; import type { FC, ReactNode } from 'react'; import './style.scss'; type Props = { children: ReactNode; + className?: string; icon?: string; iconSize?: number; tracksEventName?: string; - tracksEventProps?: { [ key: string ]: string | boolean | number }; + tracksEventProps?: Record< Lowercase< string >, unknown >; }; export const InfoTooltip: FC< Props > = ( { children, + className, icon = 'info-outline', iconSize = 14, tracksEventName, @@ -33,7 +35,6 @@ export const InfoTooltip: FC< Props > = ( { if ( ! prevState === true && tracksEventName ) { recordEvent( `jetpack_${ tracksEventName }`, { page: 'my-jetpack', - feature: 'jetpack-protect', ...tracksEventProps, } ); } @@ -51,7 +52,7 @@ export const InfoTooltip: FC< Props > = ( { }, [ setIsPopoverVisible, useTooltipRef ] ); return ( - + diff --git a/projects/packages/my-jetpack/_inc/components/info-tooltip/style.scss b/projects/packages/my-jetpack/_inc/components/info-tooltip/style.scss new file mode 100644 index 0000000000000..d1967ccb7ff50 --- /dev/null +++ b/projects/packages/my-jetpack/_inc/components/info-tooltip/style.scss @@ -0,0 +1,38 @@ +.info-tooltip__button { + display: flex; + align-items: center; + background: transparent; + border: none; + color: var(--jp-gray-50); + padding: 2px; + cursor: pointer; + svg { + margin: 0 auto; + } +} + +.info-tooltip__content { + h3 { + font-size: var(--font-title-small); + line-height: calc(var(--font-title-small) + 6px);; + color: var(--jp-black); + margin: 0 0 calc(var(--spacing-base) * 2); + font-weight: 500; + } + + p { + font-size: var(--font-body); + line-height: var(--font-title-small); + color: var(--jp-gray-70); + + margin-bottom: 0; + + a { + color: var(--jp-black); + text-decoration: underline; + } + a:hover, a:focus { + text-decoration: none; + } + } +} diff --git a/projects/packages/my-jetpack/_inc/components/jetpack-manage-banner/index.jsx b/projects/packages/my-jetpack/_inc/components/jetpack-manage-banner/index.jsx index ea79f689ae88c..c3d0c519ac04b 100644 --- a/projects/packages/my-jetpack/_inc/components/jetpack-manage-banner/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/jetpack-manage-banner/index.jsx @@ -7,9 +7,9 @@ import jetpackManageIcon from './jetpack-manage.svg'; /** * Jetpack Manager Banner component that renders a banner with CTAs. * - * @param {object} props - Component props. + * @param {object} props - Component props. * @param {boolean} props.isAgencyAccount - Whether users account is an Agency account or not. - * @returns {object} The JetpackManageBanner component. + * @return {object} The JetpackManageBanner component. */ const JetpackManageBanner = props => { // eslint-disable-next-line no-unused-vars diff --git a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx index b5cce5aa05b65..7885e276023cb 100644 --- a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx @@ -74,7 +74,7 @@ const GlobalNotice = ( { message, title, options } ) => { /** * The My Jetpack App Main Screen. * - * @returns {object} The MyJetpackScreen component. + * @return {object} The MyJetpackScreen component. */ export default function MyJetpackScreen() { useExperiment( 'explat_test_jetpack_implementation_aa_test' ); diff --git a/projects/packages/my-jetpack/_inc/components/plans-section/index.jsx b/projects/packages/my-jetpack/_inc/components/plans-section/index.jsx index 8b5b2fa9767bd..24bc2d495aaa5 100644 --- a/projects/packages/my-jetpack/_inc/components/plans-section/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/plans-section/index.jsx @@ -19,7 +19,7 @@ import styles from './style.module.scss'; * * @param {object} props - Component props. * @param {object} props.purchase - Purchase object. - * @returns {object} PlanSection react component. + * @return {object} PlanSection react component. */ function PlanSection( { purchase = {} } ) { const { product_name } = purchase; @@ -34,12 +34,12 @@ function PlanSection( { purchase = {} } ) { /** * Plan expiry component. * - * @param {object} purchase - WPCOM purchase object. - * @param {string} purchase.product_name - A product name. + * @param {object} purchase - WPCOM purchase object. + * @param {string} purchase.product_name - A product name. * @param {string} purchase.subscribed_date - A subscribed date. - * @param {string} purchase.expiry_message - An expiry message. - * @param {string} purchase.partner_slug - A partner that issued the purchase. - * @returns {object} - A plan expiry component. + * @param {string} purchase.expiry_message - An expiry message. + * @param {string} purchase.partner_slug - A partner that issued the purchase. + * @return {object} - A plan expiry component. */ function PlanExpiry( purchase ) { const { expiry_message, product_name, subscribed_date } = purchase; @@ -67,7 +67,7 @@ function PlanExpiry( purchase ) { * * @param {object} props - Component props. * @param {number} props.numberOfPurchases - Count of purchases in purchases array. - * @returns {object} PlanSectionHeader react component. + * @return {object} PlanSectionHeader react component. */ function PlanSectionHeader( { numberOfPurchases = 0 } ) { return ( @@ -85,7 +85,7 @@ function PlanSectionHeader( { numberOfPurchases = 0 } ) { * * @param {object} props - Component props. * @param {number} props.numberOfPurchases - Count of purchases in purchases array. - * @returns {object} PlanSectionFooter react component. + * @return {object} PlanSectionFooter react component. */ function PlanSectionFooter( { numberOfPurchases } ) { const { recordEvent } = useAnalytics(); @@ -160,7 +160,7 @@ function PlanSectionFooter( { numberOfPurchases } ) { /** * Plan section component. * - * @returns {object} PlansSection React component. + * @return {object} PlansSection React component. */ export default function PlansSection() { const userIsAdmin = !! getMyJetpackWindowInitialState( 'userIsAdmin' ); diff --git a/projects/packages/my-jetpack/_inc/components/product-card/index.tsx b/projects/packages/my-jetpack/_inc/components/product-card/index.tsx index 48921438620e1..fbf034bbe6d5f 100644 --- a/projects/packages/my-jetpack/_inc/components/product-card/index.tsx +++ b/projects/packages/my-jetpack/_inc/components/product-card/index.tsx @@ -36,6 +36,7 @@ export type ProductCardProps = { status: ProductStatus; onMouseEnter?: MouseEventHandler< HTMLButtonElement >; onMouseLeave?: MouseEventHandler< HTMLButtonElement >; + customLoadTracks?: Record< Lowercase< string >, unknown >; }; // ProductCard component @@ -63,6 +64,7 @@ const ProductCard: FC< ProductCardProps > = props => { onMouseEnter, onMouseLeave, recommendation, + customLoadTracks, } = props; const { ownedProducts } = getMyJetpackWindowInitialState( 'lifecycleStats' ); @@ -147,8 +149,9 @@ const ProductCard: FC< ProductCardProps > = props => { recordEvent( 'jetpack_myjetpack_product_card_load', { product: slug, status: status, + ...customLoadTracks, } ); - }, [ recordEvent, slug, status ] ); + }, [ recordEvent, slug, status, customLoadTracks ] ); return ( { +const BoostSpeedScore: BoostSpeedScoreType = () => { const { recordEvent } = useAnalytics(); const [ isLoading, setIsLoading ] = useState( false ); const [ speedLetterGrade, setSpeedLetterGrade ] = useState( '' ); const [ currentSpeedScore, setCurrentSpeedScore ] = useState< number | null >( null ); const [ previousSpeedScore, setPreviousSpeedScore ] = useState< number | null >( null ); const [ isSpeedScoreError, setIsSpeedScoreError ] = useState( false ); + const [ shouldShowTooltip, setShouldShowTooltip ] = useState( false ); const [ hasTooltipBeenViewed, setHasTooltipBeenViewed ] = useState( false ); const isMobileViewport: boolean = useViewportMatch( 'medium', '<' ); @@ -116,6 +117,14 @@ const BoostSpeedScore: BoostSpeedScoreType = ( { shouldShowTooltip } ) => { const tooltipCopy = useBoostTooltipCopy( { speedLetterGrade, boostScoreIncrease } ); + const handleEnter = useCallback( () => { + setShouldShowTooltip( true ); + }, [ setShouldShowTooltip ] ); + + const handleOut = useCallback( () => { + setShouldShowTooltip( false ); + }, [ setShouldShowTooltip ] ); + useEffect( () => { if ( latestBoostSpeedScores ) { if ( isBoostActive ) { @@ -152,7 +161,15 @@ const BoostSpeedScore: BoostSpeedScoreType = ( { shouldShowTooltip } ) => { return ( ! isSpeedScoreError && ( -
      +
      { isLoading ? ( ) : ( @@ -161,7 +178,7 @@ const BoostSpeedScore: BoostSpeedScoreType = ( { shouldShowTooltip } ) => { { __( 'Your website’s overall speed score:', 'jetpack-my-jetpack' ) } { speedLetterGrade } - { shouldShowTooltip && ( + { ! isLoading && shouldShowTooltip && ( { - const [ shouldShowTooltip, setShouldShowTooltip ] = useState( false ); // Override the primary action button to read "Boost your site" instead // of the default text, "Lern more". const primaryActionOverride = { @@ -16,23 +14,13 @@ const BoostCard: ProductCardComponent = props => { }, }; - const handleMouseEnter = useCallback( () => { - setShouldShowTooltip( true ); - }, [ setShouldShowTooltip ] ); - - const handleMouseLeave = useCallback( () => { - setShouldShowTooltip( false ); - }, [ setShouldShowTooltip ] ); - return ( - + ); }; diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/boost-card/style.scss b/projects/packages/my-jetpack/_inc/components/product-cards-section/boost-card/style.scss index 5eaf64bd43331..ed703efb0c1de 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/boost-card/style.scss +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/boost-card/style.scss @@ -3,6 +3,13 @@ $bar_height: 24px; $border_radius: math.div($bar-height, 2); +.mj-boost-speed-score { + // Increase the area to trigger the hover. + padding: calc( var( --spacing-base ) ); // 8px; + margin: calc( var( --spacing-base ) * -1 ); + margin-bottom: 0; +} + .mj-boost-speed-score__grade { font-size: var(--font-body-small); line-height: $bar_height; diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/boost-card/use-boost-tooltip-copy.ts b/projects/packages/my-jetpack/_inc/components/product-cards-section/boost-card/use-boost-tooltip-copy.ts index d96222a33b3df..5c06b4fa1d0aa 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/boost-card/use-boost-tooltip-copy.ts +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/boost-card/use-boost-tooltip-copy.ts @@ -5,10 +5,10 @@ import type { ReactElement } from 'react'; /** * Gets the translated tooltip copy based on the Boost letter grade and other factors. * - * @param {object} props - React props - * @param {string} props.speedLetterGrade - The Boost score letter grade. + * @param {object} props - React props + * @param {string} props.speedLetterGrade - The Boost score letter grade. * @param {number|null} props.boostScoreIncrease - The number of points the score increased. - * @returns {ReactElement | string} A translated JSX Element or string. + * @return {ReactElement | string} A translated JSX Element or string. */ export function useBoostTooltipCopy( { speedLetterGrade, diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/auto-firewall-status.tsx b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/auto-firewall-status.tsx index b12d721233324..5ab7c3638f187 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/auto-firewall-status.tsx +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/auto-firewall-status.tsx @@ -1,11 +1,13 @@ import { __ } from '@wordpress/i18n'; +import clsx from 'clsx'; import useProduct from '../../../data/products/use-product'; import { getMyJetpackWindowInitialState } from '../../../data/utils/get-my-jetpack-window-state'; import useMyJetpackConnection from '../../../hooks/use-my-jetpack-connection'; +import { InfoTooltip } from '../../info-tooltip'; +import baseStyles from '../style.module.scss'; import ShieldInactive from './assets/shield-inactive.svg'; import ShieldOff from './assets/shield-off.svg'; import ShieldSuccess from './assets/shield-success.svg'; -import { InfoTooltip } from './info-tooltip'; import { useProtectTooltipCopy } from './use-protect-tooltip-copy'; import type { ReactElement, PropsWithChildren } from 'react'; @@ -33,10 +35,10 @@ export const AutoFirewallStatus = () => { /** * WafStatus component * - * @param {PropsWithChildren} props - The component props + * @param {PropsWithChildren} props - The component props * @param {'active' | 'inactive' | 'off'} props.status - The status of the WAF * - * @returns {ReactElement} rendered component + * @return {ReactElement} rendered component */ function WafStatus( { status }: { status: 'active' | 'inactive' | 'off' } ) { const slug = 'protect'; @@ -48,54 +50,72 @@ function WafStatus( { status }: { status: 'active' | 'inactive' | 'off' } ) { if ( status === 'active' ) { return ( <> -
      - { +
      + { __( 'Auto-Firewall', 'jetpack-my-jetpack' ) } +
      +
      +
      + { +
      +
      { __( 'On', 'jetpack-my-jetpack' ) }
      -
      { __( 'On', 'jetpack-my-jetpack' ) }
      ); } if ( status === 'inactive' ) { return ( <> -
      - { +
      + { __( 'Auto-Firewall', 'jetpack-my-jetpack' ) } + + <> +

      { autoFirewallTooltip.title }

      +

      { autoFirewallTooltip.text }

      + +
      +
      +
      +
      + { +
      +
      + { __( 'Inactive', 'jetpack-my-jetpack' ) } +
      -
      { __( 'Inactive', 'jetpack-my-jetpack' ) }
      - - <> -

      { autoFirewallTooltip.title }

      -

      { autoFirewallTooltip.text }

      - -
      ); } return ( <> -
      - { +
      + { __( 'Auto-Firewall', 'jetpack-my-jetpack' ) } +
      +
      +
      + { +
      +
      { __( 'Off', 'jetpack-my-jetpack' ) }
      -
      { __( 'Off', 'jetpack-my-jetpack' ) }
      ); } diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/info-tooltip/style.scss b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/info-tooltip/style.scss deleted file mode 100644 index a39f6451f89ff..0000000000000 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/info-tooltip/style.scss +++ /dev/null @@ -1,12 +0,0 @@ -.info-tooltip__button { - display: flex; - align-items: center; - background: transparent; - border: none; - color: var(--jp-gray-50); - padding: 2px; - cursor: pointer; - svg { - margin: 0 auto; - } -} diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/logins-blocked-status.tsx b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/logins-blocked-status.tsx index 4459b3df94736..62af60d35f2bd 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/logins-blocked-status.tsx +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/logins-blocked-status.tsx @@ -1,11 +1,14 @@ import { __ } from '@wordpress/i18n'; +import clsx from 'clsx'; import useProduct from '../../../data/products/use-product'; import { getMyJetpackWindowInitialState } from '../../../data/utils/get-my-jetpack-window-state'; import useMyJetpackConnection from '../../../hooks/use-my-jetpack-connection'; +import numberFormat from '../../../utils/format-number'; import { isJetpackPluginActive } from '../../../utils/is-jetpack-plugin-active'; +import { InfoTooltip } from '../../info-tooltip'; +import baseStyles from '../style.module.scss'; import ShieldOff from './assets/shield-off.svg'; import ShieldPartial from './assets/shield-partial.svg'; -import { InfoTooltip } from './info-tooltip'; import { useProtectTooltipCopy } from './use-protect-tooltip-copy'; import type { ReactElement, PropsWithChildren } from 'react'; @@ -40,10 +43,10 @@ export const LoginsBlockedStatus = () => { /** * BlockedStatus component * - * @param {PropsWithChildren} props - The component props + * @param {PropsWithChildren} props - The component props * @param {'active' | 'inactive' | 'off'} props.status - The status of Brute Force Protection * - * @returns {ReactElement} rendered component + * @return {ReactElement} rendered component */ function BlockedStatus( { status }: { status: 'active' | 'inactive' | 'off' } ) { const { @@ -56,40 +59,83 @@ function BlockedStatus( { status }: { status: 'active' | 'inactive' | 'off' } ) if ( status === 'active' ) { return blockedLoginsCount > 0 ? ( -
      { blockedLoginsCount }
      + <> +
      + { __( 'Logins Blocked', 'jetpack-my-jetpack' ) } +
      +
      +
      { numberFormat( blockedLoginsCount ) }
      +
      + ) : ( <> -
      - { +
      + { __( 'Logins Blocked', 'jetpack-my-jetpack' ) } + + <> +

      { blockedLoginsTooltip.title }

      +

      { blockedLoginsTooltip.text }

      + +
      +
      +
      +
      + { +
      - - <> -

      { blockedLoginsTooltip.title }

      -

      { blockedLoginsTooltip.text }

      - -
      ); } if ( status === 'inactive' ) { return ( <> - { blockedLoginsCount > 0 ? ( - <> +
      + { __( 'Logins Blocked', 'jetpack-my-jetpack' ) } + + <> +

      { blockedLoginsTooltip.title }

      +

      { blockedLoginsTooltip.text }

      + +
      +
      +
      + { blockedLoginsCount > 0 ? ( + <> +
      + { +
      +
      { numberFormat( blockedLoginsCount ) }
      + + ) : (
      -
      { blockedLoginsCount }
      - - ) : ( -
      - { -
      - ) } - - <> -

      { blockedLoginsTooltip.title }

      -

      { blockedLoginsTooltip.text }

      - -
      + ) } +
      ); } return ( <> -
      - { +
      + { __( 'Logins Blocked', 'jetpack-my-jetpack' ) } +
      +
      +
      + { +
      +
      { __( 'Off', 'jetpack-my-jetpack' ) }
      -
      { __( 'Off', 'jetpack-my-jetpack' ) }
      ); } diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/protect-value-section.tsx b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/protect-value-section.tsx index 3c28925fed95c..015cce91ea44f 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/protect-value-section.tsx +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/protect-value-section.tsx @@ -1,7 +1,6 @@ import useProduct from '../../../data/products/use-product'; -import baseStyles from '../style.module.scss'; +import { InfoTooltip } from '../../info-tooltip'; import { AutoFirewallStatus } from './auto-firewall-status'; -import { InfoTooltip } from './info-tooltip'; import { LoginsBlockedStatus } from './logins-blocked-status'; import { ScanAndThreatStatus } from './scan-threats-status'; import { useLastScanText } from './use-last-scan-text'; @@ -26,12 +25,13 @@ const ProtectValueSection = () => { tracksEventName={ 'protect_card_tooltip_open' } tracksEventProps={ { location: 'plugins&themes', + feature: 'jetpack-protect', status: 'inactive', } } > <> -

      { pluginsThemesTooltip.title }

      -

      { pluginsThemesTooltip.text }

      +

      { pluginsThemesTooltip.title }

      +

      { pluginsThemesTooltip.text }

      ) } @@ -41,16 +41,10 @@ const ProtectValueSection = () => {
      -
      Auto-Firewall
      -
      - -
      +
      -
      Logins Blocked
      -
      - -
      +
      diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/scan-threats-status.tsx b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/scan-threats-status.tsx index bfb8757df2d1f..5165dfc611699 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/scan-threats-status.tsx +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/scan-threats-status.tsx @@ -2,16 +2,17 @@ import { Gridicon } from '@automattic/jetpack-components'; import { Popover } from '@wordpress/components'; import { useViewportMatch } from '@wordpress/compose'; import { __ } from '@wordpress/i18n'; +import clsx from 'clsx'; import { useMemo, useState, useCallback, useRef } from 'react'; import useProduct from '../../../data/products/use-product'; import { getMyJetpackWindowInitialState } from '../../../data/utils/get-my-jetpack-window-state'; import useAnalytics from '../../../hooks/use-analytics'; import useMyJetpackConnection from '../../../hooks/use-my-jetpack-connection'; +import { InfoTooltip } from '../../info-tooltip'; import baseStyles from '../style.module.scss'; import ShieldOff from './assets/shield-off.svg'; import ShieldPartial from './assets/shield-partial.svg'; import ShieldSuccess from './assets/shield-success.svg'; -import { InfoTooltip } from './info-tooltip'; import { useProtectTooltipCopy } from './use-protect-tooltip-copy'; import type { PropsWithChildren, ReactElement } from 'react'; @@ -68,11 +69,11 @@ export const ScanAndThreatStatus = () => { /** * ThreatStatus component * - * @param {PropsWithChildren} props - The component props - * @param {number} props.numThreats - The number of threats - * @param {number} props.criticalThreatCount - The number of critical threats + * @param {PropsWithChildren} props - The component props + * @param {number} props.numThreats - The number of threats + * @param {number} props.criticalThreatCount - The number of critical threats * - * @returns {ReactElement} rendered component + * @return {ReactElement} rendered component */ function ThreatStatus( { numThreats, @@ -116,36 +117,36 @@ function ThreatStatus( { if ( criticalThreatCount ) { return ( <> -
      +
      { __( 'Threats', 'jetpack-my-jetpack' ) } +
      + + { isPopoverVisible && ( + + <> +

      { scanThreatsTooltip.title }

      +

      { scanThreatsTooltip.text }

      + +
      + ) } +
      { numThreats }
      -
      - - { isPopoverVisible && ( - - <> -

      { scanThreatsTooltip.title }

      -

      { scanThreatsTooltip.text }

      - -
      - ) } -
      @@ -167,10 +168,10 @@ function ThreatStatus( { /** * ScanStatus component * - * @param {PropsWithChildren} props - The component props + * @param {PropsWithChildren} props - The component props * @param {'success' | 'partial' | 'off'} props.status - The number of threats * - * @returns { ReactElement} rendered component + * @return { ReactElement} rendered component */ function ScanStatus( { status }: { status: 'success' | 'partial' | 'off' } ) { const tooltipContent = useProtectTooltipCopy(); @@ -198,35 +199,36 @@ function ScanStatus( { status }: { status: 'success' | 'partial' | 'off' } ) { if ( status === 'partial' ) { return ( <> -
      +
      { __( 'Scan', 'jetpack-my-jetpack' ) } -
      -
      -
      - { -
      -
      - { __( 'Partial', 'jetpack-my-jetpack' ) } -
      <> -

      { scanThreatsTooltip.title }

      -

      { scanThreatsTooltip.text }

      +

      { scanThreatsTooltip.title }

      +

      { scanThreatsTooltip.text }

      +
      +
      + { +
      +
      + { __( 'Partial', 'jetpack-my-jetpack' ) } +
      +
      ); } diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/style.scss b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/style.scss index fdb895e08607f..77bb791e18b45 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/style.scss +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/style.scss @@ -9,6 +9,12 @@ align-items: flex-start; } + &__heading { + display: flex; + align-items: center; + text-wrap: nowrap; + } + &__last-scan { display: flex; align-items: center; @@ -32,27 +38,6 @@ } } - &__tooltip-heading { - font-size: var(--font-title-small); - line-height: calc(var(--font-title-small) + 6px);; - color: var(--jp-black); - margin: 0 0 calc(var(--spacing-base) * 2); - font-weight: 500; - } - - &__tooltip-content { - font-size: var(--font-body); - line-height: var(--font-title-small); - color: var(--jp-gray-70); - a { - color: var(--jp-black); - text-decoration: underline; - } - a:hover, a:focus { - text-decoration: none; - } - } - &__data { display: flex; align-items: center; @@ -105,7 +90,7 @@ .logins_blocked { &__count { - font-size: calc(var(--font-title-large) - 4px); + font-size: calc(var(--font-headline-small) - 4px); line-height: var(--font-title-large); font-weight: 400; color: var(--jp-black); diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/use-protect-tooltip-copy.ts b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/use-protect-tooltip-copy.ts index 4459d36c006b7..6f95e251ea099 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/use-protect-tooltip-copy.ts +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/protect-card/use-protect-tooltip-copy.ts @@ -1,6 +1,7 @@ import { createInterpolateElement } from '@wordpress/element'; import { __, _n, sprintf } from '@wordpress/i18n'; import { useCallback, useMemo, createElement, type ReactElement } from 'react'; +import { PRODUCT_SLUGS } from '../../../data/constants'; import useProduct from '../../../data/products/use-product'; import { getMyJetpackWindowInitialState } from '../../../data/utils/get-my-jetpack-window-state'; import useAnalytics from '../../../hooks/use-analytics'; @@ -21,10 +22,10 @@ export type TooltipContent = { /** * Gets the translated tooltip copy based on Protect Scan details. * - * @returns {TooltipContent} An object containing each tooltip's title and text content. + * @return {TooltipContent} An object containing each tooltip's title and text content. */ export function useProtectTooltipCopy(): TooltipContent { - const slug = 'protect'; + const slug = PRODUCT_SLUGS.PROTECT; const { detail } = useProduct( slug ); const { isPluginActive: isProtectPluginActive, hasPaidPlanForProduct: hasProtectPaidPlan } = detail || {}; diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/index.tsx b/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/index.tsx index d72242a16bb10..0dc77f17fc021 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/index.tsx +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/index.tsx @@ -8,6 +8,8 @@ import { PRODUCT_SLUGS } from '../../../data/constants'; import useProduct from '../../../data/products/use-product'; import { getMyJetpackWindowInitialState } from '../../../data/utils/get-my-jetpack-window-state'; import ProductCard from '../../connected-product-card'; +import { InfoTooltip } from '../../info-tooltip'; +import useTooltipCopy from './use-tooltip-copy'; import useVideoPressCardDescription from './use-videopress-description'; import VideoPressValueSection from './videopress-value-section'; import type { ProductCardComponent } from '../types'; @@ -20,29 +22,59 @@ const VideopressCard: ProductCardComponent = ( { admin } ) => { const { detail } = useProduct( slug ); const { status } = detail || {}; const { videopress: data } = getMyJetpackWindowInitialState(); + const { activeAndNoVideos } = useTooltipCopy(); + const { videoCount = 0, featuredStats } = data || {}; const isPluginActive = status === PRODUCT_STATUSES.ACTIVE || status === PRODUCT_STATUSES.CAN_UPGRADE; const descriptionText = useVideoPressCardDescription( { isPluginActive, - videoCount: data.videoCount, + videoCount, } ); + const customLoadTracks = { + stats_period: featuredStats?.period, + video_count: videoCount, + }; + const Description = useCallback( () => { return ( - { descriptionText } + { descriptionText || detail.description } + { isPluginActive && ! videoCount && ( + +

      { activeAndNoVideos.title }

      +

      { activeAndNoVideos.text }

      +
      + ) }
      ); - }, [ descriptionText ] ); + }, [ + descriptionText, + detail.description, + videoCount, + status, + activeAndNoVideos, + isPluginActive, + ] ); return ( diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/style.scss b/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/style.scss index fdfae61d3c875..28d77f8124bbb 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/style.scss +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/style.scss @@ -1,9 +1,15 @@ .videopress-card__video-count { + display: flex; + font-size: calc( var( --font-headline-small ) - 4px ); color: var( --jp-gray-90 ); line-height: 1.125; margin-top: calc( var( --spacing-base ) / 2 ); + + .videopress-card__tooltip { + height: 18px; + } } p.description { @@ -14,18 +20,60 @@ p.description { .videopress-card__value-section { display: flex; + gap: 0.75rem; + justify-content: space-between; &__container { display: flex; flex-direction: column; align-items: flex-start; + } - width: 50%; + &__value-container { + display: flex; + align-items: flex-end; + flex-wrap: wrap; } &__value { font-size: calc( var( --font-headline-small ) - 4px ); color: var( --jp-gray-90 ); - line-height: 1.125; + line-height: 1; + } + + &__previous-value { + display: flex; + align-items: center; + + font-size: var( --font-body-extra-small ); + line-height: 18px; + font-weight: 600; + } + + &__previous-value.increase { + * { + color: var( --jp-green-50 ); + fill: var( --jp-green-50 ); + } + } + + &__previous-value.decrease { + * { + color: var( --jp-red-50 ); + fill: var( --jp-red-50 ); + } + } + + &__heading { + display: flex; + align-items: center; + text-wrap: nowrap; + } +} + +.videopress-card__no-video-tooltip { + .info-tooltip__button { + display: inline; + vertical-align: middle; } } \ No newline at end of file diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/use-tooltip-copy.ts b/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/use-tooltip-copy.ts new file mode 100644 index 0000000000000..c8996a6e5cd73 --- /dev/null +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/use-tooltip-copy.ts @@ -0,0 +1,101 @@ +import { getRedirectUrl } from '@automattic/jetpack-components'; +import { createInterpolateElement } from '@wordpress/element'; +import { __, _n, sprintf } from '@wordpress/i18n'; +import { createElement, useCallback } from 'react'; +import { getMyJetpackWindowInitialState } from '../../../data/utils/get-my-jetpack-window-state'; +import useAnalytics from '../../../hooks/use-analytics'; + +const useTooltipCopy = () => { + const { recordEvent } = useAnalytics(); + const { videopress: data } = getMyJetpackWindowInitialState(); + const { featuredStats, videoCount } = data || {}; + const { period } = featuredStats || {}; + const hostingRedirectLink = getRedirectUrl( 'jetpack-videopress-my-jetpack-tooltip' ); + + const recordHostingLinkClick = useCallback( () => { + recordEvent( 'jetpack_videopress_card_tooltip_content_link_click', { + location: 'video_count', + feature: 'jetpack-videopress', + page: 'my-jetpack', + path: hostingRedirectLink, + } ); + }, [ recordEvent, hostingRedirectLink ] ); + + const inactiveWithVideos = { + title: __( 'The finest video for WordPress', 'jetpack-my-jetpack' ), + text: createInterpolateElement( + sprintf( + // translators: %d is the number of videos in the Media Library that could benefit from VideoPress. + _n( + 'You have %d video in your Media Library that could benefit from VideoPress. Start hosting it today to unlock multiple benefits: enhanced quality add-free streaming, faster load times, customizable player controls.', + 'You have %d videos in your Media Library that could benefit from VideoPress. Start hosting them today to unlock multiple benefits: enhanced quality add-free streaming, faster load times, customizable player controls.', + videoCount, + 'jetpack-my-jetpack' + ), + videoCount + ), + { + a: createElement( 'a', { + href: hostingRedirectLink, + target: '_blank', + rel: 'noreferrer noopener', + onClick: recordHostingLinkClick, + } ), + } + ), + }; + + const activeAndNoVideos = { + title: __( 'The finest video for WordPress', 'jetpack-my-jetpack' ), + text: __( + 'Give your videos a boost! 🚀 Try hosting with VideoPress for superior quality and performance.', + 'jetpack-my-jetpack' + ), + }; + + const viewsWithoutPlan = { + title: __( 'High-quality video, wherever your audience is', 'jetpack-my-jetpack' ), + text: __( 'Success! 🌟 Your video is live and gathering views.', 'jetpack-my-jetpack' ), + }; + + const thirtyDayViews = __( '30-Day views', 'jetpack-my-jetpack' ); + const yearlyViews = __( 'Yearly views', 'jetpack-my-jetpack' ); + + const viewsWithPlanTextDay = __( + 'This metric shows your total video views over the past 30 days, compared to the previous 30 days.', + 'jetpack-my-jetpack' + ); + const viewsWithPlanTextYear = __( + 'This metric shows your total video views over the past year.', + 'jetpack-my-jetpack' + ); + + const viewsWithPlan = { + title: period === 'day' ? thirtyDayViews : yearlyViews, + text: period === 'day' ? viewsWithPlanTextDay : viewsWithPlanTextYear, + }; + + const watchTimeTextDay = __( + 'This metric shows your total video viewing time over the past 30 days, compared to the previous 30 days.', + 'jetpack-my-jetpack' + ); + const watchTimeTextYear = __( + 'This metric shows total video viewing time for the last year.', + 'jetpack-my-jetpack' + ); + + const watchTime = { + title: __( 'Total time watched', 'jetpack-my-jetpack' ), + text: period === 'day' ? watchTimeTextDay : watchTimeTextYear, + }; + + return { + inactiveWithVideos, + activeAndNoVideos, + viewsWithoutPlan, + viewsWithPlan, + watchTime, + }; +}; + +export default useTooltipCopy; diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/use-videopress-description.ts b/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/use-videopress-description.ts index db68010f1f8d9..799b62dae99f6 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/use-videopress-description.ts +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/use-videopress-description.ts @@ -12,7 +12,7 @@ const useVideoPressCardDescription = ( { }: useVideoPressCardDescriptionProps ) => { if ( ! isPluginActive && videoCount ) { return preventWidows( - __( 'Existing videos you could load faster without ads:', 'jetpack-my-jetpack' ) + __( 'Load your existing videos faster and without ads.', 'jetpack-my-jetpack' ) ); } diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/videopress-value-section.tsx b/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/videopress-value-section.tsx index 9402e60d7e04a..3d7181b222d6d 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/videopress-value-section.tsx +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/videopress-card/videopress-value-section.tsx @@ -1,18 +1,64 @@ import { __ } from '@wordpress/i18n'; +import { arrowUp, arrowDown, Icon } from '@wordpress/icons'; +import clsx from 'clsx'; +import { PRODUCT_SLUGS } from '../../../data/constants'; +import useProduct from '../../../data/products/use-product'; import formatNumber from '../../../utils/format-number'; import formatTime from '../../../utils/format-time'; +import { InfoTooltip } from '../../info-tooltip'; import baseStyles from '../style.module.scss'; +import useTooltipCopy from './use-tooltip-copy'; import type { FC } from 'react'; import './style.scss'; +type VideoPressWindowData = Window[ 'myJetpackInitialState' ][ 'videopress' ]; + interface VideoPressValueSectionProps { isPluginActive: boolean; - data: Window[ 'myJetpackInitialState' ][ 'videopress' ]; + data: VideoPressWindowData; +} + +interface ValueSectionProps { + value: number; + previousValue: number; + formattedValue: string; + formattedDifference: string; + period: VideoPressWindowData[ 'featuredStats' ][ 'period' ]; } +const ValueSection: FC< ValueSectionProps > = ( { + value, + previousValue, + formattedValue, + formattedDifference, + period, +} ) => { + const hasValueIncreased = value > previousValue; + return ( +
      + { formattedValue } + + { value !== previousValue && period === 'day' && ( +
      + + { formattedDifference } +
      + ) } +
      + ); +}; + const VideoPressValueSection: FC< VideoPressValueSectionProps > = ( { isPluginActive, data } ) => { + const { detail } = useProduct( PRODUCT_SLUGS.VIDEOPRESS ); + const { status, hasPaidPlanForProduct } = detail || {}; const { videoCount, featuredStats } = data || {}; + const { inactiveWithVideos, viewsWithoutPlan, viewsWithPlan, watchTime } = useTooltipCopy(); const shortenedNumberConfig: Intl.NumberFormatOptions = { maximumFractionDigits: 1, notation: 'compact', @@ -22,37 +68,129 @@ const VideoPressValueSection: FC< VideoPressValueSectionProps > = ( { isPluginAc return null; } + const tracksProps = { + feature: 'jetpack-videopress', + has_paid_plan: hasPaidPlanForProduct, + status, + }; + if ( ! isPluginActive ) { - return { videoCount }; + return ( +
      +
      + + { __( 'Existing videos', 'jetpack-my-jetpack' ) } + +

      { inactiveWithVideos.title }

      +

      { inactiveWithVideos.text }

      +
      +
      + { videoCount } +
      +
      + ); } const currentViews = featuredStats?.data?.views?.current; const currentWatchTime = featuredStats?.data?.watch_time?.current; + const previousViews = featuredStats?.data?.views?.previous; + const previousWatchTime = featuredStats?.data?.watch_time?.previous; + const period = featuredStats?.period; + + const viewsDifference = Math.abs( currentViews - previousViews ); + const watchTimeDifference = Math.abs( currentWatchTime - previousWatchTime ); if ( currentViews === undefined || currentWatchTime === undefined ) { return null; } + const thirtyDayViews = __( '30-Day views', 'jetpack-my-jetpack' ); + const yearlyViews = __( 'Yearly views', 'jetpack-my-jetpack' ); + return (
      - - { __( '30-Day views', 'jetpack-my-jetpack' ) } - + + { period === 'day' ? thirtyDayViews : yearlyViews } - - { formatNumber( currentViews, shortenedNumberConfig ) } + + { hasPaidPlanForProduct || currentViews === 0 ? ( + <> +

      { viewsWithPlan.title }

      +

      { viewsWithPlan.text }

      + + ) : ( + <> +

      { viewsWithoutPlan.title }

      +

      { viewsWithoutPlan.text }

      + + ) } +
      + +
      - + { __( 'Total time watched', 'jetpack-my-jetpack' ) } - - - { formatTime( currentWatchTime ) } + +

      { watchTime.title }

      +

      { watchTime.text }

      +
      + +
      ); diff --git a/projects/packages/my-jetpack/_inc/components/product-detail-card/index.jsx b/projects/packages/my-jetpack/_inc/components/product-detail-card/index.jsx index 9c26ea29d51b6..97156dabd0fb4 100644 --- a/projects/packages/my-jetpack/_inc/components/product-detail-card/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/product-detail-card/index.jsx @@ -28,7 +28,7 @@ import styles from './style.module.scss'; * @param {string} props.value - Product price * @param {string} props.currency - Product current code * @param {string} props.isOld - True when the product price is old - * @returns {object} Price react component. + * @return {object} Price react component. */ function Price( { value, currency, isOld } ) { if ( ! value || ! currency ) { @@ -57,19 +57,19 @@ function Price( { value, currency, isOld } ) { /** * Product Detail component. * - * @param {object} props - Component props. - * @param {string} props.slug - Product slug - * @param {Function} props.onClick - Callback for Call To Action button click - * @param {Function} props.trackButtonClick - Function to call for tracking clicks on Call To Action button - * @param {string} props.className - A className to be concat with default ones - * @param {boolean} props.preferProductName - Use product name instead of title - * @param {React.ReactNode} props.supportingInfo - Complementary links or support/legal text - * @param {string} [props.ctaButtonLabel] - The label for the Call To Action button - * @param {boolean} [props.hideTOS] - Whether to hide the Terms of Service text - * @param {number} [props.quantity] - The quantity of the product to purchase - * @param {boolean} [props.highlightLastFeature] - Whether to highlight the last feature of the list of features - * @param {boolean} [props.isFetching] - Whether the product is being fetched - * @returns {object} ProductDetailCard react component. + * @param {object} props - Component props. + * @param {string} props.slug - Product slug + * @param {Function} props.onClick - Callback for Call To Action button click + * @param {Function} props.trackButtonClick - Function to call for tracking clicks on Call To Action button + * @param {string} props.className - A className to be concat with default ones + * @param {boolean} props.preferProductName - Use product name instead of title + * @param {React.ReactNode} props.supportingInfo - Complementary links or support/legal text + * @param {string} [props.ctaButtonLabel] - The label for the Call To Action button + * @param {boolean} [props.hideTOS] - Whether to hide the Terms of Service text + * @param {number} [props.quantity] - The quantity of the product to purchase + * @param {boolean} [props.highlightLastFeature] - Whether to highlight the last feature of the list of features + * @param {boolean} [props.isFetching] - Whether the product is being fetched + * @return {object} ProductDetailCard react component. */ const ProductDetailCard = ( { slug, @@ -237,7 +237,7 @@ const ProductDetailCard = ( { * * @param {object} props - Component props. * @param {string} props.slug - Product icon slug - * @returns {object} Icon Product component. + * @return {object} Icon Product component. */ function ProductIcon( { slug: iconSlug } ) { const ProIcon = getIconBySlug( iconSlug ); diff --git a/projects/packages/my-jetpack/_inc/components/product-detail-card/stories/broken/utils.js b/projects/packages/my-jetpack/_inc/components/product-detail-card/stories/broken/utils.js index ddc04e81ed8ff..cb1429d50b8b1 100644 --- a/projects/packages/my-jetpack/_inc/components/product-detail-card/stories/broken/utils.js +++ b/projects/packages/my-jetpack/_inc/components/product-detail-card/stories/broken/utils.js @@ -26,7 +26,7 @@ const mapResponse = { * Helper function that returns the story mock data. * * @param {string} product - Product slug - * @returns {Array} Story mock data + * @return {Array} Story mock data */ export function getMockData( product ) { const isArray = product.constructor === Array; @@ -59,7 +59,7 @@ export function getMockData( product ) { /** * Return all product mocked data. * - * @returns {Array} All products mocked data. + * @return {Array} All products mocked data. */ export function getAllMockData() { return getMockData( [ ...Object.keys( mapResponse ) ] ); @@ -68,7 +68,7 @@ export function getAllMockData() { /** * Return product slugs list * - * @returns {Array} product slugs list. + * @return {Array} product slugs list. */ export function getProductSlugs() { return [ 'anti-spam', 'backup', 'boost', 'crm', 'extras', 'scan', 'search', 'videopress' ]; diff --git a/projects/packages/my-jetpack/_inc/components/product-detail-table/index.jsx b/projects/packages/my-jetpack/_inc/components/product-detail-table/index.jsx index 27e6dc6a8c66e..b637021725c0e 100644 --- a/projects/packages/my-jetpack/_inc/components/product-detail-table/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/product-detail-table/index.jsx @@ -29,7 +29,7 @@ import { useRedirectToReferrer } from '../../hooks/use-redirect-to-referrer'; * @param {string} props.tier - Product tier slug, i.e. 'free' or 'upgraded'. * @param {Function} props.trackProductButtonClick - Tracks click event for the product button. * @param {boolean} props.preferProductName - Whether to show the product name instead of the title. - * @returns {object} - ProductDetailTableColumn component. + * @return {object} - ProductDetailTableColumn component. */ const ProductDetailTableColumn = ( { cantInstallPlugin, @@ -235,7 +235,7 @@ ProductDetailTableColumn.propTypes = { * @param {Function} props.trackProductButtonClick - Tracks click event for the product button. * @param {boolean} props.isFetching - True if there is a pending request to load the product. * @param {boolean} props.preferProductName - Whether to show the product name instead of the title. - * @returns {object} - ProductDetailTable react component. + * @return {object} - ProductDetailTable react component. */ const ProductDetailTable = ( { slug, diff --git a/projects/packages/my-jetpack/_inc/components/product-detail-table/stories/broken/utils.js b/projects/packages/my-jetpack/_inc/components/product-detail-table/stories/broken/utils.js index cc3fc1c46fb15..46211eb0eb690 100644 --- a/projects/packages/my-jetpack/_inc/components/product-detail-table/stories/broken/utils.js +++ b/projects/packages/my-jetpack/_inc/components/product-detail-table/stories/broken/utils.js @@ -10,7 +10,7 @@ const mapResponse = { * Helper function that returns the story mock data. * * @param {string} product - Product slug - * @returns {Array} Story mock data + * @return {Array} Story mock data */ export function getMockData( product ) { const isArray = product.constructor === Array; @@ -43,7 +43,7 @@ export function getMockData( product ) { /** * Return all product mocked data. * - * @returns {Array} All products mocked data. + * @return {Array} All products mocked data. */ export function getAllMockData() { return getMockData( [ ...Object.keys( mapResponse ) ] ); @@ -52,7 +52,7 @@ export function getAllMockData() { /** * Return product slugs list * - * @returns {Array} product slugs list. + * @return {Array} product slugs list. */ export function getProductSlugs() { return [ 'boost', 'protect', 'social' ]; diff --git a/projects/packages/my-jetpack/_inc/components/product-interstitial/boost.png b/projects/packages/my-jetpack/_inc/components/product-interstitial/boost.png index dd818e4664052..4e7cb0cec7511 100644 Binary files a/projects/packages/my-jetpack/_inc/components/product-interstitial/boost.png and b/projects/packages/my-jetpack/_inc/components/product-interstitial/boost.png differ diff --git a/projects/packages/my-jetpack/_inc/components/product-interstitial/crm.png b/projects/packages/my-jetpack/_inc/components/product-interstitial/crm.png index cfec3eed7beab..3984395b68047 100644 Binary files a/projects/packages/my-jetpack/_inc/components/product-interstitial/crm.png and b/projects/packages/my-jetpack/_inc/components/product-interstitial/crm.png differ diff --git a/projects/packages/my-jetpack/_inc/components/product-interstitial/extras.png b/projects/packages/my-jetpack/_inc/components/product-interstitial/extras.png index d4d49627137b5..934353751547e 100644 Binary files a/projects/packages/my-jetpack/_inc/components/product-interstitial/extras.png and b/projects/packages/my-jetpack/_inc/components/product-interstitial/extras.png differ diff --git a/projects/packages/my-jetpack/_inc/components/product-interstitial/index.jsx b/projects/packages/my-jetpack/_inc/components/product-interstitial/index.jsx index 3b11e52e1ee41..294b0a5838a71 100644 --- a/projects/packages/my-jetpack/_inc/components/product-interstitial/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/product-interstitial/index.jsx @@ -39,22 +39,22 @@ import videoPressImage from './videopress.png'; /** * Product Interstitial component. * - * @param {object} props - Component props. - * @param {string} props.slug - Product slug - * @param {string} props.bundle - Bundle including this product - * @param {object} props.children - Product additional content - * @param {string} props.existingLicenseKeyUrl - URL to enter an existing license key (e.g. Akismet) - * @param {boolean} props.installsPlugin - Whether the interstitial button installs a plugin* - * @param {React.ReactNode} props.supportingInfo - Complementary links or support/legal text - * @param {boolean} props.preferProductName - Use product name instead of title - * @param {string} props.imageContainerClassName - Append a class to the image container - * @param {string} [props.ctaButtonLabel] - The label for the Call To Action button - * @param {boolean} [props.hideTOS] - Whether to hide the Terms of Service text - * @param {number} [props.quantity] - The quantity of the product to purchase - * @param {number} [props.directCheckout] - Whether to go straight to the checkout page, e.g. for products with usage tiers - * @param {boolean} [props.highlightLastFeature] - Whether to highlight the last feature in the list of features - * @param {object} [props.ctaCallback] - Callback when the product CTA is clicked. Triggered before any activation/checkout process occurs - * @returns {object} ProductInterstitial react component. + * @param {object} props - Component props. + * @param {string} props.slug - Product slug + * @param {string} props.bundle - Bundle including this product + * @param {object} props.children - Product additional content + * @param {string} props.existingLicenseKeyUrl - URL to enter an existing license key (e.g. Akismet) + * @param {boolean} props.installsPlugin - Whether the interstitial button installs a plugin* + * @param {React.ReactNode} props.supportingInfo - Complementary links or support/legal text + * @param {boolean} props.preferProductName - Use product name instead of title + * @param {string} props.imageContainerClassName - Append a class to the image container + * @param {string} [props.ctaButtonLabel] - The label for the Call To Action button + * @param {boolean} [props.hideTOS] - Whether to hide the Terms of Service text + * @param {number} [props.quantity] - The quantity of the product to purchase + * @param {number} [props.directCheckout] - Whether to go straight to the checkout page, e.g. for products with usage tiers + * @param {boolean} [props.highlightLastFeature] - Whether to highlight the last feature in the list of features + * @param {object} [props.ctaCallback] - Callback when the product CTA is clicked. Triggered before any activation/checkout process occurs + * @return {object} ProductInterstitial react component. */ export default function ProductInterstitial( { bundle, @@ -131,10 +131,6 @@ export default function ProductInterstitial( { const clickHandler = useCallback( ( checkout, product, tier ) => { - let postCheckoutUrl = product?.postCheckoutUrl - ? product?.postCheckoutUrl - : myJetpackCheckoutUri; - ctaCallback?.( { slug, product, tier } ); if ( product?.isBundle || directCheckout ) { @@ -146,10 +142,8 @@ export default function ProductInterstitial( { activate( { productId: slug }, { - onSettled: ( { productId: activatedProduct } ) => { - postCheckoutUrl = activatedProduct?.post_checkout_url - ? activatedProduct.post_checkout_url - : myJetpackCheckoutUri; + onSettled: activatedProduct => { + const postCheckoutUrl = activatedProduct?.post_checkout_url || myJetpackCheckoutUri; // there is a separate hasRequiredTier, but it is not implemented const hasPaidPlanForProduct = product?.hasPaidPlanForProduct; const isFree = tier @@ -293,7 +287,7 @@ export default function ProductInterstitial( { /** * AntiSpamInterstitial component * - * @returns {object} AntiSpamInterstitial react component. + * @return {object} AntiSpamInterstitial react component. */ export function AntiSpamInterstitial() { const slug = 'anti-spam'; @@ -314,7 +308,7 @@ export function AntiSpamInterstitial() { /** * BackupInterstitial component * - * @returns {object} BackupInterstitial react component. + * @return {object} BackupInterstitial react component. */ export function BackupInterstitial() { return ; @@ -323,7 +317,7 @@ export function BackupInterstitial() { /** * BoostInterstitial component * - * @returns {object} BoostInterstitial react component. + * @return {object} BoostInterstitial react component. */ export function BoostInterstitial() { return ( @@ -336,7 +330,7 @@ export function BoostInterstitial() { /** * CreatorInterstitial component * - * @returns {object} CreatorInterstitial react component. + * @return {object} CreatorInterstitial react component. */ export function CreatorInterstitial() { return ; @@ -345,7 +339,7 @@ export function CreatorInterstitial() { /** * CRMInterstitial component * - * @returns {object} CRMInterstitial react component. + * @return {object} CRMInterstitial react component. */ export function CRMInterstitial() { return ( @@ -358,7 +352,7 @@ export function CRMInterstitial() { /** * ExtrasInterstitial component * - * @returns {object} ExtrasInterstitial react component. + * @return {object} ExtrasInterstitial react component. */ export function ExtrasInterstitial() { return ( @@ -371,14 +365,14 @@ export function ExtrasInterstitial() { /** * JetpackAiInterstitial component * - * @returns {object} JetpackAiInterstitial react component. + * @return {object} JetpackAiInterstitial react component. */ export { default as JetpackAiInterstitial } from './jetpack-ai'; /** * ProtectInterstitial component * - * @returns {object} ProtectInterstitial react component. + * @return {object} ProtectInterstitial react component. */ export function ProtectInterstitial() { return ; @@ -387,7 +381,7 @@ export function ProtectInterstitial() { /** * ScanInterstitial component * - * @returns {object} ScanInterstitial react component. + * @return {object} ScanInterstitial react component. */ export function ScanInterstitial() { return ; @@ -396,7 +390,7 @@ export function ScanInterstitial() { /** * SocialInterstitial component * - * @returns {object} SocialInterstitial react component. + * @return {object} SocialInterstitial react component. */ export function SocialInterstitial() { return ( @@ -415,7 +409,7 @@ export function SocialInterstitial() { /** * SearchInterstitial component * - * @returns {object} SearchInterstitial react component. + * @return {object} SearchInterstitial react component. */ export function SearchInterstitial() { const { detail } = useProduct( 'search' ); @@ -444,7 +438,7 @@ export function SearchInterstitial() { /** * StatsInterstitial component * - * @returns {object} StatsInterstitial react component. + * @return {object} StatsInterstitial react component. */ export function StatsInterstitial() { return ( @@ -468,7 +462,7 @@ export function StatsInterstitial() { /** * VideoPressInterstitial component * - * @returns {object} VideoPressInterstitial react component. + * @return {object} VideoPressInterstitial react component. */ export function VideoPressInterstitial() { return ( diff --git a/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai.png b/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai.png index bff62ed531177..b77ec6b9a18cb 100644 Binary files a/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai.png and b/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai.png differ diff --git a/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/index.jsx b/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/index.jsx index 2e0f1520e9a7b..246c1b831c90c 100644 --- a/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/index.jsx @@ -1,6 +1,7 @@ /** * External dependencies */ +import { __ } from '@wordpress/i18n'; import debugFactory from 'debug'; import { useCallback } from 'react'; /** @@ -16,7 +17,7 @@ const debug = debugFactory( 'my-jetpack:product-interstitial:jetpack-ai' ); /** * JetpackAiInterstitial component * - * @returns {object} JetpackAiInterstitial react component. + * @return {object} JetpackAiInterstitial react component. */ export default function JetpackAiInterstitial() { const slug = 'jetpack-ai'; @@ -41,13 +42,14 @@ export default function JetpackAiInterstitial() { return ( - Search + Jetpack AI ); } diff --git a/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/more-requests.jsx b/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/more-requests.jsx index 93a7cc268efed..458e1fcd21e7a 100644 --- a/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/more-requests.jsx +++ b/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/more-requests.jsx @@ -25,9 +25,9 @@ import styles from './style.module.scss'; /** * JetpackAIInterstitialMoreRequests component * - * @param {object} props - Component props. + * @param {object} props - Component props. * @param {Function} props.onClickGoBack - onClick handler for the "Back" button. - * @returns {object} JetpackAIInterstitialMoreRequests react component. + * @return {object} JetpackAIInterstitialMoreRequests react component. */ export function JetpackAIInterstitialMoreRequests( { onClickGoBack = () => {} } ) { const title = __( 'Do you need more requests for Jetpack AI Assistant?', 'jetpack-my-jetpack' ); diff --git a/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/product-page.jsx b/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/product-page.jsx index 62c0a1a724f9f..5a8981407e29e 100644 --- a/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/product-page.jsx +++ b/projects/packages/my-jetpack/_inc/components/product-interstitial/jetpack-ai/product-page.jsx @@ -31,7 +31,7 @@ const debug = debugFactory( 'my-jetpack:product-interstitial:jetpack-ai-product- /** * Product Page for Jetpack AI - * @returns {object} React component for the product page + * @return {object} React component for the product page */ export default function () { const { onClickGoBack } = useGoBack( 'jetpack-ai' ); @@ -64,10 +64,11 @@ export default function () { nextTier, usagePeriod: usage, isOverLimit, + tierPlansEnabled, } = aiAssistantFeature || {}; - const hasUnlimited = currentTier?.value === 1; const isFree = currentTier?.value === 0; + const hasUnlimited = currentTier?.value === 1 || ( ! tierPlansEnabled && ! isFree ); const hasPaidTier = ! isFree && ! hasUnlimited; const shouldContactUs = ! hasUnlimited && hasPaidTier && ! nextTier && currentTier; const freeRequestsLeft = isFree && 20 - allTimeRequests >= 0 ? 20 - allTimeRequests : 0; @@ -116,8 +117,9 @@ export default function () { 'Wait for %d days to reset your limit, or upgrade now to a higher tier for additional requests and keep your work moving forward.', 'jetpack-my-jetpack' ), - Math.floor( ( new Date( usage?.[ 'next-start' ] ) - new Date() ) / ( 1000 * 60 * 60 * 24 ) ) + Math.floor( ( new Date( usage?.nextStart || null ) - new Date() ) / ( 1000 * 60 * 60 * 24 ) ) ); + const upgradeNoticeBody = __( 'Reach for More with Jetpack AI! Upgrade now for additional requests and keep your momentum going.', 'jetpack-my-jetpack' diff --git a/projects/packages/my-jetpack/_inc/components/product-interstitial/search.png b/projects/packages/my-jetpack/_inc/components/product-interstitial/search.png index 0f77309b19f77..a5d1e8d71d33e 100644 Binary files a/projects/packages/my-jetpack/_inc/components/product-interstitial/search.png and b/projects/packages/my-jetpack/_inc/components/product-interstitial/search.png differ diff --git a/projects/packages/my-jetpack/_inc/components/product-interstitial/social.png b/projects/packages/my-jetpack/_inc/components/product-interstitial/social.png index ed91b93e0341a..00d8ac9d5c6b2 100644 Binary files a/projects/packages/my-jetpack/_inc/components/product-interstitial/social.png and b/projects/packages/my-jetpack/_inc/components/product-interstitial/social.png differ diff --git a/projects/packages/my-jetpack/_inc/components/product-interstitial/stats.png b/projects/packages/my-jetpack/_inc/components/product-interstitial/stats.png index 0c6ae45e79001..bd003303cb954 100644 Binary files a/projects/packages/my-jetpack/_inc/components/product-interstitial/stats.png and b/projects/packages/my-jetpack/_inc/components/product-interstitial/stats.png differ diff --git a/projects/packages/my-jetpack/_inc/components/product-interstitial/videopress.png b/projects/packages/my-jetpack/_inc/components/product-interstitial/videopress.png index 9a8f1dfb23c1f..f38227dcccf3e 100644 Binary files a/projects/packages/my-jetpack/_inc/components/product-interstitial/videopress.png and b/projects/packages/my-jetpack/_inc/components/product-interstitial/videopress.png differ diff --git a/projects/packages/my-jetpack/_inc/components/redeem-token-screen/index.jsx b/projects/packages/my-jetpack/_inc/components/redeem-token-screen/index.jsx index 8e56fd964dfd8..81504d09c53a2 100644 --- a/projects/packages/my-jetpack/_inc/components/redeem-token-screen/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/redeem-token-screen/index.jsx @@ -8,7 +8,7 @@ import { includesLifetimePurchase } from '../../utils/is-lifetime-purchase'; /** * The RedeemToken component of the My Jetpack app. * - * @returns {object} The RedeemTokenScreen component. + * @return {object} The RedeemTokenScreen component. */ export default function RedeemTokenScreen() { const { userConnectionData } = useMyJetpackConnection(); diff --git a/projects/packages/my-jetpack/_inc/components/stats-section/cards.jsx b/projects/packages/my-jetpack/_inc/components/stats-section/cards.jsx index 1f5d30f4e194f..baf0e5512423b 100644 --- a/projects/packages/my-jetpack/_inc/components/stats-section/cards.jsx +++ b/projects/packages/my-jetpack/_inc/components/stats-section/cards.jsx @@ -12,7 +12,7 @@ import styles from './style.module.scss'; * @param {object} props.counts - Counts object for the current period. * @param {object} props.previousCounts - Counts object for the previous period. * - * @returns {object} StatsCards React component. + * @return {object} StatsCards React component. */ const StatsCards = ( { counts, previousCounts } ) => { return ( diff --git a/projects/packages/my-jetpack/_inc/components/stats-section/count-comparison-card.jsx b/projects/packages/my-jetpack/_inc/components/stats-section/count-comparison-card.jsx index be70f993ff234..78768eae092ca 100644 --- a/projects/packages/my-jetpack/_inc/components/stats-section/count-comparison-card.jsx +++ b/projects/packages/my-jetpack/_inc/components/stats-section/count-comparison-card.jsx @@ -30,12 +30,12 @@ export const percentCalculator = ( part, whole ) => { /** * CountComparisonCard component. * - * @param {object} props - Component props. - * @param {number} props.count - Current count. - * @param {number} props.previousCount - Previous count. - * @param {React.ReactNode} props.icon - Icon to display. - * @param {React.ReactNode} props.heading - Card heading. - * @returns {object} CountComparisonCard React component. + * @param {object} props - Component props. + * @param {number} props.count - Current count. + * @param {number} props.previousCount - Previous count. + * @param {React.ReactNode} props.icon - Icon to display. + * @param {React.ReactNode} props.heading - Card heading. + * @return {object} CountComparisonCard React component. */ const CountComparisonCard = ( { count = 0, previousCount = 0, icon, heading } ) => { const difference = subtract( count, previousCount ); diff --git a/projects/packages/my-jetpack/_inc/components/welcome-banner/assets/images/site-cards.png b/projects/packages/my-jetpack/_inc/components/welcome-banner/assets/images/site-cards.png index ac5b998146619..83e562ede663c 100644 Binary files a/projects/packages/my-jetpack/_inc/components/welcome-banner/assets/images/site-cards.png and b/projects/packages/my-jetpack/_inc/components/welcome-banner/assets/images/site-cards.png differ diff --git a/projects/packages/my-jetpack/_inc/components/welcome-banner/index.jsx b/projects/packages/my-jetpack/_inc/components/welcome-banner/index.jsx index fe64c838cfb78..c40848b4610d7 100644 --- a/projects/packages/my-jetpack/_inc/components/welcome-banner/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/welcome-banner/index.jsx @@ -13,7 +13,7 @@ import styles from './style.module.scss'; /** * Component that renders the Welcome banner on My Jetpack. * - * @returns {object} The WelcomeBanner component. + * @return {object} The WelcomeBanner component. */ const WelcomeBanner = () => { const { recordEvent } = useAnalytics(); diff --git a/projects/packages/my-jetpack/_inc/components/welcome-flow/ConnectionStep.tsx b/projects/packages/my-jetpack/_inc/components/welcome-flow/ConnectionStep.tsx index 358260fce50a4..6c1111551ce38 100644 --- a/projects/packages/my-jetpack/_inc/components/welcome-flow/ConnectionStep.tsx +++ b/projects/packages/my-jetpack/_inc/components/welcome-flow/ConnectionStep.tsx @@ -19,11 +19,11 @@ type ConnectionStepProps = { /** * Component that renders the Welcome banner on My Jetpack. * - * @param {object} props - ConnectioStepProps - * @param {Function} props.onActivateSite - Alias for handleRegisterSite + * @param {object} props - ConnectioStepProps + * @param {Function} props.onActivateSite - Alias for handleRegisterSite * @param {Function} props.onUpdateWelcomeFlowExperiment - Updating the welcomeFlowExperiment state - * @param {boolean} props.isActivating - Alias for siteIsRegistering - * @returns {object} The ConnectionStep component. + * @param {boolean} props.isActivating - Alias for siteIsRegistering + * @return {object} The ConnectionStep component. */ const ConnectionStep = ( { onActivateSite, diff --git a/projects/packages/my-jetpack/_inc/components/welcome-flow/assets/images/evaluation-blank.png b/projects/packages/my-jetpack/_inc/components/welcome-flow/assets/images/evaluation-blank.png index c0eec2f7164f3..99ef267160cb6 100644 Binary files a/projects/packages/my-jetpack/_inc/components/welcome-flow/assets/images/evaluation-blank.png and b/projects/packages/my-jetpack/_inc/components/welcome-flow/assets/images/evaluation-blank.png differ diff --git a/projects/packages/my-jetpack/_inc/components/welcome-flow/assets/images/evaluation-selected.png b/projects/packages/my-jetpack/_inc/components/welcome-flow/assets/images/evaluation-selected.png index 5b7de17018047..1ff0ab37806ca 100644 Binary files a/projects/packages/my-jetpack/_inc/components/welcome-flow/assets/images/evaluation-selected.png and b/projects/packages/my-jetpack/_inc/components/welcome-flow/assets/images/evaluation-selected.png differ diff --git a/projects/packages/my-jetpack/_inc/components/welcome-flow/assets/images/site-cards.png b/projects/packages/my-jetpack/_inc/components/welcome-flow/assets/images/site-cards.png index ac5b998146619..83e562ede663c 100644 Binary files a/projects/packages/my-jetpack/_inc/components/welcome-flow/assets/images/site-cards.png and b/projects/packages/my-jetpack/_inc/components/welcome-flow/assets/images/site-cards.png differ diff --git a/projects/packages/my-jetpack/_inc/components/welcome-flow/index.tsx b/projects/packages/my-jetpack/_inc/components/welcome-flow/index.tsx index 94719828bcb2e..deb312653e88f 100644 --- a/projects/packages/my-jetpack/_inc/components/welcome-flow/index.tsx +++ b/projects/packages/my-jetpack/_inc/components/welcome-flow/index.tsx @@ -23,7 +23,8 @@ export type WelcomeFlowExperiment = { const WelcomeFlow: FC< PropsWithChildren > = ( { children } ) => { const { recordEvent } = useAnalytics(); const { dismissWelcomeBanner } = useWelcomeBanner(); - const { submitEvaluation, saveEvaluationResult } = useEvaluationRecommendations(); + const { recommendedModules, submitEvaluation, saveEvaluationResult } = + useEvaluationRecommendations(); const { siteIsRegistered, siteIsRegistering, @@ -44,15 +45,27 @@ const WelcomeFlow: FC< PropsWithChildren > = ( { children } ) => { if ( ! siteIsRegistered || welcomeFlowExperiment.isLoading ) { return 'connection'; } else if ( ! isProcessingEvaluation ) { - if ( ! isJetpackUserNew() || welcomeFlowExperiment.variation !== 'treatment' ) { - // If the user is not new, we don't show the evaluation step + if ( + ! recommendedModules && + ( welcomeFlowExperiment.variation === 'control' || ! isJetpackUserNew() ) + ) { + // If user is not new but doesn't have recommendations, we skip evaluation + // If user has recommendations, it means they were already in treatment group and they redo the evaluation return null; } + + // Otherwise, it means user is either new or just repeats the recommendation return 'evaluation'; } return 'evaluation-processing'; - }, [ isProcessingEvaluation, siteIsRegistered, welcomeFlowExperiment ] ); + }, [ + isProcessingEvaluation, + recommendedModules, + siteIsRegistered, + welcomeFlowExperiment.isLoading, + welcomeFlowExperiment.variation, + ] ); useEffect( () => { if ( prevStep !== currentStep ) { diff --git a/projects/packages/my-jetpack/_inc/data/use-jetpack-api-query.ts b/projects/packages/my-jetpack/_inc/data/use-jetpack-api-query.ts index afb9b2d8428da..d99a9a890cb2a 100644 --- a/projects/packages/my-jetpack/_inc/data/use-jetpack-api-query.ts +++ b/projects/packages/my-jetpack/_inc/data/use-jetpack-api-query.ts @@ -9,10 +9,10 @@ import { getMyJetpackWindowRestState } from './utils/get-my-jetpack-window-state * and provides react-query's powerful features like caching and automatic refetching. * * @template T The type of data expected to be returned by the query function. - * @param {object} params - The parameters for configuring the API query. - * @param {string} params.name - The unique name for the query. This name, along with the optional `explicitKey`, forms the cache key for the query's result. - * @param {Function} params.queryFn - The function to fetch data from the API. It receives a configured instance of `restApi` and must return a promise that resolves to the data of type `T`. - * @param {string} [params.errorMessage] - Optional. A custom error message to be displayed in case the query fails. This message overrides the default error handling behavior. + * @param {object} params - The parameters for configuring the API query. + * @param {string} params.name - The unique name for the query. This name, along with the optional `explicitKey`, forms the cache key for the query's result. + * @param {Function} params.queryFn - The function to fetch data from the API. It receives a configured instance of `restApi` and must return a promise that resolves to the data of type `T`. + * @param {string} [params.errorMessage] - Optional. A custom error message to be displayed in case the query fails. This message overrides the default error handling behavior. */ type QueryParams< T > = { name: string; diff --git a/projects/packages/my-jetpack/_inc/data/use-simple-mutation.ts b/projects/packages/my-jetpack/_inc/data/use-simple-mutation.ts index c0694c3d7f21b..15d9229894c03 100644 --- a/projects/packages/my-jetpack/_inc/data/use-simple-mutation.ts +++ b/projects/packages/my-jetpack/_inc/data/use-simple-mutation.ts @@ -16,12 +16,12 @@ export type APIFetchOptionsWithQueryParams = APIFetchOptions & { * an error notice if the mutation encounters an error. * * @template T The type of data expected to be returned by the mutation. - * @param {object} params - The parameters for executing the mutation. - * @param {string} params.name - A unique name for the mutation, used as part of the mutation key. - * @param {APIFetchOptions} params.query - The options to be passed to the API fetch function for the mutation. - * @param {Pick} [params.options] - Optional. Mutation options from react-query, currently supports only the 'onSuccess' option. - * @param {string} [params.errorMessage] - Optional. A custom error message that can be displayed if the mutation fails. - * @returns {UseMutationResult} The result object from the useMutation hook, containing data and state information about the mutation (e.g., isPending, isError). + * @param {object} params - The parameters for executing the mutation. + * @param {string} params.name - A unique name for the mutation, used as part of the mutation key. + * @param {APIFetchOptions} params.query - The options to be passed to the API fetch function for the mutation. + * @param {Pick} [params.options] - Optional. Mutation options from react-query, currently supports only the 'onSuccess' option. + * @param {string} [params.errorMessage] - Optional. A custom error message that can be displayed if the mutation fails. + * @return {UseMutationResult} The result object from the useMutation hook, containing data and state information about the mutation (e.g., isPending, isError). */ type QueryParams< T, E, V > = { name: string; diff --git a/projects/packages/my-jetpack/_inc/data/use-simple-query.ts b/projects/packages/my-jetpack/_inc/data/use-simple-query.ts index 40fecc6af4adc..541ec6b8ed4af 100644 --- a/projects/packages/my-jetpack/_inc/data/use-simple-query.ts +++ b/projects/packages/my-jetpack/_inc/data/use-simple-query.ts @@ -13,12 +13,12 @@ import type { APIFetchOptions } from '@wordpress/api-fetch'; * GET requests. For anything else - use useSimpleMutation. * * @template T The type of data expected from the query function. - * @param {object} params - The parameters for executing the query. - * @param {string} params.name - A unique name for the query, used as part of the query key. - * @param {APIFetchOptions} params.query - The options to be passed to the API fetch function. - * @param {Pick} [params.options] - Optional. Query options from react-query, currently supports only the 'enabled' option. - * @param {string} [params.errorMessage] - Optional. A custom error message that can be displayed if the query fails. - * @returns {UseQueryResult} The result object from the useQuery hook, containing data and state information about the query (e.g., isLoading, isError). + * @param {object} params - The parameters for executing the query. + * @param {string} params.name - A unique name for the query, used as part of the query key. + * @param {APIFetchOptions} params.query - The options to be passed to the API fetch function. + * @param {Pick} [params.options] - Optional. Query options from react-query, currently supports only the 'enabled' option. + * @param {string} [params.errorMessage] - Optional. A custom error message that can be displayed if the query fails. + * @return {UseQueryResult} The result object from the useQuery hook, containing data and state information about the query (e.g., isLoading, isError). */ type QueryParams = { name: string; diff --git a/projects/packages/my-jetpack/_inc/hooks/use-analytics/index.ts b/projects/packages/my-jetpack/_inc/hooks/use-analytics/index.ts index a6409e984ac89..75d0f62e04787 100644 --- a/projects/packages/my-jetpack/_inc/hooks/use-analytics/index.ts +++ b/projects/packages/my-jetpack/_inc/hooks/use-analytics/index.ts @@ -37,8 +37,8 @@ const useAnalytics = () => { /** * Like tracks.recordEvent but provides specifics to My Jetpack * - * @param {string} event - event name - * @param {object} properties - event propeties + * @param {string} event - event name + * @param {object} properties - event propeties */ const recordEvent = useCallback< TracksRecordEvent >( ( event, properties ) => { jetpackAnalytics.tracks.recordEvent( event, { diff --git a/projects/packages/my-jetpack/_inc/hooks/use-go-back/index.ts b/projects/packages/my-jetpack/_inc/hooks/use-go-back/index.ts index 76a9efc72bc57..eab90ddca8323 100644 --- a/projects/packages/my-jetpack/_inc/hooks/use-go-back/index.ts +++ b/projects/packages/my-jetpack/_inc/hooks/use-go-back/index.ts @@ -13,7 +13,7 @@ import useMyJetpackNavigate from '../use-my-jetpack-navigate'; * Custom React hook to handle back link click with analytics. * * @param {string} slug - My Jetpack product slug. - * @returns {object} Object with back link click handler with analytics. + * @return {object} Object with back link click handler with analytics. */ export function useGoBack( { slug }: { slug: string } ) { const { recordEvent } = useAnalytics(); diff --git a/projects/packages/my-jetpack/_inc/hooks/use-my-jetpack-connection/index.ts b/projects/packages/my-jetpack/_inc/hooks/use-my-jetpack-connection/index.ts index 0758aeea169db..f73fabb01128d 100644 --- a/projects/packages/my-jetpack/_inc/hooks/use-my-jetpack-connection/index.ts +++ b/projects/packages/my-jetpack/_inc/hooks/use-my-jetpack-connection/index.ts @@ -7,7 +7,7 @@ import { /** * React custom hook to get the site purchases data. * - * @returns {object} site purchases data + * @return {object} site purchases data */ type MyJetpackConnection = { diff --git a/projects/packages/my-jetpack/_inc/hooks/use-my-jetpack-navigate/index.ts b/projects/packages/my-jetpack/_inc/hooks/use-my-jetpack-navigate/index.ts index 9e088d8593c6c..b35c1d9a2bbfd 100644 --- a/projects/packages/my-jetpack/_inc/hooks/use-my-jetpack-navigate/index.ts +++ b/projects/packages/my-jetpack/_inc/hooks/use-my-jetpack-navigate/index.ts @@ -7,7 +7,7 @@ import type { NavigateOptions } from 'react-router-dom'; * Custom My Jetpack navigator hook * * @param {string} route - route to navigate to - * @returns {Function} - navigate function + * @return {Function} - navigate function */ export default function useMyJetpackNavigate( route: ( typeof MyJetpackRoutes )[ keyof typeof MyJetpackRoutes ] diff --git a/projects/packages/my-jetpack/_inc/hooks/use-my-jetpack-return-to-page/index.ts b/projects/packages/my-jetpack/_inc/hooks/use-my-jetpack-return-to-page/index.ts index 14096205ccdc8..b95d63fc13aa0 100644 --- a/projects/packages/my-jetpack/_inc/hooks/use-my-jetpack-return-to-page/index.ts +++ b/projects/packages/my-jetpack/_inc/hooks/use-my-jetpack-return-to-page/index.ts @@ -7,7 +7,7 @@ import { useSearchParams } from 'react-router-dom'; * it's easier on people to be sent back to a different page * (e.g., the license activation form). * - * @returns {string} the URL of a My Jetpack page that should be displayed after connection. + * @return {string} the URL of a My Jetpack page that should be displayed after connection. */ const useMyJetpackReturnToPage = () => { const [ searchParams ] = useSearchParams(); diff --git a/projects/packages/my-jetpack/_inc/hooks/use-redirect-to-referrer/index.ts b/projects/packages/my-jetpack/_inc/hooks/use-redirect-to-referrer/index.ts index 6e9f753fdbd24..b4e31df88e457 100644 --- a/projects/packages/my-jetpack/_inc/hooks/use-redirect-to-referrer/index.ts +++ b/projects/packages/my-jetpack/_inc/hooks/use-redirect-to-referrer/index.ts @@ -1,7 +1,7 @@ /** * React custom hook to get the request referrer URL when `redirect_to_referrer` parameter is present. * - * @returns {string | null} referrer URL or null if not flagged. + * @return {string | null} referrer URL or null if not flagged. */ export function useRedirectToReferrer() { // Get the current URL query string. diff --git a/projects/packages/my-jetpack/_inc/utils/format-number.ts b/projects/packages/my-jetpack/_inc/utils/format-number.ts index ec4670e3a24a4..717f4cbff574f 100644 --- a/projects/packages/my-jetpack/_inc/utils/format-number.ts +++ b/projects/packages/my-jetpack/_inc/utils/format-number.ts @@ -1,8 +1,13 @@ import { numberFormat } from '@automattic/jetpack-components'; -type FormatNumberFunction = ( number: number, config: Intl.NumberFormatOptions ) => string; +type FormatNumberFunction = ( number: number, config?: Intl.NumberFormatOptions ) => string; -const formatNumber: FormatNumberFunction = ( number, config = {} ) => { +const defaultConfig: Intl.NumberFormatOptions = { + maximumFractionDigits: 1, + notation: 'compact', +}; + +const formatNumber: FormatNumberFunction = ( number, config = defaultConfig ) => { if ( number === null || ! Number.isFinite( number ) ) { return '-'; } diff --git a/projects/packages/my-jetpack/_inc/utils/format-time.ts b/projects/packages/my-jetpack/_inc/utils/format-time.ts index 95cc4aba24b26..61f1d2ba07491 100644 --- a/projects/packages/my-jetpack/_inc/utils/format-time.ts +++ b/projects/packages/my-jetpack/_inc/utils/format-time.ts @@ -1,8 +1,9 @@ -type FormatTimeFunction = ( seconds: number ) => string; +type FormatTimeFunction = ( hours: number ) => string; -const formatTime: FormatTimeFunction = ( seconds: number ) => { +const formatTime: FormatTimeFunction = ( hours: number ) => { + const seconds = Math.floor( hours * 3600 ); const minutes = Math.floor( seconds / 60 ); - const hours = Math.floor( minutes / 60 ); + hours = Math.floor( hours ); const days = Math.floor( hours / 24 ); const years = Math.floor( days / 365 ); @@ -22,7 +23,7 @@ const formatTime: FormatTimeFunction = ( seconds: number ) => { return `${ minutes }m ${ seconds % 60 }s`; } - return `${ seconds }s`; + return `${ Math.floor( seconds ) }s`; }; export default formatTime; diff --git a/projects/packages/my-jetpack/_inc/utils/get-manage-your-plan-url.ts b/projects/packages/my-jetpack/_inc/utils/get-manage-your-plan-url.ts index 0e77b97787318..70301860fa120 100644 --- a/projects/packages/my-jetpack/_inc/utils/get-manage-your-plan-url.ts +++ b/projects/packages/my-jetpack/_inc/utils/get-manage-your-plan-url.ts @@ -5,7 +5,7 @@ import { getMyJetpackWindowInitialState } from '../data/utils/get-my-jetpack-win /** * Return the redurect URL, according to the Jetpack redurects source. * - * @returns {string} the redirect URL + * @return {string} the redirect URL */ const getManageYourPlanUrl = () => { const { siteSuffix: site = '', blogID } = getMyJetpackWindowInitialState(); diff --git a/projects/packages/my-jetpack/_inc/utils/get-purchase-plan-url.ts b/projects/packages/my-jetpack/_inc/utils/get-purchase-plan-url.ts index 545edef8d3a6e..c59e959222efa 100644 --- a/projects/packages/my-jetpack/_inc/utils/get-purchase-plan-url.ts +++ b/projects/packages/my-jetpack/_inc/utils/get-purchase-plan-url.ts @@ -8,7 +8,7 @@ import { getMyJetpackWindowInitialState } from '../data/utils/get-my-jetpack-win /** * Return the redurect URL for purchasing a plan, according to the Jetpack redurects source. * - * @returns {string} the redirect URL + * @return {string} the redirect URL */ const getPurchasePlanUrl = () => { const { diff --git a/projects/packages/my-jetpack/_inc/utils/is-jetpack-plugin-active.ts b/projects/packages/my-jetpack/_inc/utils/is-jetpack-plugin-active.ts index 2b0942d4ba902..90c2030b7a1b3 100644 --- a/projects/packages/my-jetpack/_inc/utils/is-jetpack-plugin-active.ts +++ b/projects/packages/my-jetpack/_inc/utils/is-jetpack-plugin-active.ts @@ -3,7 +3,7 @@ import { getMyJetpackWindowInitialState } from '../data/utils/get-my-jetpack-win /** * Check if the Jetpack plugin is active or not. * - * @returns {boolean} Returns true if the Jetpack plugin is active, otherwise false. + * @return {boolean} Returns true if the Jetpack plugin is active, otherwise false. */ export const isJetpackPluginActive = () => { const { plugins } = getMyJetpackWindowInitialState() || {}; diff --git a/projects/packages/my-jetpack/_inc/utils/is-lifetime-purchase.ts b/projects/packages/my-jetpack/_inc/utils/is-lifetime-purchase.ts index 6bca6493c11bf..8e208ae5f39a5 100644 --- a/projects/packages/my-jetpack/_inc/utils/is-lifetime-purchase.ts +++ b/projects/packages/my-jetpack/_inc/utils/is-lifetime-purchase.ts @@ -3,9 +3,9 @@ import type { Purchase } from '../data/types'; /** * Check if a purchase is considered "Lifetime". * - * @param {Purchase} purchase - A WPCOM purchase object. - * @param {string} purchase.partner_slug - A partner that issued the purchase. - * @returns {boolean} Returns true if a purchase is considered a lifetime purchase. + * @param {Purchase} purchase - A WPCOM purchase object. + * @param {string} purchase.partner_slug - A partner that issued the purchase. + * @return {boolean} Returns true if a purchase is considered a lifetime purchase. */ export const isLifetimePurchase = ( { partner_slug }: Purchase ) => { if ( ! partner_slug ) { @@ -20,7 +20,7 @@ export const isLifetimePurchase = ( { partner_slug }: Purchase ) => { * Look for a lifetime purchase in an array of purchases. * * @param {Array} purchases - An array of WPCOM purchase objects. - * @returns {boolean} Returns true if one of the purchase is considered a lifetime purchase. + * @return {boolean} Returns true if one of the purchase is considered a lifetime purchase. */ export function includesLifetimePurchase( purchases: Array< Purchase > ) { if ( ! Array.isArray( purchases ) ) { diff --git a/projects/packages/my-jetpack/_inc/utils/side-load-tracks.ts b/projects/packages/my-jetpack/_inc/utils/side-load-tracks.ts index 66ac82d5d9035..b594555436a5b 100644 --- a/projects/packages/my-jetpack/_inc/utils/side-load-tracks.ts +++ b/projects/packages/my-jetpack/_inc/utils/side-load-tracks.ts @@ -8,7 +8,7 @@ declare global { /** * Function to get the current year and week number. * - * @returns {string} The current year and week number. + * @return {string} The current year and week number. */ function getCurrentYearAndWeek() { const date = new Date(); @@ -32,7 +32,7 @@ function getCurrentYearAndWeek() { * and appends it to the document's head. * * @param {string} src - The URL of the script to load. - * @returns {Promise} A promise that resolves once the script has loaded. + * @return {Promise} A promise that resolves once the script has loaded. */ function loadScript( src: string ): Promise< void > { return new Promise( ( resolve, reject ) => { @@ -53,7 +53,7 @@ function loadScript( src: string ): Promise< void > { * and then loads the tracking script from the specified URL. Once the script has loaded, * the provided callback function is called. * - * @returns {Promise} A promise that resolves once the Tracks has been side loaded. + * @return {Promise} A promise that resolves once the Tracks has been side loaded. */ export default function sideloadTracks(): Promise< void > { window._tkq = window._tkq || []; diff --git a/projects/packages/my-jetpack/_inc/utils/time-since.ts b/projects/packages/my-jetpack/_inc/utils/time-since.ts index 2c8c025d369b1..825f834e57656 100644 --- a/projects/packages/my-jetpack/_inc/utils/time-since.ts +++ b/projects/packages/my-jetpack/_inc/utils/time-since.ts @@ -4,7 +4,7 @@ import { sprintf, _n, __ } from '@wordpress/i18n'; * Time Since * * @param {number} date - The past date (timestamp) to compare to the current date. - * @returns {string} - A description of the amount of time between a date and now, i.e. "5 minutes ago". + * @return {string} - A description of the amount of time between a date and now, i.e. "5 minutes ago". */ export function timeSince( date: number ) { const now = new Date(); diff --git a/projects/packages/my-jetpack/changelog/add-value-to-active-state-videopress-card b/projects/packages/my-jetpack/changelog/add-value-to-active-state-videopress-card deleted file mode 100644 index e5a8f5a36e844..0000000000000 --- a/projects/packages/my-jetpack/changelog/add-value-to-active-state-videopress-card +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: added - -Add value to active card state on VideoPress My Jetpack card diff --git a/projects/packages/my-jetpack/composer.json b/projects/packages/my-jetpack/composer.json index 2a4a36e052827..3d2957aa23cd7 100644 --- a/projects/packages/my-jetpack/composer.json +++ b/projects/packages/my-jetpack/composer.json @@ -18,11 +18,10 @@ "automattic/jetpack-plans": "@dev", "automattic/jetpack-status": "@dev", "automattic/jetpack-sync": "@dev", - "automattic/jetpack-protect-status": "@dev", - "automattic/jetpack-waf": "@dev" + "automattic/jetpack-protect-status": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev", "automattic/jetpack-search": "@dev", @@ -83,7 +82,7 @@ "link-template": "https://github.com/Automattic/jetpack-my-jetpack/compare/${old}...${new}" }, "branch-alias": { - "dev-trunk": "4.32.x-dev" + "dev-trunk": "4.33.x-dev" }, "version-constants": { "::PACKAGE_VERSION": "src/class-initializer.php" diff --git a/projects/packages/my-jetpack/global.d.ts b/projects/packages/my-jetpack/global.d.ts index f10c8dd9ab5fa..2484b4a5a2976 100644 --- a/projects/packages/my-jetpack/global.d.ts +++ b/projects/packages/my-jetpack/global.d.ts @@ -243,8 +243,9 @@ interface Window { }; }; videopress: { - featuredStats: { + featuredStats?: { label: string; + period: 'day' | 'year'; data: { views: { current: number; diff --git a/projects/packages/my-jetpack/package.json b/projects/packages/my-jetpack/package.json index bee0ff064cc31..76706c2a685b9 100644 --- a/projects/packages/my-jetpack/package.json +++ b/projects/packages/my-jetpack/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-my-jetpack", - "version": "4.32.3-alpha", + "version": "4.33.1", "description": "WP Admin page with information and configuration shared among all Jetpack stand-alone plugins", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/my-jetpack/#readme", "bugs": { @@ -75,7 +75,7 @@ "sass-loader": "12.4.0", "storybook": "8.2.9", "typescript": "5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" } } diff --git a/projects/packages/my-jetpack/src/class-activitylog.php b/projects/packages/my-jetpack/src/class-activitylog.php index 0e59226dbd508..4de90c075ded5 100644 --- a/projects/packages/my-jetpack/src/class-activitylog.php +++ b/projects/packages/my-jetpack/src/class-activitylog.php @@ -51,7 +51,7 @@ public static function add_submenu_jetpack() { 'manage_options', esc_url( Redirect::get_url( 'cloud-activity-log-wp-menu', $args ) ), null, - 1 + 8 ); } } diff --git a/projects/packages/my-jetpack/src/class-initializer.php b/projects/packages/my-jetpack/src/class-initializer.php index 3670a0ff82433..3e164192b9764 100644 --- a/projects/packages/my-jetpack/src/class-initializer.php +++ b/projects/packages/my-jetpack/src/class-initializer.php @@ -42,7 +42,7 @@ class Initializer { * * @var string */ - const PACKAGE_VERSION = '4.32.3-alpha'; + const PACKAGE_VERSION = '4.33.1'; /** * HTML container ID for the IDC screen on My Jetpack page. @@ -64,6 +64,7 @@ class Initializer { const UPDATE_HISTORICALLY_ACTIVE_JETPACK_MODULES_KEY = 'update-historically-active-jetpack-modules'; const MISSING_CONNECTION_NOTIFICATION_KEY = 'missing-connection'; const VIDEOPRESS_STATS_KEY = 'my-jetpack-videopress-stats'; + const VIDEOPRESS_PERIOD_KEY = 'my-jetpack-videopress-period'; /** * Holds info/data about the site (from the /sites/%d endpoint) @@ -219,6 +220,11 @@ public static function enqueue_scripts() { $scan_data = Protect_Status::get_status(); self::update_historically_active_jetpack_modules(); + $waf_config = array(); + if ( class_exists( 'Automattic\Jetpack\Waf\Waf_Runner' ) ) { + $waf_config = Waf_Runner::get_config(); + } + wp_localize_script( 'my_jetpack_main_app', 'myJetpackInitialState', @@ -273,7 +279,7 @@ public static function enqueue_scripts() { 'protect' => array( 'scanData' => $scan_data, 'wafConfig' => array_merge( - Waf_Runner::get_config(), + $waf_config, array( 'blocked_logins' => (int) get_site_option( 'jetpack_protect_blocked_attempts', 0 ) ) ), ), @@ -315,9 +321,34 @@ public static function get_videopress_stats() { $featured_stats = get_transient( self::VIDEOPRESS_STATS_KEY ); - if ( ! $featured_stats ) { - $videopress_stats = new VideoPress_Stats(); - $featured_stats = $videopress_stats->get_featured_stats( 60 ); + if ( $featured_stats ) { + return array( + 'featuredStats' => $featured_stats, + 'videoCount' => $video_count, + ); + } + + $stats_period = get_transient( self::VIDEOPRESS_PERIOD_KEY ); + $videopress_stats = new VideoPress_Stats(); + + // If the stats period exists, retrieve that information without checking the view count. + // If it does not, check the view count of monthly stats and determine if we want to show yearly or monthly stats. + if ( $stats_period ) { + if ( $stats_period === 'day' ) { + $featured_stats = $videopress_stats->get_featured_stats( 60, 'day' ); + } else { + $featured_stats = $videopress_stats->get_featured_stats( 2, 'year' ); + } + } else { + $featured_stats = $videopress_stats->get_featured_stats( 60, 'day' ); + + if ( + ! is_wp_error( $featured_stats ) && + $featured_stats && + ( $featured_stats['data']['views']['current'] < 500 || $featured_stats['data']['views']['previous'] < 500 ) + ) { + $featured_stats = $videopress_stats->get_featured_stats( 2, 'year' ); + } } if ( is_wp_error( $featured_stats ) || ! $featured_stats ) { @@ -326,7 +357,8 @@ public static function get_videopress_stats() { ); } - set_transient( self::VIDEOPRESS_STATS_KEY, $featured_stats, HOUR_IN_SECONDS ); + set_transient( self::VIDEOPRESS_PERIOD_KEY, $featured_stats['period'], WEEK_IN_SECONDS ); + set_transient( self::VIDEOPRESS_STATS_KEY, $featured_stats, DAY_IN_SECONDS ); return array( 'featuredStats' => $featured_stats, @@ -768,7 +800,7 @@ public static function maybe_show_red_bubble() { self::get_red_bubble_alerts(), function ( $alert ) { // We don't want to show silent alerts - return ! $alert['is_silent']; + return empty( $alert['is_silent'] ); } ); diff --git a/projects/packages/my-jetpack/src/class-jetpack-manage.php b/projects/packages/my-jetpack/src/class-jetpack-manage.php index be32839498d54..3a732192c90a9 100644 --- a/projects/packages/my-jetpack/src/class-jetpack-manage.php +++ b/projects/packages/my-jetpack/src/class-jetpack-manage.php @@ -49,7 +49,7 @@ public static function add_submenu_jetpack() { 'manage_options', esc_url( Redirect::get_url( 'cloud-manage-dashboard-wp-menu', $args ) ), null, - 100 + 15 ); } diff --git a/projects/packages/my-jetpack/src/class-wpcom-products.php b/projects/packages/my-jetpack/src/class-wpcom-products.php index e4439084a752b..83cdabfbf56b0 100644 --- a/projects/packages/my-jetpack/src/class-wpcom-products.php +++ b/projects/packages/my-jetpack/src/class-wpcom-products.php @@ -8,6 +8,7 @@ namespace Automattic\Jetpack\My_Jetpack; use Automattic\Jetpack\Connection\Client; +use Automattic\Jetpack\Connection\Manager as Connection_Manager; use Automattic\Jetpack\Status\Visitor; use Jetpack_Options; use WP_Error; @@ -30,6 +31,8 @@ class Wpcom_Products { */ const CACHE_META_NAME = 'my-jetpack-cache'; + const CACHE_CHECK_HASH_NAME = 'my-jetpack-wpcom-product-check-hash'; + const MY_JETPACK_PURCHASES_TRANSIENT_KEY = 'my-jetpack-purchases'; /** @@ -38,17 +41,25 @@ class Wpcom_Products { * @return Object|WP_Error */ private static function get_products_from_wpcom() { - $blog_id = \Jetpack_Options::get_option( 'id' ); - $ip = ( new Visitor() )->get_ip( true ); - $headers = array( + $connection = new Connection_Manager(); + $blog_id = \Jetpack_Options::get_option( 'id' ); + $ip = ( new Visitor() )->get_ip( true ); + $headers = array( 'X-Forwarded-For' => $ip, ); - // If has a blog id, use connected endpoint. - if ( $blog_id ) { + // If has a blog id, use connected endpoint. $endpoint = sprintf( '/sites/%d/products/?_locale=%s&type=jetpack', $blog_id, get_user_locale() ); + // If available in the user data, set the user's currency as one of the params + if ( $connection->is_user_connected() ) { + $user_details = $connection->get_connected_user_data(); + if ( $user_details['user_currency'] && $user_details['user_currency'] !== 'USD' ) { + $endpoint .= sprintf( '¤cy=%s', $user_details['user_currency'] ); + } + } + $wpcom_request = Client::wpcom_json_api_request_as_blog( $endpoint, '1.1', @@ -81,6 +92,32 @@ private static function get_products_from_wpcom() { } } + /** + * Super unintelligent hash string that can help us reset the cache after connection changes + * This is important because the currency can change after a user connects depending on what is set in their profile + * + * @return string + */ + private static function build_check_hash() { + $hash_string = 'check_hash_'; + $connection = new Connection_Manager(); + + if ( $connection->is_connected() ) { + $hash_string .= 'site_connected_'; + } + + if ( $connection->is_user_connected() ) { + $hash_string .= 'user_connected'; + // Add the user's currency + $user_details = $connection->get_connected_user_data(); + if ( $user_details['user_currency'] ) { + $hash_string .= '_' . $user_details['user_currency']; + } + } + + return md5( $hash_string ); + } + /** * Update the cache with new information retrieved from WPCOM * @@ -92,6 +129,7 @@ private static function get_products_from_wpcom() { */ private static function update_cache( $products_list ) { update_user_meta( get_current_user_id(), self::CACHE_DATE_META_NAME, time() ); + update_user_meta( get_current_user_id(), self::CACHE_CHECK_HASH_NAME, self::build_check_hash() ); return update_user_meta( get_current_user_id(), self::CACHE_META_NAME, $products_list ); } @@ -102,8 +140,15 @@ private static function is_cache_old() { if ( empty( self::get_products_from_cache() ) ) { return true; } + + // This allows the cache to reset after the site or user connects/ disconnects + $check_hash = get_user_meta( get_current_user_id(), self::CACHE_CHECK_HASH_NAME, true ); + if ( $check_hash !== self::build_check_hash() ) { + return true; + } + $cache_date = get_user_meta( get_current_user_id(), self::CACHE_DATE_META_NAME, true ); - return time() - (int) $cache_date > ( 7 * DAY_IN_SECONDS ); + return time() - (int) $cache_date > DAY_IN_SECONDS; } /** diff --git a/projects/packages/my-jetpack/src/products/class-jetpack-ai.php b/projects/packages/my-jetpack/src/products/class-jetpack-ai.php index a65993035db12..4bf2a21197110 100644 --- a/projects/packages/my-jetpack/src/products/class-jetpack-ai.php +++ b/projects/packages/my-jetpack/src/products/class-jetpack-ai.php @@ -93,6 +93,10 @@ public static function get_title() { * @return string[] Slugs of the available tiers */ public static function get_tiers() { + if ( ! self::are_tier_plans_enabled() ) { + return parent::get_tiers(); + } + return array( self::UPGRADED_TIER_SLUG, self::CURRENT_TIER_SLUG, @@ -105,6 +109,10 @@ public static function get_tiers() { * @return array[] Protect features comparison */ public static function get_features_by_tier() { + if ( ! self::are_tier_plans_enabled() ) { + return parent::get_features_by_tier(); + } + $current_tier = self::get_current_usage_tier(); $current_description = 0 === $current_tier ? __( 'Up to 20 requests', 'jetpack-my-jetpack' ) @@ -194,13 +202,15 @@ public static function get_current_usage_tier() { */ public static function get_next_usage_tier() { if ( ! self::is_site_connected() || ! self::has_paid_plan_for_product() ) { + // without site connection we can't know if tiers are enabled or not, + // hence we can't know if the next tier is 100 or 1 (unlimited). return 100; } $info = self::get_ai_assistant_feature(); - // Bail early if it's not possible to fetch the feature data. - if ( is_wp_error( $info ) ) { + // Bail early if it's not possible to fetch the feature data or if it's included in a plan. + if ( is_wp_error( $info ) || empty( $info ) ) { return null; } @@ -253,14 +263,21 @@ public static function get_long_description() { * @return string */ public static function get_features_by_usage_tier( $tier ) { + $is_tier_plan = $tier && intval( $tier ) > 1; + + if ( $tier === 100 && ( ! self::is_site_connected() || ! self::has_paid_plan_for_product() ) ) { + // in these cases, get_next_usage_tier() will return 100 + // 100 is fine as default when tiered plans are enabled, but not otherwise + $is_tier_plan = false; + } + $features = array( - 1 => array( - __( 'Artificial intelligence chatbot', 'jetpack-my-jetpack' ), - __( 'Generate text, tables, lists, and forms', 'jetpack-my-jetpack' ), - __( 'Refine the tone and content to your liking', 'jetpack-my-jetpack' ), - __( 'Get feedback about your post', 'jetpack-my-jetpack' ), - __( 'Seamless WordPress editor integration', 'jetpack-my-jetpack' ), - ), + __( 'Generate text, tables, lists, and forms', 'jetpack-my-jetpack' ), + __( 'Easily refine content to your liking', 'jetpack-my-jetpack' ), + __( 'Make your content easier to read', 'jetpack-my-jetpack' ), + __( 'Generate images with one-click', 'jetpack-my-jetpack' ), + __( 'Optimize your titles for better performance', 'jetpack-my-jetpack' ), + __( 'Priority support', 'jetpack-my-jetpack' ), ); $tiered_features = array( @@ -274,7 +291,7 @@ public static function get_features_by_usage_tier( $tier ) { sprintf( __( 'Up to %d requests per month', 'jetpack-my-jetpack' ), $tier ), ); - return isset( $features[ $tier ] ) ? $features[ $tier ] : $tiered_features; + return $is_tier_plan ? $tiered_features : $features; } /** @@ -305,11 +322,7 @@ public static function get_pricing_for_ui_by_usage_tier( $tier ) { return array(); } - // get info about the feature. - $info = self::get_ai_assistant_feature(); - - // flag to indicate if the tiers are enabled, case the info is available. - $tier_plans_enabled = ( ! is_wp_error( $info ) && isset( $info['tier-plans-enabled'] ) ) ? boolval( $info['tier-plans-enabled'] ) : false; + $tier_plans_enabled = self::are_tier_plans_enabled(); /* * when tiers are enabled and the price tier list is empty, @@ -360,6 +373,18 @@ public static function get_pricing_for_ui_by_usage_tier( $tier ) { * @return array Pricing details */ public static function get_pricing_for_ui() { + // no tiers + if ( ! self::are_tier_plans_enabled() ) { + return array_merge( + array( + 'available' => true, + 'wpcom_product_slug' => static::get_wpcom_product_slug(), + ), + // hardcoding 1 as next tier if tiers are not enabled + self::get_pricing_for_ui_by_usage_tier( 1 ) + ); + } + $next_tier = self::get_next_usage_tier(); $current_tier = self::get_current_usage_tier(); $current_call_to_action = $current_tier === 0 @@ -444,9 +469,15 @@ public static function has_paid_plan_for_product() { * @return boolean */ public static function is_upgradable() { - $has_ai_feature = static::does_site_have_feature( 'ai-assistant' ); - $current_tier = self::get_current_usage_tier(); - $next_tier = self::get_next_usage_tier(); + $has_ai_feature = static::does_site_have_feature( 'ai-assistant' ); + $tier_plans_enabled = self::are_tier_plans_enabled(); + $current_tier = self::get_current_usage_tier(); + + if ( $has_ai_feature && ! $tier_plans_enabled && $current_tier >= 1 ) { + return false; + } + + $next_tier = self::get_next_usage_tier(); // The check below is debatable, not having the feature should not flag as not upgradable. // If user is free (tier = 0), not unlimited (tier = 1) and has a next tier, then it's upgradable. @@ -543,6 +574,25 @@ public static function get_ai_assistant_feature() { return \Jetpack_AI_Helper::get_ai_assistance_feature(); } + /** + * Get the AI Assistant tiered plans status + * + * @return boolean + */ + public static function are_tier_plans_enabled() { + $info = self::get_ai_assistant_feature(); + if ( is_wp_error( $info ) ) { + // this is another faulty default value, we'll assume disabled while + // production is enabled + return false; + } + + if ( ! empty( $info ) && isset( $info['tier-plans-enabled'] ) ) { + return boolval( $info['tier-plans-enabled'] ); + } + return false; + } + /** * Checks whether the site is connected to WordPress.com. * diff --git a/projects/packages/my-jetpack/src/products/class-search.php b/projects/packages/my-jetpack/src/products/class-search.php index df81d2e98d9a1..af38892f444de 100644 --- a/projects/packages/my-jetpack/src/products/class-search.php +++ b/projects/packages/my-jetpack/src/products/class-search.php @@ -8,6 +8,7 @@ namespace Automattic\Jetpack\My_Jetpack\Products; use Automattic\Jetpack\Connection\Client; +use Automattic\Jetpack\Connection\Manager as Connection_Manager; use Automattic\Jetpack\Constants; use Automattic\Jetpack\My_Jetpack\Hybrid_Product; use Automattic\Jetpack\My_Jetpack\Wpcom_Products; @@ -222,22 +223,33 @@ public static function get_status() { */ public static function get_pricing_from_wpcom( $record_count ) { static $pricings = array(); + $connection = new Connection_Manager(); + $blog_id = \Jetpack_Options::get_option( 'id' ); if ( isset( $pricings[ $record_count ] ) ) { return $pricings[ $record_count ]; } - if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { - // For simple sites fetch the response directly. + // If the site is connected, request pricing with the blog token + if ( $blog_id ) { + $endpoint = sprintf( '/jetpack-search/pricing?record_count=%1$d&locale=%2$s', $record_count, get_user_locale() ); + + // If available in the user data, set the user's currency as one of the params + if ( $connection->is_user_connected() ) { + $user_details = $connection->get_connected_user_data(); + if ( $user_details['user_currency'] && $user_details['user_currency'] !== 'USD' ) { + $endpoint .= sprintf( '¤cy=%s', $user_details['user_currency'] ); + } + } + $response = Client::wpcom_json_api_request_as_blog( - sprintf( '/jetpack-search/pricing?record_count=%1$d&locale=%2$s', $record_count, get_user_locale() ), + $endpoint, '2', array( 'timeout' => 5 ), null, 'wpcom' ); } else { - // For non-simple sites we have to use the wp_remote_get, as connection might not be available. $response = wp_remote_get( sprintf( Constants::get_constant( 'JETPACK__WPCOM_JSON_API_BASE' ) . '/wpcom/v2/jetpack-search/pricing?record_count=%1$d&locale=%2$s', $record_count, get_user_locale() ), array( 'timeout' => 5 ) diff --git a/projects/packages/password-checker/CHANGELOG.md b/projects/packages/password-checker/CHANGELOG.md index 9867f0d7bad6a..3a071dacce933 100644 --- a/projects/packages/password-checker/CHANGELOG.md +++ b/projects/packages/password-checker/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.2] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## [0.3.1] - 2024-03-14 ### Changed - Internal updates. @@ -116,6 +120,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Use `composer update` rather than `install` in scripts, as composer.lock isn't checked in. +[0.3.2]: https://github.com/Automattic/jetpack-password-checker/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/Automattic/jetpack-password-checker/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/Automattic/jetpack-password-checker/compare/v0.2.14...v0.3.0 [0.2.14]: https://github.com/Automattic/jetpack-password-checker/compare/v0.2.13...v0.2.14 diff --git a/projects/packages/password-checker/composer.json b/projects/packages/password-checker/composer.json index 9011cbd73569c..03e8904e06c37 100644 --- a/projects/packages/password-checker/composer.json +++ b/projects/packages/password-checker/composer.json @@ -9,7 +9,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." diff --git a/projects/packages/patchwork-redefine-exit/CHANGELOG.md b/projects/packages/patchwork-redefine-exit/CHANGELOG.md index bc8026a400e15..137ca2e115edd 100644 --- a/projects/packages/patchwork-redefine-exit/CHANGELOG.md +++ b/projects/packages/patchwork-redefine-exit/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.1] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## 1.0.0 - 2024-05-22 ### Added - Initial version. [#37476] + +[1.0.1]: https://github.com/Automattic/patchwork-redefine-exit/compare/v1.0.0...v1.0.1 diff --git a/projects/packages/patchwork-redefine-exit/composer.json b/projects/packages/patchwork-redefine-exit/composer.json index bc19cd7f1bab4..9cec9c4871276 100644 --- a/projects/packages/patchwork-redefine-exit/composer.json +++ b/projects/packages/patchwork-redefine-exit/composer.json @@ -15,7 +15,7 @@ "antecedent/patchwork": "^2.1" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "autoload": { diff --git a/projects/packages/search/changelog/renovate-wordpress-monorepo b/projects/packages/phan-plugins/changelog/renovate-yoast-phpunit-polyfills-1.x similarity index 100% rename from projects/packages/search/changelog/renovate-wordpress-monorepo rename to projects/packages/phan-plugins/changelog/renovate-yoast-phpunit-polyfills-1.x diff --git a/projects/packages/phan-plugins/composer.json b/projects/packages/phan-plugins/composer.json index 4f685136c7e50..2d1eee4a9e525 100644 --- a/projects/packages/phan-plugins/composer.json +++ b/projects/packages/phan-plugins/composer.json @@ -14,7 +14,7 @@ "php": ">=8.0" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "autoload": { diff --git a/projects/packages/videopress/changelog/renovate-storybook-monorepo b/projects/packages/phpcs-filter/changelog/renovate-yoast-phpunit-polyfills-1.x similarity index 100% rename from projects/packages/videopress/changelog/renovate-storybook-monorepo rename to projects/packages/phpcs-filter/changelog/renovate-yoast-phpunit-polyfills-1.x diff --git a/projects/packages/phpcs-filter/composer.json b/projects/packages/phpcs-filter/composer.json index 1ab536775ac1b..9cf72a26cd8a4 100644 --- a/projects/packages/phpcs-filter/composer.json +++ b/projects/packages/phpcs-filter/composer.json @@ -19,7 +19,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "autoload": { "classmap": [ diff --git a/projects/packages/plans/CHANGELOG.md b/projects/packages/plans/CHANGELOG.md index 297c942148989..61eeb28e56c60 100644 --- a/projects/packages/plans/CHANGELOG.md +++ b/projects/packages/plans/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.4.8] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## [0.4.7] - 2024-05-06 ### Fixed - Correctly reference `Store_Product_List` class in `Plans::get_plans()`. [#37201] @@ -138,6 +142,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Deprecated - Moved the options class into Connection. [#24095] +[0.4.8]: https://github.com/Automattic/jetpack-plans/compare/v0.4.7...v0.4.8 [0.4.7]: https://github.com/Automattic/jetpack-plans/compare/v0.4.6...v0.4.7 [0.4.6]: https://github.com/Automattic/jetpack-plans/compare/v0.4.5...v0.4.6 [0.4.5]: https://github.com/Automattic/jetpack-plans/compare/v0.4.4...v0.4.5 diff --git a/projects/packages/plans/composer.json b/projects/packages/plans/composer.json index 43b2622c97ba6..3df7c90a705a0 100644 --- a/projects/packages/plans/composer.json +++ b/projects/packages/plans/composer.json @@ -8,7 +8,7 @@ "automattic/jetpack-connection": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/jetpack-status": "@dev", "automattic/wordbless": "@dev" diff --git a/projects/packages/plans/package.json b/projects/packages/plans/package.json index 0b89da4d5670a..ae2adc3d548af 100644 --- a/projects/packages/plans/package.json +++ b/projects/packages/plans/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-plans", - "version": "0.4.7", + "version": "0.4.8", "description": "Fetch information about Jetpack Plans from wpcom", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/plans/#readme", "bugs": { diff --git a/projects/packages/plugin-deactivation/CHANGELOG.md b/projects/packages/plugin-deactivation/CHANGELOG.md index b8c1a3a540873..59c5b3ee10414 100644 --- a/projects/packages/plugin-deactivation/CHANGELOG.md +++ b/projects/packages/plugin-deactivation/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.2] - 2024-08-29 +### Changed +- Updated package dependencies. [#39004] +- Updated package dependencies. [#39111] + ## [0.2.1] - 2024-03-15 ### Changed - Internal updates. @@ -47,6 +52,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added package to intercept plugin deactivation [#27081] +[0.2.2]: https://github.com/Automattic/jetpack-plugin-deactivation/compare/v0.2.1...v0.2.2 [0.2.1]: https://github.com/Automattic/jetpack-plugin-deactivation/compare/v0.2.0...v0.2.1 [0.2.0]: https://github.com/Automattic/jetpack-plugin-deactivation/compare/v0.1.6...v0.2.0 [0.1.6]: https://github.com/Automattic/jetpack-plugin-deactivation/compare/v0.1.5...v0.1.6 diff --git a/projects/packages/plugin-deactivation/composer.json b/projects/packages/plugin-deactivation/composer.json index 10082c038a5d9..d1b68e3bba6f7 100644 --- a/projects/packages/plugin-deactivation/composer.json +++ b/projects/packages/plugin-deactivation/composer.json @@ -8,7 +8,7 @@ "automattic/jetpack-assets": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "suggest": { diff --git a/projects/packages/plugin-deactivation/package.json b/projects/packages/plugin-deactivation/package.json index 7a21c67011c2c..9becad3698ca9 100644 --- a/projects/packages/plugin-deactivation/package.json +++ b/projects/packages/plugin-deactivation/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-plugin-deactivation", - "version": "0.2.1", + "version": "0.2.2", "description": "Intercept plugin deactivation with a dialog", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/plugin-deactivation/#readme", "bugs": { @@ -27,7 +27,7 @@ "sass-loader": "12.4.0", "tslib": "2.5.0", "typescript": "5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" } } diff --git a/projects/packages/plugin-deactivation/src/class-deactivation-handler.php b/projects/packages/plugin-deactivation/src/class-deactivation-handler.php index dd0ce7517c1be..30eb420e8e29f 100644 --- a/projects/packages/plugin-deactivation/src/class-deactivation-handler.php +++ b/projects/packages/plugin-deactivation/src/class-deactivation-handler.php @@ -21,7 +21,7 @@ class Deactivation_Handler { * * @var string */ - const PACKAGE_VERSION = '0.2.1'; + const PACKAGE_VERSION = '0.2.2'; /** * Slug of the plugin to intercept deactivation for. diff --git a/projects/packages/plugins-installer/CHANGELOG.md b/projects/packages/plugins-installer/CHANGELOG.md index d01df0842c93a..e36de6fe51a36 100644 --- a/projects/packages/plugins-installer/CHANGELOG.md +++ b/projects/packages/plugins-installer/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.4.2] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + ## [0.4.1] - 2024-08-15 ### Fixed - Fix incorrect next-version tokens in php `@since` and/or `@deprecated` docs. [#38869] @@ -90,6 +94,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fix method logic +[0.4.2]: https://github.com/Automattic/jetpack-plugins-installer/compare/v0.4.1...v0.4.2 [0.4.1]: https://github.com/Automattic/jetpack-plugins-installer/compare/v0.4.0...v0.4.1 [0.4.0]: https://github.com/Automattic/jetpack-plugins-installer/compare/v0.3.5...v0.4.0 [0.3.5]: https://github.com/Automattic/jetpack-plugins-installer/compare/v0.3.4...v0.3.5 diff --git a/projects/packages/plugins-installer/composer.json b/projects/packages/plugins-installer/composer.json index f966c337c0e1d..c747be7d43526 100644 --- a/projects/packages/plugins-installer/composer.json +++ b/projects/packages/plugins-installer/composer.json @@ -9,7 +9,7 @@ "automattic/jetpack-status": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "suggest": { diff --git a/projects/packages/post-list/CHANGELOG.md b/projects/packages/post-list/CHANGELOG.md index a95cc5aea0f25..7b8f19b7dcc68 100644 --- a/projects/packages/post-list/CHANGELOG.md +++ b/projects/packages/post-list/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.6.3] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## [0.6.2] - 2024-04-08 ### Changed - Internal updates. @@ -106,6 +110,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated the default columns displayed on the post and page list screens - Refactored thumbnail preview to function server side. All javascript removed. +[0.6.3]: https://github.com/automattic/jetpack-post-list/compare/v0.6.2...v0.6.3 [0.6.2]: https://github.com/automattic/jetpack-post-list/compare/v0.6.1...v0.6.2 [0.6.1]: https://github.com/automattic/jetpack-post-list/compare/v0.6.0...v0.6.1 [0.6.0]: https://github.com/automattic/jetpack-post-list/compare/v0.5.1...v0.6.0 diff --git a/projects/packages/post-list/composer.json b/projects/packages/post-list/composer.json index 560ca11ca9652..1276f1deec837 100644 --- a/projects/packages/post-list/composer.json +++ b/projects/packages/post-list/composer.json @@ -10,7 +10,7 @@ "require-dev": { "automattic/wordbless": "@dev", "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." diff --git a/projects/packages/post-list/src/class-post-list.php b/projects/packages/post-list/src/class-post-list.php index 7b1295f856188..d2f8daff3fac9 100644 --- a/projects/packages/post-list/src/class-post-list.php +++ b/projects/packages/post-list/src/class-post-list.php @@ -15,7 +15,7 @@ */ class Post_List { - const PACKAGE_VERSION = '0.6.2'; + const PACKAGE_VERSION = '0.6.3'; const FEATURE = 'enhanced_post_list'; /** diff --git a/projects/packages/protect-models/CHANGELOG.md b/projects/packages/protect-models/CHANGELOG.md index 8df2b48b6691b..b40f798bd160b 100644 --- a/projects/packages/protect-models/CHANGELOG.md +++ b/projects/packages/protect-models/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.1] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + ## [0.2.0] - 2024-08-09 ### Added - Add Scan History model. [#38117] @@ -13,4 +17,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Initial version. [#37864] +[0.2.1]: https://github.com/Automattic/jetpack-protect-models/compare/v0.2.0...v0.2.1 [0.2.0]: https://github.com/Automattic/jetpack-protect-models/compare/v0.1.0...v0.2.0 diff --git a/projects/packages/protect-models/composer.json b/projects/packages/protect-models/composer.json index 15d8525f360d5..abf424a59e1c4 100644 --- a/projects/packages/protect-models/composer.json +++ b/projects/packages/protect-models/composer.json @@ -7,7 +7,7 @@ "php": ">=7.0" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "0.4.2" }, diff --git a/projects/packages/protect-models/package.json b/projects/packages/protect-models/package.json index 5754994c2d382..599a6aa6abfdb 100644 --- a/projects/packages/protect-models/package.json +++ b/projects/packages/protect-models/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-protect-models", - "version": "0.2.0", + "version": "0.2.1", "description": "This package contains the models used in Protect. ", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/protect-models/#readme", "bugs": { diff --git a/projects/packages/protect-models/src/class-protect-models.php b/projects/packages/protect-models/src/class-protect-models.php index b5b4128154ba6..a479f90a6fb21 100644 --- a/projects/packages/protect-models/src/class-protect-models.php +++ b/projects/packages/protect-models/src/class-protect-models.php @@ -12,5 +12,5 @@ */ class Protect_Models { - const PACKAGE_VERSION = '0.2.0'; + const PACKAGE_VERSION = '0.2.1'; } diff --git a/projects/packages/protect-status/CHANGELOG.md b/projects/packages/protect-status/CHANGELOG.md index 650a85abbb2cc..a40887a960fdb 100644 --- a/projects/packages/protect-status/CHANGELOG.md +++ b/projects/packages/protect-status/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.3] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + +## [0.1.2] - 2024-08-19 +### Changed +- Internal updates. + ## [0.1.1] - 2024-08-09 ### Changed - Update dependencies. @@ -16,4 +24,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Updated package dependencies. [#37894] +[0.1.3]: https://github.com/Automattic/jetpack-protect-status/compare/v0.1.2...v0.1.3 +[0.1.2]: https://github.com/Automattic/jetpack-protect-status/compare/v0.1.1...v0.1.2 [0.1.1]: https://github.com/Automattic/jetpack-protect-status/compare/v0.1.0...v0.1.1 diff --git a/projects/packages/protect-status/changelog/renovate-lock-file-maintenance b/projects/packages/protect-status/changelog/renovate-lock-file-maintenance deleted file mode 100644 index 3109d07526368..0000000000000 --- a/projects/packages/protect-status/changelog/renovate-lock-file-maintenance +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: changed -Comment: Update Phan baseline. - - diff --git a/projects/packages/protect-status/composer.json b/projects/packages/protect-status/composer.json index d81e282a0cd45..d25429053966e 100644 --- a/projects/packages/protect-status/composer.json +++ b/projects/packages/protect-status/composer.json @@ -12,7 +12,7 @@ "automattic/jetpack-plans": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master" }, diff --git a/projects/packages/protect-status/package.json b/projects/packages/protect-status/package.json index 8a4264206e4d6..5ba6a5420f228 100644 --- a/projects/packages/protect-status/package.json +++ b/projects/packages/protect-status/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-protect-status", - "version": "0.1.2-alpha", + "version": "0.1.3", "description": "This package contains the Protect Status API functionality to retrieve a site's scan status (WordPress, Themes, and Plugins threats).", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/protect-status/#readme", "bugs": { diff --git a/projects/packages/protect-status/src/class-status.php b/projects/packages/protect-status/src/class-status.php index ffb8a58bcfee4..5d386b3202ddd 100644 --- a/projects/packages/protect-status/src/class-status.php +++ b/projects/packages/protect-status/src/class-status.php @@ -15,7 +15,7 @@ */ class Status { - const PACKAGE_VERSION = '0.1.2-alpha'; + const PACKAGE_VERSION = '0.1.3'; /** * Name of the option where status is stored * diff --git a/projects/packages/publicize/CHANGELOG.md b/projects/packages/publicize/CHANGELOG.md index e0ce0794f1ee2..7a33c43a78778 100644 --- a/projects/packages/publicize/CHANGELOG.md +++ b/projects/packages/publicize/CHANGELOG.md @@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.50.1] - 2024-08-29 +### Added +- Added share status info to Jetpack sidebar [#39073] + +### Changed +- Updated package dependencies. [#39111] + +## [0.50.0] - 2024-08-26 +### Added +- Added the new feature flag for the social share status [#39015] + +### Changed +- Social: Migrated shares data to the new script data [#38988] +- Updated package dependencies. [#39004] + +## [0.49.2] - 2024-08-21 +### Changed +- Social; Migrated the API paths from initial state to the new script data [#38962] + +## [0.49.1] - 2024-08-19 +### Changed +- Social: Migrated services list to the initial state. [#38924] +- Updated package dependencies. [#38662] + +### Fixed +- Fix incorrect next-version tokens in php `@since` and/or `@deprecated` docs. [#38869] +- Social: Fixed connection services list crash on simple sites. [#38954] + ## [0.49.0] - 2024-08-12 ### Changed - Open Graph Meta Tags: Stopped handling Fediverse tags from Publicize package. [#38809] @@ -645,6 +673,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated package dependencies. - Update package.json metadata. +[0.50.1]: https://github.com/Automattic/jetpack-publicize/compare/v0.50.0...v0.50.1 +[0.50.0]: https://github.com/Automattic/jetpack-publicize/compare/v0.49.2...v0.50.0 +[0.49.2]: https://github.com/Automattic/jetpack-publicize/compare/v0.49.1...v0.49.2 +[0.49.1]: https://github.com/Automattic/jetpack-publicize/compare/v0.49.0...v0.49.1 [0.49.0]: https://github.com/Automattic/jetpack-publicize/compare/v0.48.0...v0.49.0 [0.48.0]: https://github.com/Automattic/jetpack-publicize/compare/v0.47.4...v0.48.0 [0.47.4]: https://github.com/Automattic/jetpack-publicize/compare/v0.47.3...v0.47.4 diff --git a/projects/packages/publicize/changelog/add-social-share-status-shares-modal b/projects/packages/publicize/changelog/add-social-share-status-shares-modal new file mode 100644 index 0000000000000..bf7d182e6814d --- /dev/null +++ b/projects/packages/publicize/changelog/add-social-share-status-shares-modal @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Add share status log modal to published posts diff --git a/projects/packages/publicize/changelog/fix-incorrect-next-version-tokens b/projects/packages/publicize/changelog/fix-incorrect-next-version-tokens deleted file mode 100644 index 773098e4cd961..0000000000000 --- a/projects/packages/publicize/changelog/fix-incorrect-next-version-tokens +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fixed - -Fix incorrect next-version tokens in php `@since` and/or `@deprecated` docs. diff --git a/projects/packages/publicize/composer.json b/projects/packages/publicize/composer.json index 3f582e71cdeb3..326578c1a8e53 100644 --- a/projects/packages/publicize/composer.json +++ b/projects/packages/publicize/composer.json @@ -13,7 +13,7 @@ "automattic/jetpack-plans": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "0.4.2" }, @@ -68,7 +68,7 @@ "link-template": "https://github.com/Automattic/jetpack-publicize/compare/v${old}...v${new}" }, "branch-alias": { - "dev-trunk": "0.49.x-dev" + "dev-trunk": "0.50.x-dev" } }, "config": { diff --git a/projects/packages/publicize/package.json b/projects/packages/publicize/package.json index a8efc7eadcd9b..1b8f123ea551a 100644 --- a/projects/packages/publicize/package.json +++ b/projects/packages/publicize/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-publicize", - "version": "0.49.1-alpha", + "version": "0.50.1", "description": "Publicize makes it easy to share your site’s posts on several social media networks automatically when you publish a new post.", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/publicize/#readme", "bugs": { @@ -30,7 +30,7 @@ "@automattic/jetpack-webpack-config": "workspace:*", "@wordpress/browserslist-config": "6.5.0", "concurrently": "7.6.0", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "dependencies": { diff --git a/projects/packages/publicize/src/class-publicize-script-data.php b/projects/packages/publicize/src/class-publicize-script-data.php index d688b958f37e6..96f4d3d4934b0 100644 --- a/projects/packages/publicize/src/class-publicize-script-data.php +++ b/projects/packages/publicize/src/class-publicize-script-data.php @@ -7,8 +7,12 @@ namespace Automattic\Jetpack\Publicize; +use Automattic\Jetpack\Connection\Client; +use Automattic\Jetpack\Connection\Manager; use Automattic\Jetpack\Current_Plan; use Automattic\Jetpack\Publicize\Publicize_Utils as Utils; +use Automattic\Jetpack\Status\Host; +use Jetpack_Options; /** * Publicize_Script_Data class. @@ -28,6 +32,11 @@ public static function publicize() { */ global $publicize; + if ( ! $publicize && function_exists( 'publicize_init' ) ) { + // @phan-suppress-next-line PhanUndeclaredFunction - phan is dumb not to see the function_exists check + publicize_init(); + } + return $publicize; } @@ -47,7 +56,7 @@ public static function set_admin_script_data( $data ) { $data['social'] = self::get_admin_script_data(); - if ( empty( $data['site']['plan'] ) ) { + if ( empty( $data['site']['plan']['product_slug'] ) ) { $data['site']['plan'] = Current_Plan::get(); } @@ -72,21 +81,33 @@ public static function get_admin_script_data() { } $basic_data = array( + 'api_paths' => array(), 'is_publicize_enabled' => Utils::is_publicize_active(), 'feature_flags' => self::get_feature_flags(), + 'supported_services' => array(), + 'shares_data' => array(), ); - if ( ! Utils::is_publicize_active() || ! Utils::is_connected() ) { + if ( ! Utils::is_publicize_active() ) { + return $basic_data; + } + + // Simple sites don't have a user connection. + $is_publicize_configured = ( new Host() )->is_wpcom_simple() || Utils::is_connected(); + + if ( ! $is_publicize_configured ) { return $basic_data; } return array_merge( $basic_data, array( + 'api_paths' => self::get_api_paths(), + 'supported_services' => self::get_supported_services(), + 'shares_data' => self::get_shares_data(), /** * 'store' => self::get_store_script_data(), * 'urls' => self::get_urls(), - * 'shares_data' => self::get_shares_data(), */ ) ); @@ -133,4 +154,64 @@ public static function has_feature_flag( $feature ): bool { return Current_Plan::supports( 'social-' . $feature ); } + + /** + * Get the shares data. + * + * @return ?array + */ + public static function get_shares_data() { + return self::publicize()->get_publicize_shares_info( Jetpack_Options::get_option( 'id' ) ); + } + + /** + * Get the list of supported Publicize services. + * + * @return array List of external services and their settings. + */ + public static function get_supported_services() { + $site_id = Manager::get_site_id(); + if ( is_wp_error( $site_id ) ) { + return array(); + } + $path = sprintf( '/sites/%d/external-services', $site_id ); + $response = Client::wpcom_json_api_request_as_user( $path ); + if ( is_wp_error( $response ) ) { + return array(); + } + $body = json_decode( wp_remote_retrieve_body( $response ) ); + + $services = $body->services ?? array(); + + return array_values( + array_filter( + (array) $services, + function ( $service ) { + return isset( $service->type ) && 'publicize' === $service->type; + } + ) + ); + } + + /** + * Get the API paths. + * + * @return array + */ + public static function get_api_paths() { + + $is_simple_site = ( new Host() )->is_wpcom_simple(); + + if ( $is_simple_site ) { + return array( + 'refreshConnections' => '/wpcom/v2/publicize/connection-test-results', + 'resharePost' => '/wpcom/v2/posts/{postId}/publicize', + ); + } + + return array( + 'refreshConnections' => '/jetpack/v4/publicize/connections?test_connections=1', + 'resharePost' => '/jetpack/v4/publicize/{postId}', + ); + } } diff --git a/projects/packages/publicize/src/class-rest-controller.php b/projects/packages/publicize/src/class-rest-controller.php index 474eb0a2b0e79..95b4205e476f9 100644 --- a/projects/packages/publicize/src/class-rest-controller.php +++ b/projects/packages/publicize/src/class-rest-controller.php @@ -188,6 +188,18 @@ public function register_rest_routes() { ), ) ); + + register_rest_route( + 'jetpack/v4', + '/social/share-status/(?P\d+)', + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_post_share_status' ), + 'permission_callback' => array( $this, 'require_author_privilege_callback' ), + ), + ) + ); } /** @@ -650,4 +662,27 @@ public function update_post_shares( $request ) { array( 'status' => 500 ) ); } + + /** + * Gets the share status for a post. + * + * GET `jetpack/v4/social/share-status/` + * + * @param WP_REST_Request $request The request object. + */ + public function get_post_share_status( WP_REST_Request $request ) { + $post_id = $request->get_param( 'post_id' ); + + $shares = get_post_meta( $post_id, self::SOCIAL_SHARES_POST_META_KEY, true ); + + // If the data is not an array, it means that sharing is not done yet. + $done = is_array( $shares ); + + return rest_ensure_response( + array( + 'shares' => $done ? $shares : array(), + 'done' => $done, + ) + ); + } } diff --git a/projects/packages/publicize/src/jetpack-social-settings/class-settings.php b/projects/packages/publicize/src/jetpack-social-settings/class-settings.php index ba80820206a49..c6ede04471f17 100644 --- a/projects/packages/publicize/src/jetpack-social-settings/class-settings.php +++ b/projects/packages/publicize/src/jetpack-social-settings/class-settings.php @@ -7,9 +7,9 @@ namespace Automattic\Jetpack\Publicize\Jetpack_Social_Settings; -use Automattic\Jetpack\Connection\Client; use Automattic\Jetpack\Connection\Manager; use Automattic\Jetpack\Modules; +use Automattic\Jetpack\Publicize\Publicize_Script_Data; use Automattic\Jetpack\Publicize\Social_Image_Generator\Templates; /** @@ -52,6 +52,11 @@ class Settings { 'feature_name' => 'editor-preview', 'variable_name' => 'useEditorPreview', ), + array( + 'flag_name' => 'share_status', + 'feature_name' => 'share-status', + 'variable_name' => 'useShareStatus', + ), ); /** @@ -211,7 +216,7 @@ public function get_initial_state() { $settings['connectionData'] = array( 'connections' => $publicize->get_all_connections_for_user(), 'adminUrl' => esc_url_raw( $publicize->publicize_connections_url( 'jetpack-social-connections-admin-page' ) ), - 'services' => $this->get_services(), + 'services' => Publicize_Script_Data::get_supported_services(), ); $settings['is_publicize_enabled'] = true; @@ -231,35 +236,6 @@ public function get_initial_state() { return $settings; } - /** - * Get the list of supported Publicize services. - * - * @return array List of external services and their settings. - */ - public function get_services() { - $site_id = Manager::get_site_id(); - if ( is_wp_error( $site_id ) ) { - return array(); - } - $path = sprintf( '/sites/%d/external-services', $site_id ); - $response = Client::wpcom_json_api_request_as_user( $path ); - if ( is_wp_error( $response ) ) { - return array(); - } - $body = json_decode( wp_remote_retrieve_body( $response ) ); - - $services = $body->services ?? array(); - - return array_values( - array_filter( - (array) $services, - function ( $service ) { - return isset( $service->type ) && 'publicize' === $service->type; - } - ) - ); - } - /** * Update the settings. * diff --git a/projects/packages/publicize/webpack.config.js b/projects/packages/publicize/webpack.config.js index 123017cff7b57..bb472b1e9cc68 100644 --- a/projects/packages/publicize/webpack.config.js +++ b/projects/packages/publicize/webpack.config.js @@ -4,8 +4,8 @@ const jetpackWebpackConfig = require( '@automattic/jetpack-webpack-config/webpac module.exports = [ { entry: { - [ 'classic-editor-share-limits' ]: './src/js/classic-editor-share-limits.js', - [ 'classic-editor-connections' ]: './src/js/classic-editor-connections.js', + 'classic-editor-share-limits': './src/js/classic-editor-share-limits.js', + 'classic-editor-connections': './src/js/classic-editor-connections.js', }, mode: jetpackWebpackConfig.mode, devtool: jetpackWebpackConfig.devtool, diff --git a/projects/packages/redirect/CHANGELOG.md b/projects/packages/redirect/CHANGELOG.md index 36f315ca38f21..bfbc04631fb50 100644 --- a/projects/packages/redirect/CHANGELOG.md +++ b/projects/packages/redirect/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.3] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## [2.0.2] - 2024-04-25 ### Changed - Update dependencies. @@ -201,6 +205,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Create Jetpack Redirect package +[2.0.3]: https://github.com/Automattic/jetpack-redirect/compare/v2.0.2...v2.0.3 [2.0.2]: https://github.com/Automattic/jetpack-redirect/compare/v2.0.1...v2.0.2 [2.0.1]: https://github.com/Automattic/jetpack-redirect/compare/v2.0.0...v2.0.1 [2.0.0]: https://github.com/Automattic/jetpack-redirect/compare/v1.7.27...v2.0.0 diff --git a/projects/packages/redirect/composer.json b/projects/packages/redirect/composer.json index 58d93c054f80e..162075083616c 100644 --- a/projects/packages/redirect/composer.json +++ b/projects/packages/redirect/composer.json @@ -9,7 +9,7 @@ }, "require-dev": { "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "suggest": { diff --git a/projects/packages/roles/CHANGELOG.md b/projects/packages/roles/CHANGELOG.md index 851aa94962e1b..71a54688f2e5d 100644 --- a/projects/packages/roles/CHANGELOG.md +++ b/projects/packages/roles/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.3] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## [2.0.2] - 2024-04-22 ### Changed - Internal updates. @@ -167,6 +171,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Jetpack DNA: Introduce a Roles package +[2.0.3]: https://github.com/Automattic/jetpack-roles/compare/v2.0.2...v2.0.3 [2.0.2]: https://github.com/Automattic/jetpack-roles/compare/v2.0.1...v2.0.2 [2.0.1]: https://github.com/Automattic/jetpack-roles/compare/v2.0.0...v2.0.1 [2.0.0]: https://github.com/Automattic/jetpack-roles/compare/v1.4.25...v2.0.0 diff --git a/projects/packages/roles/composer.json b/projects/packages/roles/composer.json index 2fd0f3a48a1a9..bd6a693cddcc7 100644 --- a/projects/packages/roles/composer.json +++ b/projects/packages/roles/composer.json @@ -8,7 +8,7 @@ }, "require-dev": { "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "suggest": { diff --git a/projects/packages/scheduled-updates/CHANGELOG.md b/projects/packages/scheduled-updates/CHANGELOG.md index 6b8f35284c19d..a0f22e14b4671 100644 --- a/projects/packages/scheduled-updates/CHANGELOG.md +++ b/projects/packages/scheduled-updates/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.13.2] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + +## [0.13.1] - 2024-08-19 +### Changed +- Internal updates. + ## [0.13.0] - 2024-05-27 ### Added - Scheduled Updates: add check for staging sites. [#37449] @@ -185,6 +193,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Generate initial package for Scheduled Updates [#35796] +[0.13.2]: https://github.com/Automattic/scheduled-updates/compare/v0.13.1...v0.13.2 +[0.13.1]: https://github.com/Automattic/scheduled-updates/compare/v0.13.0...v0.13.1 [0.13.0]: https://github.com/Automattic/scheduled-updates/compare/v0.12.2...v0.13.0 [0.12.2]: https://github.com/Automattic/scheduled-updates/compare/v0.12.1...v0.12.2 [0.12.1]: https://github.com/Automattic/scheduled-updates/compare/v0.12.0...v0.12.1 diff --git a/projects/packages/scheduled-updates/changelog/renovate-lock-file-maintenance b/projects/packages/scheduled-updates/changelog/renovate-lock-file-maintenance deleted file mode 100644 index b9e1400573926..0000000000000 --- a/projects/packages/scheduled-updates/changelog/renovate-lock-file-maintenance +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: changed -Comment: Pass bool to `update_option()` `$autoload`. No change to functionality. - - diff --git a/projects/packages/scheduled-updates/composer.json b/projects/packages/scheduled-updates/composer.json index b22c4ea27cf30..4b6eb95e5e11c 100644 --- a/projects/packages/scheduled-updates/composer.json +++ b/projects/packages/scheduled-updates/composer.json @@ -12,7 +12,7 @@ "automattic/jetpack-connection": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev", "php-mock/php-mock-phpunit": "^2.10" diff --git a/projects/packages/scheduled-updates/src/class-scheduled-updates.php b/projects/packages/scheduled-updates/src/class-scheduled-updates.php index 613a02a84d383..b9e421ea31a5e 100644 --- a/projects/packages/scheduled-updates/src/class-scheduled-updates.php +++ b/projects/packages/scheduled-updates/src/class-scheduled-updates.php @@ -20,7 +20,7 @@ class Scheduled_Updates { * * @var string */ - const PACKAGE_VERSION = '0.13.1-alpha'; + const PACKAGE_VERSION = '0.13.2'; /** * The cron event hook for the scheduled plugins update. diff --git a/projects/packages/schema/.phan/baseline.php b/projects/packages/schema/.phan/baseline.php index ec13b03ff1603..512768d303724 100644 --- a/projects/packages/schema/.phan/baseline.php +++ b/projects/packages/schema/.phan/baseline.php @@ -12,17 +12,14 @@ // PhanNonClassMethodCall : 10+ occurrences // PhanParamTooFew : 5 occurrences // PhanTypeMismatchArgumentProbablyReal : 2 occurrences - // PhanImpossibleCondition : 1 occurrence // PhanImpossibleTypeComparison : 1 occurrence // PhanParamTooMany : 1 occurrence - // PhanRedundantCondition : 1 occurrence // PhanTypeMismatchArgumentNullable : 1 occurrence // PhanTypeMismatchReturn : 1 occurrence // Currently, file_suppressions and directory_suppressions are the only supported suppressions 'file_suppressions' => [ 'src/class-schema.php' => ['PhanParamTooMany'], - 'src/class-utils.php' => ['PhanImpossibleCondition', 'PhanRedundantCondition'], 'src/types/class-type-assoc-array.php' => ['PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchReturn'], 'src/types/class-type-string.php' => ['PhanImpossibleTypeComparison'], 'tests/php/integration/test-integration-fallback-values.php' => ['PhanNonClassMethodCall'], diff --git a/projects/packages/schema/CHANGELOG.md b/projects/packages/schema/CHANGELOG.md index 721294abd00ad..4f89809afb93f 100644 --- a/projects/packages/schema/CHANGELOG.md +++ b/projects/packages/schema/CHANGELOG.md @@ -5,3 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.1] - 2024-08-29 +### Changed +- Cleanup utils [#39025] + +## 0.1.0 - 2024-08-22 +### Added +- Initial version. [#38563] + +### Changed +- Updated package dependencies. [#39004] + +[0.1.1]: https://github.com/Automattic/jetpack-schema/compare/v0.1.0...v0.1.1 diff --git a/projects/packages/schema/changelog/initial-version b/projects/packages/schema/changelog/initial-version deleted file mode 100644 index fb1837c901e51..0000000000000 --- a/projects/packages/schema/changelog/initial-version +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: added - -Initial version. diff --git a/projects/packages/schema/composer.json b/projects/packages/schema/composer.json index e5df1e12b6f10..5208e5e1a3b1a 100644 --- a/projects/packages/schema/composer.json +++ b/projects/packages/schema/composer.json @@ -7,7 +7,7 @@ "php": ">=7.0" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master" }, diff --git a/projects/packages/schema/src/class-schema.php b/projects/packages/schema/src/class-schema.php index a4effdd8799ee..fe3b30f6e0be1 100644 --- a/projects/packages/schema/src/class-schema.php +++ b/projects/packages/schema/src/class-schema.php @@ -65,7 +65,7 @@ * $parsed_data = $my_schema->parse($input_data); */ class Schema { - const PACKAGE_VERSION = '0.1.0-alpha'; + const PACKAGE_VERSION = '0.1.1'; public static function as_string() { return new Schema_Parser( new Type_String() ); diff --git a/projects/packages/schema/src/class-utils.php b/projects/packages/schema/src/class-utils.php index c2a6e2611df7b..ad129291b5757 100644 --- a/projects/packages/schema/src/class-utils.php +++ b/projects/packages/schema/src/class-utils.php @@ -44,22 +44,6 @@ public static function set_mode( $mode ) { self::$mode = $mode; } - public static function debug_disable( $name ) { - // phpcs:ignore WordPress.Security.NonceVerification.Recommended - if ( isset( $_GET['ds-debug-disable'] ) && ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) ) { - // phpcs:ignore WordPress.Security.NonceVerification.Recommended - $values = explode( ',', sanitize_key( $_GET['ds-debug-disable'] ) ); - if ( ! $values || ! is_array( $values ) ) { - return false; - } - if ( $values === array( 'all' ) ) { - return true; - } - return in_array( $name, $values, true ); - } - return false; - } - /** * The schema generated by the parser can be very verbose and hard to read. * This is a helper utility that converts the schema into a more human-readable format. diff --git a/projects/packages/search/CHANGELOG.md b/projects/packages/search/CHANGELOG.md index 949269b95efda..c0adaef065a3f 100644 --- a/projects/packages/search/CHANGELOG.md +++ b/projects/packages/search/CHANGELOG.md @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.44.17] - 2024-08-26 +### Changed +- Updated package dependencies. [#39004] + +## [0.44.16] - 2024-08-21 +### Changed +- Internal updates. + +## [0.44.15] - 2024-08-19 +### Changed +- Update dependencies. [#38861] [#38662] + +### Fixed +- Fix incorrect next-version tokens in php `@since` and/or `@deprecated` docs. [#38869] + ## [0.44.14] - 2024-08-05 ### Changed - React compatibility: Changing ReactDOM.render usage to be via ReactDOM.createRoot. [#38649] @@ -996,6 +1011,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated package dependencies. - Update PHPUnit configs to include just what needs coverage rather than include everything then try to exclude stuff that doesn't. +[0.44.17]: https://github.com/Automattic/jetpack-search/compare/v0.44.16...v0.44.17 +[0.44.16]: https://github.com/Automattic/jetpack-search/compare/v0.44.15...v0.44.16 +[0.44.15]: https://github.com/Automattic/jetpack-search/compare/v0.44.14...v0.44.15 [0.44.14]: https://github.com/Automattic/jetpack-search/compare/v0.44.13...v0.44.14 [0.44.13]: https://github.com/Automattic/jetpack-search/compare/v0.44.12...v0.44.13 [0.44.12]: https://github.com/Automattic/jetpack-search/compare/v0.44.11...v0.44.12 diff --git a/projects/packages/search/changelog/add-allow-customizing-highlighted-fields b/projects/packages/search/changelog/add-allow-customizing-highlighted-fields new file mode 100644 index 0000000000000..bc31a86a45be0 --- /dev/null +++ b/projects/packages/search/changelog/add-allow-customizing-highlighted-fields @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Search: allow customizing highlighted fields diff --git a/projects/packages/search/changelog/add-more-eslint-rules b/projects/packages/search/changelog/add-more-eslint-rules new file mode 100644 index 0000000000000..2b32cb03e644c --- /dev/null +++ b/projects/packages/search/changelog/add-more-eslint-rules @@ -0,0 +1,5 @@ +Significance: patch +Type: fixed +Comment: Fix new eslint sniffs. Should be no change in functionality. + + diff --git a/projects/packages/search/changelog/fix-incorrect-next-version-tokens b/projects/packages/search/changelog/fix-incorrect-next-version-tokens deleted file mode 100644 index 773098e4cd961..0000000000000 --- a/projects/packages/search/changelog/fix-incorrect-next-version-tokens +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fixed - -Fix incorrect next-version tokens in php `@since` and/or `@deprecated` docs. diff --git a/projects/packages/search/changelog/fix-paid-requests-localization b/projects/packages/search/changelog/fix-paid-requests-localization new file mode 100644 index 0000000000000..7e14e4a1878d1 --- /dev/null +++ b/projects/packages/search/changelog/fix-paid-requests-localization @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Search: Use the user's locale when formatting request limits. diff --git a/projects/packages/search/changelog/force-a-release b/projects/packages/search/changelog/force-a-release deleted file mode 100644 index d4ad6c7cc3379..0000000000000 --- a/projects/packages/search/changelog/force-a-release +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: changed - -Update dependencies. diff --git a/projects/packages/search/changelog/renovate-lock-file-maintenance b/projects/packages/search/changelog/renovate-lock-file-maintenance deleted file mode 100644 index 3109d07526368..0000000000000 --- a/projects/packages/search/changelog/renovate-lock-file-maintenance +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: changed -Comment: Update Phan baseline. - - diff --git a/projects/packages/wordads/changelog/renovate-wordpress-monorepo b/projects/packages/search/changelog/renovate-npm-webpack-vulnerability similarity index 100% rename from projects/packages/wordads/changelog/renovate-wordpress-monorepo rename to projects/packages/search/changelog/renovate-npm-webpack-vulnerability diff --git a/projects/packages/search/changelog/update-jetpack-menu-item-order b/projects/packages/search/changelog/update-jetpack-menu-item-order new file mode 100644 index 0000000000000..4bfbd859ba2bf --- /dev/null +++ b/projects/packages/search/changelog/update-jetpack-menu-item-order @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Admin menu: change order of Jetpack sub-menu items diff --git a/projects/packages/search/composer.json b/projects/packages/search/composer.json index f89d7c84a7fe3..dd9d387d7468c 100644 --- a/projects/packages/search/composer.json +++ b/projects/packages/search/composer.json @@ -15,7 +15,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/wordbless": "0.4.2" }, "suggest": { diff --git a/projects/packages/search/package.json b/projects/packages/search/package.json index f84b09df323e7..c370738adde1b 100644 --- a/projects/packages/search/package.json +++ b/projects/packages/search/package.json @@ -1,6 +1,6 @@ { "name": "jetpack-search", - "version": "0.44.15-alpha", + "version": "0.44.17", "description": "Package for Jetpack Search products", "main": "main.js", "directories": { @@ -91,7 +91,7 @@ "sass": "1.64.1", "sass-loader": "12.4.0", "size-limit": "11.1.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "browserslist": [ diff --git a/projects/packages/search/src/class-package.php b/projects/packages/search/src/class-package.php index 5864b26c66ff6..5bbf16dd606e9 100644 --- a/projects/packages/search/src/class-package.php +++ b/projects/packages/search/src/class-package.php @@ -11,7 +11,7 @@ * Search package general information */ class Package { - const VERSION = '0.44.15-alpha'; + const VERSION = '0.44.17'; const SLUG = 'search'; /** diff --git a/projects/packages/search/src/customberg/components/app-wrapper/index.jsx b/projects/packages/search/src/customberg/components/app-wrapper/index.jsx index ec18ad43222d2..91386e378eacd 100644 --- a/projects/packages/search/src/customberg/components/app-wrapper/index.jsx +++ b/projects/packages/search/src/customberg/components/app-wrapper/index.jsx @@ -27,7 +27,7 @@ const PROPS_FROM_WINDOW = { /** * Component for wrapping Jetpack Instant Search application. * - * @returns {Element} component instance + * @return {Element} component instance */ export default function AppWrapper() { const { diff --git a/projects/packages/search/src/customberg/components/header/index.jsx b/projects/packages/search/src/customberg/components/header/index.jsx index 30c62d367ce06..5c783f2082074 100644 --- a/projects/packages/search/src/customberg/components/header/index.jsx +++ b/projects/packages/search/src/customberg/components/header/index.jsx @@ -7,9 +7,9 @@ import './styles.scss'; /** * Component for showing the Gutenberg-style header. * - * @param {object} props - component properties. + * @param {object} props - component properties. * @param {Function} props.enableSidebar - Enables the sidebar upon invocation. - * @returns {Element} component instance + * @return {Element} component instance */ function Header( { enableSidebar } ) { // translators: Product name 'Jetpack Search' should not be translated diff --git a/projects/packages/search/src/customberg/components/layout/index.jsx b/projects/packages/search/src/customberg/components/layout/index.jsx index 3a96b4a95e469..002e5b8382408 100644 --- a/projects/packages/search/src/customberg/components/layout/index.jsx +++ b/projects/packages/search/src/customberg/components/layout/index.jsx @@ -10,7 +10,7 @@ import './styles.scss'; /** * Top-level component for the Gutenberg-style Jetpack Search customization interface. * - * @returns {Element} component instance + * @return {Element} component instance */ export default function Layout() { const { isLargeViewport } = useSelect( select => ( { diff --git a/projects/packages/search/src/customberg/components/layout/interface.jsx b/projects/packages/search/src/customberg/components/layout/interface.jsx index c1f2af139aba7..3a1e0e5d2682c 100644 --- a/projects/packages/search/src/customberg/components/layout/interface.jsx +++ b/projects/packages/search/src/customberg/components/layout/interface.jsx @@ -8,7 +8,7 @@ import './styles.scss'; * Wraps the InterfaceSkeleton component with necessary parameters. * * @param {object} props - component properties. - * @returns {Element} component instance + * @return {Element} component instance */ export default function Interface( props ) { const { enabledSidebarName, enableSidebar, disableSidebar } = props; diff --git a/projects/packages/search/src/customberg/components/save-button/index.jsx b/projects/packages/search/src/customberg/components/save-button/index.jsx index 97f42027077ce..95f2475abcb44 100644 --- a/projects/packages/search/src/customberg/components/save-button/index.jsx +++ b/projects/packages/search/src/customberg/components/save-button/index.jsx @@ -7,7 +7,7 @@ import './styles.scss'; /** * Component for saving pending entity record changes. * - * @returns {Element} component instance + * @return {Element} component instance */ export default function SaveButton() { const { isSaving, hasUnsavedEdits, saveRecords } = useEntityRecordState(); diff --git a/projects/packages/search/src/customberg/components/sidebar/color-control.jsx b/projects/packages/search/src/customberg/components/sidebar/color-control.jsx index a1090708da952..3c9541afe6422 100644 --- a/projects/packages/search/src/customberg/components/sidebar/color-control.jsx +++ b/projects/packages/search/src/customberg/components/sidebar/color-control.jsx @@ -16,11 +16,11 @@ const DEFAULT_COLORS = [ /** * Color control for use in SidebarOptions tab. * - * @param {object} props - component properties. - * @param {boolean} props.disabled - disables the control. + * @param {object} props - component properties. + * @param {boolean} props.disabled - disables the control. * @param {Function} props.onChange - invoked with a new color when the selected color has changed. - * @param {string} props.value - color value prefixed with #. - * @returns {Element} component instance + * @param {string} props.value - color value prefixed with #. + * @return {Element} component instance */ export default function ColorControl( { disabled, value, onChange } ) { const colors = useSelect( select => { diff --git a/projects/packages/search/src/customberg/components/sidebar/excluded-post-types-control.jsx b/projects/packages/search/src/customberg/components/sidebar/excluded-post-types-control.jsx index 4616f8483de54..6e52bac68f12d 100644 --- a/projects/packages/search/src/customberg/components/sidebar/excluded-post-types-control.jsx +++ b/projects/packages/search/src/customberg/components/sidebar/excluded-post-types-control.jsx @@ -11,12 +11,12 @@ const VALID_POST_TYPES = global.JetpackInstantSearchOptions.postTypes; /** * Control for modifying excluded post types. * - * @param {object} props - component properties. - * @param {boolean} props.disabled - disables the control. - * @param {Function} props.onChange - invoked with new array of excluded post types when the selection has been updated. - * @param {object} props.validPostTypes - { [ postTypeId ]: { name: string, singular_name: string } }. - * @param {string} props.value - excluded post types as a CSV. - * @returns {Element} component instance + * @param {object} props - component properties. + * @param {boolean} props.disabled - disables the control. + * @param {Function} props.onChange - invoked with new array of excluded post types when the selection has been updated. + * @param {object} props.validPostTypes - { [ postTypeId ]: { name: string, singular_name: string } }. + * @param {string} props.value - excluded post types as a CSV. + * @return {Element} component instance */ export default function ExcludedPostTypesControl( { disabled, diff --git a/projects/packages/search/src/customberg/components/sidebar/index.jsx b/projects/packages/search/src/customberg/components/sidebar/index.jsx index d56c8067cc222..503e8ac235758 100644 --- a/projects/packages/search/src/customberg/components/sidebar/index.jsx +++ b/projects/packages/search/src/customberg/components/sidebar/index.jsx @@ -12,7 +12,7 @@ import './styles.scss'; * Sidebar implemented via ComplementaryArea component. Renders using the slot/fill paradigm. * * @param {object} props - component properties. - * @returns {Element} component instance + * @return {Element} component instance */ export default function Sidebar( props ) { const { enabledSidebarName, enableSidebar, disableSidebar } = props; diff --git a/projects/packages/search/src/customberg/components/sidebar/sidebar-description.jsx b/projects/packages/search/src/customberg/components/sidebar/sidebar-description.jsx index 4720d87d3ca4b..25e0f3142648e 100644 --- a/projects/packages/search/src/customberg/components/sidebar/sidebar-description.jsx +++ b/projects/packages/search/src/customberg/components/sidebar/sidebar-description.jsx @@ -7,7 +7,7 @@ import { svg as jetpackColophonSvg } from 'instant-search/components/jetpack-col /** * Description tab for the sidebar. * - * @returns {Element} component instance + * @return {Element} component instance */ export default function SidebarDescription() { return ( diff --git a/projects/packages/search/src/customberg/components/sidebar/sidebar-options.jsx b/projects/packages/search/src/customberg/components/sidebar/sidebar-options.jsx index e30abe71c5d1a..48c9c819f50f2 100644 --- a/projects/packages/search/src/customberg/components/sidebar/sidebar-options.jsx +++ b/projects/packages/search/src/customberg/components/sidebar/sidebar-options.jsx @@ -22,7 +22,7 @@ const { isFreePlan = false } = window[ SERVER_OBJECT_NAME ]; /** * Customization/configuration tab for the sidebar. * - * @returns {Element} component instance + * @return {Element} component instance */ export default function SidebarOptions() { // Initializes default values used for FormToggle in order to avoid changing diff --git a/projects/packages/search/src/customberg/components/sidebar/tabs.jsx b/projects/packages/search/src/customberg/components/sidebar/tabs.jsx index 0b49150e706d0..adaae810092ef 100644 --- a/projects/packages/search/src/customberg/components/sidebar/tabs.jsx +++ b/projects/packages/search/src/customberg/components/sidebar/tabs.jsx @@ -6,10 +6,10 @@ import { JP_SEARCH_TAB_IDENTIFIER, OPTIONS_TAB_IDENTIFIER } from 'lib/constants' /** * Sidebar tabs. * - * @param {object} props - Component properties - * @param {string} props.enabledSidebarName - Currently enabled sidebar name. - * @param {Function} props.enableSidebar - Enables the sidebar upon invocation. - * @returns {Element} component instance + * @param {object} props - Component properties + * @param {string} props.enabledSidebarName - Currently enabled sidebar name. + * @param {Function} props.enableSidebar - Enables the sidebar upon invocation. + * @return {Element} component instance */ export default function Tabs( { enabledSidebarName, enableSidebar } ) { return ( @@ -37,12 +37,12 @@ export default function Tabs( { enabledSidebarName, enableSidebar } ) { /** * Sidebar tab. * - * @param {object} props - Component properties + * @param {object} props - Component properties * @param {Function} props.enableSidebar - Callback to enable a specific sidebar by name - * @param {string} props.identifier - Identifier. - * @param {string} props.label - Label. - * @param {boolean} props.isActive - Whether the tab is active. - * @returns {Element} component instance + * @param {string} props.identifier - Identifier. + * @param {string} props.label - Label. + * @param {boolean} props.isActive - Whether the tab is active. + * @return {Element} component instance */ function Tab( { enableSidebar, identifier, label, isActive } ) { const ariaLabel = isActive diff --git a/projects/packages/search/src/customberg/components/sidebar/theme-control.jsx b/projects/packages/search/src/customberg/components/sidebar/theme-control.jsx index 3064275d863c1..c3f82cc0a6b49 100644 --- a/projects/packages/search/src/customberg/components/sidebar/theme-control.jsx +++ b/projects/packages/search/src/customberg/components/sidebar/theme-control.jsx @@ -8,11 +8,11 @@ import ThemeIcon from './theme-icon'; /** * Theme control for use in SidebarOptions tab. * - * @param {object} props - component properties. - * @param {boolean} props.disabled - disables the control. + * @param {object} props - component properties. + * @param {boolean} props.disabled - disables the control. * @param {Function} props.onChange - invoked with new theme value when a button is pressed. - * @param {string} props.value - 'dark' or 'light'. - * @returns {Element} component instance + * @param {string} props.value - 'dark' or 'light'. + * @return {Element} component instance */ export default function ThemeControl( { disabled, value, onChange } ) { return ( diff --git a/projects/packages/search/src/customberg/components/sidebar/theme-icon.jsx b/projects/packages/search/src/customberg/components/sidebar/theme-icon.jsx index c016ed59554a1..699678cf6a276 100644 --- a/projects/packages/search/src/customberg/components/sidebar/theme-icon.jsx +++ b/projects/packages/search/src/customberg/components/sidebar/theme-icon.jsx @@ -1,9 +1,9 @@ /** * Theme icon for use in SidebarOptions tab. * - * @param {object} props - component properties. + * @param {object} props - component properties. * @param {string} props.theme - 'dark' or 'light'. - * @returns {Element} component instance + * @return {Element} component instance */ export default function ThemeIcon( { theme } ) { const fill = theme === 'dark' ? '#000' : '#fff'; diff --git a/projects/packages/search/src/customberg/hooks/use-entity-record-state.js b/projects/packages/search/src/customberg/hooks/use-entity-record-state.js index a6b01f537c421..914fa105b4325 100644 --- a/projects/packages/search/src/customberg/hooks/use-entity-record-state.js +++ b/projects/packages/search/src/customberg/hooks/use-entity-record-state.js @@ -4,7 +4,7 @@ import { useCallback } from 'react'; /** * Fetches relevant entity record states for use in the configurator. * - * @returns {object} relevant entity record values. + * @return {object} relevant entity record values. */ export default function useEntityRecordState() { const { saveEntityRecord, undo, redo } = useDispatch( 'core' ); diff --git a/projects/packages/search/src/customberg/hooks/use-loading-state.js b/projects/packages/search/src/customberg/hooks/use-loading-state.js index d470f0e1325ac..62876f8caecd4 100644 --- a/projects/packages/search/src/customberg/hooks/use-loading-state.js +++ b/projects/packages/search/src/customberg/hooks/use-loading-state.js @@ -3,7 +3,7 @@ import { useSelect } from '@wordpress/data'; /** * Fetches loading state for site values. * - * @returns {object} isLoading state. + * @return {object} isLoading state. */ export default function useSiteLoadingState() { const site = useSelect( select => select( 'core' ).getSite() ); diff --git a/projects/packages/search/src/customberg/hooks/use-search-options.js b/projects/packages/search/src/customberg/hooks/use-search-options.js index c309b75961174..8c7fa3ff7bdc4 100644 --- a/projects/packages/search/src/customberg/hooks/use-search-options.js +++ b/projects/packages/search/src/customberg/hooks/use-search-options.js @@ -8,7 +8,7 @@ const VALID_POST_TYPES = global.JetpackInstantSearchOptions.postTypes; /** * Fetches values and setters for various search configuration values. * - * @returns {object} values and setters + * @return {object} values and setters */ export default function useSearchOptions() { const [ theme, setTheme ] = useEntityProp( 'root', 'site', 'jetpack_search_color_theme' ); diff --git a/projects/packages/search/src/dashboard/class-dashboard.php b/projects/packages/search/src/dashboard/class-dashboard.php index 8da1e6ea86254..ac6494edc6f23 100644 --- a/projects/packages/search/src/dashboard/class-dashboard.php +++ b/projects/packages/search/src/dashboard/class-dashboard.php @@ -102,7 +102,8 @@ public function add_wp_admin_submenu() { _x( 'Search', 'product name shown in menu', 'jetpack-search-pkg' ), 'manage_options', 'jetpack-search', - array( $this, 'render' ) + array( $this, 'render' ), + 10 ); } else { // always add the page, but hide it from the menu. diff --git a/projects/packages/search/src/dashboard/components/dashboard/wrapped-dashboard.jsx b/projects/packages/search/src/dashboard/components/dashboard/wrapped-dashboard.jsx index fd93e09b97a5c..49313904258ac 100644 --- a/projects/packages/search/src/dashboard/components/dashboard/wrapped-dashboard.jsx +++ b/projects/packages/search/src/dashboard/components/dashboard/wrapped-dashboard.jsx @@ -11,7 +11,7 @@ import { STORE_ID } from 'store'; /** * Return appropriate components. * - * @returns {React.Component} WrappedDashboard component. + * @return {React.Component} WrappedDashboard component. */ export default function WrappedDashboard() { const { isFullyConnected } = useConnection(); @@ -53,7 +53,7 @@ export default function WrappedDashboard() { /** * Returns AfterConnectionPage component if site is fully connected otherwise UpsellPage component. * - * @returns {React.Component} NewWrappedDashboard component. + * @return {React.Component} NewWrappedDashboard component. */ function WrappedDashboard202208() { const { isFullyConnected } = useConnection(); @@ -69,7 +69,7 @@ function WrappedDashboard202208() { /** * Returns SearchDashboardPage component if supports search otherwise UpsellPage component * - * @returns {React.Component} AfterConnectionPage component. + * @return {React.Component} AfterConnectionPage component. */ function AfterConnectionPage() { useSelect( select => select( STORE_ID ).getSearchPlanInfo(), [] ); diff --git a/projects/packages/search/src/dashboard/components/donut-meter-container/index.jsx b/projects/packages/search/src/dashboard/components/donut-meter-container/index.jsx index 7c7400174bc70..32dbbae8afd53 100644 --- a/projects/packages/search/src/dashboard/components/donut-meter-container/index.jsx +++ b/projects/packages/search/src/dashboard/components/donut-meter-container/index.jsx @@ -44,14 +44,14 @@ const usageInfoMessage = ( current, limit ) => { /** * Returns a DonutMeterContainer describing resource usage. * - * @param {object} props - Props - * @param {number} props.current - totalCount to the DonutMeter - * @param {number} props.limit - segmentCount to the DonutMeter - * @param {string} props.title - title to the DonutMeter + * @param {object} props - Props + * @param {number} props.current - totalCount to the DonutMeter + * @param {number} props.limit - segmentCount to the DonutMeter + * @param {string} props.title - title to the DonutMeter * @param {Function} props.iconClickedCallback - handler for click on "info" icon * @param {Function} props.linkClickedCallback - handler for click on "details" link - * @param {object} props.tooltip - tooltip data - * @returns {React.Component} DonutMeterContainer component + * @param {object} props.tooltip - tooltip data + * @return {React.Component} DonutMeterContainer component */ const DonutMeterContainer = ( { current = 0, diff --git a/projects/packages/search/src/dashboard/components/global-notices/index.jsx b/projects/packages/search/src/dashboard/components/global-notices/index.jsx index 52a0ba088d35f..26a7e10e96c0a 100644 --- a/projects/packages/search/src/dashboard/components/global-notices/index.jsx +++ b/projects/packages/search/src/dashboard/components/global-notices/index.jsx @@ -8,7 +8,7 @@ import './style.scss'; * NoticesList component * * @param {*} props - Props - * @returns {React.Component} - NoticesList component + * @return {React.Component} - NoticesList component */ export default function NoticesList( props = { handleLocalNoticeDismissClick: null, notices: Object.freeze( [] ) } diff --git a/projects/packages/search/src/dashboard/components/global-notices/store/actions.js b/projects/packages/search/src/dashboard/components/global-notices/store/actions.js index a2ff9a7c6304c..719abb03b593c 100644 --- a/projects/packages/search/src/dashboard/components/global-notices/store/actions.js +++ b/projects/packages/search/src/dashboard/components/global-notices/store/actions.js @@ -8,10 +8,10 @@ export const REMOVE_NOTICE = 'REMOVE_NOTICE'; /** * Create global notice * - * @param {*} status - success, error, info or warning. - * @param {*} text - the text to show. + * @param {*} status - success, error, info or warning. + * @param {*} text - the text to show. * @param {*} options - Options. - * @returns {object} - action object. + * @return {object} - action object. */ export function createNotice( status, text, options = {} ) { const notice = { @@ -34,7 +34,7 @@ export function createNotice( status, text, options = {} ) { * Remove notice by ID * * @param {*} noticeId - noticeID. - * @returns {object} - action object. + * @return {object} - action object. */ export function removeNotice( noticeId ) { return { type: REMOVE_NOTICE, notice: { id: noticeId } }; diff --git a/projects/packages/search/src/dashboard/components/loading/index.jsx b/projects/packages/search/src/dashboard/components/loading/index.jsx index a43566b4293e7..58ca795c6a948 100644 --- a/projects/packages/search/src/dashboard/components/loading/index.jsx +++ b/projects/packages/search/src/dashboard/components/loading/index.jsx @@ -6,7 +6,7 @@ import './style.scss'; /** * Defines a centerized spinner * - * @returns {React.Component} Loading component. + * @return {React.Component} Loading component. */ export default function Loading() { return ; diff --git a/projects/packages/search/src/dashboard/components/mocked-search/index.jsx b/projects/packages/search/src/dashboard/components/mocked-search/index.jsx index 2f770ed97d3c8..f14b83bd64a7c 100644 --- a/projects/packages/search/src/dashboard/components/mocked-search/index.jsx +++ b/projects/packages/search/src/dashboard/components/mocked-search/index.jsx @@ -5,10 +5,10 @@ import MockedLegacySearch from './mocked-legacy-search'; /** * Mocked Search component, which shows mocked Instant Search or legacy Search interface. * - * @param {object} props - Component properties. + * @param {object} props - Component properties. * @param {boolean} props.supportsOnlyClassicSearch - true if site has plan that supports only Classic Search. - * @param {boolean} props.supportsInstantSearch - true if site has plan that supports Instant Search. - * @returns {React.Component} Mocked Search interface component. + * @param {boolean} props.supportsInstantSearch - true if site has plan that supports Instant Search. + * @return {React.Component} Mocked Search interface component. */ export default function MockedSearch( { supportsInstantSearch = true, diff --git a/projects/packages/search/src/dashboard/components/mocked-search/mocked-instant-search.jsx b/projects/packages/search/src/dashboard/components/mocked-search/mocked-instant-search.jsx index 005616706ab74..8b3de6d7e21e2 100644 --- a/projects/packages/search/src/dashboard/components/mocked-search/mocked-instant-search.jsx +++ b/projects/packages/search/src/dashboard/components/mocked-search/mocked-instant-search.jsx @@ -7,7 +7,7 @@ import './mocked-instant-search.scss'; /** * Generate mocked instant search dialog * - * @returns {React.Component} Mocked Search instant dialog component. + * @return {React.Component} Mocked Search instant dialog component. */ export default function MockedInstantSearch() { return ( diff --git a/projects/packages/search/src/dashboard/components/mocked-search/mocked-legacy-search.jsx b/projects/packages/search/src/dashboard/components/mocked-search/mocked-legacy-search.jsx index 402b2b6de7908..4ca4d8be4bcfd 100644 --- a/projects/packages/search/src/dashboard/components/mocked-search/mocked-legacy-search.jsx +++ b/projects/packages/search/src/dashboard/components/mocked-search/mocked-legacy-search.jsx @@ -6,7 +6,7 @@ import './mocked-legacy-search.scss'; /** * Generate mocked search dialog * - * @returns {React.Component} Mocked Search dialog component. + * @return {React.Component} Mocked Search dialog component. */ export default function MockedLegacySearch() { return ( diff --git a/projects/packages/search/src/dashboard/components/module-control/index.jsx b/projects/packages/search/src/dashboard/components/module-control/index.jsx index 995e0906176ac..8b031f0d00ade 100644 --- a/projects/packages/search/src/dashboard/components/module-control/index.jsx +++ b/projects/packages/search/src/dashboard/components/module-control/index.jsx @@ -30,21 +30,21 @@ const WIDGETS_EDITOR_URL = 'widgets.php'; /** * Search settings component to be used within the Performance section. * - * @param {object} props - Component properties. - * @param {string} props.domain - Calypso slug. - * @param {string} props.siteAdminUrl - site admin URL. - * @param {Function} props.updateOptions - function to update settings. - * @param {boolean} props.isDisabledFromOverLimit - true if the subscription is invalid to manipulate controls. - * @param {boolean} props.isSavingEitherOption - true if Saving options. - * @param {boolean} props.isModuleEnabled - true if Search module is enabled. - * @param {boolean} props.isInstantSearchEnabled - true if Instant Search is enabled. - * @param {boolean} props.isInstantSearchPromotionActive - true if search promotion is active. - * @param {boolean} props.supportsOnlyClassicSearch - true if site has plan that supports only Classic Search. - * @param {boolean} props.supportsSearch - true if site has plan that supports either Classic or Instant Search. - * @param {boolean} props.supportsInstantSearch - true if site has plan that supports Instant Search. - * @param {boolean} props.isTogglingModule - true if toggling Search module. - * @param {boolean} props.isTogglingInstantSearch - true if toggling Instant Search option. - * @returns {React.Component} Search settings component. + * @param {object} props - Component properties. + * @param {string} props.domain - Calypso slug. + * @param {string} props.siteAdminUrl - site admin URL. + * @param {Function} props.updateOptions - function to update settings. + * @param {boolean} props.isDisabledFromOverLimit - true if the subscription is invalid to manipulate controls. + * @param {boolean} props.isSavingEitherOption - true if Saving options. + * @param {boolean} props.isModuleEnabled - true if Search module is enabled. + * @param {boolean} props.isInstantSearchEnabled - true if Instant Search is enabled. + * @param {boolean} props.isInstantSearchPromotionActive - true if search promotion is active. + * @param {boolean} props.supportsOnlyClassicSearch - true if site has plan that supports only Classic Search. + * @param {boolean} props.supportsSearch - true if site has plan that supports either Classic or Instant Search. + * @param {boolean} props.supportsInstantSearch - true if site has plan that supports Instant Search. + * @param {boolean} props.isTogglingModule - true if toggling Search module. + * @param {boolean} props.isTogglingInstantSearch - true if toggling Instant Search option. + * @return {React.Component} Search settings component. */ export default function SearchModuleControl( { siteAdminUrl, diff --git a/projects/packages/search/src/dashboard/components/pages/connection-page.jsx b/projects/packages/search/src/dashboard/components/pages/connection-page.jsx index b4a2f826f3c0c..4faf56de2f094 100644 --- a/projects/packages/search/src/dashboard/components/pages/connection-page.jsx +++ b/projects/packages/search/src/dashboard/components/pages/connection-page.jsx @@ -12,9 +12,9 @@ import './connection-page.scss'; /** * defines ConnectionPage. * - * @param {object} props - Component properties. + * @param {object} props - Component properties. * @param {string} props.isLoading - should page show Loading spinner. - * @returns {React.Component} ConnectionPage component. + * @return {React.Component} ConnectionPage component. */ export default function ConnectionPage( { isLoading = false } ) { useSelect( select => select( STORE_ID ).getSearchPricing(), [] ); diff --git a/projects/packages/search/src/dashboard/components/pages/dashboard-page.jsx b/projects/packages/search/src/dashboard/components/pages/dashboard-page.jsx index cb51ada5d6f64..597bea7f68f6f 100644 --- a/projects/packages/search/src/dashboard/components/pages/dashboard-page.jsx +++ b/projects/packages/search/src/dashboard/components/pages/dashboard-page.jsx @@ -23,9 +23,9 @@ import './dashboard-page.scss'; /** * SearchDashboard component definition. * - * @param {object} props - Component properties. + * @param {object} props - Component properties. * @param {string} props.isLoading - should page show Loading spinner. - * @returns {React.Component} Search dashboard component. + * @return {React.Component} Search dashboard component. */ export default function DashboardPage( { isLoading = false } ) { useSelect( select => select( STORE_ID ).getSearchPlanInfo(), [] ); diff --git a/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx b/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx index 9add3c70d9f27..8c5bd8bc74a01 100644 --- a/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx +++ b/projects/packages/search/src/dashboard/components/pages/upsell-page/index.jsx @@ -3,6 +3,7 @@ import { Container, Col, PricingCard, + getUserLocale, AdminSectionHero, ProductPrice, PricingTable, @@ -32,9 +33,9 @@ const JETPACK_SEARCH__LINK = 'https://jetpack.com/upgrade/search'; /** * defines UpsellPage. * - * @param {object} props - Component properties. + * @param {object} props - Component properties. * @param {string} props.isLoading - should page show Loading spinner. - * @returns {React.Component} UpsellPage component. + * @return {React.Component} UpsellPage component. */ export default function UpsellPage( { isLoading = false } ) { // Introduce the gate for new pricing with URL parameter `new_pricing_202208=1` @@ -155,7 +156,7 @@ const OldPricingComponent = ( { sendToCart } ) => { const NewPricingComponent = ( { sendToCartPaid, sendToCartFree } ) => { const siteDomain = useSelect( select => select( STORE_ID ).getCalypsoSlug(), [] ); - + const localeSlug = getUserLocale(); const priceBefore = useSelect( select => select( STORE_ID ).getPriceBefore() / 12, [] ); const priceAfter = useSelect( select => select( STORE_ID ).getPriceAfter() / 12, [] ); const priceCurrencyCode = useSelect( select => select( STORE_ID ).getPriceCurrencyCode(), [] ); @@ -166,7 +167,7 @@ const NewPricingComponent = ( { sendToCartPaid, sendToCartFree } ) => { const { hasConnectionError } = useConnectionErrorNotice(); const paidRecordsLimitRaw = useSelect( select => select( STORE_ID ).getPaidRecordsLimit(), [] ); - const paidRecordsLimit = new Intl.NumberFormat( 'en-US', { + const paidRecordsLimit = new Intl.NumberFormat( localeSlug, { notation: 'compact', compactDisplay: 'short', } ).format( paidRecordsLimitRaw ); @@ -176,14 +177,14 @@ const NewPricingComponent = ( { sendToCartPaid, sendToCartFree } ) => { const unlimitedText = __( 'Unlimited', 'jetpack-search-pkg' ); const paidRequestsLimit = hasUnlimitedRequests ? unlimitedText - : new Intl.NumberFormat( 'en-US', { + : new Intl.NumberFormat( localeSlug, { notation: 'compact', compactDisplay: 'short', } ).format( paidRequestsLimitRaw ); const unitPrice = useSelect( select => select( STORE_ID ).getAdditionalUnitPrice(), [] ); const unitQuantityRaw = useSelect( select => select( STORE_ID ).getAdditionalUnitQuantity(), [] ); - const unitQuantity = new Intl.NumberFormat( 'en-US', { + const unitQuantity = new Intl.NumberFormat( localeSlug, { notation: 'compact', compactDisplay: 'short', } ).format( unitQuantityRaw ); diff --git a/projects/packages/search/src/dashboard/components/price/index.jsx b/projects/packages/search/src/dashboard/components/price/index.jsx index 69c949feac372..7c70647d11e3c 100644 --- a/projects/packages/search/src/dashboard/components/price/index.jsx +++ b/projects/packages/search/src/dashboard/components/price/index.jsx @@ -5,12 +5,12 @@ import React from 'react'; /** * React component to render a Price composition. * - * @param {object} props - Component props. - * @param {number} props.amount - Amount. - * @param {string} props.currency - Currency code (e.g. 'USD'). + * @param {object} props - Component props. + * @param {number} props.amount - Amount. + * @param {string} props.currency - Currency code (e.g. 'USD'). * @param {boolean} props.hidePriceFraction - Whether or not to hide the fraction. - * @param {string} props.tag - Topmost element tag. - * @returns {React.ReactNode} - Price react component. + * @param {string} props.tag - Topmost element tag. + * @return {React.ReactNode} - Price react component. */ const Price = ( { amount, currency, hidePriceFraction, tag = 'span' } ) => { const { symbol, integer, fraction } = getCurrencyObject( amount, currency ); diff --git a/projects/packages/search/src/dashboard/components/record-meter/index.jsx b/projects/packages/search/src/dashboard/components/record-meter/index.jsx index 8e1628f522583..874ede380add2 100644 --- a/projects/packages/search/src/dashboard/components/record-meter/index.jsx +++ b/projects/packages/search/src/dashboard/components/record-meter/index.jsx @@ -10,13 +10,13 @@ import './style.scss'; /** * Generate Record Meter showing how many records the user has indexed * - * @param {object} props - Props - * @param {number} props.postCount - Post count number of posts in total - * @param {object} props.postTypeBreakdown - Post type breakdown (post type => number of posts) - * @param {object} props.postTypes - Post types (post type label => post type slug) + * @param {object} props - Props + * @param {number} props.postCount - Post count number of posts in total + * @param {object} props.postTypeBreakdown - Post type breakdown (post type => number of posts) + * @param {object} props.postTypes - Post types (post type label => post type slug) * @param {number} props.tierMaximumRecords - Max number of records allowed in user's current tier - * @param {string} props.lastIndexedDate - The date on which the site was last indexed in ISO 8601 format - * @returns {React.Component} RecordMeter React component + * @param {string} props.lastIndexedDate - The date on which the site was last indexed in ISO 8601 format + * @return {React.Component} RecordMeter React component */ export default function RecordMeter( { postCount, diff --git a/projects/packages/search/src/dashboard/components/record-meter/lib/record-info.js b/projects/packages/search/src/dashboard/components/record-meter/lib/record-info.js index ea4811790d144..b7277e72a0be9 100644 --- a/projects/packages/search/src/dashboard/components/record-meter/lib/record-info.js +++ b/projects/packages/search/src/dashboard/components/record-meter/lib/record-info.js @@ -4,11 +4,11 @@ const PALETTE = require( '@automattic/color-studio' ); /** * Convert provided information into a chart-consumable data form * - * @param {number} postCount - The total count of indexed post records + * @param {number} postCount - The total count of indexed post records * @param {object} postTypeBreakdown - Post type breakdown (post type => number of posts) - * @param {string} lastIndexedDate - The date on which the site was last indexed as a string - * @param {object} postTypes - Post types (post type label => post type slug) - * @returns {object} data in correct form to use in chart and notice-box + * @param {string} lastIndexedDate - The date on which the site was last indexed as a string + * @param {object} postTypes - Post types (post type label => post type slug) + * @return {object} data in correct form to use in chart and notice-box */ export default function getRecordInfo( postCount, postTypeBreakdown, lastIndexedDate, postTypes ) { const maxPostTypeCount = 5; // this value determines when to cut off displaying post times & compound into an 'other' @@ -108,8 +108,8 @@ export default function getRecordInfo( postCount, postTypeBreakdown, lastIndexed * adds the appropriate labels the post type breakdown * * @param {Array} postTypeBreakdown - an array of the different post types with their counts - * @param {Array} postTypes - an array of the different post types labels matched with their slugs - * @returns {object} updated postTypeBreakdown containing the post type slug, label, and count + * @param {Array} postTypes - an array of the different post types labels matched with their slugs + * @return {object} updated postTypeBreakdown containing the post type slug, label, and count */ export function addLabelsToPostTypeBreakdown( postTypeBreakdown, postTypes ) { const postTypeBreakdownWithLabels = postTypeBreakdown.map( postType => { @@ -127,10 +127,10 @@ export function addLabelsToPostTypeBreakdown( postTypeBreakdown, postTypes ) { * split post types into those being displayed, * and those combined into the 'other' category * - * @param {Array} postTypeBreakdown - an array of the different post types with their counts - * @param {number} numItems - count of different post types - * @param {number} maxPostTypeCount - the max number of records to display before combining the rest into the 'other' category - * @returns {object} containing included items with post type and count, and other items, split. + * @param {Array} postTypeBreakdown - an array of the different post types with their counts + * @param {number} numItems - count of different post types + * @param {number} maxPostTypeCount - the max number of records to display before combining the rest into the 'other' category + * @return {object} containing included items with post type and count, and other items, split. */ export function splitUsablePostTypes( postTypeBreakdown, numItems, maxPostTypeCount ) { const count = maxPostTypeCount <= numItems ? maxPostTypeCount : numItems; @@ -145,7 +145,7 @@ export function splitUsablePostTypes( postTypeBreakdown, numItems, maxPostTypeCo * combine remaining item count for use in 'other' category * * @param {Array} otherItems - array of items, with their counts, to be combined into 'other' - * @returns {number} sum of all 'other' item counts + * @return {number} sum of all 'other' item counts */ export function combineOtherCount( otherItems ) { let runningTotal = 0; @@ -159,10 +159,10 @@ export function combineOtherCount( otherItems ) { /** * return chart-ready data * - * @param {object} data - data object with the count for the post type item + * @param {object} data - data object with the count for the post type item * @param {string} color - color code to be used for the chart item - * @param {string} name - name of post type for the label - * @returns {object} chart ready data with data, label and background color. + * @param {string} name - name of post type for the label + * @return {object} chart ready data with data, label and background color. */ export function createData( data, color, name ) { return { diff --git a/projects/packages/search/src/dashboard/components/record-meter/notice-box.jsx b/projects/packages/search/src/dashboard/components/record-meter/notice-box.jsx index 9baca63e04d99..6e9d71d0c5863 100644 --- a/projects/packages/search/src/dashboard/components/record-meter/notice-box.jsx +++ b/projects/packages/search/src/dashboard/components/record-meter/notice-box.jsx @@ -60,13 +60,13 @@ const getNotices = ( tierMaximumRecords = null ) => { /** * Returns a notice box for displaying notices about record count and plan limits * - * @param {object} props - Props - * @param {number} props.recordCount - Current count of user's total records - * @param {number} props.recordLimit - Max number of records allowed in user's current tier + * @param {object} props - Props + * @param {number} props.recordCount - Current count of user's total records + * @param {number} props.recordLimit - Max number of records allowed in user's current tier * @param {boolean} props.hasBeenIndexed - True if site has a last indexed date - * @param {boolean} props.hasValidData - True if data is present and in valid form - * @param {boolean} props.hasItems - True if there is at least one indexed record - * @returns {React.Component} notice box component. + * @param {boolean} props.hasValidData - True if data is present and in valid form + * @param {boolean} props.hasItems - True if there is at least one indexed record + * @return {React.Component} notice box component. */ export function NoticeBox( props ) { const activeNoticeIds = []; diff --git a/projects/packages/search/src/dashboard/components/record-meter/record-count.jsx b/projects/packages/search/src/dashboard/components/record-meter/record-count.jsx index 55ddadef1e0df..659532cc92517 100644 --- a/projects/packages/search/src/dashboard/components/record-meter/record-count.jsx +++ b/projects/packages/search/src/dashboard/components/record-meter/record-count.jsx @@ -11,7 +11,7 @@ const DOCS_URL = 'https://jetpack.com/support/search/jetpack-search-record-meter * Returns record count component showing current records indexed and max records available for tier. * * @param {object} props - current record count and plan record limit. - * @returns {React.Component} record count component. + * @return {React.Component} record count component. */ export function RecordCount( props ) { if ( ! props.recordCount ) { diff --git a/projects/packages/search/src/dashboard/components/search-promotion/index.jsx b/projects/packages/search/src/dashboard/components/search-promotion/index.jsx index d56604f2b9b0b..6b13120622402 100644 --- a/projects/packages/search/src/dashboard/components/search-promotion/index.jsx +++ b/projects/packages/search/src/dashboard/components/search-promotion/index.jsx @@ -6,7 +6,7 @@ import './style.scss'; /** * SearchPromotion component definition. * - * @returns {React.Component} SearchPromotion component. + * @return {React.Component} SearchPromotion component. */ export default function SearchPromotion() { return ( diff --git a/projects/packages/search/src/dashboard/components/upsell-nudge/index.jsx b/projects/packages/search/src/dashboard/components/upsell-nudge/index.jsx index dc0eeee3fbb4a..df266550d91ba 100644 --- a/projects/packages/search/src/dashboard/components/upsell-nudge/index.jsx +++ b/projects/packages/search/src/dashboard/components/upsell-nudge/index.jsx @@ -7,7 +7,7 @@ import './style.scss'; * Upsell nudge component * * @param {object} props - Props - * @returns {React.Component} - Upsell nudge component. + * @return {React.Component} - Upsell nudge component. */ export default function InstantSearchUpsellNudge( props = { upgrade: true } ) { return ( diff --git a/projects/packages/search/src/dashboard/hooks/use-connection.jsx b/projects/packages/search/src/dashboard/hooks/use-connection.jsx index 8bd1cedd86000..18c9a3e653240 100644 --- a/projects/packages/search/src/dashboard/hooks/use-connection.jsx +++ b/projects/packages/search/src/dashboard/hooks/use-connection.jsx @@ -5,7 +5,7 @@ import { STORE_ID as SEARCH_STORE_ID } from 'store'; /** * Expose the `connectionStatus`, `isFullyConnected` state object * - * @returns {object} connectionStatus, isFullyConnected + * @return {object} connectionStatus, isFullyConnected */ export default function useConnection() { const connectionStatus = useSelect( select => ( { diff --git a/projects/packages/search/src/dashboard/hooks/use-product-checkout-workflow.jsx b/projects/packages/search/src/dashboard/hooks/use-product-checkout-workflow.jsx index 272fce7009d46..cd2d03ac8f2b1 100644 --- a/projects/packages/search/src/dashboard/hooks/use-product-checkout-workflow.jsx +++ b/projects/packages/search/src/dashboard/hooks/use-product-checkout-workflow.jsx @@ -17,15 +17,15 @@ const { * Custom hook that performs the needed steps * to concrete the checkout workflow. * - * @param {object} props - The props passed to the hook. - * @param {string} props.productSlug - The WordPress product slug. - * @param {string} props.redirectUri - The URI to redirect to after checkout. - * @param {string} [props.siteSuffix] - The site suffix. - * @param {string} [props.blogID] - The blog ID. + * @param {object} props - The props passed to the hook. + * @param {string} props.productSlug - The WordPress product slug. + * @param {string} props.redirectUri - The URI to redirect to after checkout. + * @param {string} [props.siteSuffix] - The site suffix. + * @param {string} [props.blogID] - The blog ID. * @param {Function} props.siteProductAvailabilityHandler - The function used to check whether the site already has the requested product. This will be checked after registration and the checkout page will be skipped if the promise returned resloves true. - * @param {Function} props.from - The plugin slug initiated the flow. - * @param {Function} props.isWpcom - Whether it's WPCOM site. - * @returns {Function} - The useEffect hook. + * @param {Function} props.from - The plugin slug initiated the flow. + * @param {Function} props.isWpcom - Whether it's WPCOM site. + * @return {Function} - The useEffect hook. */ export default function useProductCheckoutWorkflow( { productSlug, @@ -78,7 +78,7 @@ export default function useProductCheckoutWorkflow( { * Handler to run the checkout workflow. * * @param {Event} [event] - Event that dispatched run - * @returns {void} Nothing. + * @return {void} Nothing. */ const run = event => { event && event.preventDefault(); diff --git a/projects/packages/search/src/dashboard/store/actions/jetpack-settings.js b/projects/packages/search/src/dashboard/store/actions/jetpack-settings.js index 4f38a4783473b..290f9d723af3c 100644 --- a/projects/packages/search/src/dashboard/store/actions/jetpack-settings.js +++ b/projects/packages/search/src/dashboard/store/actions/jetpack-settings.js @@ -21,8 +21,8 @@ export const TOGGLE_SEARCH_MODULE = 'TOGGLE_SEARCH_MODULE'; * Yield actions to update Search Settings * * @param {object} settings - settings to apply. - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* updateJetpackSettings( settings ) { try { @@ -49,7 +49,7 @@ export function* updateJetpackSettings( settings ) { /** * Set state updating action * - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setUpdatingJetpackSettings() { return setJetpackSettings( { is_updating: true } ); @@ -58,7 +58,7 @@ export function setUpdatingJetpackSettings() { /** * Set state updating finished * - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setUpdatingJetpackSettingsDone() { return setJetpackSettings( { is_updating: false } ); @@ -68,7 +68,7 @@ export function setUpdatingJetpackSettingsDone() { * Set Jetpack settings action * * @param {object} options - Jetpack settings. - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setJetpackSettings( options ) { return { type: SET_JETPACK_SETTINGS, options }; diff --git a/projects/packages/search/src/dashboard/store/actions/search-pricing.js b/projects/packages/search/src/dashboard/store/actions/search-pricing.js index d814ffb502030..ad094237a4582 100644 --- a/projects/packages/search/src/dashboard/store/actions/search-pricing.js +++ b/projects/packages/search/src/dashboard/store/actions/search-pricing.js @@ -4,7 +4,7 @@ export const SET_SEARCH_PRICING = 'SET_SEARCH_PRICING'; * Action to set search pricing * * @param {*} options - pricing object. - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setSearchPricing( options ) { return { diff --git a/projects/packages/search/src/dashboard/store/actions/site-plan.js b/projects/packages/search/src/dashboard/store/actions/site-plan.js index dcff857e7c30b..2910c59ce0f7e 100644 --- a/projects/packages/search/src/dashboard/store/actions/site-plan.js +++ b/projects/packages/search/src/dashboard/store/actions/site-plan.js @@ -6,7 +6,7 @@ export const SET_SEARCH_PLAN_INFO = 'SET_SEARCH_PLAN_INFO'; * Action to set plan info * * @param {*} options - plan info. - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setSearchPlanInfo( options ) { return { diff --git a/projects/packages/search/src/dashboard/store/actions/site-stats.js b/projects/packages/search/src/dashboard/store/actions/site-stats.js index f5459901ebf0b..a530aac68a533 100644 --- a/projects/packages/search/src/dashboard/store/actions/site-stats.js +++ b/projects/packages/search/src/dashboard/store/actions/site-stats.js @@ -4,7 +4,7 @@ export const SET_SEARCH_STATS = 'SET_SEARCH_STATS'; * Action to set site stats (e.g. record usage) * * @param {*} options - stats. - * @returns {object} - an action object. + * @return {object} - an action object. */ export function setSearchStats( options ) { return { diff --git a/projects/packages/search/src/dashboard/store/controls.js b/projects/packages/search/src/dashboard/store/controls.js index e7d37a9efe2f4..0788789c2c3da 100644 --- a/projects/packages/search/src/dashboard/store/controls.js +++ b/projects/packages/search/src/dashboard/store/controls.js @@ -9,7 +9,7 @@ export const FETCH_SEARCH_PRICING = 'FETCH_SEARCH_PRICING'; /** * fetchJetpackSettings action * - * @returns {object} - an action object. + * @return {object} - an action object. */ export const fetchJetpackSettings = () => { return { @@ -21,7 +21,7 @@ export const fetchJetpackSettings = () => { * updateJetpackSettings action * * @param {*} settings - Jetpack settings object. - * @returns {object} - an action object. + * @return {object} - an action object. */ export const updateJetpackSettings = settings => { return { @@ -33,8 +33,8 @@ export const updateJetpackSettings = settings => { /** * fetchSearchPlanInfo action * - * @yields {object} - an action object. - * @returns {object} - an search plan object. + * @yield {object} - an action object. + * @return {object} - an search plan object. */ export function* fetchSearchPlanInfo() { const response = yield { @@ -46,7 +46,7 @@ export function* fetchSearchPlanInfo() { /** * fetchSearchStats action * - * @returns {object} - an action object. + * @return {object} - an action object. */ export const fetchSearchStats = () => { return { @@ -57,7 +57,7 @@ export const fetchSearchStats = () => { /** * fetchSearchPricing action * - * @returns {object} - an action object. + * @return {object} - an action object. */ export const fetchSearchPricing = () => { return { diff --git a/projects/packages/search/src/dashboard/store/resolvers.js b/projects/packages/search/src/dashboard/store/resolvers.js index 5cf482bf5d1ce..0ce9458a3fb87 100644 --- a/projects/packages/search/src/dashboard/store/resolvers.js +++ b/projects/packages/search/src/dashboard/store/resolvers.js @@ -14,8 +14,8 @@ import { /** * Yield actions to get Search Module Status * - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* getSearchModuleStatus() { try { @@ -31,8 +31,8 @@ export function* getSearchModuleStatus() { /** * Yield actions to get search plan info * - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* getSearchPlanInfo() { try { @@ -48,8 +48,8 @@ export function* getSearchPlanInfo() { /** * Yield actions to get search stats * - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* getSearchStats() { try { @@ -65,8 +65,8 @@ export function* getSearchStats() { /** * Yield actions to get search pricing * - * @yields {object} - an action object. - * @returns {object} - an action object. + * @yield {object} - an action object. + * @return {object} - an action object. */ export function* getSearchPricing() { try { diff --git a/projects/packages/search/src/instant-search/components/path-breadcrumbs.jsx b/projects/packages/search/src/instant-search/components/path-breadcrumbs.jsx index d682e2afee7dc..3ecb7abde49db 100644 --- a/projects/packages/search/src/instant-search/components/path-breadcrumbs.jsx +++ b/projects/packages/search/src/instant-search/components/path-breadcrumbs.jsx @@ -6,7 +6,7 @@ import './path-breadcrumbs.scss'; * Splits URL by slashes for rendering breadcrumbs. * * @param {string} path - String URL. - * @returns {string[]} - Array of strings. + * @return {string[]} - Array of strings. */ function splitDomainPath( path ) { const splits = path.split( '/' ).filter( piece => piece.length > 0 ); diff --git a/projects/packages/search/src/instant-search/components/product-ratings.jsx b/projects/packages/search/src/instant-search/components/product-ratings.jsx index 22e25319fe182..c898e7d7f6772 100644 --- a/projects/packages/search/src/instant-search/components/product-ratings.jsx +++ b/projects/packages/search/src/instant-search/components/product-ratings.jsx @@ -7,11 +7,11 @@ import './product-ratings.scss'; /** * Renders a hook-based component for displaying product ratings. * - * @param {object} props - Component properties. - * @param {number} props.count - Number of ratings. - * @param {number} props.rating - Average rating out of five. + * @param {object} props - Component properties. + * @param {number} props.count - Number of ratings. + * @param {number} props.rating - Average rating out of five. * @param {string} props.permalink - Permalink URL to product page. - * @returns {object} Product rating component. + * @return {object} Product rating component. */ export default function ProductRatings( { rating = 0, count = 0, permalink } ) { return ( diff --git a/projects/packages/search/src/instant-search/components/search-app.jsx b/projects/packages/search/src/instant-search/components/search-app.jsx index e00e8bfc89054..58423aaa4fae4 100644 --- a/projects/packages/search/src/instant-search/components/search-app.jsx +++ b/projects/packages/search/src/instant-search/components/search-app.jsx @@ -229,6 +229,7 @@ class SearchApp extends Component { sort: this.props.sort, postsPerPage: this.props.options.postsPerPage, adminQueryFilter: this.props.options.adminQueryFilter, + highlightFields: this.props.options.highlightFields, isInCustomizer: this.props.isInCustomizer, } ); }; diff --git a/projects/packages/search/src/instant-search/components/search-filter.jsx b/projects/packages/search/src/instant-search/components/search-filter.jsx index 516441a2e5ba1..1645cf2e9f11e 100644 --- a/projects/packages/search/src/instant-search/components/search-filter.jsx +++ b/projects/packages/search/src/instant-search/components/search-filter.jsx @@ -10,7 +10,7 @@ import { getCheckedInputNames } from '../lib/dom'; * Get date options given an interval. * * @param {string} interval - Duration interval. - * @returns {object} - Object containing date options. + * @return {object} - Object containing date options. */ function getDateOptions( interval ) { switch ( interval ) { diff --git a/projects/packages/search/src/instant-search/components/search-filters.jsx b/projects/packages/search/src/instant-search/components/search-filters.jsx index ce9f773f54b42..599aef5498470 100644 --- a/projects/packages/search/src/instant-search/components/search-filters.jsx +++ b/projects/packages/search/src/instant-search/components/search-filters.jsx @@ -49,7 +49,7 @@ class SearchFilters extends Component { ); renderStaticFilterComponent = configuration => { - if ( configuration.hasOwnProperty( 'visible' ) && ! configuration.visible ) { + if ( Object.hasOwn( configuration, 'visible' ) && ! configuration.visible ) { return null; } diff --git a/projects/packages/search/src/instant-search/components/search-result-expanded.jsx b/projects/packages/search/src/instant-search/components/search-result-expanded.jsx index 8621a077ee40d..c712740a56c40 100644 --- a/projects/packages/search/src/instant-search/components/search-result-expanded.jsx +++ b/projects/packages/search/src/instant-search/components/search-result-expanded.jsx @@ -10,7 +10,7 @@ import './search-result-expanded.scss'; * Functional component for expanded search results. * * @param {object} props - Component properties. - * @returns {Element} - Expanded search result component. + * @return {Element} - Expanded search result component. */ export default function SearchResultExpanded( props ) { const { isMultiSite, locale = 'en-US', showPostDate } = props; @@ -89,7 +89,16 @@ export default function SearchResultExpanded( props ) { className="jetpack-instant-search__search-result-expanded__content" //eslint-disable-next-line react/no-danger dangerouslySetInnerHTML={ { - __html: highlight.content.join( ' ... ' ), + __html: + highlight && typeof highlight === 'object' + ? Object.entries( highlight ) + .filter( + ( [ key, value ] ) => + key !== 'comments' && key !== 'title' && Array.isArray( value ) + ) + .map( ( [ , array ] ) => array.join( ' ... ' ) ) + .join( ' ... ' ) + : '', } } /> diff --git a/projects/packages/search/src/instant-search/components/search-result-minimal.jsx b/projects/packages/search/src/instant-search/components/search-result-minimal.jsx index 7e0adff204a37..46739b9af523b 100644 --- a/projects/packages/search/src/instant-search/components/search-result-minimal.jsx +++ b/projects/packages/search/src/instant-search/components/search-result-minimal.jsx @@ -87,7 +87,16 @@ class SearchResultMinimal extends Component { className="jetpack-instant-search__search-result-minimal-content" //eslint-disable-next-line react/no-danger dangerouslySetInnerHTML={ { - __html: this.props.result.highlight.content.join( ' ... ' ), + __html: + this.props.result.highlight && typeof this.props.result.highlight === 'object' + ? Object.entries( this.props.result.highlight ) + .filter( + ( [ key, value ] ) => + key !== 'comments' && key !== 'title' && Array.isArray( value ) + ) + .map( ( [ , array ] ) => array.join( ' ... ' ) ) + .join( ' ... ' ) + : '', } } /> ); @@ -98,7 +107,13 @@ class SearchResultMinimal extends Component { if ( result_type !== 'post' ) { return null; } - const noMatchingContent = ! highlight.content || highlight.content[ 0 ] === ''; + const noMatchingContent = + ! highlight || + typeof highlight !== 'object' || + Object.entries( highlight ).every( + ( [ key, value ] ) => + key === 'comments' || key === 'title' || ! Array.isArray( value ) || value[ 0 ] === '' + ); return (
    2. 0; + typeof highlight === 'object' && + Object.entries( highlight ).some( + ( [ key, value ] ) => + key !== 'title' && key !== 'comments' && Array.isArray( value ) && value[ 0 ]?.length > 0 + ); return (
    3. { - if ( configuration.hasOwnProperty( 'visible' ) && ! configuration.visible ) { + if ( Object.hasOwn( configuration, 'visible' ) && ! configuration.visible ) { return null; } diff --git a/projects/packages/search/src/instant-search/lib/a11y.js b/projects/packages/search/src/instant-search/lib/a11y.js index 9f7acf1bfb153..eb46bbba04617 100644 --- a/projects/packages/search/src/instant-search/lib/a11y.js +++ b/projects/packages/search/src/instant-search/lib/a11y.js @@ -2,7 +2,7 @@ * Check if the user has specified that they prefer reduced motion * * @see https://www.joshwcomeau.com/react/prefers-reduced-motion/ - * @returns {boolean} Prefers reduced motion? + * @return {boolean} Prefers reduced motion? */ export function getPrefersReducedMotion() { const query = '(prefers-reduced-motion: no-preference)'; diff --git a/projects/packages/search/src/instant-search/lib/api.js b/projects/packages/search/src/instant-search/lib/api.js index 4fd36aa2df50f..db50b9b10256d 100644 --- a/projects/packages/search/src/instant-search/lib/api.js +++ b/projects/packages/search/src/instant-search/lib/api.js @@ -25,7 +25,7 @@ resetAbortController(); * Builds ElasticSerach aggregations for filters defined by search widgets. * * @param {object[]} widgets - an array of widget configuration objects - * @returns {object} filter aggregations + * @return {object} filter aggregations */ export function buildFilterAggregations( widgets = [] ) { const aggregation = {}; @@ -42,7 +42,7 @@ export function buildFilterAggregations( widgets = [] ) { * Tried to merge the buckets, but which ended up showing too many filters. * * @param {object} newAggregations - New aggregations to operate on. - * @returns {object} - Aggregations with doc_count set to 0. + * @return {object} - Aggregations with doc_count set to 0. */ export function setDocumentCountsToZero( newAggregations ) { newAggregations = newAggregations ?? {}; @@ -63,7 +63,7 @@ export function setDocumentCountsToZero( newAggregations ) { * Builds ElasticSearch aggregations for a given filter. * * @param {object[]} filter - a filter object from a widget configuration object. - * @returns {object} filter aggregations + * @return {object} filter aggregations */ function generateAggregation( filter ) { switch ( filter.type ) { @@ -100,9 +100,9 @@ const DATE_REGEX = /(\d{4})-(\d{2})-(\d{2})/; * Generates a ElasticSearch date range filter. * * @param {string} fieldName - Name of the field (created, modified, etc). - * @param {string} input - Filter value. - * @param {string} type - Date range type (year vs month). - * @returns {object} date filter. + * @param {string} input - Filter value. + * @param {string} type - Date range type (year vs month). + * @return {object} date filter. */ export function generateDateRangeFilter( fieldName, input, type ) { let year, month; @@ -166,7 +166,7 @@ const filterKeyToEsFilter = new Map( [ * Build static filters object * * @param {object} staticFilters - list of static filter key-value. - * @returns {object} - list of selected static filters. + * @return {object} - list of selected static filters. */ function buildStaticFilters( staticFilters ) { const selectedFilters = {}; @@ -185,10 +185,10 @@ function buildStaticFilters( staticFilters ) { /** * Build an ElasticSearch filter object. * - * @param {object} filterQuery - Filter query value object. - * @param {object} adminQueryFilter - Manual ElasticSearch query override. + * @param {object} filterQuery - Filter query value object. + * @param {object} adminQueryFilter - Manual ElasticSearch query override. * @param {string} excludedPostTypes - Post types excluded via the Customizer. - * @returns {object} ElasticSearch filter object. + * @return {object} ElasticSearch filter object. */ function buildFilterObject( filterQuery, adminQueryFilter, excludedPostTypes ) { const filter = { bool: { must: [] } }; @@ -231,7 +231,7 @@ const SORT_QUERY_MAP = new Map( [ * Map sort values to ones compatible with the API. * * @param {string} sort - Sort value. - * @returns {string} Mapped sort value. + * @return {string} Mapped sort value. */ function mapSortToApiValue( sort ) { // Some sorts don't need to be mapped @@ -247,7 +247,7 @@ function mapSortToApiValue( sort ) { * Generate the query string for an API request * * @param {object} options - Options object for the function - * @returns {string} The generated query string. + * @return {string} The generated query string. */ function generateApiQueryString( { aggregations, @@ -262,6 +262,7 @@ function generateApiQueryString( { adminQueryFilter, isInCustomizer = false, additionalBlogIds = [], + highlightFields = [ 'title', 'content', 'comments' ], } ) { if ( query === null ) { query = ''; @@ -276,7 +277,6 @@ function generateApiQueryString( { 'shortcode_types', 'forum.topic_resolved', ]; - const highlightFields = [ 'title', 'content', 'comments' ]; /* Fetch image fields for non-minimal results * @@ -348,7 +348,7 @@ function generateApiQueryString( { * Generate an error handler for a given cache key * * @param {string} cacheKey - The cache key to use - * @returns {Function} An error handler to be used with a search request + * @return {Function} An error handler to be used with a search request */ function errorHandlerFactory( cacheKey ) { return function errorHandler( error ) { @@ -374,9 +374,9 @@ function errorHandlerFactory( cacheKey ) { /** * Generate a response handler for a given cache key * - * @param {string} cacheKey - The cache key to use + * @param {string} cacheKey - The cache key to use * @param {number} requestId - Sequential ID used to determine recency of requests. - * @returns {Function} A response handler to be used with a search request + * @return {Function} A response handler to be used with a search request */ function responseHandlerFactory( cacheKey, requestId ) { return function responseHandler( responseJson ) { @@ -400,9 +400,9 @@ function resetAbortController() { /** * Perform a search. * - * @param {object} options - Search options + * @param {object} options - Search options * @param {number} requestId - Sequential ID used to determine recency of requests. - * @returns {Promise} A promise to the JSON response object + * @return {Promise} A promise to the JSON response object */ export function search( options, requestId ) { const key = stringify( Array.from( arguments ) ); diff --git a/projects/packages/search/src/instant-search/lib/array-overlap.js b/projects/packages/search/src/instant-search/lib/array-overlap.js index 6083ae6e74764..c3b1a6cd5c0ba 100644 --- a/projects/packages/search/src/instant-search/lib/array-overlap.js +++ b/projects/packages/search/src/instant-search/lib/array-overlap.js @@ -3,7 +3,7 @@ * * @param {any[]} a1 - First array. * @param {any[]} a2 - Second array. - * @returns {any[]} An array containing only overlaps/intersections. + * @return {any[]} An array containing only overlaps/intersections. */ export default function arrayOverlap( a1, a2 ) { if ( ! Array.isArray( a1 ) ) { diff --git a/projects/packages/search/src/instant-search/lib/colors.js b/projects/packages/search/src/instant-search/lib/colors.js index 8ac33cb9df2ee..880dd4f477d07 100644 --- a/projects/packages/search/src/instant-search/lib/colors.js +++ b/projects/packages/search/src/instant-search/lib/colors.js @@ -2,7 +2,7 @@ * Extracts hex code from a string. Normalizes 3 digit hex into 6 digit hex. * * @param {string} input - String containing hex code, usually prepended with #. - * @returns {string} - Hex code. + * @return {string} - Hex code. */ function extractHexCode( input ) { let output; @@ -22,7 +22,7 @@ function extractHexCode( input ) { * Generates a constrasting color hex code given a color hex code. * * @param {string} input - String containing a hex color code. - * @returns {string} - Hex code for a contrasting color. + * @return {string} - Hex code for a contrasting color. */ export function getConstrastingColor( input ) { // https://gomakethings.com/dynamically-changing-the-text-color-based-on-background-color-contrast-with-vanilla-js/ diff --git a/projects/packages/search/src/instant-search/lib/customize.js b/projects/packages/search/src/instant-search/lib/customize.js index c69657e528ae3..ced17b5001b59 100644 --- a/projects/packages/search/src/instant-search/lib/customize.js +++ b/projects/packages/search/src/instant-search/lib/customize.js @@ -15,7 +15,7 @@ const SETTINGS_TO_STATE_MAP = new Map( [ /** * Detects if the current environment is within WP's Customizer. * - * @returns {boolean} is in customizer. + * @return {boolean} is in customizer. */ export function isInCustomizer() { return typeof window?.wp?.customize === 'function'; diff --git a/projects/packages/search/src/instant-search/lib/dom.js b/projects/packages/search/src/instant-search/lib/dom.js index e9927d5ac8bc2..eda84cf6fda65 100644 --- a/projects/packages/search/src/instant-search/lib/dom.js +++ b/projects/packages/search/src/instant-search/lib/dom.js @@ -2,7 +2,7 @@ * Fetches the names of all checkbox elements contained within the parent element. * * @param {Element} parentDom - Parent element containing one or more checkboxes. - * @returns {string[]} - Names of checkboxes. + * @return {string[]} - Names of checkboxes. */ export function getCheckedInputNames( parentDom ) { return [ ...parentDom.querySelectorAll( 'input[type="checkbox"]' ).values() ] @@ -14,7 +14,7 @@ export function getCheckedInputNames( parentDom ) { * Returns an object containing theme options. Values can be overridden using the optional input parameter. * * @param {object} searchOptions - Search options. - * @returns {object} - Search options. + * @return {object} - Search options. */ export function getThemeOptions( searchOptions ) { const options = { diff --git a/projects/packages/search/src/instant-search/lib/dummy-debug.js b/projects/packages/search/src/instant-search/lib/dummy-debug.js index 900130aba4188..d78406328c842 100644 --- a/projects/packages/search/src/instant-search/lib/dummy-debug.js +++ b/projects/packages/search/src/instant-search/lib/dummy-debug.js @@ -3,6 +3,6 @@ const noop = () => {}; /** * Used to replace `debug` calls in production. * - * @returns {Function} A noop function. + * @return {Function} A noop function. */ export default () => noop; diff --git a/projects/packages/search/src/instant-search/lib/errors.js b/projects/packages/search/src/instant-search/lib/errors.js index e28771f070e74..8a55153c0b54f 100644 --- a/projects/packages/search/src/instant-search/lib/errors.js +++ b/projects/packages/search/src/instant-search/lib/errors.js @@ -4,7 +4,7 @@ import { __, sprintf } from '@wordpress/i18n'; * Returns an error message based on the error code. * * @param {Error} error - Error object - * @returns {*} an error message + * @return {*} an error message */ export function getErrorMessage( error ) { switch ( error?.message ) { diff --git a/projects/packages/search/src/instant-search/lib/filters.js b/projects/packages/search/src/instant-search/lib/filters.js index 8ee4d4dbb4010..a41257261c324 100644 --- a/projects/packages/search/src/instant-search/lib/filters.js +++ b/projects/packages/search/src/instant-search/lib/filters.js @@ -27,9 +27,9 @@ export const FILTER_KEYS = Object.freeze( [ /** * Returns an array of valid filter key strings. * - * @param {object[]} widgets - Array of Jetpack Search widget objects inside the overlay sidebar. + * @param {object[]} widgets - Array of Jetpack Search widget objects inside the overlay sidebar. * @param {object[]} widgetsOutsideOverlay - Array of Jetpack Search widget objects outside the overlay sidebar. - * @returns {string[]} filterKeys + * @return {string[]} filterKeys */ export function getFilterKeys( widgets = window[ SERVER_OBJECT_NAME ]?.widgets, @@ -51,7 +51,7 @@ export function getFilterKeys( * Get a list of provided static filters. * * @param {'sidebar'|'tabbed'|undefined} variation - the filter variation to get (tabbed or sidebar), defaults to none (returns every variation). - * @returns {Array} list of available static filters. + * @return {Array} list of available static filters. */ export function getAvailableStaticFilters( variation ) { if ( ! window[ SERVER_OBJECT_NAME ]?.staticFilters ) { @@ -70,13 +70,14 @@ export function getAvailableStaticFilters( variation ) { if ( variation && filter.variation ) { return filter.variation === variation; } + return false; } ); } /** * Get static filter keys. * - * @returns {Array} list of available static filters keys. + * @return {Array} list of available static filters keys. */ export function getStaticFilterKeys() { const staticFilters = getAvailableStaticFilters(); @@ -90,7 +91,7 @@ export function getStaticFilterKeys() { * Returns an array of filter keys selectable from within the overlay. * * @param {object[]} widgets - Array of Jetpack Search widget objects inside the overlay sidebar. - * @returns {string[]} filterKeys + * @return {string[]} filterKeys */ export function getSelectableFilterKeys( widgets = window[ SERVER_OBJECT_NAME ]?.widgets ) { return ( @@ -104,7 +105,7 @@ export function getSelectableFilterKeys( widgets = window[ SERVER_OBJECT_NAME ]? * In other words, they were either selected via filters outside the search sidebar or entered manually. * * @param {object[]} widgets - Array of Jetpack Search widget objects inside the overlay sidebar. - * @returns {string[]} filterKeys + * @return {string[]} filterKeys */ export function getUnselectableFilterKeys( widgets = window[ SERVER_OBJECT_NAME ]?.widgets ) { const selectable = getSelectableFilterKeys( widgets ); @@ -115,7 +116,7 @@ export function getUnselectableFilterKeys( widgets = window[ SERVER_OBJECT_NAME * Returns an array of filter keys from a given widget. * * @param {object} widget - a Jetpack Search widget object - * @returns {string[]} filterKeys + * @return {string[]} filterKeys */ function extractFilterKeys( widget ) { return widget.filters @@ -127,7 +128,7 @@ function extractFilterKeys( widget ) { * Returns a filter key given a filter object. * * @param {object} filter - a Jetpack Search filter object - * @returns {string} filterKeys + * @return {string} filterKeys */ export function mapFilterToFilterKey( filter ) { if ( filter.type === 'date_histogram' ) { @@ -151,7 +152,7 @@ export function mapFilterToFilterKey( filter ) { * Inverse of `mapFilterToFilterKey`. * * @param {string} filterKey - filter key string to be mapped. - * @returns {object} filterObject + * @return {object} filterObject */ export function mapFilterKeyToFilter( filterKey ) { if ( filterKey.includes( 'month' ) ) { @@ -194,7 +195,7 @@ export function mapFilterKeyToFilter( filterKey ) { * Returns the type of the inputted filter object. * * @param {object} filter - filter key string to be mapped. - * @returns {string|undefined} output + * @return {string|undefined} output */ export function mapFilterToType( filter ) { if ( filter.type === 'date_histogram' ) { diff --git a/projects/packages/search/src/instant-search/lib/hooks/use-photon.js b/projects/packages/search/src/instant-search/lib/hooks/use-photon.js index 0e5e3a5be3ecd..8c6f31b0255d2 100644 --- a/projects/packages/search/src/instant-search/lib/hooks/use-photon.js +++ b/projects/packages/search/src/instant-search/lib/hooks/use-photon.js @@ -5,7 +5,7 @@ import { useEffect, useState } from 'react'; * Strips query string values from URLs; photon can't handle them. * * @param {string} url - Image URL - * @returns {string} - Image URL without any query strings. + * @return {string} - Image URL without any query strings. */ function stripQueryString( url ) { if ( ! url ) { @@ -17,11 +17,11 @@ function stripQueryString( url ) { /** * Hook for returning a Photonized image URL given width and height parameters. * - * @param {string} initialSrc - Image URL - * @param {number} width - width in pixels - * @param {number} height - height in pixels + * @param {string} initialSrc - Image URL + * @param {number} width - width in pixels + * @param {number} height - height in pixels * @param {boolean} isPhotonEnabled - Toggle photon on/off - * @returns {string} - Photonized image URL if service is available; initialSrc otherwise. + * @return {string} - Photonized image URL if service is available; initialSrc otherwise. */ export function usePhoton( initialSrc, width, height, isPhotonEnabled = true ) { const [ src, setSrc ] = useState( null ); diff --git a/projects/packages/search/src/instant-search/lib/query-string.js b/projects/packages/search/src/instant-search/lib/query-string.js index 653698786854f..06c21a199cf29 100644 --- a/projects/packages/search/src/instant-search/lib/query-string.js +++ b/projects/packages/search/src/instant-search/lib/query-string.js @@ -7,7 +7,7 @@ import { getFilterKeys, getStaticFilterKeys } from './filters'; * Parses the address bar's query string into an object. * * @param {string} search - raw query string prepended with '?' - * @returns {object} queryObject - a query object. + * @return {object} queryObject - a query object. */ export function getQuery( search = window.location.search ) { return decode( search.substring( 1 ), false, false ); @@ -44,7 +44,7 @@ function pushQueryString( queryString ) { /** * Returns a result format value from the query string. Used to override the site's configured result format. * - * @returns {null|string} resultFormatQuery + * @return {null|string} resultFormatQuery */ export function getResultFormatQuery() { const query = getQuery(); @@ -59,9 +59,9 @@ export function getResultFormatQuery() { /** * Navigates the window to a specified location with all search-related query values stirpped out. * - * @param {string} initialHref - Target location to navigate to via push/replaceState. - * @param {Function} callback - Callback to be invoked if initialHref didn't include any search queries. - * @param {boolean} replaceState - Flag to toggle replaceState or pushState invocation. Useful if this function's being invoked due to history navigation. + * @param {string} initialHref - Target location to navigate to via push/replaceState. + * @param {Function} callback - Callback to be invoked if initialHref didn't include any search queries. + * @param {boolean} replaceState - Flag to toggle replaceState or pushState invocation. Useful if this function's being invoked due to history navigation. */ export function restorePreviousHref( initialHref, callback, replaceState = false ) { if ( history.pushState && history.replaceState ) { diff --git a/projects/packages/search/src/instant-search/lib/sort.js b/projects/packages/search/src/instant-search/lib/sort.js index 4a123fa6fc9f3..a48bcba1c5d94 100644 --- a/projects/packages/search/src/instant-search/lib/sort.js +++ b/projects/packages/search/src/instant-search/lib/sort.js @@ -3,8 +3,8 @@ import { PRODUCT_SORT_OPTIONS, RESULT_FORMAT_PRODUCT, SORT_OPTIONS } from './con /** * Get the available sort options for the provided result format * - * @param {string} resultFormat - Result format - * @returns {Map} - Sort options + * @param {string} resultFormat - Result format + * @return {Map} - Sort options */ export function getSortOptions( resultFormat = null ) { if ( resultFormat !== RESULT_FORMAT_PRODUCT ) { diff --git a/projects/packages/search/src/instant-search/lib/test-helpers/tiny-lru.mock.js b/projects/packages/search/src/instant-search/lib/test-helpers/tiny-lru.mock.js index 4305c88d83134..eb15893eedefe 100644 --- a/projects/packages/search/src/instant-search/lib/test-helpers/tiny-lru.mock.js +++ b/projects/packages/search/src/instant-search/lib/test-helpers/tiny-lru.mock.js @@ -1,7 +1,7 @@ /** * Returns a mocked version of `tiny-lru`. * - * @returns {object} A mocked LRU cache object. + * @return {object} A mocked LRU cache object. */ export default function tinyLruMocked() { return { diff --git a/projects/packages/search/src/instant-search/lib/test/api.test.js b/projects/packages/search/src/instant-search/lib/test/api.test.js index 4b22f522c1414..f50ae75b867c8 100644 --- a/projects/packages/search/src/instant-search/lib/test/api.test.js +++ b/projects/packages/search/src/instant-search/lib/test/api.test.js @@ -6,17 +6,17 @@ import { generateDateRangeFilter, setDocumentCountsToZero } from '../api'; describe( 'generateDateRangeFilter', () => { test( 'generates correct ranges for yearly date ranges', () => { expect( generateDateRangeFilter( 'something', '2020-01-01 00:00:00', 'year' ) ).toEqual( { - range: { [ 'something' ]: { gte: '2020-01-01', lt: '2021-01-01' } }, + range: { something: { gte: '2020-01-01', lt: '2021-01-01' } }, } ); } ); test( 'generates correct ranges for monthly date ranges', () => { // Note that the next month value has been left padded; it's "02" instead of "2". expect( generateDateRangeFilter( 'something', '2020-01-01 00:00:00', 'month' ) ).toEqual( { - range: { [ 'something' ]: { gte: '2020-01-01', lt: '2020-02-01' } }, + range: { something: { gte: '2020-01-01', lt: '2020-02-01' } }, } ); // Note that the LT value is in 2021. expect( generateDateRangeFilter( 'something', '2020-12-01 00:00:00', 'month' ) ).toEqual( { - range: { [ 'something' ]: { gte: '2020-12-01', lt: '2021-01-01' } }, + range: { something: { gte: '2020-12-01', lt: '2021-01-01' } }, } ); } ); } ); diff --git a/projects/packages/search/src/instant-search/lib/tracks.js b/projects/packages/search/src/instant-search/lib/tracks.js index 9034f772804a2..7788f27336343 100644 --- a/projects/packages/search/src/instant-search/lib/tracks.js +++ b/projects/packages/search/src/instant-search/lib/tracks.js @@ -31,8 +31,8 @@ export function resetTrackingCookies( forceEnableAnalytics = false ) { /** * Associates the current site with events fired in the future. * - * @param {number|string} siteId - Current site identifier. - * @param {boolean} forceEnableAnalytics - Forcibly enable analytics, ignoring the isAnalyticsEnabled flag. + * @param {number|string} siteId - Current site identifier. + * @param {boolean} forceEnableAnalytics - Forcibly enable analytics, ignoring the isAnalyticsEnabled flag. */ export function identifySite( siteId, forceEnableAnalytics = false ) { if ( forceEnableAnalytics || isAnalyticsEnabled ) { @@ -43,8 +43,8 @@ export function identifySite( siteId, forceEnableAnalytics = false ) { /** * Fires a general event to Tracks. * - * @param {string} eventName - Name of the event. - * @param {object} properties - Event properties. + * @param {string} eventName - Name of the event. + * @param {object} properties - Event properties. * @param {boolean} forceEnableAnalytics - Forcibly enable analytics, ignoring the isAnalyticsEnabled flag. */ export function recordEvent( eventName, properties, forceEnableAnalytics = false ) { @@ -55,7 +55,7 @@ export function recordEvent( eventName, properties, forceEnableAnalytics = false /** * Fires a TrainTracks render event to Tracks. * - * @param {object} properties - Event properties. + * @param {object} properties - Event properties. * @param {boolean} forceEnableAnalytics - Forcibly enable analytics, ignoring the isAnalyticsEnabled flag. */ export function recordTrainTracksRender( properties, forceEnableAnalytics = false ) { @@ -65,7 +65,7 @@ export function recordTrainTracksRender( properties, forceEnableAnalytics = fals /** * Fires a TrainTracks interaction event to Tracks. * - * @param {object} properties - Event properties. + * @param {object} properties - Event properties. * @param {boolean} forceEnableAnalytics - Forcibly enable analytics, ignoring the isAnalyticsEnabled flag. */ export function recordTrainTracksInteract( properties, forceEnableAnalytics = false ) { @@ -75,7 +75,7 @@ export function recordTrainTracksInteract( properties, forceEnableAnalytics = fa /** * Fires a static filter selection event to Tracks. * - * @param {object} properties - Event properties to send to Tracks. + * @param {object} properties - Event properties to send to Tracks. * @param {boolean} forceEnableAnalytics - Forcibly enable analytics, ignoring the isAnalyticsEnabled flag. */ export function recordStaticFilterSelect( properties, forceEnableAnalytics = false ) { diff --git a/projects/packages/search/src/instant-search/store/actions.js b/projects/packages/search/src/instant-search/store/actions.js index d5d7d59cc187c..252621a6a1434 100644 --- a/projects/packages/search/src/instant-search/store/actions.js +++ b/projects/packages/search/src/instant-search/store/actions.js @@ -2,7 +2,7 @@ * Returns an action object used to make a search result request. * * @param {object} options - Search options. - * @returns {object} Action object. + * @return {object} Action object. */ export function makeSearchRequest( options ) { return { @@ -14,10 +14,10 @@ export function makeSearchRequest( options ) { /** * Returns an action object used to record a successful search request. * - * @param {object} params - Input parameters. - * @param {object} params.options - Action options that generated this API response. + * @param {object} params - Input parameters. + * @param {object} params.options - Action options that generated this API response. * @param {object} params.response - API response. - * @returns {object} Action object. + * @return {object} Action object. */ export function recordSuccessfulSearchRequest( { options, response } ) { return { @@ -31,7 +31,7 @@ export function recordSuccessfulSearchRequest( { options, response } ) { * Returns an action object used to record a failed search request. * * @param {object} error - Error from the failed search request. - * @returns {object} Action object. + * @return {object} Action object. */ export function recordFailedSearchRequest( error ) { return { @@ -43,9 +43,9 @@ export function recordFailedSearchRequest( error ) { /** * Returns an action object used to initialize query value related reducers. * - * @param {object} params - Input parameters. + * @param {object} params - Input parameters. * @param {boolean} params.isHistoryNavigation - True if this action is invoked via history navigation. - * @returns {object} Action object. + * @return {object} Action object. */ export function initializeQueryValues( { isHistoryNavigation = false } = {} ) { return { @@ -57,9 +57,9 @@ export function initializeQueryValues( { isHistoryNavigation = false } = {} ) { /** * Returns an action object used to set a search query value. * - * @param {string} query - Inputted user query. + * @param {string} query - Inputted user query. * @param {boolean} propagateToWindow - If true, will tell the effects handler to set the search query in the location bar. - * @returns {object} Action object. + * @return {object} Action object. */ export function setSearchQuery( query, propagateToWindow = true ) { return { @@ -72,9 +72,9 @@ export function setSearchQuery( query, propagateToWindow = true ) { /** * Returns an action object used to set a search sort value. * - * @param {string} sort - Sort value. + * @param {string} sort - Sort value. * @param {boolean} propagateToWindow - If true, will tell the effects handler to set the query string in the location bar. - * @returns {object} Action object. + * @return {object} Action object. */ export function setSort( sort, propagateToWindow = true ) { return { @@ -87,10 +87,10 @@ export function setSort( sort, propagateToWindow = true ) { /** * Returns an action object used to set a search filter. * - * @param {string} name - Filter name. - * @param {string[]} value - Filter values. - * @param {boolean} propagateToWindow - If true, will tell the effects handler to set the query string in the location bar. - * @returns {object} Action object. + * @param {string} name - Filter name. + * @param {string[]} value - Filter values. + * @param {boolean} propagateToWindow - If true, will tell the effects handler to set the query string in the location bar. + * @return {object} Action object. */ export function setFilter( name, value, propagateToWindow = true ) { return { @@ -104,10 +104,10 @@ export function setFilter( name, value, propagateToWindow = true ) { /** * Returns an action object used to set a static search filter. * - * @param {string} name - Filter name. - * @param {string[]} value - Filter values. - * @param {boolean} propagateToWindow - If true, will tell the effects handler to set the query string in the location bar. - * @returns {object} Action object. + * @param {string} name - Filter name. + * @param {string[]} value - Filter values. + * @param {boolean} propagateToWindow - If true, will tell the effects handler to set the query string in the location bar. + * @return {object} Action object. */ export function setStaticFilter( name, value, propagateToWindow = true ) { return { @@ -122,7 +122,7 @@ export function setStaticFilter( name, value, propagateToWindow = true ) { * Returns an action object used to clear all filter values. * * @param {boolean} propagateToWindow - If true, will tell the effects handler to update the query string in the location bar. - * @returns {object} Action object. + * @return {object} Action object. */ export function clearFilters( propagateToWindow = true ) { return { @@ -134,7 +134,7 @@ export function clearFilters( propagateToWindow = true ) { /** * Returns an action object used to clear all query values. Invoked when the search modal is dismissed. * - * @returns {object} Action object. + * @return {object} Action object. */ export function clearQueryValues() { return { @@ -146,7 +146,7 @@ export function clearQueryValues() { * Returns an action object used to disable query string integration. * Used when search app is used in the Gutenberg context. * - * @returns {object} Action object. + * @return {object} Action object. */ export function disableQueryStringIntegration() { return { diff --git a/projects/packages/search/src/instant-search/store/effects.js b/projects/packages/search/src/instant-search/store/effects.js index 0d9149959c272..92a4f79e81b50 100644 --- a/projects/packages/search/src/instant-search/store/effects.js +++ b/projects/packages/search/src/instant-search/store/effects.js @@ -26,7 +26,7 @@ const debouncedSetQuery = debounce( setQuery, DEBOUNCED_TIME_TO_SET_QUERY_MILLIS * Effect handler which will fetch search results from the API. * * @param {object} action - Action which had initiated the effect handler. - * @param {object} store - Store instance. + * @param {object} store - Store instance. */ function makeSearchAPIRequest( action, store ) { requestCounter++; @@ -50,7 +50,7 @@ function makeSearchAPIRequest( action, store ) { * Initialize query values from the browser's address bar. * * @param {object} action - Action which had initiated the effect handler. - * @param {object} store - Store instance. + * @param {object} store - Store instance. */ function initializeQueryValues( action, store ) { const queryObject = getQuery(); diff --git a/projects/packages/search/src/instant-search/store/reducer/api.js b/projects/packages/search/src/instant-search/store/reducer/api.js index c446c9d7673d8..2742bf129785e 100644 --- a/projects/packages/search/src/instant-search/store/reducer/api.js +++ b/projects/packages/search/src/instant-search/store/reducer/api.js @@ -4,9 +4,9 @@ let cachedAggregations = {}; /** * Reducer for recording if the previous search request yielded an error. * - * @param {object} state - Current state. + * @param {object} state - Current state. * @param {object} action - Dispatched action. - * @returns {object} Updated state. + * @return {object} Updated state. */ export function hasError( state = false, action ) { switch ( action.type ) { @@ -23,9 +23,9 @@ export function hasError( state = false, action ) { /** * Reducer for recording search request state. * - * @param {object} state - Current state. + * @param {object} state - Current state. * @param {object} action - Dispatched action. - * @returns {object} Updated state. + * @return {object} Updated state. */ export function isLoading( state = false, action ) { switch ( action.type ) { @@ -42,9 +42,9 @@ export function isLoading( state = false, action ) { /** * Reducer for recording search results. * - * @param {object} state - Current state. + * @param {object} state - Current state. * @param {object} action - Dispatched action. - * @returns {object} Updated state. + * @return {object} Updated state. */ export function response( state = {}, action ) { switch ( action.type ) { diff --git a/projects/packages/search/src/instant-search/store/reducer/history.js b/projects/packages/search/src/instant-search/store/reducer/history.js index 93b7252b48cb4..2a5aee1138864 100644 --- a/projects/packages/search/src/instant-search/store/reducer/history.js +++ b/projects/packages/search/src/instant-search/store/reducer/history.js @@ -1,9 +1,9 @@ /** * Returns true if the query string change was performed by a history navigation. * - * @param {object} state - Current state. + * @param {object} state - Current state. * @param {object} action - Dispatched action. - * @returns {object} Updated state. + * @return {object} Updated state. */ export function isHistoryNavigation( state = false, action ) { switch ( action.type ) { diff --git a/projects/packages/search/src/instant-search/store/reducer/query-string.js b/projects/packages/search/src/instant-search/store/reducer/query-string.js index d56918485918b..1536cf6b686bc 100644 --- a/projects/packages/search/src/instant-search/store/reducer/query-string.js +++ b/projects/packages/search/src/instant-search/store/reducer/query-string.js @@ -4,9 +4,9 @@ import { getFilterKeys, getStaticFilterKeys } from '../../lib/filters'; /** * Reducer for keeping track of the user's inputted search query * - * @param {object} state - Current state. + * @param {object} state - Current state. * @param {object} action - Dispatched action. - * @returns {object} Updated state. + * @return {object} Updated state. */ export function searchQuery( state = null, action ) { switch ( action.type ) { @@ -22,9 +22,9 @@ export function searchQuery( state = null, action ) { /** * Reducer for keeping track of the user's selected sort type * - * @param {object} state - Current state. + * @param {object} state - Current state. * @param {object} action - Dispatched action. - * @returns {object} Updated state. + * @return {object} Updated state. */ export function sort( state = null, action ) { switch ( action.type ) { @@ -44,9 +44,9 @@ export function sort( state = null, action ) { /** * Reducer for keeping track of the user's selected filter value * - * @param {object} state - Current state. + * @param {object} state - Current state. * @param {object} action - Dispatched action. - * @returns {object} Updated state. + * @return {object} Updated state. */ export function filters( state = {}, action ) { switch ( action.type ) { @@ -77,9 +77,9 @@ export function filters( state = {}, action ) { /** * Reducer for keeping track of the user's selected static filter value * - * @param {object} state - Current state. + * @param {object} state - Current state. * @param {object} action - Dispatched action. - * @returns {object} Updated state. + * @return {object} Updated state. */ export function staticFilters( state = {}, action ) { switch ( action.type ) { diff --git a/projects/packages/search/src/instant-search/store/reducer/server-options.js b/projects/packages/search/src/instant-search/store/reducer/server-options.js index 256bff0bc768d..71153c51e3710 100644 --- a/projects/packages/search/src/instant-search/store/reducer/server-options.js +++ b/projects/packages/search/src/instant-search/store/reducer/server-options.js @@ -4,7 +4,7 @@ import { SERVER_OBJECT_NAME } from '../../lib/constants'; * Reducer for storing server-generated values in the Redux store. * * @param {object} state - Current state. - * @returns {object} Updated state. + * @return {object} Updated state. */ export function serverOptions( state = window[ SERVER_OBJECT_NAME ] ?? {} ) { return state; diff --git a/projects/packages/search/src/instant-search/store/selectors.js b/projects/packages/search/src/instant-search/store/selectors.js index e7d87b8712ea2..eebe508b96047 100644 --- a/projects/packages/search/src/instant-search/store/selectors.js +++ b/projects/packages/search/src/instant-search/store/selectors.js @@ -5,7 +5,7 @@ import { getUnselectableFilterKeys, mapFilterKeyToFilter } from '../lib/filters' * Get the stored API response. * * @param {object} state - Current state. - * @returns {object} Response object. + * @return {object} Response object. */ export function getResponse( state ) { return state.response; @@ -15,7 +15,7 @@ export function getResponse( state ) { * Get the hasError flag. * * @param {object} state - Current state. - * @returns {boolean} hasError - Whether the API returned an erroneous response. + * @return {boolean} hasError - Whether the API returned an erroneous response. */ export function hasError( state ) { return state.hasError; @@ -25,7 +25,7 @@ export function hasError( state ) { * Get the hasNextPage flag. * * @param {object} state - Current state. - * @returns {boolean} hasNextPage - Whether the API contains a page handle for a subsequent page. + * @return {boolean} hasNextPage - Whether the API contains a page handle for a subsequent page. */ export function hasNextPage( state ) { return ! hasError( state ) && getResponse( state )?.page_handle; @@ -35,7 +35,7 @@ export function hasNextPage( state ) { * Get the isLoading flag. * * @param {object} state - Current state. - * @returns {boolean} isLoading - Whether the API request is still loading. + * @return {boolean} isLoading - Whether the API request is still loading. */ export function isLoading( state ) { return state.isLoading; @@ -45,7 +45,7 @@ export function isLoading( state ) { * Get the search query. * * @param {object} state - Current state. - * @returns {string} searchQuery - The search query entered by the user. + * @return {string} searchQuery - The search query entered by the user. */ export function getSearchQuery( state ) { return state.searchQuery; @@ -54,9 +54,9 @@ export function getSearchQuery( state ) { /** * Get the sort key. * - * @param {object} state - Current state. + * @param {object} state - Current state. * @param {string?} defaultSort - Default sort order specified via the Customizer. - * @returns {string} sort - The selected sort key for the search interface. + * @return {string} sort - The selected sort key for the search interface. */ export function getSort( state, defaultSort ) { // Default non-string defaultSort to 'relevance' @@ -70,7 +70,7 @@ export function getSort( state, defaultSort ) { * Get the filters. * * @param {object} state - Current state. - * @returns {object} filters - An object mapping filter keys and its selected values. + * @return {object} filters - An object mapping filter keys and its selected values. */ export function getFilters( state ) { return state.filters; @@ -80,7 +80,7 @@ export function getFilters( state ) { * Get the selected static filters. * * @param {object} state - Current state. - * @returns {object} filters - An object mapping filter keys and its selected values. + * @return {object} filters - An object mapping filter keys and its selected values. */ export function getStaticFilters( state ) { return state.staticFilters; @@ -90,7 +90,7 @@ export function getStaticFilters( state ) { * Checks if any filters have been selected. * * @param {object} state - Current state. - * @returns {object} hasFilters - true if any filter has been selected. + * @return {object} hasFilters - true if any filter has been selected. */ export function hasFilters( state ) { return Object.keys( state.filters ).length > 0; @@ -100,7 +100,7 @@ export function hasFilters( state ) { * Checks if any static filters have been selected. * * @param {object} state - Current state. - * @returns {object} hasStaticFilters - true if any filter has been selected. + * @return {object} hasStaticFilters - true if any filter has been selected. */ function hasStaticFilters( state ) { return Object.keys( state.staticFilters ).length > 0; @@ -110,7 +110,7 @@ function hasStaticFilters( state ) { * Checks if there is an active search-related query values. * * @param {object} state - Current state. - * @returns {object} hasActiveQuery - true if any search-related query value has been defined. + * @return {object} hasActiveQuery - true if any search-related query value has been defined. */ export function hasActiveQuery( state ) { return ( @@ -127,7 +127,7 @@ export function hasActiveQuery( state ) { * This is used to render a single SearchFilters component for all filters selected outside the search overlay. * * @param {object} state - Redux state tree. - * @returns {{ filters: object[] }} pseudoWidget - contains `filters`, an array of filter objects selected outside the search overlay. + * @return {{ filters: object[] }} pseudoWidget - contains `filters`, an array of filter objects selected outside the search overlay. */ export function getWidgetOutsideOverlay( state ) { // Both of these values should default to [] when empty; they should never be falsy. @@ -146,7 +146,7 @@ export function getWidgetOutsideOverlay( state ) { * Returns true if the query string change was performed by a history navigation. * * @param {object} state - Current state. - * @returns {boolean} isHistoryNavigation. + * @return {boolean} isHistoryNavigation. */ export function isHistoryNavigation( state ) { return state.isHistoryNavigation; diff --git a/projects/packages/search/tools/define-palette-colors-as-static-variables.js b/projects/packages/search/tools/define-palette-colors-as-static-variables.js index 66f6daf021742..28d2401e7505d 100644 --- a/projects/packages/search/tools/define-palette-colors-as-static-variables.js +++ b/projects/packages/search/tools/define-palette-colors-as-static-variables.js @@ -5,7 +5,7 @@ const webpack = require( 'webpack' ); /** * Returns an instance of the DefinePlugin that adds color-studio colors as literals. * - * @returns {object} DefinePlugin instance. + * @return {object} DefinePlugin instance. */ function definePaletteColorsAsStaticVariables() { return new webpack.DefinePlugin( { diff --git a/projects/packages/search/tools/webpack.instant.config.js b/projects/packages/search/tools/webpack.instant.config.js index 156163122a08b..b971d5b1602c3 100644 --- a/projects/packages/search/tools/webpack.instant.config.js +++ b/projects/packages/search/tools/webpack.instant.config.js @@ -14,7 +14,7 @@ const webpack = jetpackWebpackConfig.webpack; * This enables us to alias Preact to all React imports. * * @param {string} request - Requested module - * @returns {(string|string[]|undefined)} Script global + * @return {(string|string[]|undefined)} Script global */ function requestToExternal( request ) { // Ensure that React will be aliased to preact/compat by preventing externalization. diff --git a/projects/packages/stats-admin/CHANGELOG.md b/projects/packages/stats-admin/CHANGELOG.md index e74bc55159130..dc2d660511c07 100644 --- a/projects/packages/stats-admin/CHANGELOG.md +++ b/projects/packages/stats-admin/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.21.1 - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## 0.21.0 - 2024-07-08 ### Added - Stats: Add purchases endpoint [#38150] diff --git a/projects/packages/stats-admin/composer.json b/projects/packages/stats-admin/composer.json index 378c7ebae405d..8a319a8c28c3c 100644 --- a/projects/packages/stats-admin/composer.json +++ b/projects/packages/stats-admin/composer.json @@ -13,7 +13,7 @@ "automattic/jetpack-jitm": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master" }, diff --git a/projects/packages/stats-admin/package.json b/projects/packages/stats-admin/package.json index d8924f20ca0ac..0876b7964fabb 100644 --- a/projects/packages/stats-admin/package.json +++ b/projects/packages/stats-admin/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-stats-admin", - "version": "0.21.0", + "version": "0.21.1", "description": "Stats Dashboard", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/stats-admin/#readme", "bugs": { diff --git a/projects/packages/stats-admin/src/class-main.php b/projects/packages/stats-admin/src/class-main.php index e7cc914c9a523..c7d8cae97bee4 100644 --- a/projects/packages/stats-admin/src/class-main.php +++ b/projects/packages/stats-admin/src/class-main.php @@ -22,7 +22,7 @@ class Main { /** * Stats version. */ - const VERSION = '0.21.0'; + const VERSION = '0.21.1'; /** * Singleton Main instance. diff --git a/projects/packages/stats/CHANGELOG.md b/projects/packages/stats/CHANGELOG.md index 49eac965e79f9..a8301159a65fb 100644 --- a/projects/packages/stats/CHANGELOG.md +++ b/projects/packages/stats/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.13.1] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + ## [0.13.0] - 2024-06-10 ### Added - Staging: deprecating staging mode and separating the logic into is_development_site and in_safe_mode [#37023] @@ -174,6 +178,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixing static method which was called without self reference. [#26640] +[0.13.1]: https://github.com/Automattic/jetpack-stats/compare/v0.13.0...v0.13.1 [0.13.0]: https://github.com/Automattic/jetpack-stats/compare/v0.12.5...v0.13.0 [0.12.5]: https://github.com/Automattic/jetpack-stats/compare/v0.12.4...v0.12.5 [0.12.4]: https://github.com/Automattic/jetpack-stats/compare/v0.12.3...v0.12.4 diff --git a/projects/packages/stats/composer.json b/projects/packages/stats/composer.json index 0ea571c7ef9a2..67fc3d472ab36 100644 --- a/projects/packages/stats/composer.json +++ b/projects/packages/stats/composer.json @@ -10,7 +10,7 @@ "automattic/jetpack-status": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master" }, diff --git a/projects/packages/stats/src/class-package-version.php b/projects/packages/stats/src/class-package-version.php index be8dc496c81ca..35e9ebcf8dae5 100644 --- a/projects/packages/stats/src/class-package-version.php +++ b/projects/packages/stats/src/class-package-version.php @@ -12,7 +12,7 @@ */ class Package_Version { - const PACKAGE_VERSION = '0.13.0'; + const PACKAGE_VERSION = '0.13.1'; const PACKAGE_SLUG = 'stats'; diff --git a/projects/packages/status/CHANGELOG.md b/projects/packages/status/CHANGELOG.md index 04c3c8d6d08d0..ed2449849431f 100644 --- a/projects/packages/status/CHANGELOG.md +++ b/projects/packages/status/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.3.4] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + +## [3.3.3] - 2024-08-19 +### Changed +- Internal updates. + ## [3.3.2] - 2024-06-24 ### Changed - Internal updates. @@ -381,6 +389,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Packages: Introduce a status package +[3.3.4]: https://github.com/Automattic/jetpack-status/compare/v3.3.3...v3.3.4 +[3.3.3]: https://github.com/Automattic/jetpack-status/compare/v3.3.2...v3.3.3 [3.3.2]: https://github.com/Automattic/jetpack-status/compare/v3.3.1...v3.3.2 [3.3.1]: https://github.com/Automattic/jetpack-status/compare/v3.3.0...v3.3.1 [3.3.0]: https://github.com/Automattic/jetpack-status/compare/v3.2.3...v3.3.0 diff --git a/projects/packages/status/changelog/renovate-lock-file-maintenance b/projects/packages/status/changelog/renovate-lock-file-maintenance deleted file mode 100644 index 3109d07526368..0000000000000 --- a/projects/packages/status/changelog/renovate-lock-file-maintenance +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: changed -Comment: Update Phan baseline. - - diff --git a/projects/packages/status/composer.json b/projects/packages/status/composer.json index f3f9f33e29a52..cf7d7f895a4b5 100644 --- a/projects/packages/status/composer.json +++ b/projects/packages/status/composer.json @@ -9,7 +9,7 @@ }, "require-dev": { "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/jetpack-connection": "@dev", "automattic/jetpack-plans": "@dev", diff --git a/projects/plugins/boost/changelog/renovate-definitelytyped b/projects/packages/stub-generator/changelog/renovate-yoast-phpunit-polyfills-1.x similarity index 100% rename from projects/plugins/boost/changelog/renovate-definitelytyped rename to projects/packages/stub-generator/changelog/renovate-yoast-phpunit-polyfills-1.x diff --git a/projects/packages/stub-generator/changelog/try-no-version-bumps-in-trunk b/projects/packages/stub-generator/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..91efe85c55e06 --- /dev/null +++ b/projects/packages/stub-generator/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/packages/stub-generator/composer.json b/projects/packages/stub-generator/composer.json index abb7f82c246e1..2f384bc24947b 100644 --- a/projects/packages/stub-generator/composer.json +++ b/projects/packages/stub-generator/composer.json @@ -17,7 +17,7 @@ "symfony/console": "^5.3 || ^6.0 || ^7.0" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "autoload": { diff --git a/projects/packages/sync/CHANGELOG.md b/projects/packages/sync/CHANGELOG.md index 27648eeaf19d1..8f72a9d22eae9 100644 --- a/projects/packages/sync/CHANGELOG.md +++ b/projects/packages/sync/CHANGELOG.md @@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.8.1] - 2024-08-29 +### Changed +- Sync: Add subscription type for HPOS orders only if WooCommerce Subscriptions plugin exists [#39118] + +## [3.8.0] - 2024-08-26 +### Changed +- Sync: Updated allowed order types in HPOS Module [#39022] + +### Fixed +- Sync: Ensure filtering orders by status when doing HPOS Checksums [#39020] + +## [3.7.1] - 2024-08-23 +### Changed +- Updated package dependencies. [#39004] + +## [3.7.0] - 2024-08-21 +### Added +- Synced Order Data: adds filtering to the filtered order data [#38955] + ## [3.6.0] - 2024-08-15 ### Added - Sync: Add a new callable for Sync Active Modules [#38831] @@ -1239,6 +1258,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Packages: Move sync to a classmapped package +[3.8.1]: https://github.com/Automattic/jetpack-sync/compare/v3.8.0...v3.8.1 +[3.8.0]: https://github.com/Automattic/jetpack-sync/compare/v3.7.1...v3.8.0 +[3.7.1]: https://github.com/Automattic/jetpack-sync/compare/v3.7.0...v3.7.1 +[3.7.0]: https://github.com/Automattic/jetpack-sync/compare/v3.6.0...v3.7.0 [3.6.0]: https://github.com/Automattic/jetpack-sync/compare/v3.5.1...v3.6.0 [3.5.1]: https://github.com/Automattic/jetpack-sync/compare/v3.5.0...v3.5.1 [3.5.0]: https://github.com/Automattic/jetpack-sync/compare/v3.4.1...v3.5.0 diff --git a/projects/packages/sync/changelog/add-social-share-status-shares-modal b/projects/packages/sync/changelog/add-social-share-status-shares-modal new file mode 100644 index 0000000000000..bf7d182e6814d --- /dev/null +++ b/projects/packages/sync/changelog/add-social-share-status-shares-modal @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Add share status log modal to published posts diff --git a/projects/packages/sync/composer.json b/projects/packages/sync/composer.json index 423bc092a5cc5..db452a140e4eb 100644 --- a/projects/packages/sync/composer.json +++ b/projects/packages/sync/composer.json @@ -14,7 +14,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-search": "@dev", "automattic/jetpack-waf": "@dev", "automattic/wordbless": "@dev" @@ -59,7 +59,7 @@ "link-template": "https://github.com/Automattic/jetpack-sync/compare/v${old}...v${new}" }, "branch-alias": { - "dev-trunk": "3.6.x-dev" + "dev-trunk": "3.8.x-dev" }, "dependencies": { "test-only": [ diff --git a/projects/packages/sync/src/class-package-version.php b/projects/packages/sync/src/class-package-version.php index bea1c23cfe552..4c54e9df610a0 100644 --- a/projects/packages/sync/src/class-package-version.php +++ b/projects/packages/sync/src/class-package-version.php @@ -12,7 +12,7 @@ */ class Package_Version { - const PACKAGE_VERSION = '3.6.0'; + const PACKAGE_VERSION = '3.8.1'; const PACKAGE_SLUG = 'sync'; diff --git a/projects/packages/sync/src/modules/class-woocommerce-hpos-orders.php b/projects/packages/sync/src/modules/class-woocommerce-hpos-orders.php index d3abc38330079..90a7a101f7145 100644 --- a/projects/packages/sync/src/modules/class-woocommerce-hpos-orders.php +++ b/projects/packages/sync/src/modules/class-woocommerce-hpos-orders.php @@ -14,6 +14,11 @@ */ class WooCommerce_HPOS_Orders extends Module { + /** + * The slug of WooCommerce Subscriptions plugin. + */ + const WOOCOMMERCE_SUBSCRIPTIONS_PATH = 'woocommerce-subscriptions/woocommerce-subscriptions.php'; + /** * Order table name. There are four order tables (order, addresses, operational_data and meta), but for sync purposes we only care about the main table since it has the order ID. * @@ -66,6 +71,11 @@ public function __construct() { */ public static function get_order_types_to_sync( $prefixed = false ) { $types = array( 'order', 'order_refund' ); + + if ( is_plugin_active( self::WOOCOMMERCE_SUBSCRIPTIONS_PATH ) ) { + $types[] = 'subscription'; + } + if ( $prefixed ) { $types = array_map( function ( $type ) { @@ -166,7 +176,7 @@ public function get_objects_by_id( $object_type, $ids ) { array( 'post__in' => $ids, 'type' => self::get_order_types_to_sync( true ), - 'post_status' => $this->get_all_possible_order_status_keys(), + 'post_status' => self::get_all_possible_order_status_keys(), 'limit' => -1, ) ); @@ -301,21 +311,29 @@ private function filter_order_data( $order_object ) { if ( '' === $filtered_order_data['status'] ) { $filtered_order_data['status'] = 'pending'; } - $filtered_order_data['status'] = $this->get_wc_order_status_with_prefix( $filtered_order_data['status'] ); - - return $filtered_order_data; + $filtered_order_data['status'] = self::get_wc_order_status_with_prefix( $filtered_order_data['status'] ); + + /** + * Filter the order data before syncing. + * + * @since 3.7.0 + * + * @param array $filtered_order_data The Filtered order data. + * @param \WC_Abstract_Order $order_object The Order object. + */ + return apply_filters( 'jetpack_sync_filtered_hpos_order_data', $filtered_order_data, $order_object ); } /** * Returns all possible order status keys, including 'auto-draft' and 'trash'. * - * @access protected + * @access public * * @return array An array of all possible status keys, including 'auto-draft' and 'trash'. */ - protected function get_all_possible_order_status_keys() { + public static function get_all_possible_order_status_keys() { $order_statuses = array( 'auto-draft', 'trash' ); - $wc_order_statuses = $this->wc_get_order_status_keys(); + $wc_order_statuses = self::wc_get_order_status_keys(); return array_unique( array_merge( $wc_order_statuses, $order_statuses ) ); } @@ -327,8 +345,8 @@ protected function get_all_possible_order_status_keys() { * * @return string The WC order status with the 'wc-' prefix if it's a valid order status, initial $status otherwise. */ - protected function get_wc_order_status_with_prefix( string $status ) { - return in_array( 'wc-' . $status, $this->wc_get_order_status_keys(), true ) ? 'wc-' . $status : $status; + protected static function get_wc_order_status_with_prefix( string $status ) { + return in_array( 'wc-' . $status, self::wc_get_order_status_keys(), true ) ? 'wc-' . $status : $status; } /** @@ -338,7 +356,7 @@ protected function get_wc_order_status_with_prefix( string $status ) { * * @return array Filtered order metadata. */ - private function wc_get_order_status_keys() { + private static function wc_get_order_status_keys() { $wc_order_statuses = array(); if ( function_exists( 'wc_get_order_statuses' ) ) { $wc_order_statuses = array_keys( wc_get_order_statuses() ); diff --git a/projects/packages/sync/src/replicastore/class-table-checksum.php b/projects/packages/sync/src/replicastore/class-table-checksum.php index 2413a5e9f8014..30d0bc1caaf7c 100644 --- a/projects/packages/sync/src/replicastore/class-table-checksum.php +++ b/projects/packages/sync/src/replicastore/class-table-checksum.php @@ -315,10 +315,14 @@ protected function get_default_tables() { 'checksum_fields' => array( 'date_updated_gmt', 'total_amount' ), 'checksum_text_fields' => array( 'type', 'status' ), 'filter_values' => array( - 'type' => array( + 'type' => array( 'operator' => 'IN', 'values' => WooCommerce_HPOS_Orders::get_order_types_to_sync( true ), ), + 'status' => array( + 'operator' => 'IN', + 'values' => WooCommerce_HPOS_Orders::get_all_possible_order_status_keys(), + ), ), 'is_table_enabled_callback' => 'Automattic\Jetpack\Sync\Replicastore\Table_Checksum::enable_woocommerce_hpos_tables', ), diff --git a/projects/plugins/boost/changelog/renovate-lock-file-maintenance b/projects/packages/transport-helper/changelog/renovate-yoast-phpunit-polyfills-1.x similarity index 100% rename from projects/plugins/boost/changelog/renovate-lock-file-maintenance rename to projects/packages/transport-helper/changelog/renovate-yoast-phpunit-polyfills-1.x diff --git a/projects/packages/transport-helper/changelog/try-no-version-bumps-in-trunk b/projects/packages/transport-helper/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..91efe85c55e06 --- /dev/null +++ b/projects/packages/transport-helper/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/packages/transport-helper/composer.json b/projects/packages/transport-helper/composer.json index c9a858e428de2..f116659c6684c 100644 --- a/projects/packages/transport-helper/composer.json +++ b/projects/packages/transport-helper/composer.json @@ -9,7 +9,7 @@ "automattic/jetpack-connection": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master" }, diff --git a/projects/packages/videopress/CHANGELOG.md b/projects/packages/videopress/CHANGELOG.md index a480140d1bb2c..186aacb68088a 100644 --- a/projects/packages/videopress/CHANGELOG.md +++ b/projects/packages/videopress/CHANGELOG.md @@ -5,6 +5,27 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.24.3] - 2024-08-26 +### Added +- Add context switching to videopress card from yearly views to monthly views [#38979] + +### Changed +- Updated package dependencies. [#39004] + +## [0.24.2] - 2024-08-21 +### Changed +- Internal updates. + +## [0.24.1] - 2024-08-19 +### Added +- Add value to active card state on VideoPress My Jetpack card. [#38812] + +### Changed +- Updated package dependencies. [#38893] + +### Fixed +- Lossless image optimization for images (should improve performance with no visible changes). [#38750] + ## [0.24.0] - 2024-08-15 ### Changed - Updated package dependencies. [#38665] @@ -1395,6 +1416,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Created empty package [#24952] +[0.24.3]: https://github.com/Automattic/jetpack-videopress/compare/v0.24.2...v0.24.3 +[0.24.2]: https://github.com/Automattic/jetpack-videopress/compare/v0.24.1...v0.24.2 +[0.24.1]: https://github.com/Automattic/jetpack-videopress/compare/v0.24.0...v0.24.1 [0.24.0]: https://github.com/Automattic/jetpack-videopress/compare/v0.23.31...v0.24.0 [0.23.31]: https://github.com/Automattic/jetpack-videopress/compare/v0.23.30...v0.23.31 [0.23.30]: https://github.com/Automattic/jetpack-videopress/compare/v0.23.29...v0.23.30 diff --git a/projects/packages/videopress/changelog/add-more-eslint-rules b/projects/packages/videopress/changelog/add-more-eslint-rules new file mode 100644 index 0000000000000..2b32cb03e644c --- /dev/null +++ b/projects/packages/videopress/changelog/add-more-eslint-rules @@ -0,0 +1,5 @@ +Significance: patch +Type: fixed +Comment: Fix new eslint sniffs. Should be no change in functionality. + + diff --git a/projects/packages/videopress/changelog/add-value-to-active-state-videopress-card b/projects/packages/videopress/changelog/add-value-to-active-state-videopress-card deleted file mode 100644 index e5a8f5a36e844..0000000000000 --- a/projects/packages/videopress/changelog/add-value-to-active-state-videopress-card +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: added - -Add value to active card state on VideoPress My Jetpack card diff --git a/projects/plugins/boost/changelog/renovate-storybook-monorepo b/projects/packages/videopress/changelog/renovate-npm-webpack-vulnerability similarity index 100% rename from projects/plugins/boost/changelog/renovate-storybook-monorepo rename to projects/packages/videopress/changelog/renovate-npm-webpack-vulnerability diff --git a/projects/packages/videopress/changelog/renovate-storybook-monorepo#2 b/projects/packages/videopress/changelog/renovate-storybook-monorepo#2 deleted file mode 100644 index 725319cd88d1c..0000000000000 --- a/projects/packages/videopress/changelog/renovate-storybook-monorepo#2 +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: fixed -Comment: Move `@storybook/addon-actions` to devDependencies. - - diff --git a/projects/packages/videopress/changelog/update-jetpack-menu-item-order b/projects/packages/videopress/changelog/update-jetpack-menu-item-order new file mode 100644 index 0000000000000..4bfbd859ba2bf --- /dev/null +++ b/projects/packages/videopress/changelog/update-jetpack-menu-item-order @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Admin menu: change order of Jetpack sub-menu items diff --git a/projects/packages/videopress/composer.json b/projects/packages/videopress/composer.json index e31d8ae6d1abe..e0f685d077ab9 100644 --- a/projects/packages/videopress/composer.json +++ b/projects/packages/videopress/composer.json @@ -12,7 +12,7 @@ "automattic/jetpack-plans": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev", "brain/monkey": "2.6.1" diff --git a/projects/packages/videopress/package.json b/projects/packages/videopress/package.json index 52b06f3bea291..57374a8cd25f1 100644 --- a/projects/packages/videopress/package.json +++ b/projects/packages/videopress/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@automattic/jetpack-videopress", - "version": "0.24.1-alpha", + "version": "0.24.3", "description": "VideoPress package", "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/packages/videopress/#readme", "bugs": { @@ -53,7 +53,7 @@ "sass-loader": "12.4.0", "storybook": "8.2.9", "typescript": "5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "dependencies": { diff --git a/projects/packages/videopress/src/class-admin-ui.php b/projects/packages/videopress/src/class-admin-ui.php index 6c5784fd31b74..ef5182a691076 100644 --- a/projects/packages/videopress/src/class-admin-ui.php +++ b/projects/packages/videopress/src/class-admin-ui.php @@ -39,7 +39,8 @@ public static function init() { _x( 'VideoPress', 'The Jetpack VideoPress product name, without the Jetpack prefix', 'jetpack-videopress-pkg' ), 'manage_options', self::ADMIN_PAGE_SLUG, - array( __CLASS__, 'plugin_settings_page' ) + array( __CLASS__, 'plugin_settings_page' ), + 3 ); add_action( 'load-' . $page_suffix, array( __CLASS__, 'admin_init' ) ); diff --git a/projects/packages/videopress/src/class-package-version.php b/projects/packages/videopress/src/class-package-version.php index 39010f2746aa9..87ae115a7475f 100644 --- a/projects/packages/videopress/src/class-package-version.php +++ b/projects/packages/videopress/src/class-package-version.php @@ -11,7 +11,7 @@ * The Package_Version class. */ class Package_Version { - const PACKAGE_VERSION = '0.24.1-alpha'; + const PACKAGE_VERSION = '0.24.3'; const PACKAGE_SLUG = 'videopress'; diff --git a/projects/packages/videopress/src/class-stats.php b/projects/packages/videopress/src/class-stats.php index ee29d788881e9..056f6284c46cd 100644 --- a/projects/packages/videopress/src/class-stats.php +++ b/projects/packages/videopress/src/class-stats.php @@ -87,15 +87,16 @@ public static function get_today_plays() { /** * Returns the featured stats for VideoPress. * - * @param int $days (optional) The number of days to consider. + * @param int $period_count (optional) The number of days to consider. + * @param string $period (optional) The period to consider. * * @return array|WP_Error a list of stats, or WP_Error on failure. */ - public static function get_featured_stats( $days = 14 ) { + public static function get_featured_stats( $period_count = 14, $period = 'day' ) { $response = self::fetch_video_plays( array( - 'period' => 'day', - 'num' => $days, + 'period' => $period, + 'num' => $period_count, 'complete_stats' => true, ) ); @@ -117,29 +118,32 @@ public static function get_featured_stats( $days = 14 ) { $dates = $data['days']; // Organize the data into the planned stats - return self::prepare_featured_stats( $dates, $days ); + return self::prepare_featured_stats( $dates, $period_count, $period ); } /** * Prepares the featured stats for VideoPress. * - * @param array $dates The list of dates returned by the API. - * @param int $total_days The total number of days to consider. + * @param array $dates The list of dates returned by the API. + * @param int $period_count The total number of days to consider. + * @param string $period The period to consider. * @return array a list of stats. */ - public static function prepare_featured_stats( $dates, $total_days ) { + public static function prepare_featured_stats( $dates, $period_count, $period = 'day' ) { /** * Ensure the sorting of the dates, recent ones first. * This way, the first 7 positions are from the last 7 days, * and the next 7 positions are from the 7 days before it. */ krsort( $dates ); + $period_of_data = floor( $period_count / 2 ); // template for the response $featured_stats = array( - // translators: %d is the number of days - 'label' => sprintf( __( 'last %d days', 'jetpack-videopress-pkg' ), floor( $total_days / 2 ) ), - 'data' => array( + // translators: %1$d is the number of units of time, %2$s is the period in which the units of time are measured ex. 'day' or 'year'. + 'label' => sprintf( _n( 'last %1$d %2$s', 'last %1$d %2$ss', (int) $period_of_data, 'jetpack-videopress-pkg' ), $period_of_data, $period ), + 'period' => $period, + 'data' => array( 'views' => array( 'current' => 0, 'previous' => 0, @@ -160,7 +164,7 @@ public static function prepare_featured_stats( $dates, $total_days ) { foreach ( $dates as $date_info ) { $date_totals = $date_info['total']; - if ( $counter < floor( $total_days / 2 ) ) { + if ( $counter < floor( $period_count / 2 ) ) { // the first 7 elements are for the current period $featured_stats['data']['views']['current'] += $date_totals['views']; diff --git a/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx b/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx index 7178449b89919..51867437b2aa4 100644 --- a/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx @@ -108,8 +108,6 @@ const useDashboardVideos = () => { setVideosQuery( { search: searchFromSearchParam, } ); - - return; } }, [ totalOfPages, page, pageFromSearchParam, search, searchFromSearchParam, tempPage.current ] ); diff --git a/projects/packages/videopress/src/client/admin/components/clipboard-button-input/index.tsx b/projects/packages/videopress/src/client/admin/components/clipboard-button-input/index.tsx index 40816b7886905..9eaf2a927b95c 100644 --- a/projects/packages/videopress/src/client/admin/components/clipboard-button-input/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/clipboard-button-input/index.tsx @@ -16,7 +16,7 @@ import type React from 'react'; * ClipboardButtionInput component * * @param {ClipboardButtonInput} props - Component props. - * @returns {React.ReactNode} - ClipboardButtonInput react component. + * @return {React.ReactNode} - ClipboardButtonInput react component. */ const ClipboardButtonInput: React.FC< ClipboardButtonInputProps > = ( { text, diff --git a/projects/packages/videopress/src/client/admin/components/global-notice/index.tsx b/projects/packages/videopress/src/client/admin/components/global-notice/index.tsx index 48962e1fbcd21..b73a161ff25ea 100644 --- a/projects/packages/videopress/src/client/admin/components/global-notice/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/global-notice/index.tsx @@ -47,14 +47,14 @@ const getIconByLevel = ( level: NoticeStatusProp ) => { /** * VideoPress Logo component * - * @param {object} props - Component props - * @param {NoticeStatusProp} props.status - Notice status severity - * @param {boolean} props.isDismissible - Whether the notice is dismissible - * @param {string} props.className - Additional class name - * @param {Function} props.onRemove - Callback when the notice is removed - * @param {React.ReactNode} props.children - Notice content - * @param {Array} props.actions - Notice actions - * @returns {React.ReactElement} Component template + * @param {object} props - Component props + * @param {NoticeStatusProp} props.status - Notice status severity + * @param {boolean} props.isDismissible - Whether the notice is dismissible + * @param {string} props.className - Additional class name + * @param {Function} props.onRemove - Callback when the notice is removed + * @param {React.ReactNode} props.children - Notice content + * @param {Array} props.actions - Notice actions + * @return {React.ReactElement} Component template */ export default function GlobalNotice( { status = 'error', diff --git a/projects/packages/videopress/src/client/admin/components/input/index.tsx b/projects/packages/videopress/src/client/admin/components/input/index.tsx index b52134162226d..841fc22901654 100644 --- a/projects/packages/videopress/src/client/admin/components/input/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/input/index.tsx @@ -51,7 +51,7 @@ const InputWrapper = ( { onChange: handleChangeEvent, onKeyUp: handleKeyUpEvent, disabled: disabled, - [ 'aria-disabled' ]: disabled, + 'aria-disabled': disabled, }; const isTextarea = inputProps?.type === 'textarea'; @@ -89,7 +89,7 @@ const InputWrapper = ( { * Input component * * @param {InputProps} props - Component props. - * @returns {React.ReactNode} - Input react component. + * @return {React.ReactNode} - Input react component. */ export const Input = ( { name, @@ -120,7 +120,7 @@ export const Input = ( { * Search Input component * * @param {InputProps} props - Component props. - * @returns {React.ReactNode} - Input react component. + * @return {React.ReactNode} - Input react component. */ export const SearchInput = ( { placeholder = __( 'Search your library', 'jetpack-videopress-pkg' ), diff --git a/projects/packages/videopress/src/client/admin/components/pagination/index.tsx b/projects/packages/videopress/src/client/admin/components/pagination/index.tsx index b35cc5ee1fa47..e4e74173dc8c6 100644 --- a/projects/packages/videopress/src/client/admin/components/pagination/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/pagination/index.tsx @@ -33,7 +33,7 @@ const Ellipsis = () => ( * Pagination component * * @param {PaginationProps} props - Component props. - * @returns {React.ReactNode} - Pagination react component. + * @return {React.ReactNode} - Pagination react component. */ const Pagination: React.FC< PaginationProps > = ( { className, diff --git a/projects/packages/videopress/src/client/admin/components/publish-first-video-popover/index.tsx b/projects/packages/videopress/src/client/admin/components/publish-first-video-popover/index.tsx index 3fde0068f123a..f53ba1eac829a 100644 --- a/projects/packages/videopress/src/client/admin/components/publish-first-video-popover/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/publish-first-video-popover/index.tsx @@ -22,7 +22,7 @@ import type React from 'react'; * Publish First Video Popover component * * @param {PublishFirstVideoPopoverProps} props - Component props. - * @returns {React.ReactNode} - PublishFirstVideoPopover react component. + * @return {React.ReactNode} - PublishFirstVideoPopover react component. */ const PublishFirstVideoPopover = ( { id, diff --git a/projects/packages/videopress/src/client/admin/components/site-settings-section/index.tsx b/projects/packages/videopress/src/client/admin/components/site-settings-section/index.tsx index 2e67f771a9f7c..636f31e52e7db 100644 --- a/projects/packages/videopress/src/client/admin/components/site-settings-section/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/site-settings-section/index.tsx @@ -20,7 +20,7 @@ import type React from 'react'; * VideoPress SettingsSection component * * @param {SiteSettingsSectionProps} props - Component props. - * @returns {React.ReactElement} Component template + * @return {React.ReactElement} Component template */ const SiteSettingsSection: React.FC< SiteSettingsSectionProps > = ( { videoPressVideosPrivateForSite, diff --git a/projects/packages/videopress/src/client/admin/components/video-card/error.tsx b/projects/packages/videopress/src/client/admin/components/video-card/error.tsx index 30b259c82c4eb..f5bd1732c2beb 100644 --- a/projects/packages/videopress/src/client/admin/components/video-card/error.tsx +++ b/projects/packages/videopress/src/client/admin/components/video-card/error.tsx @@ -30,7 +30,7 @@ import type React from 'react'; * Video Card Error component * * @param {VideoCardProps} props - Component props. - * @returns {React.ReactNode} - VideoCardError react component. + * @return {React.ReactNode} - VideoCardError react component. */ export const VideoCardError = ( { title, id }: VideoCardProps ) => { const { dismissErroredVideo } = useDispatch( STORE_ID ); diff --git a/projects/packages/videopress/src/client/admin/components/video-card/index.tsx b/projects/packages/videopress/src/client/admin/components/video-card/index.tsx index 62f31bca64821..6f2d53098ee6c 100644 --- a/projects/packages/videopress/src/client/admin/components/video-card/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/video-card/index.tsx @@ -60,7 +60,7 @@ const QuickActions = ( { * Video Card component * * @param {VideoCardProps} props - Component props. - * @returns {React.ReactNode} - VideoCard react component. + * @return {React.ReactNode} - VideoCard react component. */ export const VideoCard = ( { title, diff --git a/projects/packages/videopress/src/client/admin/components/video-grid/index.tsx b/projects/packages/videopress/src/client/admin/components/video-grid/index.tsx index 5d3af2d6b1e7c..1f184fe3c2563 100644 --- a/projects/packages/videopress/src/client/admin/components/video-grid/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/video-grid/index.tsx @@ -15,7 +15,7 @@ import type React from 'react'; * Video Grid component * * @param {VideoGridProps} props - Component props. - * @returns {React.ReactNode} - VideoGrid react component. + * @return {React.ReactNode} - VideoGrid react component. */ const VideoGrid = ( { videos, count = 6, onVideoDetailsClick, loading }: VideoGridProps ) => { const gridVideos = videos.slice( 0, count ); diff --git a/projects/packages/videopress/src/client/admin/components/video-stats-group/index.tsx b/projects/packages/videopress/src/client/admin/components/video-stats-group/index.tsx index a6e9151650019..6bab26428ef01 100644 --- a/projects/packages/videopress/src/client/admin/components/video-stats-group/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/video-stats-group/index.tsx @@ -26,7 +26,7 @@ const Stats = ( { label, value = 0 }: { label: string; value: number } ) => { * Video Stats Group component * * @param {VideoStatsGroupProps} props - Component props. - * @returns {React.ReactNode} - VideoStatsGroup react component. + * @return {React.ReactNode} - VideoStatsGroup react component. */ const VideoStatsGroup = ( { className, diff --git a/projects/packages/videopress/src/client/admin/components/video-storage-meter/index.tsx b/projects/packages/videopress/src/client/admin/components/video-storage-meter/index.tsx index 7e383239ddc47..2cc98688c61ea 100644 --- a/projects/packages/videopress/src/client/admin/components/video-storage-meter/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/video-storage-meter/index.tsx @@ -23,7 +23,7 @@ import type React from 'react'; * Video Storage Meter component * * @param {VideoStorageMeterProps} props - Component props. - * @returns {React.ReactNode} - VideoStorageMeter react component. + * @return {React.ReactNode} - VideoStorageMeter react component. */ const VideoStorageMeter: React.FC< VideoStorageMeterProps > = ( { className, diff --git a/projects/packages/videopress/src/client/admin/components/video-thumbnail-selector-modal/index.tsx b/projects/packages/videopress/src/client/admin/components/video-thumbnail-selector-modal/index.tsx index 33f5b13799905..4b3451c08e3a1 100644 --- a/projects/packages/videopress/src/client/admin/components/video-thumbnail-selector-modal/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/video-thumbnail-selector-modal/index.tsx @@ -18,7 +18,7 @@ import { VideoThumbnailSelectorModalProps } from './types'; * Video Thumbnail Selector component * * @param {VideoThumbnailSelectorModalProps} props - Component props. - * @returns {ReactNode} - VideoThumbnailSelector react component. + * @return {ReactNode} - VideoThumbnailSelector react component. */ const VideoThumbnailSelectorModal = ( { url, diff --git a/projects/packages/videopress/src/client/admin/components/video-thumbnail/index.tsx b/projects/packages/videopress/src/client/admin/components/video-thumbnail/index.tsx index c0f728d216c0b..5fb30edbebfb8 100644 --- a/projects/packages/videopress/src/client/admin/components/video-thumbnail/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/video-thumbnail/index.tsx @@ -163,7 +163,7 @@ const ErrorThumbnail = ( { isRow } ) => ( * React component to display video thumbnail. * * @param {VideoThumbnailProps} props - Component props. - * @returns {React.ReactNode} - VideoThumbnail react component. + * @return {React.ReactNode} - VideoThumbnail react component. */ const VideoThumbnail = forwardRef< HTMLDivElement, VideoThumbnailProps >( ( diff --git a/projects/packages/videopress/src/client/admin/components/video-upload-area/index.tsx b/projects/packages/videopress/src/client/admin/components/video-upload-area/index.tsx index 006d1f85db45b..6631bba41c3ef 100644 --- a/projects/packages/videopress/src/client/admin/components/video-upload-area/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/video-upload-area/index.tsx @@ -22,7 +22,7 @@ import type { ReactNode } from 'react'; * Video Upload Area component * * @param {VideoUploadAreaProps} props - Component props. - * @returns {ReactNode} - VideoUploadArea react component. + * @return {ReactNode} - VideoUploadArea react component. */ const VideoUploadArea = ( { className, onSelectFiles }: VideoUploadAreaProps ) => { const [ isSm ] = useBreakpointMatch( 'sm' ); diff --git a/projects/packages/videopress/src/client/admin/hooks/use-plan/index.ts b/projects/packages/videopress/src/client/admin/hooks/use-plan/index.ts index 5d6118cb450f6..cb5f785e79f57 100644 --- a/projects/packages/videopress/src/client/admin/hooks/use-plan/index.ts +++ b/projects/packages/videopress/src/client/admin/hooks/use-plan/index.ts @@ -43,7 +43,7 @@ export const usePlan = (): usePlanProps => { * Check if the user has a plan that includes VideoPress * * @param {string} productSlug - wpcom prtoduct slug - * @returns {boolean} true if the product is owned by the user + * @return {boolean} true if the product is owned by the user */ function hasPurchase( productSlug ) { return purchasesCamelCase.some( product => product.productSlug === productSlug ); diff --git a/projects/packages/videopress/src/client/admin/hooks/use-playback-token/index.ts b/projects/packages/videopress/src/client/admin/hooks/use-playback-token/index.ts index d569e64781d07..706a3b7376c9a 100644 --- a/projects/packages/videopress/src/client/admin/hooks/use-playback-token/index.ts +++ b/projects/packages/videopress/src/client/admin/hooks/use-playback-token/index.ts @@ -12,7 +12,7 @@ import { VideopressSelectors, VideoPressVideo } from '../../types'; * React custom hook to get the the video's playback token. * * @param {VideoPressVideo} video - The VideoPress video - * @returns {object} Playback token + * @return {object} Playback token */ export default function usePlaybackToken( video: VideoPressVideo ) { const videoNeedsPlaybackToken = video.needsPlaybackToken; diff --git a/projects/packages/videopress/src/client/admin/hooks/use-search-params/index.ts b/projects/packages/videopress/src/client/admin/hooks/use-search-params/index.ts index 5b5518ddbf293..346c4b81df69c 100644 --- a/projects/packages/videopress/src/client/admin/hooks/use-search-params/index.ts +++ b/projects/packages/videopress/src/client/admin/hooks/use-search-params/index.ts @@ -14,8 +14,8 @@ export const useSearchParams = () => { * Gets a given parameter from the search query. * * @param {SearchParamNameProp} parameterName - The name of the parameter to get from the query string. - * @param {string} defaultValue - The default value to return if the given parameter is not set on the query string. - * @returns {string|null} The value of the parameter if it's set. The defaultValue if the parameter is not set. + * @param {string} defaultValue - The default value to return if the given parameter is not set on the query string. + * @return {string|null} The value of the parameter if it's set. The defaultValue if the parameter is not set. */ const getParam = ( parameterName: SearchParamNameProp, defaultValue: string = null ): string => { return searchParams.has( parameterName ) ? searchParams.get( parameterName ) : defaultValue; @@ -25,7 +25,7 @@ export const useSearchParams = () => { * Sets a given parameter on the search query data, but does not refresh the URL. * * @param {SearchParamNameProp} parameterName - The name of the parameter to set on the query string. - * @param {string} value - The value to be set for the parameter on the query string. + * @param {string} value - The value to be set for the parameter on the query string. */ const setParam = ( parameterName: SearchParamNameProp, value: string = null ) => { searchParams.set( parameterName, value ); diff --git a/projects/packages/videopress/src/client/admin/hooks/use-unload-prevent/index.ts b/projects/packages/videopress/src/client/admin/hooks/use-unload-prevent/index.ts index 57147b807ad16..d420df978148d 100644 --- a/projects/packages/videopress/src/client/admin/hooks/use-unload-prevent/index.ts +++ b/projects/packages/videopress/src/client/admin/hooks/use-unload-prevent/index.ts @@ -20,7 +20,6 @@ const useUnloadPrevent = ( { // Note: The message only shows on older browsers, with a standard non-customizable message on current browsers // ref https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event#compatibility_notes event.returnValue = message; - return; }; window.addEventListener( 'beforeunload', beforeUnloadListener ); diff --git a/projects/packages/videopress/src/client/admin/hooks/use-users/index.js b/projects/packages/videopress/src/client/admin/hooks/use-users/index.js index baf4788e6ed28..40606fdf68040 100644 --- a/projects/packages/videopress/src/client/admin/hooks/use-users/index.js +++ b/projects/packages/videopress/src/client/admin/hooks/use-users/index.js @@ -10,7 +10,7 @@ import { STORE_ID } from '../../../state/constants'; /** * React custom hook to get the Users. * - * @returns {object} Users + * @return {object} Users */ export default function useUsers() { // Data diff --git a/projects/packages/videopress/src/client/admin/hooks/use-video/index.ts b/projects/packages/videopress/src/client/admin/hooks/use-video/index.ts index 449c2acf1c9a4..69e66b2bce62a 100644 --- a/projects/packages/videopress/src/client/admin/hooks/use-video/index.ts +++ b/projects/packages/videopress/src/client/admin/hooks/use-video/index.ts @@ -12,9 +12,9 @@ import { VideopressSelectors, VideoPressVideo } from '../../types'; /** * React custom hook to get specific video. * - * @param {number} id - Video ID + * @param {number} id - Video ID * @param {boolean} addAtEnd - Whether to add the video to the end of the list if not loaded. - * @returns {object} video + * @return {object} video */ export default function useVideo( id: number | string, addAtEnd = false ) { const dispatch = useDispatch( STORE_ID ); diff --git a/projects/packages/videopress/src/client/admin/hooks/use-videos/index.js b/projects/packages/videopress/src/client/admin/hooks/use-videos/index.js index 7f9e876bff5b4..dbdcdba987d2c 100644 --- a/projects/packages/videopress/src/client/admin/hooks/use-videos/index.js +++ b/projects/packages/videopress/src/client/admin/hooks/use-videos/index.js @@ -10,7 +10,7 @@ import { STORE_ID } from '../../../state/constants'; /** * React custom hook to get the videos. * - * @returns {object} videos + * @return {object} videos */ export default function useVideos() { // Data @@ -86,7 +86,7 @@ export const useLocalVideos = () => { /** * React custom hook to get the videos query. * - * @returns {object} search query information + * @return {object} search query information */ export const useVideosQuery = () => { // Data diff --git a/projects/packages/videopress/src/client/admin/index.js b/projects/packages/videopress/src/client/admin/index.js index b2ec7fe93a4d8..e6d5735744add 100644 --- a/projects/packages/videopress/src/client/admin/index.js +++ b/projects/packages/videopress/src/client/admin/index.js @@ -21,7 +21,7 @@ initStore(); /** * Component to scroll window to top on route change. * - * @returns {null} Null. + * @return {null} Null. */ function ScrollToTop() { const location = useLocation(); diff --git a/projects/packages/videopress/src/client/admin/mock/assets/poster-01.png b/projects/packages/videopress/src/client/admin/mock/assets/poster-01.png index f202e42dcaadd..c3518b2e5e810 100644 Binary files a/projects/packages/videopress/src/client/admin/mock/assets/poster-01.png and b/projects/packages/videopress/src/client/admin/mock/assets/poster-01.png differ diff --git a/projects/packages/videopress/src/client/admin/mock/assets/poster-02.png b/projects/packages/videopress/src/client/admin/mock/assets/poster-02.png index 761b680c2a602..c2a58765f76bd 100644 Binary files a/projects/packages/videopress/src/client/admin/mock/assets/poster-02.png and b/projects/packages/videopress/src/client/admin/mock/assets/poster-02.png differ diff --git a/projects/packages/videopress/src/client/admin/mock/assets/poster-03.png b/projects/packages/videopress/src/client/admin/mock/assets/poster-03.png index 6f36017710bb9..c946837727b87 100644 Binary files a/projects/packages/videopress/src/client/admin/mock/assets/poster-03.png and b/projects/packages/videopress/src/client/admin/mock/assets/poster-03.png differ diff --git a/projects/packages/videopress/src/client/admin/mock/assets/poster-04.png b/projects/packages/videopress/src/client/admin/mock/assets/poster-04.png index 820296854d032..1d2999ecf782f 100644 Binary files a/projects/packages/videopress/src/client/admin/mock/assets/poster-04.png and b/projects/packages/videopress/src/client/admin/mock/assets/poster-04.png differ diff --git a/projects/packages/videopress/src/client/admin/mock/assets/poster-05.png b/projects/packages/videopress/src/client/admin/mock/assets/poster-05.png index 5f42f74df3463..9bb13930d48eb 100644 Binary files a/projects/packages/videopress/src/client/admin/mock/assets/poster-05.png and b/projects/packages/videopress/src/client/admin/mock/assets/poster-05.png differ diff --git a/projects/packages/videopress/src/client/admin/mock/assets/poster-06.png b/projects/packages/videopress/src/client/admin/mock/assets/poster-06.png index bf000390b7a45..363afe9ff3d80 100644 Binary files a/projects/packages/videopress/src/client/admin/mock/assets/poster-06.png and b/projects/packages/videopress/src/client/admin/mock/assets/poster-06.png differ diff --git a/projects/packages/videopress/src/client/admin/mock/assets/poster-square-01.jpg b/projects/packages/videopress/src/client/admin/mock/assets/poster-square-01.jpg index fbcf2405a7cdd..934666d854639 100644 Binary files a/projects/packages/videopress/src/client/admin/mock/assets/poster-square-01.jpg and b/projects/packages/videopress/src/client/admin/mock/assets/poster-square-01.jpg differ diff --git a/projects/packages/videopress/src/client/admin/mock/assets/poster-square-02.jpg b/projects/packages/videopress/src/client/admin/mock/assets/poster-square-02.jpg index 3723e8b939819..b083d462b8b3e 100644 Binary files a/projects/packages/videopress/src/client/admin/mock/assets/poster-square-02.jpg and b/projects/packages/videopress/src/client/admin/mock/assets/poster-square-02.jpg differ diff --git a/projects/packages/videopress/src/client/admin/mock/assets/poster-square-03.jpg b/projects/packages/videopress/src/client/admin/mock/assets/poster-square-03.jpg index 2dcfbc72191e2..d8276efe50438 100644 Binary files a/projects/packages/videopress/src/client/admin/mock/assets/poster-square-03.jpg and b/projects/packages/videopress/src/client/admin/mock/assets/poster-square-03.jpg differ diff --git a/projects/packages/videopress/src/client/admin/mock/assets/poster-square-04.jpg b/projects/packages/videopress/src/client/admin/mock/assets/poster-square-04.jpg index bf0fda1f04c0a..22ee7c797e5e8 100644 Binary files a/projects/packages/videopress/src/client/admin/mock/assets/poster-square-04.jpg and b/projects/packages/videopress/src/client/admin/mock/assets/poster-square-04.jpg differ diff --git a/projects/packages/videopress/src/client/admin/mock/assets/poster-square-05.jpg b/projects/packages/videopress/src/client/admin/mock/assets/poster-square-05.jpg index 73194870f7cd5..e310edc9f3a78 100644 Binary files a/projects/packages/videopress/src/client/admin/mock/assets/poster-square-05.jpg and b/projects/packages/videopress/src/client/admin/mock/assets/poster-square-05.jpg differ diff --git a/projects/packages/videopress/src/client/admin/mock/assets/poster-square-06.jpg b/projects/packages/videopress/src/client/admin/mock/assets/poster-square-06.jpg index 40ee484cedb05..a6a8772efa807 100644 Binary files a/projects/packages/videopress/src/client/admin/mock/assets/poster-square-06.jpg and b/projects/packages/videopress/src/client/admin/mock/assets/poster-square-06.jpg differ diff --git a/projects/packages/videopress/src/client/admin/mock/index.ts b/projects/packages/videopress/src/client/admin/mock/index.ts index 1c4ac9a579d2c..e59c44fb7aa62 100644 --- a/projects/packages/videopress/src/client/admin/mock/index.ts +++ b/projects/packages/videopress/src/client/admin/mock/index.ts @@ -32,7 +32,7 @@ export const postersArray = [ /** * Return a random poster image * - * @returns {string} Random poster image + * @return {string} Random poster image */ export function randomPoster() { const max = postersArray.length - 1; diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/connect-banner.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/connect-banner.tsx index 917316140d045..a4ec01bab7afd 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/connect-banner.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/connect-banner.tsx @@ -23,7 +23,7 @@ type ConnectBannerProps = { * Connect Banner component * * @param {ConnectBannerProps} props - component props - * @returns {React.ReactElement} Connect banner component. + * @return {React.ReactElement} Connect banner component. */ export default function ConnectBanner( { onConnect, diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/index.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/index.tsx index 4b85e54f0dc57..e6501db60bd1b 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/index.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/banner/index.tsx @@ -20,11 +20,11 @@ export type BlockBannerProps = { /** * React component to render a banner above a block. * - * @param {BlockBannerProps} props - Component props. - * @param {React.ReactNode} props.action - Banner action button. - * @param {React.ReactNode} props.children - Banner content. - * @param {React.ReactNode} props.icon - Banner icon. - * @returns {React.ReactElement } Banner component. + * @param {BlockBannerProps} props - Component props. + * @param {React.ReactNode} props.action - Banner action button. + * @param {React.ReactNode} props.children - Banner content. + * @param {React.ReactNode} props.icon - Banner icon. + * @return {React.ReactElement } Banner component. */ export default function BlockBanner( { icon = warning, diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/color-panel/dynamic-colors.png b/projects/packages/videopress/src/client/block-editor/blocks/video/components/color-panel/dynamic-colors.png index 5339b62b6f47c..1c4bb970b55e6 100644 Binary files a/projects/packages/videopress/src/client/block-editor/blocks/video/components/color-panel/dynamic-colors.png and b/projects/packages/videopress/src/client/block-editor/blocks/video/components/color-panel/dynamic-colors.png differ diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/color-panel/index.native.js b/projects/packages/videopress/src/client/block-editor/blocks/video/components/color-panel/index.native.js index 720722476f09f..1942e26468ef4 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/color-panel/index.native.js +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/color-panel/index.native.js @@ -12,10 +12,10 @@ import { Icon, chevronRight } from '@wordpress/icons'; /** * React component that renders the playback bar color settings panel. * - * @param {object} props - Component properties. - * @param {object} props.attributes - Block attributes. + * @param {object} props - Component properties. + * @param {object} props.attributes - Block attributes. * @param {Function} props.setAttributes - Function to set block attributes. - * @returns {import('react').ReactElement} - Playback bar color settings panel. + * @return {import('react').ReactElement} - Playback bar color settings panel. */ export default function ColorPanel( { attributes, setAttributes } ) { const [ showSubSheet, setShowSubSheet ] = useState( false ); diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/color-panel/index.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/color-panel/index.tsx index e51ab5fbfc076..3f7e6474e8fb7 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/color-panel/index.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/color-panel/index.tsx @@ -26,7 +26,7 @@ import type React from 'react'; * Sidebar Control component. * * @param {VideoControlProps} props - Component props. - * @returns {React.ReactElement} Component template + * @return {React.ReactElement} Component template */ export default function ColorPanel( { clientId, attributes, setAttributes }: VideoControlProps ) { const { useAverageColor, seekbarColor, seekbarLoadingColor, seekbarPlayedColor } = attributes; diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/details-panel/index.native.js b/projects/packages/videopress/src/client/block-editor/blocks/video/components/details-panel/index.native.js index 41784a9f423c9..2d68c58936ee0 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/details-panel/index.native.js +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/details-panel/index.native.js @@ -11,11 +11,11 @@ import VideoNotOwnedWarning from '../video-not-owned-warning'; /** * React component that renders the details settings panel. * - * @param {object} props - Component properties. - * @param {object} props.attributes - Block attributes. - * @param {Function} props.setAttributes - Function to set attributes. + * @param {object} props - Component properties. + * @param {object} props.attributes - Block attributes. + * @param {Function} props.setAttributes - Function to set attributes. * @param {Function} props.videoBelongToSite - Determines if the video belongs to the current site. - * @returns {import('react').ReactElement} - Details panel component. + * @return {import('react').ReactElement} - Details panel component. */ export default function DetailsPanel( { attributes, setAttributes, videoBelongToSite } ) { const { title, description } = attributes; diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/details-panel/index.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/details-panel/index.tsx index 9b9fd933cd0aa..52c38b2fcb02b 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/details-panel/index.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/details-panel/index.tsx @@ -29,7 +29,7 @@ const CHARACTERS_PER_LINE = 31; * React component that renders a Video details control * * @param {DetailsPanelProps} props - Component properties. - * @returns {React.ReactElement} Details panel component. + * @return {React.ReactElement} Details panel component. */ export default function DetailsPanel( { filename, diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/details-panel/learn-how-notice/index.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/details-panel/learn-how-notice/index.tsx index c36969161ab69..b8cbf19218d3b 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/details-panel/learn-how-notice/index.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/details-panel/learn-how-notice/index.tsx @@ -17,7 +17,7 @@ type LearnHowModalProps = { * React component that renders the Learn How modal * * @param {LearnHowModalProps} props - Component properties. - * @returns {object} Notice component + * @return {object} Notice component */ export default function LearnHowModal( { isOpen, onClose }: LearnHowModalProps ) { if ( ! isOpen ) { diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/playback-panel/index.native.js b/projects/packages/videopress/src/client/block-editor/blocks/video/components/playback-panel/index.native.js index cdb8ac2d2099b..bd8f632905fda 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/playback-panel/index.native.js +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/playback-panel/index.native.js @@ -11,10 +11,10 @@ import { Text } from 'react-native'; /** * Sidebar Control component. * - * @param {object} props - Component props. - * @param {object} props.attributes - Block attributes. + * @param {object} props - Component props. + * @param {object} props.attributes - Block attributes. * @param {Function} props.setAttributes - Function to set attributes. - * @returns {import('react').ReactElement} - Playback block sidebar panel + * @return {import('react').ReactElement} - Playback block sidebar panel */ export default function PlaybackPanel( { attributes, setAttributes } ) { const [ showSubSheet, setShowSubSheet ] = useState( false ); diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/playback-panel/index.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/playback-panel/index.tsx index c7c7311f0afd1..b2636a4fd1f1c 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/playback-panel/index.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/playback-panel/index.tsx @@ -18,7 +18,7 @@ import type React from 'react'; * Sidebar Control component. * * @param {VideoControlProps} props - Component props. - * @returns {React.ReactElement} Playback block sidebar panel + * @return {React.ReactElement} Playback block sidebar panel */ export default function PlaybackPanel( { attributes, setAttributes }: VideoControlProps ) { const { autoplay, loop, muted, controls, playsinline, preload, posterData } = attributes; diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/player/index.native.js b/projects/packages/videopress/src/client/block-editor/blocks/video/components/player/index.native.js index 37b2a756f90ac..753f817b08886 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/player/index.native.js +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/player/index.native.js @@ -27,10 +27,10 @@ const IS_ANDROID = Platform.isAndroid; /** * VideoPlayer react component * - * @param {object} props - Component props. - * @param {object} props.attributes - Block attributes. + * @param {object} props - Component props. + * @param {object} props.attributes - Block attributes. * @param {boolean} props.isSelected - Whether the block is selected. - * @returns {import('react').ReactElement} - React component. + * @return {import('react').ReactElement} - React component. */ export default function Player( { isSelected, attributes } ) { const { diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/player/index.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/player/index.tsx index fac351b80e6d3..6c8ea329fc27e 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/player/index.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/player/index.tsx @@ -42,8 +42,8 @@ if ( window?.videoPressEditorState?.playerBridgeUrl ) { /** * VideoPlayer react component * - * @param {PlayerProps} props - Component props. - * @returns {React.ReactElement} Playback block sidebar panel + * @param {PlayerProps} props - Component props. + * @return {React.ReactElement} Playback block sidebar panel */ export default function Player( { showCaption, @@ -160,7 +160,7 @@ export default function Player( { const { atTime, previewOnHover, previewAtTime, previewLoopDuration, type } = attributes.posterData; - let timeToSetPlayerPosition = undefined; + let timeToSetPlayerPosition; if ( type === 'video-frame' ) { if ( previewOnHover ) { timeToSetPlayerPosition = previewAtTime; diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/poster-image-block-control/index.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/poster-image-block-control/index.tsx index c7a1175761521..2b4185b1c7d43 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/poster-image-block-control/index.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/poster-image-block-control/index.tsx @@ -23,7 +23,7 @@ import type React from 'react'; * Simple component that renders info about video poster. * * @param {VideoPosterCardProps} props - Component props. - * @returns {React.ReactElement} VideoPosterCard component + * @return {React.ReactElement} VideoPosterCard component */ export function VideoPosterCard( { poster, className }: VideoPosterCardProps ): React.ReactElement { const notes = createInterpolateElement( @@ -53,7 +53,7 @@ export function VideoPosterCard( { poster, className }: VideoPosterCardProps ): * Poster image control react component. * * @param {VideoControlProps} props - Component props. - * @returns {React.ReactElement} PosterImageBlockControl block control + * @return {React.ReactElement} PosterImageBlockControl block control */ export default function PosterImageBlockControl( { attributes, diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/poster-panel/index.native.js b/projects/packages/videopress/src/client/block-editor/blocks/video/components/poster-panel/index.native.js index e5277b7599410..73a5fd5cec9a3 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/poster-panel/index.native.js +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/poster-panel/index.native.js @@ -4,7 +4,7 @@ export const isVideoFramePosterEnabled = () => /** * Sidebar Control component. * - * @returns {import('react').ReactElement} Component template + * @return {import('react').ReactElement} Component template */ export default function PosterPanel() { return null; diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/poster-panel/index.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/poster-panel/index.tsx index 2a8cfc1519936..48a9537c51d09 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/poster-panel/index.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/poster-panel/index.tsx @@ -92,7 +92,7 @@ if ( window?.videoPressEditorState?.playerBridgeUrl ) { * Sidebar Control component. * * @param {VideoControlProps} props - Component props. - * @returns {React.ReactElement} Component template + * @return {React.ReactElement} Component template */ export function PosterDropdown( { clientId, @@ -207,7 +207,7 @@ export function PosterDropdown( { * given the iframe's ref. * * @param {React.MutableRefObject< HTMLDivElement >} iFrameRef - iframe ref - * @returns {Window | null} Window object of the iframe + * @return {Window | null} Window object of the iframe */ export const getIframeWindowFromRef = ( iFrameRef: React.MutableRefObject< HTMLDivElement > @@ -230,7 +230,7 @@ type PosterFramePickerProps = { * React component to pick a frame from the VideoPress video * * @param {PosterFramePickerProps} props - Component properties - * @returns { React.ReactElement} React component + * @return { React.ReactElement} React component */ function VideoFramePicker( { guid, @@ -326,7 +326,7 @@ type VideoHoverPreviewControlProps = { * React component to select the video preview options when the user hovers the video * * @param {VideoHoverPreviewControlProps} props - Component properties - * @returns { React.ReactElement} React component + * @return { React.ReactElement} React component */ export function VideoHoverPreviewControl( { previewOnHover = false, @@ -344,7 +344,7 @@ export function VideoHoverPreviewControl( { Math.min( MAX_LOOP_DURATION, videoDuration - previewAtTime ) ); - const maxLoopDurationSeconds = ( ( maxLoopDuration / 10 ) | 0 ) / 100; + const maxLoopDurationSeconds = Math.floor( maxLoopDuration / 10 ) / 100; const startingPointHelp = createInterpolateElement( sprintf( @@ -432,7 +432,7 @@ export function VideoHoverPreviewControl( { * Sidebar Control component. * * @param {VideoControlProps} props - Component props. - * @returns {React.ReactElement} Component template + * @return {React.ReactElement} Component template */ export default function PosterPanel( { attributes, diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/index.native.js b/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/index.native.js index 5110cf08e69e6..30b516df9438b 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/index.native.js +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/index.native.js @@ -14,12 +14,12 @@ import PrivacyAndRatingSettings from './privacy-and-rating-settings'; /** * React component that renders the main privacy and ratings panel. * - * @param {object} props - Component props. - * @param {object} props.attributes - Block attributes. - * @param {Function} props.setAttributes - Function to set block attributes. - * @param {boolean} props.privateEnabledForSite - True if the site's privacy is set to Private. - * @param {boolean} props.videoBelongToSite - Determines if the video belongs to the current site. - * @returns {import('react').ReactElement} - Panel to contain privacy and ratings settings. + * @param {object} props - Component props. + * @param {object} props.attributes - Block attributes. + * @param {Function} props.setAttributes - Function to set block attributes. + * @param {boolean} props.privateEnabledForSite - True if the site's privacy is set to Private. + * @param {boolean} props.videoBelongToSite - Determines if the video belongs to the current site. + * @return {import('react').ReactElement} - Panel to contain privacy and ratings settings. */ export default function PrivacyAndRatingPanel( { attributes, diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/index.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/index.tsx index 140e1d62cafe0..005b2967b61f2 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/index.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/index.tsx @@ -12,7 +12,7 @@ import type React from 'react'; * React component that renders the main privacy and ratings panel. * * @param {PrivacyAndRatingPanelProps} props - Component props. - * @returns {React.ReactElement} Panel to contain privacy and ratings settings. + * @return {React.ReactElement} Panel to contain privacy and ratings settings. */ export default function PrivacyAndRatingPanel( { attributes, diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/privacy-and-rating-settings.native.js b/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/privacy-and-rating-settings.native.js index 3f615320ae9e2..35af313cf5f7d 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/privacy-and-rating-settings.native.js +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/privacy-and-rating-settings.native.js @@ -20,12 +20,12 @@ import VideoNotOwnedWarning from '../video-not-owned-warning'; /** * React component that renders the settings within the privacy and ratings panel. * - * @param {object} props - Component props. - * @param {object} props.attributes - Block attributes. - * @param {Function} props.setAttributes - Function to set block attributes. - * @param {boolean} props.privateEnabledForSite - True if the site's privacy is set to Private. - * @param {boolean} props.videoBelongToSite - Determines if the video belongs to the current site. - * @returns {import('react').ReactElement} - Settings to change video's privacy and ratings. + * @param {object} props - Component props. + * @param {object} props.attributes - Block attributes. + * @param {Function} props.setAttributes - Function to set block attributes. + * @param {boolean} props.privateEnabledForSite - True if the site's privacy is set to Private. + * @param {boolean} props.videoBelongToSite - Determines if the video belongs to the current site. + * @return {import('react').ReactElement} - Settings to change video's privacy and ratings. */ export default function PrivacyAndRatingSettings( { attributes, diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/privacy-and-rating-settings.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/privacy-and-rating-settings.tsx index 4137b507ddb3e..1bff6857e5e32 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/privacy-and-rating-settings.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/privacy-and-rating-panel/privacy-and-rating-settings.tsx @@ -25,7 +25,7 @@ import type React from 'react'; * React component that renders the settings within the privacy and ratings panel. * * @param {PrivacyAndRatingPanelProps} props - Component props. - * @returns {React.ReactElement} Settings to change video's privacy and ratings. + * @return {React.ReactElement} Settings to change video's privacy and ratings. */ export default function PrivacyAndRatingSettings( { attributes, diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/tracks-control/index.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/tracks-control/index.tsx index 834922bc216f8..8496f188cb176 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/tracks-control/index.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/tracks-control/index.tsx @@ -29,7 +29,7 @@ const debug = debugFactory( 'videopress:tracks:tracks-control' ); * Track Item component. * * @param {TrackItemProps} props - Component props. - * @returns {React.ReactElement} TrackItem react component + * @return {React.ReactElement} TrackItem react component */ function TrackItem( { track, guid, onDelete }: TrackItemProps ): React.ReactElement { const [ isDeleting, setIsDeleting ] = useState( false ); @@ -64,7 +64,7 @@ function TrackItem( { track, guid, onDelete }: TrackItemProps ): React.ReactElem * Track List React component. * * @param {TrackListProps} props - Component props. - * @returns {React.ReactElement} TracksControl block control + * @return {React.ReactElement} TracksControl block control */ function TrackList( { tracks, guid, onTrackListUpdate }: TrackListProps ): React.ReactElement { if ( ! tracks?.length ) { @@ -111,7 +111,7 @@ function TrackList( { tracks, guid, onTrackListUpdate }: TrackListProps ): React * Tracks control react component. * * @param {VideoControlProps} props - Component props. - * @returns {React.ReactElement} TracksControl block control + * @return {React.ReactElement} TracksControl block control */ export default function TracksControl( { attributes, diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/tracks-control/track-form.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/components/tracks-control/track-form.tsx index 63390b6f8d6a4..c66493e795de6 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/tracks-control/track-form.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/tracks-control/track-form.tsx @@ -40,7 +40,7 @@ const debug = debugFactory( 'videopress:tracks:track-form' ); * Track From component * * @param {TrackFormProps} props - Component props. - * @returns {React.ReactElement} Track form react component. + * @return {React.ReactElement} Track form react component. */ export default function TrackForm( { onCancel, diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/video-not-owned-warning/index.native.js b/projects/packages/videopress/src/client/block-editor/blocks/video/components/video-not-owned-warning/index.native.js index 2f70bf4d4a331..e1eb3b842a824 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/video-not-owned-warning/index.native.js +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/video-not-owned-warning/index.native.js @@ -16,7 +16,7 @@ import styles from './styles.scss'; /** * React component that renders a warning message about the video not owned by the site. * - * @returns {import('react').ReactElement} - Details panel component. + * @return {import('react').ReactElement} - Details panel component. */ export default function VideoNotOwnedWarning() { const msgStyle = usePreferredColorSchemeStyle( diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/components/videopress-uploader/index.js b/projects/packages/videopress/src/client/block-editor/blocks/video/components/videopress-uploader/index.js index c32b241f3699b..e7c2b99039535 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/components/videopress-uploader/index.js +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/components/videopress-uploader/index.js @@ -102,7 +102,7 @@ const VideoPressUploader = ( { * Handler to add a video via an URL. * * @param {string} videoSource - URL of the video to attach - * @param {string} id - Attachment ID if available + * @param {string} id - Attachment ID if available */ function onSelectURL( videoSource, id ) { // If the video source is a VideoPress URL, we can use it directly. @@ -161,7 +161,7 @@ const VideoPressUploader = ( { * Uploading file handler. * * @param {File} media - media file to upload - * @returns {void} + * @return {void} */ function onSelectVideo( media ) { /* diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/deprecated/index.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/deprecated/index.tsx index dfd01fd77f1d6..53c89dd04e73d 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/deprecated/index.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/deprecated/index.tsx @@ -21,9 +21,9 @@ type videoBlockSaveProps = { /** * VideoPress block save function * - * @param {object} props - Component props. - * @param {object} props.attributes - Block attributes. - * @returns {object} - React component. + * @param {object} props - Component props. + * @param {object} props.attributes - Block attributes. + * @return {object} - React component. */ function save( { attributes }: videoBlockSaveProps ): React.ReactNode { const { diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/edit.native.js b/projects/packages/videopress/src/client/block-editor/blocks/video/edit.native.js index 52b53d303cc53..8d61239a476db 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/edit.native.js +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/edit.native.js @@ -35,14 +35,14 @@ import style from './style.scss'; /** * VideoPress block Edit react components * - * @param {object} props - Component props. - * @param {object} props.attributes - Block attributes. - * @param {object} props.clientId - Block client Id. - * @param {Function} props.setAttributes - Function to set block attributes. - * @param {boolean} props.isSelected - Whether block is selected. - * @param {Function} props.onFocus - Callback to notify when block should gain focus. + * @param {object} props - Component props. + * @param {object} props.attributes - Block attributes. + * @param {object} props.clientId - Block client Id. + * @param {Function} props.setAttributes - Function to set block attributes. + * @param {boolean} props.isSelected - Whether block is selected. + * @param {Function} props.onFocus - Callback to notify when block should gain focus. * @param {Function} props.insertBlocksAfter - Function to insert a new block after the current block. - * @returns {import('react').ReactNode} - React component. + * @return {import('react').ReactNode} - React component. */ export default function VideoPressEdit( { attributes, diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/edit.tsx b/projects/packages/videopress/src/client/block-editor/blocks/video/edit.tsx index c80c2cde45a0c..a9a3621cb85cd 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/edit.tsx +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/edit.tsx @@ -96,12 +96,12 @@ export const PlaceholderWrapper = withNotices( function ( { /** * VideoPress block Edit react components * - * @param {object} props - Component props. - * @param {object} props.attributes - Block attributes. + * @param {object} props - Component props. + * @param {object} props.attributes - Block attributes. * @param {Function} props.setAttributes - Function to set block attributes. - * @param {boolean} props.isSelected - Whether the block is selected. - * @param {string} props.clientId - Block client ID. - * @returns {React.ReactNode} - React component. + * @param {boolean} props.isSelected - Whether the block is selected. + * @param {string} props.clientId - Block client ID. + * @return {React.ReactNode} - React component. */ export default function VideoPressEdit( { attributes, diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/index.native.ts b/projects/packages/videopress/src/client/block-editor/blocks/video/index.native.ts index 0d8229e00b595..6e534055e14da 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/index.native.ts +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/index.native.ts @@ -18,7 +18,7 @@ export const { name, title, description, attributes } = metadata; /** * Registers the VideoPress block if the availability requirements are met. * - * @returns {object|boolean} Either false if the block is not available, or the results of `registerBlockType` + * @return {object|boolean} Either false if the block is not available, or the results of `registerBlockType` */ export default function registerVideoPressBlock() { const { available } = getJetpackExtensionAvailability( name ); diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/videopress-block-example-image.jpg b/projects/packages/videopress/src/client/block-editor/blocks/video/videopress-block-example-image.jpg index 077782375e8d1..56ae5aa8c1062 100644 Binary files a/projects/packages/videopress/src/client/block-editor/blocks/video/videopress-block-example-image.jpg and b/projects/packages/videopress/src/client/block-editor/blocks/video/videopress-block-example-image.jpg differ diff --git a/projects/packages/videopress/src/client/block-editor/blocks/video/view.ts b/projects/packages/videopress/src/client/block-editor/blocks/video/view.ts index d3f0c87e757da..d2cdfd09d9517 100644 --- a/projects/packages/videopress/src/client/block-editor/blocks/video/view.ts +++ b/projects/packages/videopress/src/client/block-editor/blocks/video/view.ts @@ -11,7 +11,7 @@ import './style.scss'; /** * Preview on Hover effect for VideoPress videos. * - * @returns {void} + * @return {void} */ function previewOnHoverEffect(): void { /* diff --git a/projects/packages/videopress/src/client/block-editor/extend/core-video/index.js b/projects/packages/videopress/src/client/block-editor/extend/core-video/index.js index dcc2c84a842e1..d510b59832bac 100644 --- a/projects/packages/videopress/src/client/block-editor/extend/core-video/index.js +++ b/projects/packages/videopress/src/client/block-editor/extend/core-video/index.js @@ -60,7 +60,7 @@ addFilter( * * @param {object} attributes - core/video block attributes * @param {object} defaultAttributes - default core/video block attributes - * @returns {object} The new attributes + * @return {object} The new attributes */ function getVideoPressVideoBlockAttributes( attributes, defaultAttributes ) { const attrs = attributes || defaultAttributes; @@ -84,7 +84,7 @@ function getVideoPressVideoBlockAttributes( attributes, defaultAttributes ) { * * @param {object} props - component props * @param {object} props.BlockListBlock - BlockListBlock - * @returns {React.ReactNode} BlockListBlock if the block is valid, or the recovery warning. + * @return {React.ReactNode} BlockListBlock if the block is valid, or the recovery warning. */ function JetpackCoreVideoDeprecation( { BlockListBlock, ...props } ) { const { block } = props; diff --git a/projects/packages/videopress/src/client/block-editor/extensions/index.ts b/projects/packages/videopress/src/client/block-editor/extensions/index.ts index 5f4f976787aea..5f930b6c74448 100644 --- a/projects/packages/videopress/src/client/block-editor/extensions/index.ts +++ b/projects/packages/videopress/src/client/block-editor/extensions/index.ts @@ -17,7 +17,7 @@ debug( 'Extensions: %o', extensions ); * Helper function to check if a given extension is enabled. * * @param {string} extension - The extension to check. - * @returns {boolean} - Whether the extension is enabled. + * @return {boolean} - Whether the extension is enabled. */ export function isExtensionEnabled( extension: string ) { const vpExtension = extensions.find( ext => ext.name === extension ); @@ -28,7 +28,7 @@ export function isExtensionEnabled( extension: string ) { * Helper function to check if the given extension is beta. * * @param {string} extension - The extension to check. - * @returns {boolean} - Whether the extension is beta. + * @return {boolean} - Whether the extension is beta. */ export function isBetaExtension( extension: string ) { const vpExtension = extensions.find( ext => ext.name === extension ); diff --git a/projects/packages/videopress/src/client/block-editor/hooks/use-sync-media/index.native.js b/projects/packages/videopress/src/client/block-editor/hooks/use-sync-media/index.native.js index fd833d0e9dcd5..13912820bc75b 100644 --- a/projects/packages/videopress/src/client/block-editor/hooks/use-sync-media/index.native.js +++ b/projects/packages/videopress/src/client/block-editor/hooks/use-sync-media/index.native.js @@ -63,9 +63,9 @@ const invalidateEmbedResolutionFields = [ * React hook to keep the data in-sync * between the media item and the block attributes. * - * @param {object} attributes - Block attributes. - * @param {Function} setAttributes - Block attributes setter. - * @returns {object} - Hook API object. + * @param {object} attributes - Block attributes. + * @param {Function} setAttributes - Block attributes setter. + * @return {object} - Hook API object. */ export function useSyncMedia( attributes, setAttributes ) { const { id, guid, isPrivate } = attributes; diff --git a/projects/packages/videopress/src/client/block-editor/hooks/use-sync-media/index.ts b/projects/packages/videopress/src/client/block-editor/hooks/use-sync-media/index.ts index 1b5c16012c758..1376a491118be 100644 --- a/projects/packages/videopress/src/client/block-editor/hooks/use-sync-media/index.ts +++ b/projects/packages/videopress/src/client/block-editor/hooks/use-sync-media/index.ts @@ -79,9 +79,9 @@ const invalidateEmbedResolutionFields = [ * Re-arrange the tracks to match the block attribute format. * Also, check if the tracks is out of sync with the media item. * - * @param {VideoDataProps} videoData - Video data, provided by server. + * @param {VideoDataProps} videoData - Video data, provided by server. * @param {VideoBlockAttributes} attributes - Block attributes. - * @returns {VideoBlockAttributes} Video block attributes. + * @return {VideoBlockAttributes} Video block attributes. */ function arrangeTracksAttributes( videoData: VideoDataProps, @@ -143,9 +143,9 @@ function arrangeTracksAttributes( * React hook to keep the data in-sync * between the media item and the block attributes. * - * @param {object} attributes - Block attributes. + * @param {object} attributes - Block attributes. * @param {Function} setAttributes - Block attributes setter. - * @returns {UseSyncMedia} Hook API object. + * @return {UseSyncMedia} Hook API object. */ export function useSyncMedia( attributes: VideoBlockAttributes, diff --git a/projects/packages/videopress/src/client/block-editor/hooks/use-video-data-update/index.ts b/projects/packages/videopress/src/client/block-editor/hooks/use-video-data-update/index.ts index c011226792aa2..cac8e968e7427 100644 --- a/projects/packages/videopress/src/client/block-editor/hooks/use-video-data-update/index.ts +++ b/projects/packages/videopress/src/client/block-editor/hooks/use-video-data-update/index.ts @@ -12,7 +12,7 @@ import { VideoId } from '../../blocks/video/types'; * Hook to update the media data by hitting the VideoPress API. * * @param {VideoId} id - Media ID. - * @returns {Function} Update Promise handler. + * @return {Function} Update Promise handler. */ export default function useMediaDataUpdate( id: VideoId ) { const updateMediaItem = data => { diff --git a/projects/packages/videopress/src/client/block-editor/hooks/use-video-data/index.ts b/projects/packages/videopress/src/client/block-editor/hooks/use-video-data/index.ts index 12b75a487e8b0..dd2729312b798 100644 --- a/projects/packages/videopress/src/client/block-editor/hooks/use-video-data/index.ts +++ b/projects/packages/videopress/src/client/block-editor/hooks/use-video-data/index.ts @@ -25,7 +25,7 @@ const isUserConnected = getIsUserConnected(); * React hook to fetch the video data from the media library. * * @param {UseVideoDataArgumentsProps} args - Hook arguments object - * @returns {UseVideoDataProps} Hook API object. + * @return {UseVideoDataProps} Hook API object. */ export default function useVideoData( { id, diff --git a/projects/packages/videopress/src/client/block-editor/hooks/use-video-player/index.ts b/projects/packages/videopress/src/client/block-editor/hooks/use-video-player/index.ts index 968e551dca5d3..867060303a33e 100644 --- a/projects/packages/videopress/src/client/block-editor/hooks/use-video-player/index.ts +++ b/projects/packages/videopress/src/client/block-editor/hooks/use-video-player/index.ts @@ -17,7 +17,7 @@ const debug = debugFactory( 'videopress:use-video-player' ); * given the iframe's ref. * * @param {React.MutableRefObject< HTMLDivElement >} iFrameRef - iframe ref - * @returns {Window | null} Window object of the iframe + * @return {Window | null} Window object of the iframe */ export const getIframeWindowFromRef = ( iFrameRef: React.MutableRefObject< HTMLDivElement > @@ -31,10 +31,10 @@ export const getIframeWindowFromRef = ( /** * Custom hook to set the player ready to use: * - * @param {React.MutableRefObject< HTMLDivElement >} iFrameRef - useRef of the sandbox wrapper. - * @param {boolean} isRequestingPreview - Whether the preview is being requested. - * @param {UseVideoPlayerOptions} options - Options object. - * @returns {UseVideoPlayer} playerIsReady and playerState + * @param {React.MutableRefObject< HTMLDivElement >} iFrameRef - useRef of the sandbox wrapper. + * @param {boolean} isRequestingPreview - Whether the preview is being requested. + * @param {UseVideoPlayerOptions} options - Options object. + * @return {UseVideoPlayer} playerIsReady and playerState */ const useVideoPlayer = ( iFrameRef: React.MutableRefObject< HTMLDivElement >, diff --git a/projects/packages/videopress/src/client/block-editor/hooks/use-video-poster-data/index.ts b/projects/packages/videopress/src/client/block-editor/hooks/use-video-poster-data/index.ts index 5240d8b140045..e4b835dcc0a63 100644 --- a/projects/packages/videopress/src/client/block-editor/hooks/use-video-poster-data/index.ts +++ b/projects/packages/videopress/src/client/block-editor/hooks/use-video-poster-data/index.ts @@ -23,7 +23,7 @@ const debug = debugFactory( 'videopress:video:use-sync-media' ); * React hook to handle video poster generation based on block attributes changes and post save events. * * @param {VideoBlockAttributes} attributes - Block attributes. - * @returns {boolean} isGeneratingPoster - Whether the poster image is being generated. + * @return {boolean} isGeneratingPoster - Whether the poster image is being generated. */ export function useVideoPosterData( attributes: VideoBlockAttributes ) { // Detect when the post has been just saved. diff --git a/projects/packages/videopress/src/client/block-editor/utils/add-token-iframe-source.js b/projects/packages/videopress/src/client/block-editor/utils/add-token-iframe-source.js index 596cc5b38a5bd..ccecbbf5ea1f6 100644 --- a/projects/packages/videopress/src/client/block-editor/utils/add-token-iframe-source.js +++ b/projects/packages/videopress/src/client/block-editor/utils/add-token-iframe-source.js @@ -1,9 +1,9 @@ /** * Adds token via the query param `metadata_token` into VideoPress iframe's source. * - * @param {string} html - VideoPress iframe HTML. + * @param {string} html - VideoPress iframe HTML. * @param {string} token - Token. - * @returns {string} - VideoPres iframe HTML with source updated with token. + * @return {string} - VideoPres iframe HTML with source updated with token. */ export default function addTokenIntoIframeSource( html, token ) { if ( ! html || ! token ) { diff --git a/projects/packages/videopress/src/client/block-editor/utils/editor-image-url.ts b/projects/packages/videopress/src/client/block-editor/utils/editor-image-url.ts index d93ade4a2ba9b..ad639eaf935ae 100644 --- a/projects/packages/videopress/src/client/block-editor/utils/editor-image-url.ts +++ b/projects/packages/videopress/src/client/block-editor/utils/editor-image-url.ts @@ -9,7 +9,7 @@ const { imagesURLBase = '' } = window?.videoPressEditorState || {}; * Helper function to get the correct image URL. * * @param {string} image - The imported image. - * @returns {string} - The image URL. + * @return {string} - The image URL. */ export default function editorImageURL( image: string ): string { // Get the file name from the image path, including build hash. diff --git a/projects/packages/videopress/src/client/block-editor/utils/is-local-file.native.js b/projects/packages/videopress/src/client/block-editor/utils/is-local-file.native.js index 891f16d60b925..f2adabb730d72 100644 --- a/projects/packages/videopress/src/client/block-editor/utils/is-local-file.native.js +++ b/projects/packages/videopress/src/client/block-editor/utils/is-local-file.native.js @@ -6,8 +6,8 @@ import { isURL, getProtocol } from '@wordpress/url'; /** * Determines if a URL points to a local file. * - * @param {string} url - URL to check. - * @returns {boolean} - True if the URL points to a local file. + * @param {string} url - URL to check. + * @return {boolean} - True if the URL points to a local file. */ export default function isLocalFile( url ) { return !! url && isURL( url ) && getProtocol( url ) === 'file:'; diff --git a/projects/packages/videopress/src/client/block-editor/utils/video.ts b/projects/packages/videopress/src/client/block-editor/utils/video.ts index 200c09259e628..c7e95ed9ffe3b 100644 --- a/projects/packages/videopress/src/client/block-editor/utils/video.ts +++ b/projects/packages/videopress/src/client/block-editor/utils/video.ts @@ -3,7 +3,7 @@ * based on its mime type. * * @param {File} file - File to check. - * @returns {boolean} Whether the file is a video. + * @return {boolean} Whether the file is a video. */ export function isVideoFile( file: File ): boolean { if ( ! file?.type ) { @@ -17,7 +17,7 @@ export function isVideoFile( file: File ): boolean { * Filter an array of files to only include video files. * * @param {File[]} files - Array of files to filter. - * @returns {File[]} Array of video files. + * @return {File[]} Array of video files. */ export function filterVideoFiles( files: File[] ): File[] { return files.filter( isVideoFile ); diff --git a/projects/packages/videopress/src/client/components/timestamp-control/index.tsx b/projects/packages/videopress/src/client/components/timestamp-control/index.tsx index fc6bf56bdec40..d9b6b077dd5c2 100644 --- a/projects/packages/videopress/src/client/components/timestamp-control/index.tsx +++ b/projects/packages/videopress/src/client/components/timestamp-control/index.tsx @@ -26,7 +26,7 @@ import type React from 'react'; * Fallback implementation of useBaseControlProps. * * @param {object} props - The component props. - * @returns {object} - The computed control props. + * @return {object} - The computed control props. */ function useBaseControlPropsFallback( props: Record< string, unknown > ): { baseControlProps: Record< string, unknown >; @@ -112,10 +112,10 @@ type TimeDataProps = { /** * Return the time data based on the given value. * - * @param {number} value - The value to be converted. + * @param {number} value - The value to be converted. * @param {DecimalPlacesProp} decimalPlaces - The number of decimal places to be used. - * @param {number} max - The maximum value. - * @returns {TimeDataProps} The time data. + * @param {number} max - The maximum value. + * @return {TimeDataProps} The time data. */ function getTimeDataByValue( value: number, @@ -287,7 +287,7 @@ export const TimestampInput = ( { * TimestampControl component * * @param {TimestampControlProps} props - Component props. - * @returns {React.ReactElement} TimestampControl react component. + * @return {React.ReactElement} TimestampControl react component. */ export const TimestampControl = ( props: TimestampControlProps ): React.ReactElement => { const { diff --git a/projects/packages/videopress/src/client/hooks/use-meta-update.js b/projects/packages/videopress/src/client/hooks/use-meta-update.js index d3b53c2fae852..08628b9537e02 100644 --- a/projects/packages/videopress/src/client/hooks/use-meta-update.js +++ b/projects/packages/videopress/src/client/hooks/use-meta-update.js @@ -25,7 +25,6 @@ const useMetaUpdate = id => { // check for code, if set if ( 'success' !== result?.code ) { reject(); - return; } } ) .catch( e => reject( e ) ) diff --git a/projects/packages/videopress/src/client/hooks/use-resumable-uploader/index.ts b/projects/packages/videopress/src/client/hooks/use-resumable-uploader/index.ts index 05f271a45805e..335c145509cae 100644 --- a/projects/packages/videopress/src/client/hooks/use-resumable-uploader/index.ts +++ b/projects/packages/videopress/src/client/hooks/use-resumable-uploader/index.ts @@ -53,7 +53,7 @@ const useResumableUploader = ( { onProgress, onSuccess, onError } ): UseResumabl * Upload a file * * @param {File} file - the file to upload - * @returns {*} ??? + * @return {*} ??? */ async function uploadHandler( file: File ) { const tokenData = await getMediaToken( 'upload-jwt' ); diff --git a/projects/packages/videopress/src/client/lib/connection/index.ts b/projects/packages/videopress/src/client/lib/connection/index.ts index 42109bfe9c9b7..a5565eec03d72 100644 --- a/projects/packages/videopress/src/client/lib/connection/index.ts +++ b/projects/packages/videopress/src/client/lib/connection/index.ts @@ -17,7 +17,7 @@ const debug = debugFactory( 'videopress:connection' ); * both exposed by the connection class-block-editor-extension.php. * * @see {@link ../class-block-editor-extension.php} - * @returns {boolean} True if the user is connected, false otherwise. + * @return {boolean} True if the user is connected, false otherwise. */ export function isUserConnected(): boolean { if ( siteType === 'simple' ) { @@ -37,7 +37,7 @@ export function isUserConnected(): boolean { /** * Check whether the Jetpack VideoPress module is active. * - * @returns {boolean} True if the module is active, false otherwise. + * @return {boolean} True if the module is active, false otherwise. */ export function isVideoPressModuleActive(): boolean { return window?.videoPressEditorState?.isVideoPressModuleActive === '1'; @@ -51,7 +51,7 @@ export function isVideoPressModuleActive(): boolean { * Note: It's possible to have the module active, * but the user not connected. * - * @returns {boolean} True if the feature is active, false otherwise. + * @return {boolean} True if the feature is active, false otherwise. */ export function isVideoPressActive(): boolean { if ( ! isUserConnected() ) { @@ -64,7 +64,7 @@ export function isVideoPressActive(): boolean { /** * Return whether the standalone plugin is active. * - * @returns {boolean} True if the feature is active, false otherwise. + * @return {boolean} True if the feature is active, false otherwise. */ export function isStandaloneActive(): boolean { return window?.videoPressEditorState?.isStandaloneActive === '1'; diff --git a/projects/packages/videopress/src/client/lib/fetch-video-item/index.ts b/projects/packages/videopress/src/client/lib/fetch-video-item/index.ts index f3758a6be8d33..31181b163fdf1 100644 --- a/projects/packages/videopress/src/client/lib/fetch-video-item/index.ts +++ b/projects/packages/videopress/src/client/lib/fetch-video-item/index.ts @@ -25,13 +25,13 @@ const debug = debugFactory( 'videopress:lib:fetch-video-item' ); /** * Fetches the video item from the v1.1/videos endpoint. * - * @param {object} parameters - The function parameters. - * @param {VideoGUID} parameters.guid - The video GUID. - * @param {boolean} parameters.isPrivate - Whether the video is private. - * @param {string} parameters.token - The token to use in the request. - * @param {boolean} parameters.skipRatingControl - Whether to skip the rating control. - * @param {number} parameters.retries - The number of retries. - * @returns {WPCOMRestAPIVideosGetEndpointResponseProps} Props + * @param {object} parameters - The function parameters. + * @param {VideoGUID} parameters.guid - The video GUID. + * @param {boolean} parameters.isPrivate - Whether the video is private. + * @param {string} parameters.token - The token to use in the request. + * @param {boolean} parameters.skipRatingControl - Whether to skip the rating control. + * @param {number} parameters.retries - The number of retries. + * @return {WPCOMRestAPIVideosGetEndpointResponseProps} Props */ export async function fetchVideoItem( { guid, diff --git a/projects/packages/videopress/src/client/lib/get-media-token/index.native.ts b/projects/packages/videopress/src/client/lib/get-media-token/index.native.ts index 8ed8d2f9643eb..e03eb03c5e4ad 100644 --- a/projects/packages/videopress/src/client/lib/get-media-token/index.native.ts +++ b/projects/packages/videopress/src/client/lib/get-media-token/index.native.ts @@ -19,9 +19,9 @@ type Response = { /** * Request media token data hiting WPCOM API. * - * @param {MediaTokenScopeProps} scope - The scope of the token to request. - * @param {GetMediaTokenArgsProps} args - function arguments. - * @returns {MediaTokenProps} Media token data. + * @param {MediaTokenScopeProps} scope - The scope of the token to request. + * @param {GetMediaTokenArgsProps} args - function arguments. + * @return {MediaTokenProps} Media token data. */ const requestMediaToken = function ( scope: MediaTokenScopeProps, @@ -69,9 +69,9 @@ const requestMediaToken = function ( * * NOTE: In the native version, the token is not persisted. * - * @param {MediaTokenScopeProps} scope - The scope of the token to request. - * @param {GetMediaTokenArgsProps} args - function arguments. - * @returns {MediaTokenProps} Media token data. + * @param {MediaTokenScopeProps} scope - The scope of the token to request. + * @param {GetMediaTokenArgsProps} args - function arguments. + * @return {MediaTokenProps} Media token data. */ async function getMediaToken( scope: MediaTokenScopeProps, diff --git a/projects/packages/videopress/src/client/lib/get-media-token/index.ts b/projects/packages/videopress/src/client/lib/get-media-token/index.ts index 02bcdb02a9adb..8a727ee9ef4e1 100644 --- a/projects/packages/videopress/src/client/lib/get-media-token/index.ts +++ b/projects/packages/videopress/src/client/lib/get-media-token/index.ts @@ -26,9 +26,9 @@ const TOKEN_LIFETIME = 1000 * 60 * 60 * 24; // 24 hours /** * Request media token data hiting the admin-ajax endpoint. * - * @param {MediaTokenScopeProps} scope - The scope of the token to request. - * @param {GetMediaTokenArgsProps} args - function arguments. - * @returns {MediaTokenProps} Media token data. + * @param {MediaTokenScopeProps} scope - The scope of the token to request. + * @param {GetMediaTokenArgsProps} args - function arguments. + * @return {MediaTokenProps} Media token data. */ const requestMediaToken = function ( scope: MediaTokenScopeProps, @@ -123,9 +123,9 @@ const requestMediaToken = function ( * from the localStore in case it is still valid, * otherwise request it from the admin-ajax endpoint. * - * @param {MediaTokenScopeProps} scope - The scope of the token to request. - * @param {GetMediaTokenArgsProps} args - function arguments. - * @returns {MediaTokenProps} Media token data. + * @param {MediaTokenScopeProps} scope - The scope of the token to request. + * @param {GetMediaTokenArgsProps} args - function arguments. + * @return {MediaTokenProps} Media token data. */ async function getMediaToken( scope: MediaTokenScopeProps, diff --git a/projects/packages/videopress/src/client/lib/poster/index.ts b/projects/packages/videopress/src/client/lib/poster/index.ts index c0553c1664146..2192264f6f244 100644 --- a/projects/packages/videopress/src/client/lib/poster/index.ts +++ b/projects/packages/videopress/src/client/lib/poster/index.ts @@ -61,12 +61,12 @@ export const hasVideoPosterGenerated = async function ( guid: VideoGUID ): Promi * Polls the API to check if * the video poster image has been generated. * - * @param {VideoGUID} guid - The video guid. - * @param {object} options - Options for the polling. - * @param {number} options.wait - The time to wait between polls, in milliseconds. - * @param {number} options.attemps - The number of times to poll before giving up. - * @param {boolean} options.initialWait - Whether to wait before the first poll. - * @returns {Promise} Whether the poster image has been generated. + * @param {VideoGUID} guid - The video guid. + * @param {object} options - Options for the polling. + * @param {number} options.wait - The time to wait between polls, in milliseconds. + * @param {number} options.attemps - The number of times to poll before giving up. + * @param {boolean} options.initialWait - Whether to wait before the first poll. + * @return {Promise} Whether the poster image has been generated. */ export async function pollGeneratingPosterImage( guid: VideoGUID, diff --git a/projects/packages/videopress/src/client/lib/token-bridge/index.ts b/projects/packages/videopress/src/client/lib/token-bridge/index.ts index 3ad920b0d6967..06d98561b10c6 100644 --- a/projects/packages/videopress/src/client/lib/token-bridge/index.ts +++ b/projects/packages/videopress/src/client/lib/token-bridge/index.ts @@ -32,7 +32,7 @@ type TokenBrigeEventProps = { /** * Quick docReady implementation. - * @returns {Promise} promise. + * @return {Promise} promise. */ function ready(): Promise< void > { return new Promise( function ( resolve ) { @@ -49,7 +49,7 @@ function ready(): Promise< void > { * Check if the guid has an associated subscriptionPlanId. * * @param {VideoGUID} guid - The guid. - * @returns {Promise} promise. + * @return {Promise} promise. */ async function getSubscriberPlanIdIfExists( guid: VideoGUID ): Promise< number > { await ready(); diff --git a/projects/packages/videopress/src/client/lib/url/index.ts b/projects/packages/videopress/src/client/lib/url/index.ts index 26f1972734bb3..3d1951dcbebbd 100644 --- a/projects/packages/videopress/src/client/lib/url/index.ts +++ b/projects/packages/videopress/src/client/lib/url/index.ts @@ -114,7 +114,7 @@ export const pickGUIDFromUrl: ( url: string ) => null | string = url => { * Check if a string is a valid VideoPress GUID. * * @param {string} value - The string to check. - * @returns {boolean | VideoGUID} Video GUID if the string is valid, false otherwise. + * @return {boolean | VideoGUID} Video GUID if the string is valid, false otherwise. */ export function isVideoPressGuid( value: string ): boolean | VideoGUID { const guid = value.match( /^[a-zA-Z\d]{8}$/ ); @@ -134,9 +134,9 @@ type BuildVideoPressURLProps = { * Build a VideoPress URL from a VideoPress GUID or a VideoPress URL. * The function returns an { url, guid } object, or false. * - * @param {string | VideoGUID} value - The VideoPress GUID or URL. + * @param {string | VideoGUID} value - The VideoPress GUID or URL. * @param {VideoBlockAttributes} attributes - The VideoPress URL options. - * @returns {false | string} VideoPress URL if the string is valid, false otherwise. + * @return {false | string} VideoPress URL if the string is valid, false otherwise. */ export function buildVideoPressURL( value: string | VideoGUID, @@ -167,9 +167,9 @@ export const removeFileNameExtension = ( name: string ) => { * Return the VideoPress video URL * based on the privacy of the video. * - * @param {VideoGUID} guid - The VideoPress GUID. - * @param {boolean} isPrivate - Whether the video is private or not. - * @returns {string} VideoPress URL. + * @param {VideoGUID} guid - The VideoPress GUID. + * @param {boolean} isPrivate - Whether the video is private or not. + * @return {string} VideoPress URL. */ export function getVideoUrlBasedOnPrivacy( guid: VideoGUID, isPrivate: boolean ) { if ( isPrivate ) { @@ -183,7 +183,7 @@ export function getVideoUrlBasedOnPrivacy( guid: VideoGUID, isPrivate: boolean ) * Determines if a given URL is a VideoPress URL. * * @param {string} url - The URL to check. - * @returns {boolean} bool True if the URL is a VideoPress URL, false otherwise. + * @return {boolean} bool True if the URL is a VideoPress URL, false otherwise. */ export function isVideoPressUrl( url: string ): boolean { const pattern = @@ -194,8 +194,8 @@ export function isVideoPressUrl( url: string ): boolean { /** * Pick and map VideoPress block attributes from a VideoPress URL. * - * @param {string} url - The VideoPress URL. - * @returns {VideoBlockAttributes} VideoPress block attributes. + * @param {string} url - The VideoPress URL. + * @return {VideoBlockAttributes} VideoPress block attributes. */ export function pickVideoBlockAttributesFromUrl( url: string ): VideoBlockAttributes { let queryParams: URLSearchParams; diff --git a/projects/packages/videopress/src/client/lib/video-tracks/index.ts b/projects/packages/videopress/src/client/lib/video-tracks/index.ts index c932f5befef88..ec2d41fef5435 100644 --- a/projects/packages/videopress/src/client/lib/video-tracks/index.ts +++ b/projects/packages/videopress/src/client/lib/video-tracks/index.ts @@ -38,9 +38,9 @@ type isAutogeneratedChaterFileParamsProps = { * based on the block attributes. * If the first request fails, it will try again with the token. * - * @param {string} fileUrl - the track file url - * @param {isAutogeneratedChaterFileParamsProps} params - function parameters - * @returns {Promise} true if the file is autogenerated. + * @param {string} fileUrl - the track file url + * @param {isAutogeneratedChaterFileParamsProps} params - function parameters + * @return {Promise} true if the file is autogenerated. */ export async function isAutogeneratedChapterFile( fileUrl: string, @@ -119,8 +119,8 @@ const videoPressUploadTrack = function ( track: UploadTrackDataProps, guid: stri * Uses different methods depending on Jetpack or WPCOM. * * @param {object} track - the track file - * @param {string} guid - the video guid - * @returns {Promise} the api request promise + * @param {string} guid - the video guid + * @return {Promise} the api request promise */ export const uploadTrackForGuid = ( track: UploadTrackDataProps, guid: string ) => { const { kind, srcLang, label, tmpFile } = track; @@ -196,8 +196,8 @@ const videoPressDeleteTrack = function ( { kind, srcLang }, guid ) { * -Uses different methods depending on Jetpack or WPCOM. * * @param {object} track - the track file - * @param {string} guid - the video guid - * @returns {Promise} the api request promise + * @param {string} guid - the video guid + * @return {Promise} the api request promise */ export const deleteTrackForGuid = ( track: DeleteTrackDataProps, guid: string ) => { const { kind, srcLang } = track; diff --git a/projects/packages/videopress/src/client/state/actions.js b/projects/packages/videopress/src/client/state/actions.js index 572d9f1878eca..4fbb1e494a70c 100644 --- a/projects/packages/videopress/src/client/state/actions.js +++ b/projects/packages/videopress/src/client/state/actions.js @@ -210,7 +210,7 @@ const updateVideoPrivacy = * used as a primary hint for the UI to update. * * @param {string|number} id - Video post ID - * @returns {object} Action object + * @return {object} Action object */ const removeVideo = id => { return { type: REMOVE_VIDEO, id }; @@ -220,7 +220,7 @@ const removeVideo = id => { * Thunk action to remove a video from the state, * * @param {string|number} id - Video post ID - * @returns {Function} Thunk action + * @return {Function} Thunk action */ const deleteVideo = id => @@ -264,7 +264,7 @@ const deleteVideo = * Thunk action to upload videos for VideoPress. * * @param {File} file - File to upload - * @returns {Function} Thunk action + * @return {Function} Thunk action */ const uploadVideo = file => @@ -309,7 +309,7 @@ const uploadVideo = * Thunk action to upload local videos for VideoPress. * * @param {object} file - File data - * @returns {Function} Thunk action + * @return {Function} Thunk action */ const uploadVideoFromLibrary = file => @@ -448,7 +448,7 @@ const setVideoPressSettings = videoPressSettings => { * Thunk action to remove a video from the state, * * @param {object} settings - VideoPress settings - * @returns {Function} Thunk action + * @return {Function} Thunk action */ const updateVideoPressSettings = settings => diff --git a/projects/packages/videopress/src/client/state/reducers.js b/projects/packages/videopress/src/client/state/reducers.js index f5b5c1f7ad9d3..f538ceb3f0177 100644 --- a/projects/packages/videopress/src/client/state/reducers.js +++ b/projects/packages/videopress/src/client/state/reducers.js @@ -51,7 +51,7 @@ import { /** * Retunr default query values * - * @returns {object} Full query object. + * @return {object} Full query object. */ export function getDefaultQuery() { return { diff --git a/projects/packages/videopress/src/client/state/resolvers.js b/projects/packages/videopress/src/client/state/resolvers.js index 35709fe0869cb..15c611f6018d4 100644 --- a/projects/packages/videopress/src/client/state/resolvers.js +++ b/projects/packages/videopress/src/client/state/resolvers.js @@ -35,7 +35,7 @@ const { apiRoot } = window?.jetpackVideoPressInitialState || {}; * @param {object} video - Video object. * @param {object} resolveSelect - Containing the store’s selectors pre-bound to state * @param {object} dispatch - Containing the store’s actions pre-bound to state - * @returns {object} Tokenized video data object. + * @return {object} Tokenized video data object. */ async function populateVideoDataWithToken( video, resolveSelect, dispatch ) { if ( ! video.needsPlaybackToken ) { diff --git a/projects/packages/videopress/src/client/state/utils/video-is-private.ts b/projects/packages/videopress/src/client/state/utils/video-is-private.ts index f745a17203634..8e6e11a7913c0 100644 --- a/projects/packages/videopress/src/client/state/utils/video-is-private.ts +++ b/projects/packages/videopress/src/client/state/utils/video-is-private.ts @@ -12,9 +12,9 @@ import { * Determines if a video is private taking into account the video * privacy setting and the site default privacy setting. * - * @param {PrivacySettingProp} privacySetting - The privacy setting for the video - * @param {boolean} privateEnabledForSite - The site default privacy setting, if it's private or not - * @returns {boolean} - true if the video is private, false otherwise + * @param {PrivacySettingProp} privacySetting - The privacy setting for the video + * @param {boolean} privateEnabledForSite - The site default privacy setting, if it's private or not + * @return {boolean} - true if the video is private, false otherwise */ export const videoIsPrivate = ( privacySetting: PrivacySettingProp, diff --git a/projects/packages/videopress/src/client/utils/map-object-keys-to-camel-case/index.ts b/projects/packages/videopress/src/client/utils/map-object-keys-to-camel-case/index.ts index 414d596561bb7..095228d70f6f2 100644 --- a/projects/packages/videopress/src/client/utils/map-object-keys-to-camel-case/index.ts +++ b/projects/packages/videopress/src/client/utils/map-object-keys-to-camel-case/index.ts @@ -2,7 +2,7 @@ * Convert snake case string to camel case string. * * @param {string} string - String to convert. - * @returns {string} - Converted string. + * @return {string} - Converted string. */ export function snakeToCamel( string ) { return string.replace( /([-_][a-z])/gi, $1 => { @@ -14,7 +14,7 @@ export function snakeToCamel( string ) { * Check is the string has snake shape. * * @param {string} string - String to check. - * @returns {boolean} - True if the string has snake shape. + * @return {boolean} - True if the string has snake shape. */ function isSnake( string ) { return string.indexOf( '_' ) !== -1; @@ -25,14 +25,14 @@ function isSnake( string ) { * * @param {object} originalObject - Object to be converted. * @param {boolean} deleteOriginalProp - Whether to delete the original property. False by default. - * @returns {object} - Converted object. + * @return {object} - Converted object. */ export function mapObjectKeysToCamel( originalObject, deleteOriginalProp = false ) { // avoid to override original object const object = Object.assign( {}, originalObject ); for ( const key in object ) { - if ( object.hasOwnProperty( key ) && isSnake( key ) ) { + if ( Object.hasOwn( object, key ) && isSnake( key ) ) { object[ snakeToCamel( key ) ] = object[ key ]; if ( deleteOriginalProp ) { diff --git a/projects/packages/videopress/src/client/utils/time/index.ts b/projects/packages/videopress/src/client/utils/time/index.ts index ffbc3d90f080c..0f64dab49e9be 100644 --- a/projects/packages/videopress/src/client/utils/time/index.ts +++ b/projects/packages/videopress/src/client/utils/time/index.ts @@ -3,7 +3,7 @@ * adding hours and minutes only when needed. * * @param {number} ms - The time in milliseconds to format. - * @returns {string} The formatted time string. + * @return {string} The formatted time string. * @example * const formattedTime1 = formatTime(1234567); // Returns "20:34.56" * const formattedTime2 = formatTime(45123); // Returns "45.12" diff --git a/projects/packages/videopress/src/client/utils/video-chapters/extract-video-chapters/index.ts b/projects/packages/videopress/src/client/utils/video-chapters/extract-video-chapters/index.ts index 5f32f34622847..1cbdfbbc3a63c 100644 --- a/projects/packages/videopress/src/client/utils/video-chapters/extract-video-chapters/index.ts +++ b/projects/packages/videopress/src/client/utils/video-chapters/extract-video-chapters/index.ts @@ -3,8 +3,8 @@ import type { VideoPressChapter } from '../types'; /** * Extracts chapter information from a single text line * - * @param {string} line - The line to be processed - * @returns {VideoPressChapter} - Title and start time of the chapter + * @param {string} line - The line to be processed + * @return {VideoPressChapter} - Title and start time of the chapter */ function extractSingleChapter( line: string ): VideoPressChapter | null { const regex = /(?\(?(?
    4. ) : (
      diff --git a/projects/plugins/boost/app/assets/src/js/features/performance-history/performance-history.module.scss b/projects/plugins/boost/app/assets/src/js/features/performance-history/performance-history.module.scss index cd0ffd55e2b77..c7a29143bb150 100644 --- a/projects/plugins/boost/app/assets/src/js/features/performance-history/performance-history.module.scss +++ b/projects/plugins/boost/app/assets/src/js/features/performance-history/performance-history.module.scss @@ -5,7 +5,12 @@ border-radius: 8px; } + :global(.components-panel__body-title > button) { + font-size: 14px; + font-weight: 400; + } + &-body { border-color: transparent; } -} \ No newline at end of file +} diff --git a/projects/plugins/boost/app/assets/src/js/features/premium-tooltip/premium-tooltip.module.scss b/projects/plugins/boost/app/assets/src/js/features/premium-tooltip/premium-tooltip.module.scss index 24679f593e12b..b2c02b4256396 100644 --- a/projects/plugins/boost/app/assets/src/js/features/premium-tooltip/premium-tooltip.module.scss +++ b/projects/plugins/boost/app/assets/src/js/features/premium-tooltip/premium-tooltip.module.scss @@ -27,3 +27,18 @@ bottom: 0; fill: #8c8f94; } + +.upgrade-cta { + p { + display: block; + } + + :global(button) { + margin-top: 0; + margin-bottom: 0; + } + + :global(svg) { + position: relative; + } +} diff --git a/projects/plugins/boost/app/assets/src/js/features/premium-tooltip/premium-tooltip.tsx b/projects/plugins/boost/app/assets/src/js/features/premium-tooltip/premium-tooltip.tsx index c6d1cef90d93b..579f6fc1f5e4e 100644 --- a/projects/plugins/boost/app/assets/src/js/features/premium-tooltip/premium-tooltip.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/premium-tooltip/premium-tooltip.tsx @@ -1,19 +1,9 @@ import { IconTooltip } from '@automattic/jetpack-components'; -import React from 'react'; import { __ } from '@wordpress/i18n'; -import { recordBoostEvent } from '$lib/utils/analytics'; import styles from './premium-tooltip.module.scss'; -import { useNavigate } from 'react-router-dom'; +import UpgradeCTA from '$features/upgrade-cta/upgrade-cta'; const PremiumTooltip = () => { - const navigate = useNavigate(); - - function showBenefits( event: React.MouseEvent< HTMLAnchorElement > ) { - event.preventDefault(); - const eventProps = {}; - recordBoostEvent( 'upsell_cta_from_settings_page_tooltip_in_plugin', eventProps ); - navigate( '/upgrade' ); - } return ( { ) }
- { __( 'If you’d like automatic Critical CSS regeneration', 'jetpack-boost' ) } -
- { /* eslint-disable-next-line jsx-a11y/anchor-is-valid */ } - - { __( 'Upgrade now', 'jetpack-boost' ) } - + +
+ +
); }; diff --git a/projects/plugins/boost/app/assets/src/js/features/speed-score/speed-score.module.scss b/projects/plugins/boost/app/assets/src/js/features/speed-score/speed-score.module.scss index 3dc5a43acf714..268f8e054bd89 100644 --- a/projects/plugins/boost/app/assets/src/js/features/speed-score/speed-score.module.scss +++ b/projects/plugins/boost/app/assets/src/js/features/speed-score/speed-score.module.scss @@ -32,6 +32,16 @@ fill: $jetpack-green; } } + + :global(.jb-score-bar__no_boost_score_tooltip) { + top: -68px; + font-size: 16px; + } + + :global(.jb-score-bar__no_boost_score_tooltip::after) { + font-size: 0.7em; + left: 50%; + } } :global(.jb-dashboard) .speed-scores h2 { diff --git a/projects/plugins/boost/app/assets/src/js/features/upgrade-cta/upgrade-cta.tsx b/projects/plugins/boost/app/assets/src/js/features/upgrade-cta/upgrade-cta.tsx index 3d1b8eee33cec..53a86d0552802 100644 --- a/projects/plugins/boost/app/assets/src/js/features/upgrade-cta/upgrade-cta.tsx +++ b/projects/plugins/boost/app/assets/src/js/features/upgrade-cta/upgrade-cta.tsx @@ -9,13 +9,18 @@ import { useNavigate } from 'react-router-dom'; type UpgradeCTAProps = { description: string; identifier: string; + eventName?: string; }; -const UpgradeCTA = ( { description, identifier }: UpgradeCTAProps ) => { +const UpgradeCTA = ( { + description, + identifier, + eventName = 'upsell_cta_from_settings_page_in_plugin', +}: UpgradeCTAProps ) => { const navigate = useNavigate(); const showBenefits = () => { - recordBoostEvent( 'upsell_cta_from_settings_page_in_plugin', { identifier } ); + recordBoostEvent( eventName, { identifier } ); navigate( '/upgrade' ); }; diff --git a/projects/plugins/boost/app/assets/src/js/layout/settings-page/support/support.tsx b/projects/plugins/boost/app/assets/src/js/layout/settings-page/support/support.tsx index 2b26f93b4b5a4..6f5c73f3afb06 100644 --- a/projects/plugins/boost/app/assets/src/js/layout/settings-page/support/support.tsx +++ b/projects/plugins/boost/app/assets/src/js/layout/settings-page/support/support.tsx @@ -1,4 +1,5 @@ import { __ } from '@wordpress/i18n'; +import { Button } from '@automattic/jetpack-components'; import styles from './support.module.scss'; const Support = () => { @@ -21,13 +22,9 @@ const Support = () => {

- +
diff --git a/projects/plugins/boost/app/assets/src/js/svg/automattic.svg b/projects/plugins/boost/app/assets/src/js/svg/automattic.svg index 7142a47aeadb5..651c664bdb947 100644 --- a/projects/plugins/boost/app/assets/src/js/svg/automattic.svg +++ b/projects/plugins/boost/app/assets/src/js/svg/automattic.svg @@ -1 +1,10 @@ - \ No newline at end of file + + + + + + + + + + \ No newline at end of file diff --git a/projects/plugins/boost/app/assets/src/js/svg/checkbox.svg b/projects/plugins/boost/app/assets/src/js/svg/checkbox.svg index c7e39bc787b02..cc8621e57a395 100644 --- a/projects/plugins/boost/app/assets/src/js/svg/checkbox.svg +++ b/projects/plugins/boost/app/assets/src/js/svg/checkbox.svg @@ -1 +1,9 @@ - \ No newline at end of file + + + + + diff --git a/projects/plugins/boost/app/assets/src/js/svg/chevron-left.svg b/projects/plugins/boost/app/assets/src/js/svg/chevron-left.svg index f117db5186a80..359cf65c9d00c 100644 --- a/projects/plugins/boost/app/assets/src/js/svg/chevron-left.svg +++ b/projects/plugins/boost/app/assets/src/js/svg/chevron-left.svg @@ -1 +1,8 @@ - \ No newline at end of file + + + diff --git a/projects/plugins/boost/app/assets/src/js/svg/chevron-right.svg b/projects/plugins/boost/app/assets/src/js/svg/chevron-right.svg index fba97a2665d84..3719353da2096 100644 --- a/projects/plugins/boost/app/assets/src/js/svg/chevron-right.svg +++ b/projects/plugins/boost/app/assets/src/js/svg/chevron-right.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/projects/plugins/boost/app/assets/src/js/svg/info.svg b/projects/plugins/boost/app/assets/src/js/svg/info.svg index 2d3be95f8dc83..cbf99a4f2847d 100644 --- a/projects/plugins/boost/app/assets/src/js/svg/info.svg +++ b/projects/plugins/boost/app/assets/src/js/svg/info.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/projects/plugins/boost/app/assets/src/js/svg/jetpack-green.svg b/projects/plugins/boost/app/assets/src/js/svg/jetpack-green.svg index 85389ed5ca5bb..dd9b69d472f7f 100644 --- a/projects/plugins/boost/app/assets/src/js/svg/jetpack-green.svg +++ b/projects/plugins/boost/app/assets/src/js/svg/jetpack-green.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/projects/plugins/boost/app/assets/src/js/svg/jetpack.svg b/projects/plugins/boost/app/assets/src/js/svg/jetpack.svg index 7550bf6123935..18174d04beb9f 100644 --- a/projects/plugins/boost/app/assets/src/js/svg/jetpack.svg +++ b/projects/plugins/boost/app/assets/src/js/svg/jetpack.svg @@ -1 +1,7 @@ - \ No newline at end of file + + + \ No newline at end of file diff --git a/projects/plugins/boost/app/assets/src/js/svg/logo.svg b/projects/plugins/boost/app/assets/src/js/svg/logo.svg index 58f163013e33d..42e76f7f5f666 100644 --- a/projects/plugins/boost/app/assets/src/js/svg/logo.svg +++ b/projects/plugins/boost/app/assets/src/js/svg/logo.svg @@ -1 +1,18 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + diff --git a/projects/plugins/boost/app/assets/src/js/svg/notice-outline.svg b/projects/plugins/boost/app/assets/src/js/svg/notice-outline.svg index 4d60e08c8a667..47e32a2b3ea2e 100644 --- a/projects/plugins/boost/app/assets/src/js/svg/notice-outline.svg +++ b/projects/plugins/boost/app/assets/src/js/svg/notice-outline.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/projects/plugins/boost/app/assets/src/js/svg/refresh.svg b/projects/plugins/boost/app/assets/src/js/svg/refresh.svg index 81e0ec84b9334..4b513de2d92e0 100644 --- a/projects/plugins/boost/app/assets/src/js/svg/refresh.svg +++ b/projects/plugins/boost/app/assets/src/js/svg/refresh.svg @@ -1 +1,10 @@ - \ No newline at end of file + + + + + diff --git a/projects/plugins/boost/app/assets/src/js/svg/warning-outline.svg b/projects/plugins/boost/app/assets/src/js/svg/warning-outline.svg index 3819652fc8cff..a554c98e3dfd5 100644 --- a/projects/plugins/boost/app/assets/src/js/svg/warning-outline.svg +++ b/projects/plugins/boost/app/assets/src/js/svg/warning-outline.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/projects/plugins/boost/app/assets/static/images/check.svg b/projects/plugins/boost/app/assets/static/images/check.svg index c1c333b3aaf58..74c22455ded83 100644 --- a/projects/plugins/boost/app/assets/static/images/check.svg +++ b/projects/plugins/boost/app/assets/static/images/check.svg @@ -1 +1,8 @@ - \ No newline at end of file + + + + + + + + diff --git a/projects/plugins/boost/app/assets/static/images/color-shift.svg b/projects/plugins/boost/app/assets/static/images/color-shift.svg index 156f1d7ca37d9..26311aef27fae 100644 --- a/projects/plugins/boost/app/assets/static/images/color-shift.svg +++ b/projects/plugins/boost/app/assets/static/images/color-shift.svg @@ -1 +1,41 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/plugins/boost/app/assets/static/images/cross.svg b/projects/plugins/boost/app/assets/static/images/cross.svg index cb40bcdf7d5e9..f66a96060e41f 100644 --- a/projects/plugins/boost/app/assets/static/images/cross.svg +++ b/projects/plugins/boost/app/assets/static/images/cross.svg @@ -1 +1,8 @@ - \ No newline at end of file + + + + + + + + diff --git a/projects/plugins/boost/app/assets/static/images/jetpack-colors.svg b/projects/plugins/boost/app/assets/static/images/jetpack-colors.svg index 74eced3b128ec..2b4b45f483cb1 100644 --- a/projects/plugins/boost/app/assets/static/images/jetpack-colors.svg +++ b/projects/plugins/boost/app/assets/static/images/jetpack-colors.svg @@ -1 +1,14 @@ - \ No newline at end of file + + + + + + + + + + + + + + \ No newline at end of file diff --git a/projects/plugins/boost/app/assets/static/images/jetpack-logo.svg b/projects/plugins/boost/app/assets/static/images/jetpack-logo.svg index 7c88a6c5006fe..dad3792e7de02 100644 --- a/projects/plugins/boost/app/assets/static/images/jetpack-logo.svg +++ b/projects/plugins/boost/app/assets/static/images/jetpack-logo.svg @@ -1 +1,17 @@ - \ No newline at end of file + diff --git a/projects/plugins/boost/app/assets/static/images/pencil.svg b/projects/plugins/boost/app/assets/static/images/pencil.svg index 3eaaf53453a91..9aa34b2de50f5 100644 --- a/projects/plugins/boost/app/assets/static/images/pencil.svg +++ b/projects/plugins/boost/app/assets/static/images/pencil.svg @@ -1 +1,12 @@ - \ No newline at end of file + + + + + + + + diff --git a/projects/plugins/boost/app/lib/critical-css/Critical_CSS_Invalidator.php b/projects/plugins/boost/app/lib/critical-css/Critical_CSS_Invalidator.php index 71ce3fd324986..e1013a4ae9d32 100644 --- a/projects/plugins/boost/app/lib/critical-css/Critical_CSS_Invalidator.php +++ b/projects/plugins/boost/app/lib/critical-css/Critical_CSS_Invalidator.php @@ -7,7 +7,11 @@ namespace Automattic\Jetpack_Boost\Lib\Critical_CSS; +use Automattic\Jetpack_Boost\Admin\Regenerate_Admin_Notice; use Automattic\Jetpack_Boost\Lib\Boost_Health; +use Automattic\Jetpack_Boost\Lib\Critical_CSS\Source_Providers\Source_Providers; +use Automattic\Jetpack_Boost\Modules\Modules_Setup; +use Automattic\Jetpack_Boost\Modules\Optimizations\Cloud_CSS\Cloud_CSS; use Automattic\Jetpack_Boost\Modules\Optimizations\Cloud_CSS\Cloud_CSS_Followup; /** @@ -21,21 +25,35 @@ class Critical_CSS_Invalidator { * Register hooks. */ public static function init() { - add_action( 'jetpack_boost_deactivate', array( __CLASS__, 'clear_data' ) ); + add_action( 'jetpack_boost_deactivate', array( __CLASS__, 'reset_data' ) ); add_action( 'jetpack_boost_critical_css_environment_changed', array( __CLASS__, 'handle_environment_change' ) ); add_filter( 'jetpack_boost_total_problem_count', array( __CLASS__, 'update_boost_problem_count' ) ); } /** - * Clear Critical CSS data. + * Reset Critical CSS data. + * For Cloud CSS, we need to make sure there are providers in the state, + * otherwise Cloud CSS cannot be stored after it is generated by the cloud. */ - public static function clear_data() { + public static function reset_data() { $storage = new Critical_CSS_Storage(); $storage->clear(); $state = new Critical_CSS_State(); $state->clear(); + if ( self::is_cloud_css() ) { + $state->prepare_for_generation( ( new Source_Providers() )->get_provider_sources() ); + $state->save(); + + // Clear the regenerate flag so things are nice and tidy. + jetpack_boost_ds_delete( 'critical_css_suggest_regenerate' ); + // Also clear the admin notice flag, so the notice doesn't show up in case + // the user is reverted to free Boost. + Regenerate_Admin_Notice::dismiss(); + + } + Cloud_CSS_Followup::unschedule(); } @@ -44,7 +62,7 @@ public static function clear_data() { */ public static function handle_environment_change( $is_major_change ) { if ( $is_major_change ) { - self::clear_data(); + self::reset_data(); do_action( 'jetpack_boost_critical_css_invalidated' ); } @@ -58,4 +76,9 @@ public static function update_boost_problem_count( $count ) { return $count; } + + public static function is_cloud_css() { + $optimizations = ( new Modules_Setup() )->get_status(); + return isset( $optimizations[ Cloud_CSS::get_slug() ] ) && $optimizations[ Cloud_CSS::get_slug() ]; + } } diff --git a/projects/plugins/boost/app/lib/critical-css/Critical_CSS_State.php b/projects/plugins/boost/app/lib/critical-css/Critical_CSS_State.php index 77337d121c297..07e7c978b5132 100644 --- a/projects/plugins/boost/app/lib/critical-css/Critical_CSS_State.php +++ b/projects/plugins/boost/app/lib/critical-css/Critical_CSS_State.php @@ -186,6 +186,19 @@ public function set_pending_providers( $providers ) { return $this; } + /** + * Add providers to the state, sets their status to pending + * and sets the generation status to pending. + * + * @param array $providers The providers to include in the state and set as pending. + * @return $this + */ + public function prepare_for_generation( $providers ) { + $this->set_pending_providers( $providers ); + $this->state['status'] = self::GENERATION_STATES['pending']; + return $this; + } + /** * Get fresh state */ diff --git a/projects/plugins/boost/app/lib/critical-css/Regenerate.php b/projects/plugins/boost/app/lib/critical-css/Regenerate.php index 9a74b501352b9..6b25fdf434c3c 100644 --- a/projects/plugins/boost/app/lib/critical-css/Regenerate.php +++ b/projects/plugins/boost/app/lib/critical-css/Regenerate.php @@ -45,7 +45,7 @@ public function start() { // Dismiss admin notices Regenerate_Admin_Notice::dismiss(); - jetpack_boost_ds_delete( 'critical_css_suggest_regenerate', null ); + jetpack_boost_ds_delete( 'critical_css_suggest_regenerate' ); return $data; } diff --git a/projects/plugins/boost/app/modules/image-guide/src/index.ts b/projects/plugins/boost/app/modules/image-guide/src/index.ts index 60ac6042d6077..ac73bdb538e13 100644 --- a/projects/plugins/boost/app/modules/image-guide/src/index.ts +++ b/projects/plugins/boost/app/modules/image-guide/src/index.ts @@ -30,7 +30,7 @@ async function fetchWeightUsingProxy( url: string ): Promise< Response > { // If the JSON data contains the content length, create a new response object with the JSON headers and the original response body. const headers = new Headers(); for ( const key in json.data ) { - if ( json.data.hasOwnProperty( key ) ) { + if ( Object.hasOwn( json.data, key ) ) { headers.set( key, json.data[ key ] ); } } diff --git a/projects/plugins/boost/app/modules/image-size-analysis/data-sync/init.php b/projects/plugins/boost/app/modules/image-size-analysis/data-sync/init.php index b68118043c044..2d459ba128f97 100644 --- a/projects/plugins/boost/app/modules/image-size-analysis/data-sync/init.php +++ b/projects/plugins/boost/app/modules/image-size-analysis/data-sync/init.php @@ -1,6 +1,6 @@ get(); - if ( isset( $data['providers'] ) ) { + if ( ! empty( $data['providers'] ) ) { $providers = $data['providers']; } else { $source_providers = new Source_Providers(); diff --git a/projects/plugins/boost/changelog/fix-mu-wpcom-scssphp b/projects/plugins/boost/changelog/fix-mu-wpcom-scssphp deleted file mode 100644 index 427aa2192f0dc..0000000000000 --- a/projects/plugins/boost/changelog/fix-mu-wpcom-scssphp +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: added -Comment: Add production-include for wikimedia/aho-corasick, now required via my-jetpack in #38332. - - diff --git a/projects/plugins/boost/changelog/fix-querying-null-object b/projects/plugins/boost/changelog/fix-querying-null-object deleted file mode 100644 index 3227e34840181..0000000000000 --- a/projects/plugins/boost/changelog/fix-querying-null-object +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fixed - -Misc: Fix PHP warning when generating critical css for some taxonomy pages. diff --git a/projects/plugins/boost/changelog/init-new-plugin-cycle b/projects/plugins/boost/changelog/init-new-plugin-cycle deleted file mode 100644 index 634cf14fea933..0000000000000 --- a/projects/plugins/boost/changelog/init-new-plugin-cycle +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: changed -Comment: Init 3.4.8-alpha. - - diff --git a/projects/plugins/boost/changelog/try-lossless-image-optmization-part-2 b/projects/plugins/boost/changelog/try-lossless-image-optmization-part-2 deleted file mode 100644 index 69c2d0f105cb4..0000000000000 --- a/projects/plugins/boost/changelog/try-lossless-image-optmization-part-2 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: fixed - -Lossless image optimization of images in projects/plugins [subdirectories from a* through social] diff --git a/projects/plugins/boost/changelog/update-jsx-namespace-usage b/projects/plugins/boost/changelog/update-jsx-namespace-usage deleted file mode 100644 index b8ccf72e8ff1b..0000000000000 --- a/projects/plugins/boost/changelog/update-jsx-namespace-usage +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: changed - -React: Changing global JSX namespace to React.JSX diff --git a/projects/plugins/boost/composer.json b/projects/plugins/boost/composer.json index 12db65dfc9138..42111cea71dbe 100644 --- a/projects/plugins/boost/composer.json +++ b/projects/plugins/boost/composer.json @@ -3,7 +3,7 @@ "description": "Boost your WordPress site's performance, from the creators of Jetpack", "type": "library", "license": "GPL-2.0-or-later", - "version": "3.4.8-alpha", + "version": "3.4.8-beta", "authors": [ { "name": "Automattic, Inc.", @@ -26,6 +26,7 @@ "automattic/jetpack-image-cdn": "@dev", "automattic/jetpack-my-jetpack": "@dev", "automattic/jetpack-plugin-deactivation": "@dev", + "automattic/jetpack-schema": "@dev", "automattic/jetpack-status": "@dev", "automattic/jetpack-sync": "@dev", "automattic/jetpack-wp-js-data-sync": "@dev", @@ -36,7 +37,7 @@ "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "0.4.2", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "scripts": { "phpunit": [ @@ -73,7 +74,7 @@ "platform": { "ext-intl": "0.0.0" }, - "autoloader-suffix": "b1e77e6231d50e7663f84529b6a3dfda_jetpack_boostⓥ3_4_8_alpha", + "autoloader-suffix": "b1e77e6231d50e7663f84529b6a3dfda_jetpack_boostⓥ3_4_8_beta", "allow-plugins": { "roots/wordpress-core-installer": true, "automattic/jetpack-autoloader": true, diff --git a/projects/plugins/boost/composer.lock b/projects/plugins/boost/composer.lock index 5a7a51bbad014..1a0994083316b 100644 --- a/projects/plugins/boost/composer.lock +++ b/projects/plugins/boost/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "453fdc3419d099e4ca8fe71380ac627b", + "content-hash": "c2eacb3d7a1fb66fa975acc4522b1230", "packages": [ { "name": "automattic/jetpack-a8c-mc-stats", @@ -12,14 +12,14 @@ "dist": { "type": "path", "url": "../../packages/a8c-mc-stats", - "reference": "29e2de602fcb803984eed4229ffa60a2f96a53f9" + "reference": "1608695e54d44f088960b6a7bfa0c5779c372ee6" }, "require": { "php": ">=7.0" }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -62,7 +62,7 @@ "dist": { "type": "path", "url": "../../packages/admin-ui", - "reference": "b191c34a0e21f625069eab0c054d8827b9542dfa" + "reference": "7330d0d7b9011e4b516c62a87c10d64f1a168eb7" }, "require": { "php": ">=7.0" @@ -71,7 +71,7 @@ "automattic/jetpack-changelogger": "@dev", "automattic/jetpack-logo": "@dev", "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -124,7 +124,7 @@ "dist": { "type": "path", "url": "../../packages/assets", - "reference": "9a9e8b6703e074750408f276c14011262b388ddc" + "reference": "58de4ea5a64ffa0899cd5903840499c76d253f4b" }, "require": { "automattic/jetpack-constants": "@dev", @@ -134,7 +134,7 @@ "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", "wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -190,7 +190,7 @@ "dist": { "type": "path", "url": "../../packages/autoloader", - "reference": "6bb097db25b5b249079fcb03ff39d493f59076a6" + "reference": "8e9867c7b1f5bac0c5652f87946fd2cd41a88f70" }, "require": { "composer-plugin-api": "^1.1 || ^2.0", @@ -199,7 +199,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "composer/composer": "^1.1 || ^2.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "type": "composer-plugin", "extra": { @@ -254,7 +254,7 @@ "dist": { "type": "path", "url": "../../packages/boost-core", - "reference": "402efb3188837598621d70876c3c2cd085df93a8" + "reference": "254e450eefc86995a797518cc1cbc041f1509222" }, "require": { "automattic/jetpack-connection": "@dev", @@ -263,7 +263,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -319,7 +319,7 @@ "dist": { "type": "path", "url": "../../packages/boost-speed-score", - "reference": "6ab34e20ce114b8ad71262ab2ad7f547d69b7784" + "reference": "6d24ca9aca1b0cda4e925bbe6dcaad4bbd3a16be" }, "require": { "automattic/jetpack-boost-core": "@dev", @@ -328,7 +328,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "^2.6", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -392,7 +392,7 @@ "dist": { "type": "path", "url": "../../packages/composer-plugin", - "reference": "9dd2a092b3de5ed00ee778f1f40704f7d913a836" + "reference": "b6fe2427cac6dd3bbef0a7e915c16bef55ad7c9b" }, "require": { "composer-plugin-api": "^2.1.0", @@ -401,7 +401,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "composer/composer": "^2.2 || ^2.4", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "type": "composer-plugin", "extra": { @@ -521,7 +521,7 @@ "dist": { "type": "path", "url": "../../packages/connection", - "reference": "2e4a3b9a72cb4f590de3ffcbd5ea0146d584483e" + "reference": "61beeb1eadc51c94a4ba35310bed89a1f15702e3" }, "require": { "automattic/jetpack-a8c-mc-stats": "@dev", @@ -539,7 +539,7 @@ "automattic/jetpack-sync": "@dev", "automattic/wordbless": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -607,7 +607,7 @@ "dist": { "type": "path", "url": "../../packages/constants", - "reference": "3fd2bf1d1ba0bb374918e6b7dd670735ce554c2b" + "reference": "e58ffa801a8e816c562f15bdc4731824f8f9c64a" }, "require": { "php": ">=7.0" @@ -615,7 +615,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -658,14 +658,14 @@ "dist": { "type": "path", "url": "../../packages/device-detection", - "reference": "a6696f57f2f6f29f4a6930727ae5063c4e89fab4" + "reference": "d97d4ed63b8e702834bb60496f02e99d30197619" }, "require": { "php": ">=7.0" }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -708,7 +708,7 @@ "dist": { "type": "path", "url": "../../packages/explat", - "reference": "04730c821356389b213b361f33a2fc696826ad77" + "reference": "d53b06a5550c6f8c2f009c183b5ab037e6c648c5" }, "require": { "automattic/jetpack-connection": "@dev", @@ -716,7 +716,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -780,7 +780,7 @@ "dist": { "type": "path", "url": "../../packages/image-cdn", - "reference": "fdd9e3c288c7ada8ddcc70fb46ff4ae1426b3309" + "reference": "a5b2d15b86d745342dc1de2ed0478e07e29df4ef" }, "require": { "automattic/jetpack-assets": "@dev", @@ -790,7 +790,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -843,7 +843,7 @@ "dist": { "type": "path", "url": "../../packages/ip", - "reference": "b696350993b7f42257788add260e0efa7c9934f4" + "reference": "5f9e9900d766e6f2aa25f6b80f6da591e02af8c5" }, "require": { "php": ">=7.0" @@ -851,7 +851,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -898,7 +898,7 @@ "dist": { "type": "path", "url": "../../packages/jitm", - "reference": "c21ef5f64d44c453e7a7dddbe13202c41aecb942" + "reference": "695db30039999154283059f6b2fe34fff746cd25" }, "require": { "automattic/jetpack-a8c-mc-stats": "@dev", @@ -913,7 +913,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -970,7 +970,7 @@ "dist": { "type": "path", "url": "../../packages/licensing", - "reference": "4b35f767b1121c4691abc75e17ea650d6539d046" + "reference": "2507ac1d1f2bbc7a12e8dddb1cb9fa3f9423d8d7" }, "require": { "automattic/jetpack-connection": "@dev", @@ -979,7 +979,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1029,14 +1029,14 @@ "dist": { "type": "path", "url": "../../packages/logo", - "reference": "e152a4c83d1f952442d40260c559c4880757b298" + "reference": "0cbca46f49b19ea8f252cba7a7c67cf2b222824f" }, "require": { "php": ">=7.0" }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1079,7 +1079,7 @@ "dist": { "type": "path", "url": "../../packages/my-jetpack", - "reference": "2c06449483ed175f949e69ba407e6e92363c3b84" + "reference": "df3217bf04a3c78de203fadcd4a1b796f21a5b60" }, "require": { "automattic/jetpack-admin-ui": "@dev", @@ -1096,7 +1096,6 @@ "automattic/jetpack-redirect": "@dev", "automattic/jetpack-status": "@dev", "automattic/jetpack-sync": "@dev", - "automattic/jetpack-waf": "@dev", "php": ">=7.0" }, "require-dev": { @@ -1104,7 +1103,7 @@ "automattic/jetpack-search": "@dev", "automattic/jetpack-videopress": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1118,7 +1117,7 @@ "link-template": "https://github.com/Automattic/jetpack-my-jetpack/compare/${old}...${new}" }, "branch-alias": { - "dev-trunk": "4.32.x-dev" + "dev-trunk": "4.33.x-dev" }, "version-constants": { "::PACKAGE_VERSION": "src/class-initializer.php" @@ -1181,7 +1180,7 @@ "dist": { "type": "path", "url": "../../packages/password-checker", - "reference": "16182898ae3faae3eb6ca9e5d2c490fd0b844243" + "reference": "b10057021f5d77cc3617afaa2672044e1e8ce1d5" }, "require": { "php": ">=7.0" @@ -1189,7 +1188,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1239,7 +1238,7 @@ "dist": { "type": "path", "url": "../../packages/plans", - "reference": "572028d8755c1c303f0643b2d3663b555e5ce87b" + "reference": "5b2084083304385b29ab96840abf799afd0f79c2" }, "require": { "automattic/jetpack-connection": "@dev", @@ -1249,7 +1248,7 @@ "automattic/jetpack-changelogger": "@dev", "automattic/jetpack-status": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1304,7 +1303,7 @@ "dist": { "type": "path", "url": "../../packages/plugin-deactivation", - "reference": "f79b33e19916f3efb0339e32af0936ccfa47d5cf" + "reference": "bc916add364c9661485ad0f397422d594c1c4794" }, "require": { "automattic/jetpack-assets": "@dev", @@ -1312,7 +1311,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1369,7 +1368,7 @@ "dist": { "type": "path", "url": "../../packages/plugins-installer", - "reference": "c244721eaf5c40706e6275ce995a1f64931d6cd8" + "reference": "94f77ef5fa17584be1cf6ff0f3157c78ca888e31" }, "require": { "automattic/jetpack-a8c-mc-stats": "@dev", @@ -1378,7 +1377,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1422,7 +1421,7 @@ "dist": { "type": "path", "url": "../../packages/protect-models", - "reference": "7acb119f496f32361379b236b6dbbcca68680d4d" + "reference": "de2bfbb992d4877826018aca7bd808072b34c62f" }, "require": { "php": ">=7.0" @@ -1430,7 +1429,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "0.4.2", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1489,7 +1488,7 @@ "dist": { "type": "path", "url": "../../packages/protect-status", - "reference": "297c3a5f7826a8e4c76f9bc992d2bc3417a1b669" + "reference": "813bfcce0178120e2fe389bf2223a3c5b8802163" }, "require": { "automattic/jetpack-connection": "@dev", @@ -1502,7 +1501,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1561,7 +1560,7 @@ "dist": { "type": "path", "url": "../../packages/redirect", - "reference": "effd6fdea78e9c3cb1bebf479474b4a9262444a1" + "reference": "3a861643edfc325a9150008bbde9a13d3aa77bb6" }, "require": { "automattic/jetpack-status": "@dev", @@ -1570,7 +1569,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1613,7 +1612,7 @@ "dist": { "type": "path", "url": "../../packages/roles", - "reference": "0ac6d02e8ef2adb058f8f52e80a4924a33fa9b86" + "reference": "f89c7b97f2a26162f238096d290765510b387458" }, "require": { "php": ">=7.0" @@ -1621,7 +1620,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1659,24 +1658,20 @@ } }, { - "name": "automattic/jetpack-status", + "name": "automattic/jetpack-schema", "version": "dev-trunk", "dist": { "type": "path", - "url": "../../packages/status", - "reference": "782aceefdf8ebfcf4d24049700da9409628bf4de" + "url": "../../packages/schema", + "reference": "be04299bd366af85656cead6917aa99a2d61cdd8" }, "require": { - "automattic/jetpack-constants": "@dev", "php": ">=7.0" }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "automattic/jetpack-connection": "@dev", - "automattic/jetpack-ip": "@dev", - "automattic/jetpack-plans": "@dev", - "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "automattic/wordbless": "dev-master", + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1684,18 +1679,16 @@ "type": "jetpack-library", "extra": { "autotagger": true, - "mirror-repo": "Automattic/jetpack-status", - "changelogger": { - "link-template": "https://github.com/Automattic/jetpack-status/compare/v${old}...v${new}" - }, "branch-alias": { - "dev-trunk": "3.3.x-dev" + "dev-trunk": "0.1.x-dev" }, - "dependencies": { - "test-only": [ - "packages/connection", - "packages/plans" - ] + "changelogger": { + "link-template": "https://github.com/Automattic/jetpack-schema/compare/v${old}...v${new}" + }, + "mirror-repo": "Automattic/jetpack-schema", + "textdomain": "jetpack-schema", + "version-constants": { + "::PACKAGE_VERSION": "src/class-schema.php" } }, "autoload": { @@ -1704,44 +1697,52 @@ ] }, "scripts": { + "build-development": [ + "echo 'Add your build step to composer.json, please!'" + ], + "build-production": [ + "echo 'Add your build step to composer.json, please!'" + ], "phpunit": [ "./vendor/phpunit/phpunit/phpunit --colors=always" ], "test-php": [ "@composer phpunit" + ], + "post-install-cmd": [ + "WorDBless\\Composer\\InstallDropin::copy" + ], + "post-update-cmd": [ + "WorDBless\\Composer\\InstallDropin::copy" ] }, "license": [ "GPL-2.0-or-later" ], - "description": "Used to retrieve information about the current status of Jetpack and the site overall.", + "description": "Define a schema to validate or sanitize data in php", "transport-options": { "relative": true } }, { - "name": "automattic/jetpack-sync", + "name": "automattic/jetpack-status", "version": "dev-trunk", "dist": { "type": "path", - "url": "../../packages/sync", - "reference": "1647bd686ed11800513f14aa1c93956e16a3b7f5" + "url": "../../packages/status", + "reference": "7ff2e0454b5d9dafdd6ddd7c1917065f739408e0" }, "require": { - "automattic/jetpack-connection": "@dev", "automattic/jetpack-constants": "@dev", - "automattic/jetpack-ip": "@dev", - "automattic/jetpack-password-checker": "@dev", - "automattic/jetpack-roles": "@dev", - "automattic/jetpack-status": "@dev", "php": ">=7.0" }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "automattic/jetpack-search": "@dev", - "automattic/jetpack-waf": "@dev", - "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "automattic/jetpack-connection": "@dev", + "automattic/jetpack-ip": "@dev", + "automattic/jetpack-plans": "@dev", + "brain/monkey": "2.6.1", + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1749,21 +1750,17 @@ "type": "jetpack-library", "extra": { "autotagger": true, - "mirror-repo": "Automattic/jetpack-sync", - "textdomain": "jetpack-sync", - "version-constants": { - "::PACKAGE_VERSION": "src/class-package-version.php" - }, + "mirror-repo": "Automattic/jetpack-status", "changelogger": { - "link-template": "https://github.com/Automattic/jetpack-sync/compare/v${old}...v${new}" + "link-template": "https://github.com/Automattic/jetpack-status/compare/v${old}...v${new}" }, "branch-alias": { - "dev-trunk": "3.6.x-dev" + "dev-trunk": "3.3.x-dev" }, "dependencies": { "test-only": [ - "packages/search", - "packages/waf" + "packages/connection", + "packages/plans" ] } }, @@ -1778,42 +1775,39 @@ ], "test-php": [ "@composer phpunit" - ], - "post-install-cmd": [ - "WorDBless\\Composer\\InstallDropin::copy" - ], - "post-update-cmd": [ - "WorDBless\\Composer\\InstallDropin::copy" ] }, "license": [ "GPL-2.0-or-later" ], - "description": "Everything needed to allow syncing to the WP.com infrastructure.", + "description": "Used to retrieve information about the current status of Jetpack and the site overall.", "transport-options": { "relative": true } }, { - "name": "automattic/jetpack-waf", + "name": "automattic/jetpack-sync", "version": "dev-trunk", "dist": { "type": "path", - "url": "../../packages/waf", - "reference": "6e2fd903a4dc024db95b51904989506f65013e0e" + "url": "../../packages/sync", + "reference": "64ed9303f16e3377d99091c67842f3c4b07b71eb" }, "require": { "automattic/jetpack-connection": "@dev", "automattic/jetpack-constants": "@dev", "automattic/jetpack-ip": "@dev", + "automattic/jetpack-password-checker": "@dev", + "automattic/jetpack-roles": "@dev", "automattic/jetpack-status": "@dev", - "php": ">=7.0", - "wikimedia/aho-corasick": "^1.0" + "php": ">=7.0" }, "require-dev": { "automattic/jetpack-changelogger": "@dev", + "automattic/jetpack-search": "@dev", + "automattic/jetpack-waf": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1821,46 +1815,47 @@ "type": "jetpack-library", "extra": { "autotagger": true, - "mirror-repo": "Automattic/jetpack-waf", - "textdomain": "jetpack-waf", + "mirror-repo": "Automattic/jetpack-sync", + "textdomain": "jetpack-sync", + "version-constants": { + "::PACKAGE_VERSION": "src/class-package-version.php" + }, "changelogger": { - "link-template": "https://github.com/Automattic/jetpack-waf/compare/v${old}...v${new}" + "link-template": "https://github.com/Automattic/jetpack-sync/compare/v${old}...v${new}" }, "branch-alias": { - "dev-trunk": "0.18.x-dev" + "dev-trunk": "3.8.x-dev" + }, + "dependencies": { + "test-only": [ + "packages/search", + "packages/waf" + ] } }, "autoload": { - "files": [ - "cli.php" - ], "classmap": [ "src/" ] }, "scripts": { "phpunit": [ - "./vendor/phpunit/phpunit/phpunit --configuration tests/php/integration/phpunit.xml.dist --colors=always", - "./vendor/phpunit/phpunit/phpunit --configuration tests/php/unit/phpunit.xml.dist --colors=always" + "./vendor/phpunit/phpunit/phpunit --colors=always" + ], + "test-php": [ + "@composer phpunit" ], "post-install-cmd": [ "WorDBless\\Composer\\InstallDropin::copy" ], "post-update-cmd": [ "WorDBless\\Composer\\InstallDropin::copy" - ], - "test-coverage-html": [ - "php -dpcov.directory=. ./vendor/bin/phpunit --coverage-html ./coverage --configuration tests/php/integration/phpunit.xml.dist", - "php -dpcov.directory=. ./vendor/bin/phpunit --coverage-html ./coverage --configuration tests/php/unit/phpunit.xml.dist" - ], - "test-php": [ - "@composer phpunit" ] }, "license": [ "GPL-2.0-or-later" ], - "description": "Tools to assist with the Jetpack Web Application Firewall", + "description": "Everything needed to allow syncing to the WP.com infrastructure.", "transport-options": { "relative": true } @@ -1871,15 +1866,16 @@ "dist": { "type": "path", "url": "../../packages/wp-js-data-sync", - "reference": "f8920aa8cefffdfe45b1e5f100ccefe116cab1e0" + "reference": "47509e3b3baaea36a0ae646e8054b742455361b0" }, "require": { + "automattic/jetpack-schema": "@dev", "php": ">=7.0" }, "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1892,7 +1888,7 @@ }, "autotagger": true, "branch-alias": { - "dev-trunk": "0.4.x-dev" + "dev-trunk": "0.5.x-dev" }, "textdomain": "jetpack-wp-js-data-sync", "version-constants": { @@ -2112,57 +2108,6 @@ "source": "https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port" }, "time": "2018-01-15T15:26:51+00:00" - }, - { - "name": "wikimedia/aho-corasick", - "version": "v1.0.1", - "source": { - "type": "git", - "url": "https://github.com/wikimedia/AhoCorasick.git", - "reference": "2f3a1bd765913637a66eade658d11d82f0e551be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wikimedia/AhoCorasick/zipball/2f3a1bd765913637a66eade658d11d82f0e551be", - "reference": "2f3a1bd765913637a66eade658d11d82f0e551be", - "shasum": "" - }, - "require": { - "php": ">=5.5.9" - }, - "require-dev": { - "jakub-onderka/php-console-highlighter": "0.3.2", - "jakub-onderka/php-parallel-lint": "1.0.0", - "mediawiki/mediawiki-codesniffer": "18.0.0", - "mediawiki/minus-x": "0.3.1", - "phpunit/phpunit": "4.8.36 || ^6.5" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Ori Livneh", - "email": "ori@wikimedia.org" - } - ], - "description": "An implementation of the Aho-Corasick string matching algorithm.", - "homepage": "https://gerrit.wikimedia.org/g/AhoCorasick", - "keywords": [ - "ahocorasick", - "matcher" - ], - "support": { - "source": "https://github.com/wikimedia/AhoCorasick/tree/v1.0.1" - }, - "time": "2018-05-01T18:13:32+00:00" } ], "packages-dev": [ @@ -2220,7 +2165,7 @@ "dist": { "type": "path", "url": "../../packages/changelogger", - "reference": "d945e0cd8dec218ab24445d5ddc95894c9f24534" + "reference": "8489a82ca328626854da99e29f3cb0f017529cb5" }, "require": { "php": ">=7.0", @@ -2229,7 +2174,7 @@ }, "require-dev": { "wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "bin": [ "bin/changelogger" @@ -5226,16 +5171,16 @@ }, { "name": "yoast/phpunit-polyfills", - "version": "1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/Yoast/PHPUnit-Polyfills.git", - "reference": "224e4a1329c03d8bad520e3fc4ec980034a4b212" + "reference": "a0f7d708794a738f328d7b6c94380fd1d6c40446" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/224e4a1329c03d8bad520e3fc4ec980034a4b212", - "reference": "224e4a1329c03d8bad520e3fc4ec980034a4b212", + "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/a0f7d708794a738f328d7b6c94380fd1d6c40446", + "reference": "a0f7d708794a738f328d7b6c94380fd1d6c40446", "shasum": "" }, "require": { @@ -5243,7 +5188,9 @@ "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, "require-dev": { - "yoast/yoastcs": "^2.3.0" + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "yoast/yoastcs": "^3.1.0" }, "type": "library", "extra": { @@ -5280,9 +5227,10 @@ ], "support": { "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues", + "security": "https://github.com/Yoast/PHPUnit-Polyfills/security/policy", "source": "https://github.com/Yoast/PHPUnit-Polyfills" }, - "time": "2023-08-19T14:25:08+00:00" + "time": "2024-04-05T16:01:51+00:00" } ], "aliases": [], @@ -5300,6 +5248,7 @@ "automattic/jetpack-image-cdn": 20, "automattic/jetpack-my-jetpack": 20, "automattic/jetpack-plugin-deactivation": 20, + "automattic/jetpack-schema": 20, "automattic/jetpack-status": 20, "automattic/jetpack-sync": 20, "automattic/jetpack-wp-js-data-sync": 20, diff --git a/projects/plugins/boost/jetpack-boost.php b/projects/plugins/boost/jetpack-boost.php index e192ea617e27d..f86d755b14c81 100644 --- a/projects/plugins/boost/jetpack-boost.php +++ b/projects/plugins/boost/jetpack-boost.php @@ -9,7 +9,7 @@ * Plugin Name: Jetpack Boost * Plugin URI: https://jetpack.com/boost * Description: Boost your WordPress site's performance, from the creators of Jetpack - * Version: 3.4.8-alpha + * Version: 3.4.8-beta * Author: Automattic - Jetpack Site Speed team * Author URI: https://jetpack.com/boost/ * License: GPL-2.0+ @@ -29,7 +29,7 @@ die; } -define( 'JETPACK_BOOST_VERSION', '3.4.8-alpha' ); +define( 'JETPACK_BOOST_VERSION', '3.4.8-beta' ); define( 'JETPACK_BOOST_SLUG', 'jetpack-boost' ); if ( ! defined( 'JETPACK_BOOST_CLIENT_NAME' ) ) { diff --git a/projects/plugins/boost/package.json b/projects/plugins/boost/package.json index f31639a28a006..539ecfad43dde 100644 --- a/projects/plugins/boost/package.json +++ b/projects/plugins/boost/package.json @@ -1,6 +1,6 @@ { "name": "jetpack-boost", - "version": "3.4.8-alpha", + "version": "3.4.8-beta", "description": "Boost your WordPress site's performance, from the creators of Jetpack", "directories": { "test": "tests" @@ -51,7 +51,7 @@ "storybook": "8.2.9", "tslib": "2.5.0", "typescript": "5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" }, "browserslist": [ diff --git a/projects/plugins/boost/readme.txt b/projects/plugins/boost/readme.txt index 3d3100fedba0e..c5da92b15a2a9 100644 --- a/projects/plugins/boost/readme.txt +++ b/projects/plugins/boost/readme.txt @@ -183,9 +183,18 @@ If you run into compatibility issues, please do let us know. You can drop us a l 2. Jetpack Boost Speed Improvement == Changelog == -### 3.4.7 - 2024-07-10 -#### Security -- General: Improved image and CSS proxy functionalities with CDN support, caching, and other enhancements. +### 3.4.8-beta - 2024-08-29 +#### Changed +- Admin menu: change order of Jetpack sub-menu items +- React: Changing global JSX namespace to React.JSX + +#### Fixed +- Cloud CSS: Fixed not properly storing CSS returned from the cloud after a theme switch. +- Lossless image optimization for images (should improve performance with no visible changes). +- Misc: Fix PHP warning when generating critical css for some taxonomy pages. +- Revert recent SVG image optimizations. +- UI: Fix inconsistencies. +- Updated package dependencies. -------- diff --git a/projects/plugins/boost/tests/e2e/specs/page-cache/page-cache.test.js b/projects/plugins/boost/tests/e2e/specs/page-cache/page-cache.test.js index c11a43f319288..4d5fda06826c2 100644 --- a/projects/plugins/boost/tests/e2e/specs/page-cache/page-cache.test.js +++ b/projects/plugins/boost/tests/e2e/specs/page-cache/page-cache.test.js @@ -58,7 +58,7 @@ test.describe( 'Cache module', () => { } expect( - response.headers().hasOwnProperty( 'X-Jetpack-Boost-Cache'.toLowerCase() ), + Object.hasOwn( response.headers(), 'X-Jetpack-Boost-Cache'.toLowerCase() ), 'Page Cache header should not be present' ).toBeFalsy(); } ); @@ -122,13 +122,13 @@ test.describe( 'Cache module', () => { // First visit should always be a miss. if ( totalVisits === 1 ) { expect( - responseHeaders.hasOwnProperty( cacheHeaderName ) && + Object.hasOwn( responseHeaders, cacheHeaderName ) && responseHeaders[ cacheHeaderName ] === 'miss', 'Page Cache header should be set to miss on first visit.' ).toBeTruthy(); } else { expect( - responseHeaders.hasOwnProperty( cacheHeaderName ) && + Object.hasOwn( responseHeaders, cacheHeaderName ) && responseHeaders[ cacheHeaderName ] === 'hit', 'Page Cache header should be set to hit on second visit.' ).toBeTruthy(); diff --git a/projects/plugins/boost/wp-js-data-sync.php b/projects/plugins/boost/wp-js-data-sync.php index 21de53d4607ca..064565f667c28 100644 --- a/projects/plugins/boost/wp-js-data-sync.php +++ b/projects/plugins/boost/wp-js-data-sync.php @@ -1,11 +1,11 @@ =7.0" }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -62,7 +62,7 @@ "dist": { "type": "path", "url": "../../packages/assets", - "reference": "9a9e8b6703e074750408f276c14011262b388ddc" + "reference": "58de4ea5a64ffa0899cd5903840499c76d253f4b" }, "require": { "automattic/jetpack-constants": "@dev", @@ -72,7 +72,7 @@ "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", "wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -128,7 +128,7 @@ "dist": { "type": "path", "url": "../../packages/autoloader", - "reference": "6bb097db25b5b249079fcb03ff39d493f59076a6" + "reference": "8e9867c7b1f5bac0c5652f87946fd2cd41a88f70" }, "require": { "composer-plugin-api": "^1.1 || ^2.0", @@ -137,7 +137,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "composer/composer": "^1.1 || ^2.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "type": "composer-plugin", "extra": { @@ -192,7 +192,7 @@ "dist": { "type": "path", "url": "../../packages/classic-theme-helper", - "reference": "2a143c5d437250ba07b2c633257be1cb616dd4ff" + "reference": "2ef40dc91652b8370108a7d3cb358947e43b0218" }, "require": { "automattic/jetpack-assets": "@dev", @@ -201,7 +201,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -260,7 +260,7 @@ "dist": { "type": "path", "url": "../../packages/composer-plugin", - "reference": "9dd2a092b3de5ed00ee778f1f40704f7d913a836" + "reference": "b6fe2427cac6dd3bbef0a7e915c16bef55ad7c9b" }, "require": { "composer-plugin-api": "^2.1.0", @@ -269,7 +269,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "composer/composer": "^2.2 || ^2.4", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "type": "composer-plugin", "extra": { @@ -389,7 +389,7 @@ "dist": { "type": "path", "url": "../../packages/constants", - "reference": "3fd2bf1d1ba0bb374918e6b7dd670735ce554c2b" + "reference": "e58ffa801a8e816c562f15bdc4731824f8f9c64a" }, "require": { "php": ">=7.0" @@ -397,7 +397,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -440,7 +440,7 @@ "dist": { "type": "path", "url": "../../packages/plugins-installer", - "reference": "c244721eaf5c40706e6275ce995a1f64931d6cd8" + "reference": "94f77ef5fa17584be1cf6ff0f3157c78ca888e31" }, "require": { "automattic/jetpack-a8c-mc-stats": "@dev", @@ -449,7 +449,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -493,7 +493,7 @@ "dist": { "type": "path", "url": "../../packages/status", - "reference": "782aceefdf8ebfcf4d24049700da9409628bf4de" + "reference": "7ff2e0454b5d9dafdd6ddd7c1917065f739408e0" }, "require": { "automattic/jetpack-constants": "@dev", @@ -505,7 +505,7 @@ "automattic/jetpack-ip": "@dev", "automattic/jetpack-plans": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -604,7 +604,7 @@ "dist": { "type": "path", "url": "../../packages/changelogger", - "reference": "d945e0cd8dec218ab24445d5ddc95894c9f24534" + "reference": "8489a82ca328626854da99e29f3cb0f017529cb5" }, "require": { "php": ">=7.0", @@ -613,7 +613,7 @@ }, "require-dev": { "wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "bin": [ "bin/changelogger" @@ -3610,16 +3610,16 @@ }, { "name": "yoast/phpunit-polyfills", - "version": "1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/Yoast/PHPUnit-Polyfills.git", - "reference": "224e4a1329c03d8bad520e3fc4ec980034a4b212" + "reference": "a0f7d708794a738f328d7b6c94380fd1d6c40446" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/224e4a1329c03d8bad520e3fc4ec980034a4b212", - "reference": "224e4a1329c03d8bad520e3fc4ec980034a4b212", + "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/a0f7d708794a738f328d7b6c94380fd1d6c40446", + "reference": "a0f7d708794a738f328d7b6c94380fd1d6c40446", "shasum": "" }, "require": { @@ -3627,7 +3627,9 @@ "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, "require-dev": { - "yoast/yoastcs": "^2.3.0" + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "yoast/yoastcs": "^3.1.0" }, "type": "library", "extra": { @@ -3664,9 +3666,10 @@ ], "support": { "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues", + "security": "https://github.com/Yoast/PHPUnit-Polyfills/security/policy", "source": "https://github.com/Yoast/PHPUnit-Polyfills" }, - "time": "2023-08-19T14:25:08+00:00" + "time": "2024-04-05T16:01:51+00:00" } ], "aliases": [], diff --git a/projects/plugins/classic-theme-helper-plugin/package.json b/projects/plugins/classic-theme-helper-plugin/package.json index cd746f317dfc0..0bd9c2eb218e7 100644 --- a/projects/plugins/classic-theme-helper-plugin/package.json +++ b/projects/plugins/classic-theme-helper-plugin/package.json @@ -50,7 +50,7 @@ "jest-environment-jsdom": "29.7.0", "sass": "1.64.1", "sass-loader": "12.4.0", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" } } diff --git a/projects/plugins/crm/.wordpress-org/icon.svg b/projects/plugins/crm/.wordpress-org/icon.svg index 9bd0529008a7c..037e8b5d38c5c 100644 --- a/projects/plugins/crm/.wordpress-org/icon.svg +++ b/projects/plugins/crm/.wordpress-org/icon.svg @@ -1 +1,14 @@ - \ No newline at end of file + + + + + + + + + + + + + + diff --git a/projects/plugins/crm/ZeroBSCRM.php b/projects/plugins/crm/ZeroBSCRM.php index 122609e38c0ef..510e48fecc161 100644 --- a/projects/plugins/crm/ZeroBSCRM.php +++ b/projects/plugins/crm/ZeroBSCRM.php @@ -3,7 +3,7 @@ * Plugin Name: Jetpack CRM * Plugin URI: https://jetpackcrm.com * Description: Jetpack CRM is the simplest CRM for WordPress. Self host your own Customer Relationship Manager using WP. - * Version: 6.4.5-alpha + * Version: 6.4.4 * Author: Automattic - Jetpack CRM team * Author URI: https://jetpackcrm.com * Text Domain: zero-bs-crm diff --git a/projects/plugins/jetpack/changelog/renovate-wordpress-monorepo b/projects/plugins/crm/changelog/renovate-npm-webpack-vulnerability similarity index 78% rename from projects/plugins/jetpack/changelog/renovate-wordpress-monorepo rename to projects/plugins/crm/changelog/renovate-npm-webpack-vulnerability index 1eaea6a769e84..c47cb18e82997 100644 --- a/projects/plugins/jetpack/changelog/renovate-wordpress-monorepo +++ b/projects/plugins/crm/changelog/renovate-npm-webpack-vulnerability @@ -1,4 +1,4 @@ Significance: patch -Type: other +Type: changed Updated package dependencies. diff --git a/projects/plugins/crm/changelog/renovate-yoast-phpunit-polyfills-1.x b/projects/plugins/crm/changelog/renovate-yoast-phpunit-polyfills-1.x new file mode 100644 index 0000000000000..c47cb18e82997 --- /dev/null +++ b/projects/plugins/crm/changelog/renovate-yoast-phpunit-polyfills-1.x @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Updated package dependencies. diff --git a/projects/plugins/crm/changelog/revert-svg-image-optimizations b/projects/plugins/crm/changelog/revert-svg-image-optimizations new file mode 100644 index 0000000000000..356496f8a1f8f --- /dev/null +++ b/projects/plugins/crm/changelog/revert-svg-image-optimizations @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Revert recent SVG image optimizations. diff --git a/projects/plugins/crm/changelog/try-lossless-image-optmization-part-3 b/projects/plugins/crm/changelog/try-lossless-image-optmization-part-3 new file mode 100644 index 0000000000000..cf77a8b55bb43 --- /dev/null +++ b/projects/plugins/crm/changelog/try-lossless-image-optmization-part-3 @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Lossless image optimization for images (should improve performance with no visible changes). diff --git a/projects/plugins/crm/changelog/try-no-version-bumps-in-trunk b/projects/plugins/crm/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..91efe85c55e06 --- /dev/null +++ b/projects/plugins/crm/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/plugins/crm/changelog/update-jsdoc-comments-for-wp-coding-standards b/projects/plugins/crm/changelog/update-jsdoc-comments-for-wp-coding-standards new file mode 100644 index 0000000000000..0e655b2b8b7a3 --- /dev/null +++ b/projects/plugins/crm/changelog/update-jsdoc-comments-for-wp-coding-standards @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Reformat jsdoc comments. No change to meaning or functionality. + + diff --git a/projects/plugins/crm/composer.json b/projects/plugins/crm/composer.json index 6da912dc2d1fd..353644f8509a1 100644 --- a/projects/plugins/crm/composer.json +++ b/projects/plugins/crm/composer.json @@ -10,7 +10,7 @@ "codeception/module-db": "^2.0 || 3.1.0 || ^3.1.2", "codeception/module-filesystem": "^2.0 || ^3.0", "codeception/util-universalframework": "^1.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "scripts": { "build-development": [ @@ -42,7 +42,7 @@ ] }, "config": { - "autoloader-suffix": "06c775433a83ed276f0a1d8ac25f93ba_crmⓥ6_4_5_alpha", + "autoloader-suffix": "06c775433a83ed276f0a1d8ac25f93ba_crmⓥ6_4_4", "allow-plugins": { "automattic/jetpack-autoloader": true, "automattic/jetpack-composer-plugin": true, diff --git a/projects/plugins/crm/composer.lock b/projects/plugins/crm/composer.lock index 29e07c09dd810..db726bbbb49dc 100644 --- a/projects/plugins/crm/composer.lock +++ b/projects/plugins/crm/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "865135122fc93afe20ff360fce38e054", + "content-hash": "bfd4738d720476b4bef81b56eb5817cb", "packages": [ { "name": "automattic/jetpack-assets", @@ -12,7 +12,7 @@ "dist": { "type": "path", "url": "../../packages/assets", - "reference": "9a9e8b6703e074750408f276c14011262b388ddc" + "reference": "58de4ea5a64ffa0899cd5903840499c76d253f4b" }, "require": { "automattic/jetpack-constants": "@dev", @@ -22,7 +22,7 @@ "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", "wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -78,7 +78,7 @@ "dist": { "type": "path", "url": "../../packages/autoloader", - "reference": "6bb097db25b5b249079fcb03ff39d493f59076a6" + "reference": "8e9867c7b1f5bac0c5652f87946fd2cd41a88f70" }, "require": { "composer-plugin-api": "^1.1 || ^2.0", @@ -87,7 +87,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "composer/composer": "^1.1 || ^2.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "type": "composer-plugin", "extra": { @@ -142,7 +142,7 @@ "dist": { "type": "path", "url": "../../packages/composer-plugin", - "reference": "9dd2a092b3de5ed00ee778f1f40704f7d913a836" + "reference": "b6fe2427cac6dd3bbef0a7e915c16bef55ad7c9b" }, "require": { "composer-plugin-api": "^2.1.0", @@ -151,7 +151,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "composer/composer": "^2.2 || ^2.4", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "type": "composer-plugin", "extra": { @@ -199,7 +199,7 @@ "dist": { "type": "path", "url": "../../packages/constants", - "reference": "3fd2bf1d1ba0bb374918e6b7dd670735ce554c2b" + "reference": "e58ffa801a8e816c562f15bdc4731824f8f9c64a" }, "require": { "php": ">=7.0" @@ -207,7 +207,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -589,7 +589,7 @@ "dist": { "type": "path", "url": "../../packages/changelogger", - "reference": "d945e0cd8dec218ab24445d5ddc95894c9f24534" + "reference": "8489a82ca328626854da99e29f3cb0f017529cb5" }, "require": { "php": ">=7.0", @@ -598,7 +598,7 @@ }, "require-dev": { "wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "bin": [ "bin/changelogger" @@ -5176,16 +5176,16 @@ }, { "name": "yoast/phpunit-polyfills", - "version": "1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/Yoast/PHPUnit-Polyfills.git", - "reference": "224e4a1329c03d8bad520e3fc4ec980034a4b212" + "reference": "a0f7d708794a738f328d7b6c94380fd1d6c40446" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/224e4a1329c03d8bad520e3fc4ec980034a4b212", - "reference": "224e4a1329c03d8bad520e3fc4ec980034a4b212", + "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/a0f7d708794a738f328d7b6c94380fd1d6c40446", + "reference": "a0f7d708794a738f328d7b6c94380fd1d6c40446", "shasum": "" }, "require": { @@ -5193,7 +5193,9 @@ "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, "require-dev": { - "yoast/yoastcs": "^2.3.0" + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "yoast/yoastcs": "^3.1.0" }, "type": "library", "extra": { @@ -5230,9 +5232,10 @@ ], "support": { "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues", + "security": "https://github.com/Yoast/PHPUnit-Polyfills/security/policy", "source": "https://github.com/Yoast/PHPUnit-Polyfills" }, - "time": "2023-08-19T14:25:08+00:00" + "time": "2024-04-05T16:01:51+00:00" } ], "aliases": [], diff --git a/projects/plugins/crm/css/img/sprite-orange.png b/projects/plugins/crm/css/img/sprite-orange.png index 28307e6e3768a..d4658d2555e66 100644 Binary files a/projects/plugins/crm/css/img/sprite-orange.png and b/projects/plugins/crm/css/img/sprite-orange.png differ diff --git a/projects/plugins/crm/fonts/fontawesome-webfont.svg b/projects/plugins/crm/fonts/fontawesome-webfont.svg index ed52c6f6d3ee6..855c845e538b6 100644 --- a/projects/plugins/crm/fonts/fontawesome-webfont.svg +++ b/projects/plugins/crm/fonts/fontawesome-webfont.svg @@ -1 +1,2671 @@ - \ No newline at end of file + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/plugins/crm/i/Email.png b/projects/plugins/crm/i/Email.png index 6db6af4f160bf..4a2ee3c551465 100644 Binary files a/projects/plugins/crm/i/Email.png and b/projects/plugins/crm/i/Email.png differ diff --git a/projects/plugins/crm/i/ext/aweber.png b/projects/plugins/crm/i/ext/aweber.png index e9ca68e9e2f14..3e484627fef87 100755 Binary files a/projects/plugins/crm/i/ext/aweber.png and b/projects/plugins/crm/i/ext/aweber.png differ diff --git a/projects/plugins/crm/i/ext/client-password-manager.png b/projects/plugins/crm/i/ext/client-password-manager.png index e4027ad44cb72..048b1856feae1 100755 Binary files a/projects/plugins/crm/i/ext/client-password-manager.png and b/projects/plugins/crm/i/ext/client-password-manager.png differ diff --git a/projects/plugins/crm/i/ext/client-portal-pro.png b/projects/plugins/crm/i/ext/client-portal-pro.png index 51fff1582c647..0691e441ba482 100755 Binary files a/projects/plugins/crm/i/ext/client-portal-pro.png and b/projects/plugins/crm/i/ext/client-portal-pro.png differ diff --git a/projects/plugins/crm/i/ext/invoicing-pro.png b/projects/plugins/crm/i/ext/invoicing-pro.png index 8c1aed6d19078..9c257cd360714 100755 Binary files a/projects/plugins/crm/i/ext/invoicing-pro.png and b/projects/plugins/crm/i/ext/invoicing-pro.png differ diff --git a/projects/plugins/crm/i/ext/mail-campaigns-1.png b/projects/plugins/crm/i/ext/mail-campaigns-1.png index f250e29968f0f..f781a754a1ced 100755 Binary files a/projects/plugins/crm/i/ext/mail-campaigns-1.png and b/projects/plugins/crm/i/ext/mail-campaigns-1.png differ diff --git a/projects/plugins/crm/i/ext/mailchip.png b/projects/plugins/crm/i/ext/mailchip.png index cd109de24bc91..110ec26be57cd 100755 Binary files a/projects/plugins/crm/i/ext/mailchip.png and b/projects/plugins/crm/i/ext/mailchip.png differ diff --git a/projects/plugins/crm/i/ext/paypal.png b/projects/plugins/crm/i/ext/paypal.png index 01f9d3bcc1dc6..df966bcb74e2a 100755 Binary files a/projects/plugins/crm/i/ext/paypal.png and b/projects/plugins/crm/i/ext/paypal.png differ diff --git a/projects/plugins/crm/i/ext/twillo.png b/projects/plugins/crm/i/ext/twillo.png index ed106b98567eb..8f05ef9394a17 100755 Binary files a/projects/plugins/crm/i/ext/twillo.png and b/projects/plugins/crm/i/ext/twillo.png differ diff --git a/projects/plugins/crm/i/external-link.svg b/projects/plugins/crm/i/external-link.svg index 50d22267ff82e..2d379eb18ce6e 100644 --- a/projects/plugins/crm/i/external-link.svg +++ b/projects/plugins/crm/i/external-link.svg @@ -1 +1,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/projects/plugins/crm/i/givewp.png b/projects/plugins/crm/i/givewp.png index 81d44d88cff66..7b5d7298b2c7e 100644 Binary files a/projects/plugins/crm/i/givewp.png and b/projects/plugins/crm/i/givewp.png differ diff --git a/projects/plugins/crm/i/gridicon-info.svg b/projects/plugins/crm/i/gridicon-info.svg index 6b24c0c0196a8..0a5ec67b06fd3 100644 --- a/projects/plugins/crm/i/gridicon-info.svg +++ b/projects/plugins/crm/i/gridicon-info.svg @@ -1 +1,6 @@ - \ No newline at end of file + + + + + + \ No newline at end of file diff --git a/projects/plugins/crm/i/mailpoet-logo.svg b/projects/plugins/crm/i/mailpoet-logo.svg index 3608818470d58..e31c3d2e4a02c 100644 --- a/projects/plugins/crm/i/mailpoet-logo.svg +++ b/projects/plugins/crm/i/mailpoet-logo.svg @@ -1 +1,86 @@ - \ No newline at end of file + + + + +logo + + + + + + + + + + + + + + + diff --git a/projects/plugins/crm/i/sms.png b/projects/plugins/crm/i/sms.png index e7061850cd0bd..5124651ce5a44 100644 Binary files a/projects/plugins/crm/i/sms.png and b/projects/plugins/crm/i/sms.png differ diff --git a/projects/plugins/crm/package.json b/projects/plugins/crm/package.json index 0a3c6b80e3d62..436d979a26791 100644 --- a/projects/plugins/crm/package.json +++ b/projects/plugins/crm/package.json @@ -1,6 +1,6 @@ { "name": "@automattic/jetpack-crm", - "version": "6.4.5-alpha", + "version": "6.4.4", "description": "The CRM for WordPress", "author": "Automattic", "license": "GPL-2.0", @@ -54,7 +54,7 @@ "sass": "1.64.1", "sass-loader": "12.4.0", "typescript": "5.0.4", - "webpack": "5.76.0", + "webpack": "5.94.0", "webpack-cli": "4.9.1" } } diff --git a/projects/plugins/crm/src/js/components/admin-page/index.tsx b/projects/plugins/crm/src/js/components/admin-page/index.tsx index 0ee41342ef274..c733f43b50bad 100644 --- a/projects/plugins/crm/src/js/components/admin-page/index.tsx +++ b/projects/plugins/crm/src/js/components/admin-page/index.tsx @@ -15,7 +15,7 @@ import type React from 'react'; * All content must be passed as children wrapped in as many elements as needed. * * @param {AdminPageProps} props - Component properties. - * @returns {React.ReactNode} AdminPage component. + * @return {React.ReactNode} AdminPage component. */ const AdminPage: React.FC< AdminPageProps > = props => { const pageProps = { diff --git a/projects/plugins/crm/src/js/data/hooks/queries.ts b/projects/plugins/crm/src/js/data/hooks/queries.ts index be7238aa2cad7..39fd92d046965 100644 --- a/projects/plugins/crm/src/js/data/hooks/queries.ts +++ b/projects/plugins/crm/src/js/data/hooks/queries.ts @@ -6,7 +6,7 @@ import { Workflow } from 'crm/state/automations-admin/types'; * Gets the Automation Workflows. * * @param {Function} hydrate - A function which takes an array of workflows and hydrates the store with them. - * @returns {UseQueryResult} - The result of the query. + * @return {UseQueryResult} - The result of the query. */ export const useGetAutomationWorkflows = ( hydrate: ( workflows: Workflow[] ) => void ) => useQuery( { diff --git a/projects/plugins/crm/src/js/state/automations-admin/util.ts b/projects/plugins/crm/src/js/state/automations-admin/util.ts index 131808556aee6..3f863aad39b8f 100644 --- a/projects/plugins/crm/src/js/state/automations-admin/util.ts +++ b/projects/plugins/crm/src/js/state/automations-admin/util.ts @@ -4,7 +4,7 @@ import { Workflow, ServerPreparedWorkflow } from 'crm/state/automations-admin/ty * Gets a workflow which has been prepared for sending to the server. * * @param {Workflow} workflow - The workflow to prepare - * @returns {ServerPreparedWorkflow} The prepared workflow + * @return {ServerPreparedWorkflow} The prepared workflow */ export const getServerPreparedWorkflow = ( workflow: Workflow ) => { return { diff --git a/projects/plugins/debug-helper/changelog/add-more-eslint-rules b/projects/plugins/debug-helper/changelog/add-more-eslint-rules new file mode 100644 index 0000000000000..b295a1d1a8826 --- /dev/null +++ b/projects/plugins/debug-helper/changelog/add-more-eslint-rules @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Actually call `e.preventDefault()` in various 'click' handlers. diff --git a/projects/plugins/boost/changelog/add-new-sync-active-modules-callable b/projects/plugins/debug-helper/changelog/renovate-yoast-phpunit-polyfills-1.x similarity index 100% rename from projects/plugins/boost/changelog/add-new-sync-active-modules-callable rename to projects/plugins/debug-helper/changelog/renovate-yoast-phpunit-polyfills-1.x diff --git a/projects/plugins/debug-helper/changelog/try-no-version-bumps-in-trunk b/projects/plugins/debug-helper/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..91efe85c55e06 --- /dev/null +++ b/projects/plugins/debug-helper/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/plugins/debug-helper/changelog/update-jsdoc-comments-for-wp-coding-standards b/projects/plugins/debug-helper/changelog/update-jsdoc-comments-for-wp-coding-standards new file mode 100644 index 0000000000000..0e655b2b8b7a3 --- /dev/null +++ b/projects/plugins/debug-helper/changelog/update-jsdoc-comments-for-wp-coding-standards @@ -0,0 +1,5 @@ +Significance: patch +Type: changed +Comment: Reformat jsdoc comments. No change to meaning or functionality. + + diff --git a/projects/plugins/debug-helper/composer.lock b/projects/plugins/debug-helper/composer.lock index 479f7d5b5f6a8..ca6286ae65703 100644 --- a/projects/plugins/debug-helper/composer.lock +++ b/projects/plugins/debug-helper/composer.lock @@ -13,7 +13,7 @@ "dist": { "type": "path", "url": "../../packages/changelogger", - "reference": "d945e0cd8dec218ab24445d5ddc95894c9f24534" + "reference": "8489a82ca328626854da99e29f3cb0f017529cb5" }, "require": { "php": ">=7.0", @@ -22,7 +22,7 @@ }, "require-dev": { "wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "bin": [ "bin/changelogger" diff --git a/projects/plugins/debug-helper/modules/inc/js/broken-token.js b/projects/plugins/debug-helper/modules/inc/js/broken-token.js index c716f3301ec54..29a865812a8d8 100644 --- a/projects/plugins/debug-helper/modules/inc/js/broken-token.js +++ b/projects/plugins/debug-helper/modules/inc/js/broken-token.js @@ -8,12 +8,12 @@ class BrokenToken { ); this.setCustomBlogTokenButton.addEventListener( 'click', e => { - e.preventDefault; + e.preventDefault(); this.displayEditBlogToken(); } ); this.cancelEditBlogTokenButton.addEventListener( 'click', e => { - e.preventDefault; + e.preventDefault(); this.cancelEditBlogToken(); } ); @@ -26,12 +26,12 @@ class BrokenToken { ); this.setCustomUserTokenButton.addEventListener( 'click', e => { - e.preventDefault; + e.preventDefault(); this.displayEditUserToken(); } ); this.cancelEditUserTokenButton.addEventListener( 'click', e => { - e.preventDefault; + e.preventDefault(); this.cancelEditUserToken(); } ); @@ -41,12 +41,12 @@ class BrokenToken { this.cancelEditBlogIDButton = document.getElementById( 'broken-token-cancel-edit-blog-id' ); this.setCustomBlogIDButton.addEventListener( 'click', e => { - e.preventDefault; + e.preventDefault(); this.displayEditBlogID(); } ); this.cancelEditBlogIDButton.addEventListener( 'click', e => { - e.preventDefault; + e.preventDefault(); this.cancelEditBlogID(); } ); } diff --git a/projects/plugins/debug-helper/modules/inc/js/loader.js b/projects/plugins/debug-helper/modules/inc/js/loader.js index e67cc36525efa..fc58b7843d94a 100644 --- a/projects/plugins/debug-helper/modules/inc/js/loader.js +++ b/projects/plugins/debug-helper/modules/inc/js/loader.js @@ -2,7 +2,7 @@ * Initialize the loader object, and retrieve the `on()` and `off()` methods. * * @param {Element} button - The button HTMLElement - * @returns {{off: Function, on: Function}} The loader button. + * @return {{off: Function, on: Function}} The loader button. */ export default function loaderButton( button ) { const label = button.innerHTML; diff --git a/projects/plugins/debug-helper/plugin.php b/projects/plugins/debug-helper/plugin.php index bc90c8b493f4f..56754fe72d512 100644 --- a/projects/plugins/debug-helper/plugin.php +++ b/projects/plugins/debug-helper/plugin.php @@ -3,7 +3,7 @@ * Plugin Name: Jetpack Debug Tools * Description: Give me a Jetpack connection, and I'll break it every way possible. * Author: Automattic - Jetpack Crew - * Version: 2.1.0-alpha + * Version: 2.0.1 * Text Domain: jetpack * * @package automattic/jetpack-debug-helper. @@ -33,7 +33,7 @@ * The plugin version. * Increase that if you do any edits to ensure refreshing the cached assets. */ -define( 'JETPACK_DEBUG_HELPER_VERSION', '2.1.0-alpha' ); +define( 'JETPACK_DEBUG_HELPER_VERSION', '2.0.1' ); /** * Include file names from the modules directory here. diff --git a/projects/plugins/inspect/changelog/renovate-yoast-phpunit-polyfills-1.x#2 b/projects/plugins/inspect/changelog/renovate-yoast-phpunit-polyfills-1.x#2 new file mode 100644 index 0000000000000..c47cb18e82997 --- /dev/null +++ b/projects/plugins/inspect/changelog/renovate-yoast-phpunit-polyfills-1.x#2 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Updated package dependencies. diff --git a/projects/plugins/inspect/composer.json b/projects/plugins/inspect/composer.json index 08eb62aad6609..39ef0813fe4aa 100644 --- a/projects/plugins/inspect/composer.json +++ b/projects/plugins/inspect/composer.json @@ -24,7 +24,7 @@ "automattic/jetpack-config": "@dev" }, "require-dev": { - "yoast/phpunit-polyfills": "1.1.0", + "yoast/phpunit-polyfills": "^1.1.1", "automattic/jetpack-changelogger": "@dev" }, "config": { diff --git a/projects/plugins/inspect/composer.lock b/projects/plugins/inspect/composer.lock index ed04fbe751582..6eab760322f1d 100644 --- a/projects/plugins/inspect/composer.lock +++ b/projects/plugins/inspect/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5488cdd18711b9b96901a4a1ce424c1e", + "content-hash": "6db1887b31eb54a09c9e11ce6f073093", "packages": [ { "name": "automattic/jetpack-a8c-mc-stats", @@ -12,14 +12,14 @@ "dist": { "type": "path", "url": "../../packages/a8c-mc-stats", - "reference": "29e2de602fcb803984eed4229ffa60a2f96a53f9" + "reference": "1608695e54d44f088960b6a7bfa0c5779c372ee6" }, "require": { "php": ">=7.0" }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -62,7 +62,7 @@ "dist": { "type": "path", "url": "../../packages/admin-ui", - "reference": "b191c34a0e21f625069eab0c054d8827b9542dfa" + "reference": "7330d0d7b9011e4b516c62a87c10d64f1a168eb7" }, "require": { "php": ">=7.0" @@ -71,7 +71,7 @@ "automattic/jetpack-changelogger": "@dev", "automattic/jetpack-logo": "@dev", "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -124,7 +124,7 @@ "dist": { "type": "path", "url": "../../packages/assets", - "reference": "9a9e8b6703e074750408f276c14011262b388ddc" + "reference": "58de4ea5a64ffa0899cd5903840499c76d253f4b" }, "require": { "automattic/jetpack-constants": "@dev", @@ -134,7 +134,7 @@ "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", "wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -190,7 +190,7 @@ "dist": { "type": "path", "url": "../../packages/autoloader", - "reference": "6bb097db25b5b249079fcb03ff39d493f59076a6" + "reference": "8e9867c7b1f5bac0c5652f87946fd2cd41a88f70" }, "require": { "composer-plugin-api": "^1.1 || ^2.0", @@ -199,7 +199,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "composer/composer": "^1.1 || ^2.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "type": "composer-plugin", "extra": { @@ -254,7 +254,7 @@ "dist": { "type": "path", "url": "../../packages/composer-plugin", - "reference": "9dd2a092b3de5ed00ee778f1f40704f7d913a836" + "reference": "b6fe2427cac6dd3bbef0a7e915c16bef55ad7c9b" }, "require": { "composer-plugin-api": "^2.1.0", @@ -263,7 +263,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "composer/composer": "^2.2 || ^2.4", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "type": "composer-plugin", "extra": { @@ -383,7 +383,7 @@ "dist": { "type": "path", "url": "../../packages/connection", - "reference": "2e4a3b9a72cb4f590de3ffcbd5ea0146d584483e" + "reference": "61beeb1eadc51c94a4ba35310bed89a1f15702e3" }, "require": { "automattic/jetpack-a8c-mc-stats": "@dev", @@ -401,7 +401,7 @@ "automattic/jetpack-sync": "@dev", "automattic/wordbless": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -469,7 +469,7 @@ "dist": { "type": "path", "url": "../../packages/constants", - "reference": "3fd2bf1d1ba0bb374918e6b7dd670735ce554c2b" + "reference": "e58ffa801a8e816c562f15bdc4731824f8f9c64a" }, "require": { "php": ">=7.0" @@ -477,7 +477,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -520,7 +520,7 @@ "dist": { "type": "path", "url": "../../packages/redirect", - "reference": "effd6fdea78e9c3cb1bebf479474b4a9262444a1" + "reference": "3a861643edfc325a9150008bbde9a13d3aa77bb6" }, "require": { "automattic/jetpack-status": "@dev", @@ -529,7 +529,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -572,7 +572,7 @@ "dist": { "type": "path", "url": "../../packages/roles", - "reference": "0ac6d02e8ef2adb058f8f52e80a4924a33fa9b86" + "reference": "f89c7b97f2a26162f238096d290765510b387458" }, "require": { "php": ">=7.0" @@ -580,7 +580,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -623,7 +623,7 @@ "dist": { "type": "path", "url": "../../packages/status", - "reference": "782aceefdf8ebfcf4d24049700da9409628bf4de" + "reference": "7ff2e0454b5d9dafdd6ddd7c1917065f739408e0" }, "require": { "automattic/jetpack-constants": "@dev", @@ -635,7 +635,7 @@ "automattic/jetpack-ip": "@dev", "automattic/jetpack-plans": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -686,7 +686,7 @@ "dist": { "type": "path", "url": "../../packages/changelogger", - "reference": "d945e0cd8dec218ab24445d5ddc95894c9f24534" + "reference": "8489a82ca328626854da99e29f3cb0f017529cb5" }, "require": { "php": ">=7.0", @@ -695,7 +695,7 @@ }, "require-dev": { "wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "bin": [ "bin/changelogger" @@ -3259,16 +3259,16 @@ }, { "name": "yoast/phpunit-polyfills", - "version": "1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/Yoast/PHPUnit-Polyfills.git", - "reference": "224e4a1329c03d8bad520e3fc4ec980034a4b212" + "reference": "a0f7d708794a738f328d7b6c94380fd1d6c40446" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/224e4a1329c03d8bad520e3fc4ec980034a4b212", - "reference": "224e4a1329c03d8bad520e3fc4ec980034a4b212", + "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/a0f7d708794a738f328d7b6c94380fd1d6c40446", + "reference": "a0f7d708794a738f328d7b6c94380fd1d6c40446", "shasum": "" }, "require": { @@ -3276,7 +3276,9 @@ "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, "require-dev": { - "yoast/yoastcs": "^2.3.0" + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "yoast/yoastcs": "^3.1.0" }, "type": "library", "extra": { @@ -3313,9 +3315,10 @@ ], "support": { "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues", + "security": "https://github.com/Yoast/PHPUnit-Polyfills/security/policy", "source": "https://github.com/Yoast/PHPUnit-Polyfills" }, - "time": "2023-08-19T14:25:08+00:00" + "time": "2024-04-05T16:01:51+00:00" } ], "aliases": [], diff --git a/projects/plugins/jetpack/.phan/baseline.php b/projects/plugins/jetpack/.phan/baseline.php index bd0a0bf496b72..63c5c04ab2a06 100644 --- a/projects/plugins/jetpack/.phan/baseline.php +++ b/projects/plugins/jetpack/.phan/baseline.php @@ -15,11 +15,12 @@ // PhanTypeMismatchArgumentProbablyReal : 200+ occurrences // PhanTypeMismatchReturn : 150+ occurrences // PhanTypeMismatchReturnProbablyReal : 130+ occurrences - // PhanDeprecatedFunction : 120+ occurrences + // PhanDeprecatedFunction : 110+ occurrences // PhanTypePossiblyInvalidDimOffset : 95+ occurrences // PhanRedundantCondition : 70+ occurrences // PhanPossiblyUndeclaredVariable : 60+ occurrences // PhanTypeArraySuspiciousNullable : 60+ occurrences + // PhanRedefineFunction : 50+ occurrences // PhanTypeMismatchArgumentNullable : 50+ occurrences // PhanTypeExpectedObjectPropAccess : 45+ occurrences // PhanParamTooMany : 40+ occurrences @@ -28,7 +29,6 @@ // PhanUndeclaredProperty : 35+ occurrences // PhanParamSignatureMismatch : 25+ occurrences // PhanPluginSimplifyExpressionBool : 25+ occurrences - // PhanRedefineFunction : 25+ occurrences // PhanTypeMismatchDefault : 25+ occurrences // PhanTypeMismatchPropertyProbablyReal : 25+ occurrences // PhanTypeMissingReturn : 25+ occurrences @@ -51,13 +51,13 @@ // PhanUndeclaredFunction : 10+ occurrences // PhanTypeComparisonToArray : 9 occurrences // PhanPluginRedundantAssignment : 8 occurrences - // PhanDeprecatedClass : 7 occurrences + // PhanRedefinedClassReference : 8 occurrences // PhanTypeInvalidLeftOperandOfNumericOp : 7 occurrences // PhanTypeMismatchArgumentInternalReal : 7 occurrences // PhanCommentAbstractOnInheritedMethod : 6 occurrences + // PhanDeprecatedClass : 5 occurrences // PhanImpossibleCondition : 5 occurrences // PhanNonClassMethodCall : 5 occurrences - // PhanRedefinedClassReference : 5 occurrences // PhanTypeArraySuspiciousNull : 5 occurrences // PhanTypeMismatchDimAssignment : 5 occurrences // PhanTypeSuspiciousStringExpression : 5 occurrences @@ -74,7 +74,6 @@ // PhanTypeConversionFromArray : 3 occurrences // PhanTypeMismatchArgumentReal : 3 occurrences // PhanTypeObjectUnsetDeclaredProperty : 3 occurrences - // PhanUndeclaredConstant : 3 occurrences // PhanUndeclaredMethodInCallable : 3 occurrences // PhanCompatibleNegativeStringOffset : 2 occurrences // PhanImpossibleConditionInLoop : 2 occurrences @@ -96,6 +95,7 @@ // PhanTypeComparisonFromArray : 1 occurrence // PhanTypeInvalidRightOperandOfNumericOp : 1 occurrence // PhanTypeVoidArgument : 1 occurrence + // PhanUndeclaredConstant : 1 occurrence // PhanUndeclaredExtendedClass : 1 occurrence // PhanUndeclaredTypeReturnType : 1 occurrence @@ -329,11 +329,6 @@ 'modules/comments/comments.php' => ['PhanPluginDuplicateConditionalNullCoalescing', 'PhanRedundantCondition', 'PhanTypeExpectedObjectPropAccess', 'PhanTypeMismatchArgument', 'PhanUndeclaredFunction'], 'modules/comments/subscription-modal-on-comment/class-jetpack-subscription-modal-on-comment.php' => ['PhanTypeMismatchReturnNullable'], 'modules/copy-post.php' => ['PhanNoopNew'], - 'modules/custom-css/csstidy/class.csstidy-ctype.php' => ['PhanRedefineFunctionInternal'], - 'modules/custom-css/csstidy/class.csstidy-optimise.php' => ['PhanPluginDuplicateExpressionAssignmentOperation', 'PhanPluginSimplifyExpressionBool', 'PhanTypeComparisonFromArray', 'PhanTypeConversionFromArray', 'PhanTypeExpectedObjectPropAccess', 'PhanTypeInvalidRightOperandOfNumericOp', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentInternal', 'PhanTypeMismatchArgumentNullableInternal', 'PhanTypeMismatchReturnProbablyReal'], - 'modules/custom-css/csstidy/class.csstidy-print.php' => ['PhanPluginRedundantAssignmentInLoop', 'PhanTypeMismatchReturn'], - 'modules/custom-css/csstidy/class.csstidy.php' => ['PhanCompatibleNegativeStringOffset', 'PhanImpossibleCondition', 'PhanInfiniteRecursion', 'PhanParamTooMany', 'PhanRedundantCondition', 'PhanTypeMismatchArgument'], - 'modules/custom-css/custom-css.php' => ['PhanPluginMixedKeyNoKey', 'PhanTypeArraySuspiciousNullable', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'modules/custom-post-types/nova.php' => ['PhanTypeExpectedObjectPropAccess', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchArgumentProbablyReal', 'PhanTypeSuspiciousNonTraversableForeach'], 'modules/custom-post-types/portfolios.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentProbablyReal', 'PhanTypeMismatchReturn', 'PhanTypeMismatchReturnProbablyReal', 'PhanTypeSuspiciousNonTraversableForeach'], 'modules/custom-post-types/testimonial.php' => ['PhanTypeMismatchArgumentProbablyReal'], @@ -364,7 +359,6 @@ 'modules/seo-tools.php' => ['PhanNoopNew'], 'modules/seo-tools/class-jetpack-seo.php' => ['PhanPluginDuplicateConditionalNullCoalescing'], 'modules/sharedaddy/recaptcha.php' => ['PhanPluginDuplicateExpressionAssignmentOperation'], - 'modules/sharedaddy/sharedaddy.php' => ['PhanDeprecatedClass', 'PhanDeprecatedFunction', 'PhanTypeMismatchReturnProbablyReal', 'PhanUndeclaredConstant'], 'modules/sharedaddy/sharing-service.php' => ['PhanPluginDuplicateConditionalNullCoalescing', 'PhanTypeArraySuspicious', 'PhanTypeMismatchArgument', 'PhanTypeMismatchProperty', 'PhanTypeMismatchPropertyDefault', 'PhanTypeMismatchPropertyProbablyReal', 'PhanTypePossiblyInvalidDimOffset', 'PhanUndeclaredFunction'], 'modules/sharedaddy/sharing-sources.php' => ['PhanParamSignatureMismatch', 'PhanTypeMismatchArgumentInternal', 'PhanTypeMismatchProperty', 'PhanTypeSuspiciousNonTraversableForeach'], 'modules/sharedaddy/sharing.php' => ['PhanRedundantCondition', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentProbablyReal', 'PhanTypePossiblyInvalidDimOffset'], @@ -427,12 +421,13 @@ 'modules/theme-tools/compat/twentynineteen.php' => ['PhanRedefineFunction'], 'modules/theme-tools/compat/twentysixteen.php' => ['PhanParamTooMany', 'PhanRedefineFunction'], 'modules/theme-tools/compat/twentytwenty.php' => ['PhanParamTooMany'], - 'modules/theme-tools/content-options/author-bio.php' => ['PhanTypeMismatchArgument'], - 'modules/theme-tools/content-options/blog-display.php' => ['PhanPluginDuplicateExpressionAssignmentOperation'], - 'modules/theme-tools/content-options/customizer.php' => ['PhanTypeMismatchReturn'], - 'modules/theme-tools/content-options/featured-images-fallback.php' => ['PhanTypeMismatchArgument', 'PhanTypePossiblyInvalidDimOffset'], - 'modules/theme-tools/content-options/featured-images.php' => ['PhanPluginSimplifyExpressionBool', 'PhanTypeMismatchArgument'], - 'modules/theme-tools/content-options/post-details.php' => ['PhanTypeArraySuspiciousNullable'], + 'modules/theme-tools/content-options.php' => ['PhanRedefineFunction'], + 'modules/theme-tools/content-options/author-bio.php' => ['PhanRedefineFunction', 'PhanTypeMismatchArgument'], + 'modules/theme-tools/content-options/blog-display.php' => ['PhanPluginDuplicateExpressionAssignmentOperation', 'PhanRedefineFunction'], + 'modules/theme-tools/content-options/customizer.php' => ['PhanRedefineClass', 'PhanRedefineFunction', 'PhanRedefinedClassReference', 'PhanTypeMismatchReturn'], + 'modules/theme-tools/content-options/featured-images-fallback.php' => ['PhanRedefineFunction', 'PhanTypeMismatchArgument', 'PhanTypePossiblyInvalidDimOffset'], + 'modules/theme-tools/content-options/featured-images.php' => ['PhanPluginSimplifyExpressionBool', 'PhanRedefineFunction', 'PhanTypeMismatchArgument'], + 'modules/theme-tools/content-options/post-details.php' => ['PhanRedefineFunction'], 'modules/theme-tools/responsive-videos.php' => ['PhanRedefineFunction'], 'modules/theme-tools/site-breadcrumbs.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchReturn'], 'modules/theme-tools/site-logo/inc/class-site-logo.php' => ['PhanRedundantCondition', 'PhanTypeComparisonToArray', 'PhanTypeMismatchReturn'], diff --git a/projects/plugins/jetpack/.phan/config.php b/projects/plugins/jetpack/.phan/config.php index f1bdc31787fbc..f62a26300d741 100644 --- a/projects/plugins/jetpack/.phan/config.php +++ b/projects/plugins/jetpack/.phan/config.php @@ -29,7 +29,6 @@ 'exclude_analysis_directory_list' => array( // This file breaks analysis, Phan gets lost recursing in trying to figure out some types. // @todo Add type declarations so Phan won't have to do it itself. Or update to a modern less lib. - 'modules/custom-css/custom-css/preprocessors/lessc.inc.php', ), 'parse_file_list' => array( // Reference files to handle code checking for stuff from other in-monorepo plugins. diff --git a/projects/plugins/jetpack/.w.org-assets/icon.svg b/projects/plugins/jetpack/.w.org-assets/icon.svg index 3c23ef42bf339..e445783c50ef3 100644 --- a/projects/plugins/jetpack/.w.org-assets/icon.svg +++ b/projects/plugins/jetpack/.w.org-assets/icon.svg @@ -1 +1,6 @@ - \ No newline at end of file + + + + + + diff --git a/projects/plugins/jetpack/CHANGELOG.md b/projects/plugins/jetpack/CHANGELOG.md index d230edfd39293..11483832bafcf 100644 --- a/projects/plugins/jetpack/CHANGELOG.md +++ b/projects/plugins/jetpack/CHANGELOG.md @@ -2,6 +2,85 @@ ### This is a list detailing changes for all Jetpack releases. +## 13.8-a.7 - 2024-08-26 +### Enhancements +- Newsletters: Adds Gutenberg plugin icon to the header, with a plugin sidebar with email preview feature. [#39039] + +### Bug fixes +- Blocks: Ensure that the Contact Info stylesheet is properly loaded. [#39018] +- Blocks: Fix the editor freeze after inserting a pattern with the Donations block. [#38961] +- Blocks: Ensure that the Payment Button stylesheet is properly loaded. [#39018] + +### Other changes +- AI Assistant: Accept Breve typo suggestions [#39008] +- AI Assistant: Add retry for Write Brief. [#38998] +- AI Assistant: Load dictionaries from CDN. [#38943] +- AI Assistant: Recompute Breve highlights when dictionary is loaded. [#38999] +- AI Assistant: Update connection button text. [#39031] +- Dashboard: Remove extra link in banner to invite admins to activate stats. [#39026] +- Newsletters: Don't prompt for connection on Simple sites. [#39064] +- Newsletters: Improve Sender Name and Reply-to settings. [#38833] +- Newsletters: Make preview non-clickable. [#39035] +- General: Adds to-test.md contents for Jetpack 13.8. [#39071] +- General: Adds tracks to featured flagged feature. [#39032] +- General: Fix incorrect case fall-through in `_inc/client/state/site/reducer.js`. [#39000] +- General: Updated package dependencies. [#39004] +- Legacy Widgets: Ensure widgets are available for Simple sites until the block API is fixed. [#38610] +- Social: Moved PostPublishPanels component to publicize-coomponents package. [#39049] +- Stats: Moved stats to the top of the Jetpack menu. [#39061] +- Sharing: Remove functions that were deprecated in Jetpack 11.0. [#38991] +- Site Breadcrumbs: Requiring the feature from the Classic Theme Helper package. [#38931] +- Subscriptions: Render the Close button lower than the Marketing bar. [#39065] +- Top Posts & Pages Block: Ensure deleted content does not display. [#37251] + +## 13.8-a.5 - 2024-08-21 +### Improved compatibility +- Sharing Block: Improve performance when hooking the block into single post templates. [#38727] +- WordPress.com Toolbar: Removed feature from self-hosted Jetpack sites. [#38804] + +### Bug fixes +- Social Icons Widget: Ensure the social network icons are displayed properly. [#38965] +- Social Menus: Ensure the SVG can be displayed properly. [#38966] + +### Other changes +- A4A: Add a4a_is_dev_site attribute to Sites API response. [#38964] +- Contact Form: Prevent direct file access. [#38982] +- Google Analytics: Delete the Google Analytics removal notices. [#38882] +- Security Settings: Redirect to Protect dashboard for Firewall settings, when available. [#38741] +- SVG Optimizations: Revert recent SVG image optimizations. [#38981] + +## 13.8-a.3 - 2024-08-19 +### Improved compatibility +- AMP: Avoid errors when using Jetpack's classic slideshows on a site where Jetpack blocks are disabled. [#38744] +- Tiled Galleries: Defer loading of the Tiled Gallery script for improved performance. [#38928] + +### Other changes +- AI Assistant: Add flag for Breve typo detection support. [#38895] +- AI Assistant: Add general improvements in Breve UX. [#38856] +- AI Assistant: Add spelling mistake detection to Breve. [#38923] +- AI Assistant: Allow dismiss suggestion in all states [#38848] +- AI Assistant: Change Breve type markup and restrict types. [#38867] +- AI Assistant: Remove Breve highlight popover when feature is disabled. [#38814] +- AI Assistant: Remove unique-id sass function call from animation name. [#38922] +- Email preview: ensure the email is visible [#38934] +- Jetpack AI: Register the ai-title-optimization-keywords-support beta flag. [#38891] +- Jetpack Color & Tonesque: Add deprecation warning in the codebase. [#38338] +- Open Graph Meta Tags: Check if the Open Graph integration in the ActivityPub plugin is active instead of checking for the class. [#38875] +- Open Graph Meta Tags: Do not display Fediverse tag on WordPress.com Simple. [#38874] +- Paywall Block: Improve styles. [#38837] +- Protect: Make allow list settings always accessible [#38886] +- REST API: Add a /wpcom/v2/profile endpoint that returns user profile, admin color and locale. [#38879] +- Site Breadcrumbs: Wrapping functions in function_exists as part of functionality move to package. [#38880] +- Small change under feature flag. [#38862] +- Social Links: Requiring feature from Classic Theme Helper package instead of Jetpack module. [#38730] +- Subscribe Block: p tag styles leaking in from theme. [#38840] +- Sync: Add a new callable for Sync Active Modules. [#38831] +- Title Optimization: Add keywords section to UI and make it send the keywords on the request. [#38921] +- Title Optimization: Change UI labels when keywords beta flag is enabled. [#38911] +- Title Optimization: Include feedback link on the footer. [#38940] +- Updated package dependencies. [#38662] [#38665] [#38822] +- WP.com: Hide the Customizer link on WP.com sites. [#38852] + ## 13.8-a.1 - 2024-08-12 ### Enhancements - Social: Display Fediverse creator meta tag when a post has an active Mastodon connection. [#38809] @@ -28,47 +107,6 @@ - Tests: Removed react-test-renderer as not in use. [#38755] ## 13.7-beta2 - 2024-08-06 -### Other changes -- Internal updates. - -## 13.7-beta - 2024-08-05 -### Enhancements -- AI Assistant: Make Jetpack Breve available to general public. [#38697] -- Jetpack: Port additional Full Site Editing features from WP Cloud. [#38212] -- Jetpack AI: Enable the AI Logo generator extension. [#38696] -- Jetpack Newsletter: Add Jetpack Newsletter menu with preview option. [#38675] - -### Bug fixes -- Jetpack Comments: Fix replying to comments in Chrome when logged in to both WordPress.com and Jetpack. [#38554] -- Sharing: Do not include Gravatar images in Open Graph Meta tags. [#38692] - -### Other changes -- Admin bar: Help center and notification icons now follow color scheme. [#38672] -- AI Assistant: Add ignore button for AI Proofread. [#38517] -- AI Assistant: Change Breve readability score text. [#38620] -- AI Assistant: Disable AI Proofread by default. [#38715] -- AI Assistant: Release Breve for 50% of sites. [#38604] -- AI Assistant: Remove slash highlights on Breve. [#38700] -- AI Logo Generator: Fix the retry button when a feature request fails. [#38630] -- AI Logo Generator: Only extend the logo block when the AI Assistant is available and not hidden on the editor. [#38603] -- AI Logo Generator: Release site logo extension to 10% of sites. [#38646] -- Fix suggestion invalidation on different features. [#38633] -- Jetpack AI: Apply text-wrap: pretty to AI assistant sidebar sections. [#38653] -- Jetpack AI: useExperiment note. [#38602] -- Jetpack AI Breve: Disable feature toggles on main toggle. [#38678] -- Jetpack Social: Added feature flag management. [#38669] -- Jetpack Social: Removed the media auto-conversion UI. [#38497] -- Jetpack Stats: Disable blog stats block for simple sites. [#38564] -- General: Changing global JSX namespace to React.JSX. [#38585] -- General: Changing ReactDOM.render usage to be via ReactDOM.createRoot. [#38649] -- General: Modify the Google Analytics notice to notify of the feature removal. [#38701] -- Newsletter: Add source for the paid importer. [#38679] -- Newsletter: Set all settings on the page disabled when module is disabled. [#38716] -- Jetpack Blocks: Update Podcast Player blockt to be compatible with React 19. [#38619] -- Social Links: Adding a function_exists check within the social-links.php file, to prevent conflicts with package version. [#38593] -- WP.com API: Include errors listed for broken themes. [#38642] - -## 13.7-a.7 - 2024-07-29 ### Enhancements - AI Assistant: Add feedback link to the sidebar. [#38528] - AI Assistant: Breve UI enhancements. [#38545] @@ -76,139 +114,147 @@ - AI Assistant: Disable long sentences Breve feature by default. [#38508] - AI Assistant: Enable Breve for 10% of production sites. [#38465] - AI Assistant: Enable Breve for 20% of production sites. [#38572] -- General: Losslessly optimized PNG images. [#38398] -- Site Editor: Remove extra site editor notices in favor of the ones provided by WordPress directly. [#38459] - -### Improved compatibility -- Masterbar: Always show the notification bell. [#38494] - -### Other changes -- Admin page: Remove propTypes and defaultProps from code due to React legacy code warnings. [#38546] -- AI Assistant: Add animation on loading for AI Proofread. [#38541] -- AI Assistant: Add events for Breve. [#38481] -- AI Assistant: Breve UI and text enhancements. [#38553] -- AI Assistant: Fix highlight not working on formatted texts. [#38540] -- AI Assistant: Display AI sidebar on first highlight hover. [#38468] -- AI Assistant: Fix block inserter behavior when Breve is enabled. [#38483] -- AI Assistant: Remove Breve readability star. [#38524] -- AI Assistant: Rename Breve and proofread entries on sidebar [#38456] -- AI Logo Generator: Support saving the logo and the icon when an image is ready. [#38552] -- Google Analytics: Remove the module and its remnants. [#37960] -- Jetpack AI: Add action links on sidebar for feature discoverability. [#38531] -- Jetpack AI: Connect the site logo block extension to AI Logo Generator modal. [#38491] -- Jetpack AI: Fix event tracking of logo generator to inform the proper placement. [#38574] -- Jetpack AI: Remove unused ai-assistant-panel component. [#38489] -- Jetpack Editor State: Add is_my_jetpack_available to initial state. [#38500] -- Newsletter: Byline settings return the correct default value. [#38435] -- Popover: Refactor some code to use refs, adding in tests to future proof. [#38339] -- Premium Content Block: Only show it as a transformation option if group or columns blocks are selected or if multiple blocks are selected. [#38569] -- Remove Browse sites from sidebar as it's on WordPress logo in masterbar. [#38547] -- Shortcode: Fix the test-class.gravatar.php tests. [#38582] -- Social Menus: Requiring the feature from the Classic Theme Helper package. [#38297] -- Tests: Removing test_sync_maybe_update_core test skip as core bug now fixed. [#38583] -- Tests: Skipping test_sync_maybe_update_core test due to core bug. [#38476] -- WPCOM API: Return actual value instead of bool for some settings after update. [#38498] -- WPCOM API: Return list of newsletter category IDs after saving. [#38560] -- WPCOM Connection test: use better ciphers than RC4, which is no longer available on many hosts. [#38393] -- WPCOM Settings API: Add synced options from Jetpack WAF. [#37957] - -## 13.7-a.5 - 2024-07-22 -### Enhancements +- AI Assistant: Make Jetpack Breve available to general public. [#38697] +- AI Assistant: The general purpose image generator is now available to all users. [#38203] +- Blocks: Add the EventCoutdown block. [#38250] +- Blocks: Add the Timeline block. [#38255] - Dashboard: Add a dashboard card for AI Assistant. [#38413] +- General: Losslessly optimized PNG images. [#38398] +- Jetpack: Port additional Full Site Editing features from WP Cloud. [#38212] +- Jetpack AI: Enable the AI Logo generator extension. [#38696] +- Jetpack Newsletter: Add Jetpack Newsletter menu with preview option. [#38675] +- Newsletter: Improve the modal overlay. [#38266] - Security: Add separate IP allow and block list toggles in Web Application Firewall settings. [#38267] - Settings: Add a link to the AI assistant product page. [#38414] +- Site Editor: Remove extra site editor notices in favor of the ones provided by WordPress directly. [#38459] +- Social: Added recommendation steps for the Social plan. [#38219] +- Subscriptions: Add command palette commands for quickly changing post access. [#37716] +- Subscriptions: Implemented a more dynamic approach to displaying the modal. [#38079] +- Subscriptions: Improve the Subscribe block loading animation. [#38174] ### Improved compatibility +- Blocks: Changed the use of default parameters in the Map block for React 19 compatibility. [#38274] - Contact Form: Ensure checkboxes are properly displayed when using the Twenty Twenty or the Twenty Twenty One theme. [#38407] - General: Remove code for compatibility with WordPress versions before 6.5. [#38386] - General: Update WordPress version requirements to WordPress 6.5. [#38382] +- Masterbar: Always show the notification bell. [#38494] ### Bug fixes - Blocks: Check if the fontFamily block attribute is a string before trying to format. [#38321] - -### Other changes -- AI Logo Generator: Extend the site logo block to include an AI button on the toolbar. [#38439] -- AI Proofread: Add long sentences and unconfident word checks. [#38443] -- AI Proofread: Add suggestions handling on AI Proofread. [#38344] -- AI Proofread: Improve Popover UX on AI Proofread. [#38342] -- AI Proofread: Invalidate Suggestions on AI Proofread based on actions. [#38434] -- AI Proofread: Target specific term occurrence. [#38397] -- AI Proofread: Wrap suggestion text. [#38431] -- Connection Screen: Remove mention of Stats from the list of available free features. [#38328] -- Custom Post Types: Remove Comic post type. [#38307] -- Google Fonts: Added an optional filter to short circuit fetching google font data. [#38343] -- Jetpack AI: Add logo generator codebase to ai-client package and solve issues. [#38391] -- Jetpack Color and Tonesque: Add existence guard. [#38341] -- Jetpack Dashboard: use flex-start alignment for dash item cards for more consistent header-content spacing. [#38371] -- JSON API: Fix Warnings in post endpoints. [#38365] -- Security: Remove "new" badge from Jetpack Firewall settings card. [#38415] -- Subscriptions: Update Newsletter module toggle label. [#38373] -- Stats: Ensure Jetpack posts stats link points to WP Admin stats. [#38376] -- WordPress.com REST API: Expose is_a4a_client attribute with sites API response. [#38403] - -## 13.7-a.3 - 2024-07-15 -### Enhancements -- Blocks: Add the EventCoutdown block. [#38250] -- Blocks: Add the Timeline block. [#38255] -- Newsletter: Improve the modal overlay. [#38266] -- Social: Added recommendation steps for the Social plan. [#38219] -- Subscriptions: Implemented a more dynamic approach to displaying the modal. [#38079] - -### Improved compatibility -- Blocks: Changed the use of default parameters in the Map block for React 19 compatibility. [#38274] - -### Bug fixes - Donations Block: Fix undefined array key warnings with old/malformed blocks. [#38281] +- Jetpack Comments: Fix replying to comments in Chrome when logged in to both WordPress.com and Jetpack. [#38554] +- Like block: Fix warning displayed when trying to load the Like block on unsupported pages. [#38199] +- Sharing: Do not include Gravatar images in Open Graph Meta tags. [#38692] ### Other changes - Admin: Redirect Jetpack pages. [#38148] +- Admin bar: Help center and notification icons now follow color scheme. [#38672] +- Admin page: Remove propTypes and defaultProps from code due to React legacy code warnings. [#38546] - AI Assistant: Add ambiguous words to proofread features list. [#38292] +- AI Assistant: Add animation on loading for AI Proofread. [#38541] +- AI Assistant: Add events for Breve. [#38481] +- AI Assistant: Add feature to tracks event. [#38207] +- AI Assistant: Add ignore button for AI Proofread. [#38517] - AI Assistant: Add long sentences feature to proofread. [#38314] - AI Assistant: Add Popover content for AI Proofread. [#38290] +- AI Assistant: Breve UI and text enhancements. [#38553] +- AI Assistant: Change Breve readability score text. [#38620] +- AI Assistant: Disable AI Proofread by default. [#38715] +- AI Assistant: Display AI sidebar on first highlight hover. [#38468] +- AI Assistant: Fix block inserter behavior when Breve is enabled. [#38483] - AI Assistant: Fix blocks content definition. [#38270] +- AI Assistant: Fix highlight not working on formatted texts. [#38540] - AI Assistant: Integrate AI Proofread toggle with code. [#38280] +- AI Assistant: Release Breve for 50% of sites. [#38604] +- AI Assistant: Remove Breve readability star. [#38524] +- AI Assistant: Remove slash highlights on Breve. [#38700] +- AI Assistant: Rename Breve and proofread entries on sidebar [#38456] +- AI Assistant: Update Breve implementation to React. [#38125] +- AI Assistant: Update Breve toggle location. [#38157] - AI Breve: Update highlight. [#38189] +- AI Logo Generator: Extend the site logo block to include an AI button on the toolbar. [#38439] +- AI Logo Generator: Fix the retry button when a feature request fails. [#38630] +- AI Logo Generator: Only extend the logo block when the AI Assistant is available and not hidden on the editor. [#38603] +- AI Logo Generator: Release site logo extension to 10% of sites. [#38646] +- AI Logo Generator: Support saving the logo and the icon when an image is ready. [#38552] +- AI Proofread: Add long sentences and unconfident word checks. [#38443] +- AI Proofread: Add suggestions handling on AI Proofread. [#38344] +- AI Proofread: Change Breve request endpoint. [#38149] +- AI Proofread: Improve Popover UX on AI Proofread. [#38342] +- AI Proofread: Invalidate Suggestions on AI Proofread based on actions. [#38434] +- AI Proofread: Move prompts to the backend. [#38182] +- AI Proofread: Target specific term occurrence. [#38397] - AI Proofread: Toggle specific feature. [#38286] - AI Proofread: Update hover events. [#38261] - AI Proofread: Update sidebar layout. [#38289] +- AI Proofread: Wrap suggestion text. [#38431] - Blocks: Honor the `$symbol` arg when passed an unknown currency. [#38281] - Calypsoify: Removing functionality from Jetpack. [#38259] -- Custom Post Types: Remove Comic post type. [#38309] -- Jetpack AI: Add beta flag to control logo generator extension. [#38322] -- Jetpack AI Image: Trigger featured image auto generation when there is content on the post. [#38262] -- General: Fix redirect for comments pending approval. [#38301] -- MU WPCOM: Move countdown and timeline blocks from jetpack to jetpack-mu-wpcom. [#38298] -- Newsletter Settings: Fix default value for Full text vs Excerpt. [#38256] -- Random Redirect: Remove module. [#38310] -- Theme tools: Add social menu to Classic Theme Helper package. [#38243] -- WPCOM Block Editor: Removing functionality from Jetpack. [#38299] -- WooCommerce Analytics: Initialize the module only if is not initialized in WooCommerce core. [#38236] - -## 13.7-a.1 - 2024-07-08 -### Enhancements -- AI Assistant: The general purpose image generator is now available to all users. [#38203] -- Subscriptions: Add command palette commands for quickly changing post access. [#37716] -- Subscriptions: Improve the Subscribe block loading animation. [#38174] - -### Bug fixes -- Like block: Fix warning displayed when trying to load the Like block on unsupported pages. [#38199] - -### Other changes -- AI Assistant: Add feature to tracks event. [#38207] -- AI Assistant: Update Breve implementation to React. [#38125] -- AI Assistant: Update Breve toggle location. [#38157] -- AI Proofread: Change Breve request endpoint. [#38149] -- AI Proofread: Move prompts to the backend. [#38182] - Carousel: Updating event listener to remove unnecessary default event prevention function call. [#38143] - Classic Theme Helper: Require Responsive Videos and Featured Content files. [#37969] +- Connection Screen: Remove mention of Stats from the list of available free features. [#38328] +- Custom Post Types: Remove Comic post type. [#38307] +- Custom Post Types: Remove Comic post type. [#38309] - Featured Content: Don't call setup for wpcom platform since jetpack-mu-wpcom already takes care of that. [#38215] +- Fix suggestion invalidation on different features. [#38633] +- General: Changing global JSX namespace to React.JSX. [#38585] +- General: Changing ReactDOM.render usage to be via ReactDOM.createRoot. [#38649] +- General: Fix redirect for comments pending approval. [#38301] +- General: Modify the Google Analytics notice to notify of the feature removal. [#38701] +- Google Analytics: Remove the module and its remnants. [#37960] +- Google Fonts: Added an optional filter to short circuit fetching google font data. [#38343] +- Internal updates. +- Jetpack AI: Add action links on sidebar for feature discoverability. [#38531] +- Jetpack AI: Add beta flag to control logo generator extension. [#38322] +- Jetpack AI: Add logo generator codebase to ai-client package and solve issues. [#38391] +- Jetpack AI: Apply text-wrap: pretty to AI assistant sidebar sections. [#38653] +- Jetpack AI: Connect the site logo block extension to AI Logo Generator modal. [#38491] +- Jetpack AI: Fix event tracking of logo generator to inform the proper placement. [#38574] +- Jetpack AI: Remove unused ai-assistant-panel component. [#38489] +- Jetpack AI: useExperiment note. [#38602] +- Jetpack AI Breve: Disable feature toggles on main toggle. [#38678] - Jetpack AI Breve: Fix popover font and css classnames. [#38161] - Jetpack AI Image: Include new entrypoint as a button on the image/gallery/slideshow block. [#38123] +- Jetpack AI Image: Trigger featured image auto generation when there is content on the post. [#38262] - Jetpack AI Image: Use better names when saving images. [#38179] +- Jetpack Blocks: Update Podcast Player blockt to be compatible with React 19. [#38619] +- Jetpack Color and Tonesque: Add existence guard. [#38341] +- Jetpack Dashboard: use flex-start alignment for dash item cards for more consistent header-content spacing. [#38371] +- Jetpack Editor State: Add is_my_jetpack_available to initial state. [#38500] +- Jetpack Social: Added feature flag management. [#38669] +- Jetpack Social: Removed the media auto-conversion UI. [#38497] +- Jetpack Stats: Disable blog stats block for simple sites. [#38564] +- JSON API: Fix Warnings in post endpoints. [#38365] - Masterbar: Deprecate module files. [#38109] +- MU WPCOM: Move countdown and timeline blocks from jetpack to jetpack-mu-wpcom. [#38298] +- Newsletter: Add source for the paid importer. [#38679] +- Newsletter: Byline settings return the correct default value. [#38435] +- Newsletter: Set all settings on the page disabled when module is disabled. [#38716] +- Newsletter Settings: Fix default value for Full text vs Excerpt. [#38256] - Newsletter settings: fix reply to example email when comment reply chosen. [#38151] +- Popover: Refactor some code to use refs, adding in tests to future proof. [#38339] +- Premium Content Block: Only show it as a transformation option if group or columns blocks are selected or if multiple blocks are selected. [#38569] +- Random Redirect: Remove module. [#38310] +- Remove Browse sites from sidebar as it's on WordPress logo in masterbar. [#38547] - Search: Update search close button behaviour. [#38204] +- Security: Remove "new" badge from Jetpack Firewall settings card. [#38415] +- Shortcode: Fix the test-class.gravatar.php tests. [#38582] +- Social Links: Adding a function_exists check within the social-links.php file, to prevent conflicts with package version. [#38593] +- Social Menus: Requiring the feature from the Classic Theme Helper package. [#38297] +- Stats: Ensure Jetpack posts stats link points to WP Admin stats. [#38376] +- Subscriptions: Update Newsletter module toggle label. [#38373] +- Tests: Removing test_sync_maybe_update_core test skip as core bug now fixed. [#38583] +- Tests: Skipping test_sync_maybe_update_core test due to core bug. [#38476] +- Theme tools: Add social menu to Classic Theme Helper package. [#38243] - Updated package dependencies. [#38132] [#38228] [#38235] +- WooCommerce Analytics: Initialize the module only if is not initialized in WooCommerce core. [#38236] +- WordPress.com REST API: Expose is_a4a_client attribute with sites API response. [#38403] +- WP.com API: Include errors listed for broken themes. [#38642] +- WPCOM API: Return actual value instead of bool for some settings after update. [#38498] +- WPCOM API: Return list of newsletter category IDs after saving. [#38560] +- WPCOM Block Editor: Removing functionality from Jetpack. [#38299] +- WPCOM Connection test: use better ciphers than RC4, which is no longer available on many hosts. [#38393] +- WPCOM Settings API: Add synced options from Jetpack WAF. [#37957] ## 13.6 - 2024-07-02 ### Enhancements diff --git a/projects/plugins/jetpack/_inc/client/admin.js b/projects/plugins/jetpack/_inc/client/admin.js index 32e9e54e530c9..db0bf39317f8d 100644 --- a/projects/plugins/jetpack/_inc/client/admin.js +++ b/projects/plugins/jetpack/_inc/client/admin.js @@ -106,7 +106,7 @@ function render() { * Get translated route name according to route path * * @param {string} path - route path - * @returns {string} translated route name + * @return {string} translated route name */ export function getRouteName( path ) { switch ( path ) { diff --git a/projects/plugins/jetpack/_inc/client/at-a-glance/backup-upgrade/bar-chart.tsx b/projects/plugins/jetpack/_inc/client/at-a-glance/backup-upgrade/bar-chart.tsx index af5f0a9443dd6..14a65f43a3331 100644 --- a/projects/plugins/jetpack/_inc/client/at-a-glance/backup-upgrade/bar-chart.tsx +++ b/projects/plugins/jetpack/_inc/client/at-a-glance/backup-upgrade/bar-chart.tsx @@ -11,7 +11,7 @@ import { BarChartProps } from './types'; * and comments * * @param {BarChartProps} props - Props - * @returns {React.ReactElement} - JSX Element + * @return {React.ReactElement} - JSX Element */ export const BarChart: React.FC< BarChartProps > = ( { comments, diff --git a/projects/plugins/jetpack/_inc/client/at-a-glance/backup-upgrade/index.tsx b/projects/plugins/jetpack/_inc/client/at-a-glance/backup-upgrade/index.tsx index 541e838b5f39f..f24f8abe17733 100644 --- a/projects/plugins/jetpack/_inc/client/at-a-glance/backup-upgrade/index.tsx +++ b/projects/plugins/jetpack/_inc/client/at-a-glance/backup-upgrade/index.tsx @@ -18,7 +18,7 @@ const MIN_POSTS_FOR_VISIBLE_BAR = 20; * It renders a bar chart if the user has more than a certain number of posts * * @param {BackupUpgradeProps} props - Props - * @returns {React.ReactElement} - JSX Element + * @return {React.ReactElement} - JSX Element */ const BackupUpgrade: React.FC< BackupUpgradeProps > = ( { comments, diff --git a/projects/plugins/jetpack/_inc/client/at-a-glance/backup-upgrade/popup.tsx b/projects/plugins/jetpack/_inc/client/at-a-glance/backup-upgrade/popup.tsx index 7ce98a5c4ec07..a329d2ced925f 100644 --- a/projects/plugins/jetpack/_inc/client/at-a-glance/backup-upgrade/popup.tsx +++ b/projects/plugins/jetpack/_inc/client/at-a-glance/backup-upgrade/popup.tsx @@ -7,7 +7,7 @@ import { PopupProps } from './types'; * The popup is a simple React component that displays a popup with a title, a lock icon, and a message * * @param {PopupProps} props - Props - * @returns {React.ReactElement} - JSX Element + * @return {React.ReactElement} - JSX Element */ export const Popup: React.FC< PopupProps > = ( { posts, comments, onClosePopup } ) => { return ( diff --git a/projects/plugins/jetpack/_inc/client/at-a-glance/backups.jsx b/projects/plugins/jetpack/_inc/client/at-a-glance/backups.jsx index ba025aad3591e..d0ba35d684d6c 100644 --- a/projects/plugins/jetpack/_inc/client/at-a-glance/backups.jsx +++ b/projects/plugins/jetpack/_inc/client/at-a-glance/backups.jsx @@ -36,8 +36,8 @@ import BackupUpgrade from './backup-upgrade'; /** * Displays a card for Backups based on the props given. * - * @param {object} props - Settings to render the card. - * @returns {object} Backups card + * @param {object} props - Settings to render the card. + * @return {object} Backups card */ const renderCard = props => ( \ No newline at end of file + + + diff --git a/projects/plugins/jetpack/_inc/client/at-a-glance/crm/people.svg b/projects/plugins/jetpack/_inc/client/at-a-glance/crm/people.svg index cf50d2843e1eb..1a7a346a3e07c 100644 --- a/projects/plugins/jetpack/_inc/client/at-a-glance/crm/people.svg +++ b/projects/plugins/jetpack/_inc/client/at-a-glance/crm/people.svg @@ -1 +1,6 @@ - \ No newline at end of file + + + + + + diff --git a/projects/plugins/jetpack/_inc/client/at-a-glance/index.jsx b/projects/plugins/jetpack/_inc/client/at-a-glance/index.jsx index 2385bd398acb4..23057c73c4a3f 100644 --- a/projects/plugins/jetpack/_inc/client/at-a-glance/index.jsx +++ b/projects/plugins/jetpack/_inc/client/at-a-glance/index.jsx @@ -54,9 +54,9 @@ class AtAGlance extends Component { /** * Determines whether a card should be added based on the feature and module availability. * - * @param {string} feature - The feature to check. + * @param {string} feature - The feature to check. * @param {boolean} [checkModuleAvailability=false] - Whether to check module availability. - * @returns {boolean} - Whether the card should be added. + * @return {boolean} - Whether the card should be added. */ shouldAddCard = ( feature, checkModuleAvailability = false ) => { const isActive = 'inactive' !== this.props.getModuleOverride( feature ); diff --git a/projects/plugins/jetpack/_inc/client/at-a-glance/jetpack-ai.jsx b/projects/plugins/jetpack/_inc/client/at-a-glance/jetpack-ai.jsx index 2d271a82c5faf..7f90a7451a420 100644 --- a/projects/plugins/jetpack/_inc/client/at-a-glance/jetpack-ai.jsx +++ b/projects/plugins/jetpack/_inc/client/at-a-glance/jetpack-ai.jsx @@ -24,7 +24,7 @@ import { siteHasFeature } from 'state/site'; /** * Jetpack AI Dashboard card. * @param {object} props - Component props - * @returns {object} DashJetpackAi component + * @return {object} DashJetpackAi component */ function DashJetpackAi( props ) { const { hasFeature, hasConnectedOwner, isOffline, isMyJetpackReachable } = props; diff --git a/projects/plugins/jetpack/_inc/client/at-a-glance/scan.jsx b/projects/plugins/jetpack/_inc/client/at-a-glance/scan.jsx index c979ceb51f98c..ad0dc801c49b7 100644 --- a/projects/plugins/jetpack/_inc/client/at-a-glance/scan.jsx +++ b/projects/plugins/jetpack/_inc/client/at-a-glance/scan.jsx @@ -36,8 +36,8 @@ import { isPluginInstalled } from 'state/site/plugins'; /** * Displays a card for Security Scan based on the props given. * - * @param {object} props - Settings to render the card. - * @returns {object} Security Scan card + * @param {object} props - Settings to render the card. + * @return {object} Security Scan card */ const renderCard = props => ( ( \ No newline at end of file + + + + + + diff --git a/projects/plugins/jetpack/_inc/client/at-a-glance/stats/index.jsx b/projects/plugins/jetpack/_inc/client/at-a-glance/stats/index.jsx index f772affead829..0ef2de6a71417 100644 --- a/projects/plugins/jetpack/_inc/client/at-a-glance/stats/index.jsx +++ b/projects/plugins/jetpack/_inc/client/at-a-glance/stats/index.jsx @@ -129,7 +129,7 @@ export class DashStats extends Component { /** * Checks that the stats fetching didn't return errors. * - * @returns {object|boolean} Returns statsData.general.errors or false if it is not an object + * @return {object|boolean} Returns statsData.general.errors or false if it is not an object */ statsErrors() { return get( this.props.statsData, [ 'general', 'errors' ], false ); diff --git a/projects/plugins/jetpack/_inc/client/at-a-glance/test/fixtures.js b/projects/plugins/jetpack/_inc/client/at-a-glance/test/fixtures.js index 28b8e143b0d2d..4e54e854c61af 100644 --- a/projects/plugins/jetpack/_inc/client/at-a-glance/test/fixtures.js +++ b/projects/plugins/jetpack/_inc/client/at-a-glance/test/fixtures.js @@ -1,9 +1,9 @@ /** * Build an object that can be used as a Redux store initial state. * - * @param {object} options - Options + * @param {object} options - Options * @param {boolean} options.userIsLinked - whether the current user is connected to wpcom. - * @returns {object} – initial Redux state + * @return {object} – initial Redux state */ export function buildInitialState( { userIsLinked = true } = {} ) { return { diff --git a/projects/plugins/jetpack/_inc/client/components/banner/index.jsx b/projects/plugins/jetpack/_inc/client/components/banner/index.jsx index d8db0c0fa867e..d91edc439fc06 100644 --- a/projects/plugins/jetpack/_inc/client/components/banner/index.jsx +++ b/projects/plugins/jetpack/_inc/client/components/banner/index.jsx @@ -205,7 +205,7 @@ export class Banner extends Component { * Redux-connect a Banner or subclass. * * @param {Banner} BannerComponent - Component to connect. - * @returns {Component} Wrapped component. + * @return {Component} Wrapped component. */ export function connect( BannerComponent ) { return reduxConnect( state => ( { diff --git a/projects/plugins/jetpack/_inc/client/components/contextualized-connection/index.jsx b/projects/plugins/jetpack/_inc/client/components/contextualized-connection/index.jsx index 7b2db7cd992bc..308dd36ebd5f0 100644 --- a/projects/plugins/jetpack/_inc/client/components/contextualized-connection/index.jsx +++ b/projects/plugins/jetpack/_inc/client/components/contextualized-connection/index.jsx @@ -12,7 +12,7 @@ import './style.scss'; * The Contextualized Connection component. * * @param {object} props -- The properties. - * @returns {React.Component} The `ContextualizedConnection` component. + * @return {React.Component} The `ContextualizedConnection` component. */ const ContextualizedConnection = props => { const { diff --git a/projects/plugins/jetpack/_inc/client/components/dash-item/test/fixtures.js b/projects/plugins/jetpack/_inc/client/components/dash-item/test/fixtures.js index fd92c4133cceb..3d67e7d432dc4 100644 --- a/projects/plugins/jetpack/_inc/client/components/dash-item/test/fixtures.js +++ b/projects/plugins/jetpack/_inc/client/components/dash-item/test/fixtures.js @@ -1,9 +1,9 @@ /** * Build an object that can be used as a Redux store initial state. * - * @param {object} options - Options + * @param {object} options - Options * @param {boolean} options.isOffline - whether we're in offline mode. - * @returns {object} – initial Redux state + * @return {object} – initial Redux state */ export function buildInitialState( { isOffline = false } = {} ) { return { diff --git a/projects/plugins/jetpack/_inc/client/components/footer/index.jsx b/projects/plugins/jetpack/_inc/client/components/footer/index.jsx index cfa76b23261e3..56a20c1142438 100644 --- a/projects/plugins/jetpack/_inc/client/components/footer/index.jsx +++ b/projects/plugins/jetpack/_inc/client/components/footer/index.jsx @@ -27,6 +27,7 @@ export class Footer extends React.Component { static displayName = 'Footer'; resetOnClick = () => { + // eslint-disable-next-line no-alert -- @todo Is there a better dialog we could use? if ( window.confirm( __( 'This will reset all Jetpack options, are you sure?', 'jetpack' ) ) ) { this.props.resetOptions(); } diff --git a/projects/plugins/jetpack/_inc/client/components/form/clipboard-button/index.jsx b/projects/plugins/jetpack/_inc/client/components/form/clipboard-button/index.jsx index 5d19191d16385..58f43e9031507 100644 --- a/projects/plugins/jetpack/_inc/client/components/form/clipboard-button/index.jsx +++ b/projects/plugins/jetpack/_inc/client/components/form/clipboard-button/index.jsx @@ -38,6 +38,7 @@ export default class ClipboardButton extends React.Component { } displayPrompt = () => { + // eslint-disable-next-line no-alert -- Fallback if clipboard doesn't work, lets the user copy it manually. window.prompt( this.props.prompt, this.props.text ); }; diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-banner/index.jsx b/projects/plugins/jetpack/_inc/client/components/jetpack-banner/index.jsx index 21ac15cad9e7d..2a425e491f1d4 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-banner/index.jsx +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-banner/index.jsx @@ -55,7 +55,7 @@ export class JetpackBanner extends Banner { * Redux-connect a JetpackBanner or subclass. * * @param {JetpackBanner} Component - Component to connect. - * @returns {Component} Wrapped component. + * @return {Component} Wrapped component. */ export function connect( Component ) { return reduxConnect( ( state, ownProps ) => { diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-benefits/index.jsx b/projects/plugins/jetpack/_inc/client/components/jetpack-benefits/index.jsx index 85330ebae8848..a932609577249 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-benefits/index.jsx +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-benefits/index.jsx @@ -10,10 +10,10 @@ import './style.scss'; /** * Shows a list of benefits that Jetpack provides. * - * @param {object} props - The component props. - * @param {Array} props.siteBenefits - An array of site benefits. - * @param {Array} props.context - Context in which the component will be used. disconnect or deactivate. - * @returns {React.Component} - The JetpackBenefits component. + * @param {object} props - The component props. + * @param {Array} props.siteBenefits - An array of site benefits. + * @param {Array} props.context - Context in which the component will be used. disconnect or deactivate. + * @return {React.Component} - The JetpackBenefits component. */ const JetpackBenefits = props => { const { siteBenefits, context = 'disconnect' } = props; diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-manage-banner/jetpack-manage.svg b/projects/plugins/jetpack/_inc/client/components/jetpack-manage-banner/jetpack-manage.svg index 423a6860475e4..1cbd2e8265f80 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-manage-banner/jetpack-manage.svg +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-manage-banner/jetpack-manage.svg @@ -1 +1,10 @@ - \ No newline at end of file + + + + + + + + + + diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/index.jsx b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/index.jsx index 85686df8191d0..c70ecf81b2e3d 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/index.jsx +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/index.jsx @@ -30,14 +30,10 @@ import { userCanConnectSite, userIsSubscriber, getConnectionErrors, - getSiteAdminUrl, isWoASite, } from 'state/initial-state'; import { getLicensingError, clearLicensingError } from 'state/licensing'; -import { getModule } from 'state/modules'; import { getSiteDataErrors } from 'state/site'; -import { isPluginActive } from 'state/site/plugins'; -import { StartFreshDeprecationWarning } from '../../writing/custom-css'; import DismissableNotices from './dismissable'; import JetpackConnectionErrors from './jetpack-connection-errors'; import PlanConflictWarning from './plan-conflict-warning'; @@ -187,20 +183,22 @@ class JetpackNotices extends React.Component { const cookieParsed = cookie.parse( document.cookie ); this.state = { - isGoogleAnalyticsNoticeDismissed: + isMasterbarNoticeDismissed: cookieParsed && - cookieParsed.hasOwnProperty( - 'jetpack_deprecate_dismissed[jetpack-ga-admin-removal-notice]' + Object.hasOwn( + cookieParsed, + 'jetpack_deprecate_dismissed[jetpack-masterbar-admin-removal-notice]' ) && - '1' === cookieParsed[ 'jetpack_deprecate_dismissed[jetpack-ga-admin-removal-notice]' ], + '1' === + cookieParsed[ 'jetpack_deprecate_dismissed[jetpack-masterbar-admin-removal-notice]' ], }; - - this.dismissGoogleAnalyticsNotice = this.dismissGoogleAnalyticsNotice.bind( this ); } - dismissGoogleAnalyticsNotice() { + dismissMasterbarNotice = () => { + this.setState( { isMasterbarNoticeDismissed: true } ); + document.cookie = cookie.serialize( - 'jetpack_deprecate_dismissed[jetpack-ga-admin-removal-notice]', + 'jetpack_deprecate_dismissed[jetpack-masterbar-admin-removal-notice]', '1', { path: '/', @@ -208,17 +206,17 @@ class JetpackNotices extends React.Component { SameSite: 'None', } ); - this.setState( { isGoogleAnalyticsNoticeDismissed: true } ); - } + }; render() { const siteDataErrors = this.props.siteDataErrors.filter( error => - error.hasOwnProperty( 'action' ) + Object.hasOwn( error, 'action' ) ); const isUserConnectScreen = this.props.location.pathname.startsWith( '/connect-user' ); - const showGoogleAnalyticsNotice = - this.props.showGoogleAnalyticsNotice && ! this.state.isGoogleAnalyticsNoticeDismissed; + + const showMasterbarNotice = + this.props.showMasterbarNotice && ! this.state.isMasterbarNoticeDismissed; return (
@@ -272,21 +270,19 @@ class JetpackNotices extends React.Component { onDismissClick={ this.props.clearLicensingError } /> ) } - { this.props.startFreshEnabled && ( - - - - ) } - { showGoogleAnalyticsNotice && ( + + { showMasterbarNotice && ( -
{ __( "Jetpack's Google Analytics has been removed.", 'jetpack' ) }
- +
+ { __( "Jetpack's WordPress.com Toolbar feature has been removed.", 'jetpack' ) } +
+ { __( - 'To keep tracking visits and more information on this change, please refer to this document', + 'To find out more about what this means for you, please refer to this document', 'jetpack' ) } @@ -316,20 +312,7 @@ export default connect( isReconnectingSite: isReconnectingSite( state ), licensingError: getLicensingError( state ), hasConnectedOwner: hasConnectedOwner( state ), - siteAdminUrl: getSiteAdminUrl( state ), - startFreshEnabled: !! getModule( state, 'custom-css' )?.options?.replace, - showGoogleAnalyticsNotice: - window.Initial_State?.isGoogleAnalyticsActive && - ! isWoASite( state ) && - isPluginActive( - // Making sure the plugins are loaded with no flickering caused by "isFetchingPluginsData". - state, - 'jetpack/jetpack.php' - ) && - ! isPluginActive( - state, - 'jetpack-legacy-google-analytics/jetpack-legacy-google-analytics.php' - ), + showMasterbarNotice: window.Initial_State?.isMasterbarActive && ! isWoASite( state ), }; }, dispatch => { diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/jetpack-connection-errors.jsx b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/jetpack-connection-errors.jsx index 5175343774e08..0a73fbb68a955 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/jetpack-connection-errors.jsx +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/jetpack-connection-errors.jsx @@ -56,7 +56,7 @@ export default class JetpackConnectionErrors extends React.Component { error.action, error.message, error.code, - error.hasOwnProperty( 'data' ) ? error.data : {}, + Object.hasOwn( error, 'data' ) ? error.data : {}, supportURl ); @@ -67,10 +67,10 @@ export default class JetpackConnectionErrors extends React.Component { render() { const errorsToDisplay = {}; - const errors = this.props.errors.filter( error => error.hasOwnProperty( 'action' ) ); + const errors = this.props.errors.filter( error => Object.hasOwn( error, 'action' ) ); for ( const error of errors ) { - if ( ! errorsToDisplay.hasOwnProperty( error.action ) ) { + if ( ! Object.hasOwn( errorsToDisplay, error.action ) ) { errorsToDisplay[ error.action ] = error; } } diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/notice-action-reconnect.jsx b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/notice-action-reconnect.jsx index f01b66d23888a..4fb777cacffdc 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/notice-action-reconnect.jsx +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/notice-action-reconnect.jsx @@ -42,7 +42,7 @@ const NoticeActionReconnect = props => { /** * Initiate the restore connection process. * - * @returns {Promise} - The API request promise. + * @return {Promise} - The API request promise. */ const doReconnect = useCallback( () => { props.beforeReconnectSite(); diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/plan-conflict-warning.jsx b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/plan-conflict-warning.jsx index d0381e2a96df8..11e0f10b7be43 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-notices/plan-conflict-warning.jsx +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-notices/plan-conflict-warning.jsx @@ -8,7 +8,7 @@ import { getActiveSitePurchases } from 'state/site'; /** * PlanConflictWarning component * - * @returns {object} component + * @return {object} component */ export function PlanConflictWarning( { activeSitePurchases, location: { pathname } } ) { // Only show on plans page. diff --git a/projects/plugins/jetpack/_inc/client/components/jetpack-product-card/test/component.js b/projects/plugins/jetpack/_inc/client/components/jetpack-product-card/test/component.js index d2b229ba41c56..72d1c143bb9e3 100644 --- a/projects/plugins/jetpack/_inc/client/components/jetpack-product-card/test/component.js +++ b/projects/plugins/jetpack/_inc/client/components/jetpack-product-card/test/component.js @@ -25,9 +25,9 @@ describe( 'Jetpack Product Card', () => { expect( screen.getByRole( 'heading', { name: mockAttributes.title } ) ).toBeInTheDocument(); expect( screen.getByText( mockAttributes.description ) ).toBeInTheDocument(); - mockAttributes.features.map( feature => { + for ( const feature of mockAttributes.features ) { expect( screen.getByText( feature ) ).toBeInTheDocument(); - } ); + } } ); it( 'price is shown', () => { diff --git a/projects/plugins/jetpack/_inc/client/components/module-settings/connect-module-options.jsx b/projects/plugins/jetpack/_inc/client/components/module-settings/connect-module-options.jsx index 85292ba0047cf..feb44c158f444 100644 --- a/projects/plugins/jetpack/_inc/client/components/module-settings/connect-module-options.jsx +++ b/projects/plugins/jetpack/_inc/client/components/module-settings/connect-module-options.jsx @@ -22,8 +22,8 @@ import { * High order component that connects to Jetpack modules'options * redux state selectors and action creators. * - * @param {React.Component} Component The component to be connected to the state - * @return {[React.Component]} The component with some props connected to the state + * @param {React.Component} Component The component to be connected to the state + * @return {[React.Component]} The component with some props connected to the state */ export function connectModuleOptions( Component ) { return connect( diff --git a/projects/plugins/jetpack/_inc/client/components/module-settings/with-module-settings-form-helpers.jsx b/projects/plugins/jetpack/_inc/client/components/module-settings/with-module-settings-form-helpers.jsx index 87dd40469b2c1..50a5b9353a461 100644 --- a/projects/plugins/jetpack/_inc/client/components/module-settings/with-module-settings-form-helpers.jsx +++ b/projects/plugins/jetpack/_inc/client/components/module-settings/with-module-settings-form-helpers.jsx @@ -7,8 +7,8 @@ import React from 'react'; * High order component that provides a
with functionality * to handle input values on the forms' own React component state. * - * @param {React.Component} InnerComponent The component with a top level form element - * @return {[React.Component]} The component with new functionality + * @param {React.Component} InnerComponent The component with a top level form element + * @return {[React.Component]} The component with new functionality */ export function withModuleSettingsFormHelpers( InnerComponent ) { class SettingsForm extends React.Component { @@ -34,9 +34,9 @@ export function withModuleSettingsFormHelpers( InnerComponent ) { * Updates the list of form values to save, usually options to set or modules to activate. * Receives an object with key => value pairs to set multiple options or a string and a value to set a single option. * - * @param {string|object} optionMaybeOptions options to update. - * @param {*} optionValue value to set if it's a single option - * @returns {boolean} Always true + * @param {string|object} optionMaybeOptions options to update. + * @param {*} optionValue value to set if it's a single option + * @return {boolean} Always true */ updateFormStateOptionValue = ( optionMaybeOptions, optionValue = undefined ) => { if ( 'string' === typeof optionMaybeOptions ) { @@ -69,9 +69,9 @@ export function withModuleSettingsFormHelpers( InnerComponent ) { * If the module is active, only the option is added to the list of form values to send. * If it's inactive, an additional option stating that the module must be activated is added to the list. * - * @param {String} module the module. - * @param {String} moduleOption the option slug for the module. - * @param {Boolean} deactivate whether to deactive the module too. + * @param {String} module the module. + * @param {String} moduleOption the option slug for the module. + * @param {Boolean} deactivate whether to deactive the module too. */ updateFormStateModuleOption = ( module, moduleOption, deactivate = false ) => { this.trackSettingsToggle( module, moduleOption, ! this.getOptionValue( moduleOption ) ); @@ -102,7 +102,7 @@ export function withModuleSettingsFormHelpers( InnerComponent ) { /** * Instantly activate or deactivate a module. * - * @param {String} module the module slug. + * @param {String} module the module slug. */ toggleModuleNow = module => { this.props.updateOptions( { [ module ]: ! this.getOptionValue( module ) } ); @@ -141,10 +141,10 @@ export function withModuleSettingsFormHelpers( InnerComponent ) { /** * Retrieves an option from an existing module, or from an array of modules * if the form was initialized with an array - * @param {String} settingName the setting to get. - * @param {String} module the module related to the setting. - * @param {boolean} ignoreDisabledModules - Whether to ignore settings for disabled modules. - * @returns {*} the current value of the settings. + * @param {String} settingName the setting to get. + * @param {String} module the module related to the setting. + * @param {boolean} ignoreDisabledModules - Whether to ignore settings for disabled modules. + * @return {*} the current value of the settings. */ getOptionValue = ( settingName, module = '', ignoreDisabledModules = true ) => { return get( @@ -162,7 +162,7 @@ export function withModuleSettingsFormHelpers( InnerComponent ) { /** * Check if there are unsaved settings in the card. * - * @returns {Boolean} True if the form has unsaved changes. + * @return {Boolean} True if the form has unsaved changes. */ isDirty = () => { return !! Object.keys( this.state.options ).length; @@ -171,9 +171,9 @@ export function withModuleSettingsFormHelpers( InnerComponent ) { /** * Checks if a setting is currently being saved. * - * @param {String|Array} settings The settings to check for a current saving in progress + * @param {String|Array} settings The settings to check for a current saving in progress * - * @returns {Boolean} True if specified settings are being saved, false otherwise. + * @return {Boolean} True if specified settings are being saved, false otherwise. */ isSavingAnyOption = ( settings = '' ) => { return this.props.isUpdating( settings ); diff --git a/projects/plugins/jetpack/_inc/client/components/navigation/index.jsx b/projects/plugins/jetpack/_inc/client/components/navigation/index.jsx index 60281ea65201c..918bed1297918 100644 --- a/projects/plugins/jetpack/_inc/client/components/navigation/index.jsx +++ b/projects/plugins/jetpack/_inc/client/components/navigation/index.jsx @@ -128,7 +128,7 @@ export class Navigation extends React.Component { count: ( { 'markdown', 'infinite-scroll', 'gravatar-hovercards', - 'custom-css', 'sharedaddy', 'widgets', 'shortcodes', diff --git a/projects/plugins/jetpack/_inc/client/components/settings-group/test/component.js b/projects/plugins/jetpack/_inc/client/components/settings-group/test/component.js index 368959bd5c180..187dd7b951410 100644 --- a/projects/plugins/jetpack/_inc/client/components/settings-group/test/component.js +++ b/projects/plugins/jetpack/_inc/client/components/settings-group/test/component.js @@ -16,7 +16,6 @@ describe( 'SettingsGroup', () => { 'markdown', 'infinite-scroll', 'gravatar-hovercards', - 'custom-css', 'sharedaddy', 'widgets', 'shortcodes', diff --git a/projects/plugins/jetpack/_inc/client/components/tree-selector/utils.jsx b/projects/plugins/jetpack/_inc/client/components/tree-selector/utils.jsx index ebdbb60901527..f2fb1d5e72808 100644 --- a/projects/plugins/jetpack/_inc/client/components/tree-selector/utils.jsx +++ b/projects/plugins/jetpack/_inc/client/components/tree-selector/utils.jsx @@ -2,7 +2,7 @@ * Adds depth and parentNames property to an array of tree items. * * @param {Array} items - Array of objects containing at least id, parent, and name. - * @returns {Array} flatList - Array of objects including a depth property and an array of parent names. + * @return {Array} flatList - Array of objects including a depth property and an array of parent names. */ function createFlatTreeItems( items ) { const map = {}; diff --git a/projects/plugins/jetpack/_inc/client/discussion/comments.jsx b/projects/plugins/jetpack/_inc/client/discussion/comments.jsx index a423b2b9d0947..a6e7d614218e8 100644 --- a/projects/plugins/jetpack/_inc/client/discussion/comments.jsx +++ b/projects/plugins/jetpack/_inc/client/discussion/comments.jsx @@ -16,8 +16,8 @@ class CommentsComponent extends React.Component { * If markdown module is inactive and this is toggling markdown for comments on, activate module. * If markdown for posts is off and this is toggling markdown for comments off, deactivate module. * - * @param {string} module - the module slug. - * @returns {*} the updated value + * @param {string} module - the module slug. + * @return {*} the updated value */ updateFormStateByMarkdown = module => { if ( this.props.getSettingCurrentValue( 'wpcom_publish_posts_with_markdown', module ) ) { diff --git a/projects/plugins/jetpack/_inc/client/earn/index.jsx b/projects/plugins/jetpack/_inc/client/earn/index.jsx index 613ece03c3e60..37989978b5a3e 100644 --- a/projects/plugins/jetpack/_inc/client/earn/index.jsx +++ b/projects/plugins/jetpack/_inc/client/earn/index.jsx @@ -24,7 +24,7 @@ import { Ads } from './ads'; * Earn Feature description card. * * @param {object} props - Component props. - * @returns {React.Component} Feature description and CTA. + * @return {React.Component} Feature description and CTA. */ function EarnFeatureButton( props ) { const { @@ -78,7 +78,7 @@ function EarnFeatureButton( props ) { * Earn Section. * * @param {object} props - Component props. - * @returns {React.Component} Earn settings component. + * @return {React.Component} Earn settings component. */ function Earn( props ) { const { active, hasConnectedOwner, isModuleFound, isOffline, searchTerm, siteRawUrl, blogID } = diff --git a/projects/plugins/jetpack/_inc/client/lib/decode-entities/index.js b/projects/plugins/jetpack/_inc/client/lib/decode-entities/index.js index 0b02263b011c9..83e8dcdd75974 100644 --- a/projects/plugins/jetpack/_inc/client/lib/decode-entities/index.js +++ b/projects/plugins/jetpack/_inc/client/lib/decode-entities/index.js @@ -3,7 +3,7 @@ * * @since 5.8.0 * - * @param {String} text The text to decode + * @param {String} text The text to decode * @return {String} Returns the string with HTML entities decoded if DOMParser is available. Returns the original text otherwise. */ export default function decodeEntities( text ) { diff --git a/projects/plugins/jetpack/_inc/client/lib/device-detector/index.js b/projects/plugins/jetpack/_inc/client/lib/device-detector/index.js index cc3cd2d14b55d..f483a4262e163 100644 --- a/projects/plugins/jetpack/_inc/client/lib/device-detector/index.js +++ b/projects/plugins/jetpack/_inc/client/lib/device-detector/index.js @@ -9,7 +9,7 @@ /** * Determines type of device. Only checks for several major operating systems. * - * @returns {string} 'windows' | 'android' | 'ios' | 'unknown' + * @return {string} 'windows' | 'android' | 'ios' | 'unknown' */ function detectMobileDevice() { const userAgent = navigator.userAgent || navigator.vendor || window.opera; diff --git a/projects/plugins/jetpack/_inc/client/lib/plans/constants.js b/projects/plugins/jetpack/_inc/client/lib/plans/constants.js index 1a33d575e9221..3c8d820a5a8b8 100644 --- a/projects/plugins/jetpack/_inc/client/lib/plans/constants.js +++ b/projects/plugins/jetpack/_inc/client/lib/plans/constants.js @@ -415,7 +415,7 @@ export const JETPACK_FEATURE_PRODUCT_UPSELL_MAP = { * Checks if a plan slug represents a monthly plan. * * @param {string} plan - The plan slug - * @returns {boolean} True if it's monthly plan + * @return {boolean} True if it's monthly plan */ export function isMonthly( plan ) { return includes( JETPACK_MONTHLY_PLANS, plan ); @@ -424,7 +424,7 @@ export function isMonthly( plan ) { * Checks if a plan slug is in the group of popular plans. * * @param {string} plan - The plan slug - * @returns {boolean} True if it's popular plan + * @return {boolean} True if it's popular plan */ export function isPopular( plan ) { return includes( POPULAR_PLANS, plan ); @@ -433,7 +433,7 @@ export function isPopular( plan ) { * Checks if a plan slug is a new plan. * * @param {string} plan - The plan slug - * @returns {boolean} True if it's new plan + * @return {boolean} True if it's new plan */ export function isNew( plan ) { return includes( NEW_PLANS, plan ); @@ -443,7 +443,7 @@ export function isNew( plan ) { * Determines if a plan includes Jetpack Anti-Spam. * * @param {string} plan - The plan slug - * @returns {boolean} True if the plan includes Jetpack Anti-Spam + * @return {boolean} True if the plan includes Jetpack Anti-Spam */ export function isJetpackPlanWithAntiSpam( plan ) { return includes( JETPACK_PLANS_WITH_ANTI_SPAM, plan ); @@ -453,7 +453,7 @@ export function isJetpackPlanWithAntiSpam( plan ) { * Determines if a plan includes backup features. * * @param {string} plan - The plan slug - * @returns {boolean} True if the plan contains backup features + * @return {boolean} True if the plan contains backup features */ export function isJetpackPlanWithBackup( plan ) { return includes( JETPACK_PLANS_WITH_BACKUP, plan ); @@ -463,7 +463,7 @@ export function isJetpackPlanWithBackup( plan ) { * Determines if a product is Jetpack Backup. * * @param {string} product - The product slug - * @returns {boolean} True if the product is Jetpack Backup + * @return {boolean} True if the product is Jetpack Backup */ export function isJetpackBackup( product ) { return includes( JETPACK_BACKUP_PRODUCTS, product ); @@ -473,7 +473,7 @@ export function isJetpackBackup( product ) { * Checks if a product slug is Jetpack Search. * * @param {string} product - The product slug - * @returns {boolean} True if the product is Jetpack Search + * @return {boolean} True if the product is Jetpack Search */ export function isJetpackSearch( product ) { return includes( JETPACK_SEARCH_PRODUCTS, product ); @@ -483,7 +483,7 @@ export function isJetpackSearch( product ) { * Checks if a product slug is Jetpack Scan. * * @param {string} product - The product slug - * @returns {boolean} True if the product is Jetpack Scan + * @return {boolean} True if the product is Jetpack Scan */ export function isJetpackScan( product ) { return JETPACK_SCAN_PRODUCTS.includes( product ); @@ -493,7 +493,7 @@ export function isJetpackScan( product ) { * Checks if a product slug is Jetpack Anti-Spam. * * @param {string} product - The product slug - * @returns {boolean} True if the product is Jetpack Anti-Spam + * @return {boolean} True if the product is Jetpack Anti-Spam */ export function isJetpackAntiSpam( product ) { return JETPACK_ANTI_SPAM_PRODUCTS.includes( product ); @@ -503,7 +503,7 @@ export function isJetpackAntiSpam( product ) { * Determines if a product is Jetpack VideoPress. * * @param {string} product - The product id. - * @returns {boolean} True if the product is Jetpack VideoPress, false otherwise. + * @return {boolean} True if the product is Jetpack VideoPress, false otherwise. */ export function isJetpackVideoPress( product ) { return JETPACK_VIDEOPRESS_PRODUCTS.includes( product ); @@ -513,7 +513,7 @@ export function isJetpackVideoPress( product ) { * Determines if a product is Jetpack Social. * * @param {string} product - The product id. - * @returns {boolean} True if the product is Jetpack Social, false otherwise. + * @return {boolean} True if the product is Jetpack Social, false otherwise. */ export function isJetpackSocial( product ) { return JETPACK_SOCIAL_PRODUCTS.includes( product ); @@ -523,7 +523,7 @@ export function isJetpackSocial( product ) { * Determines if a product is Jetpack Boost. * * @param {string} product - The product id. - * @returns {boolean} True if the product is Jetpack Social, false otherwise. + * @return {boolean} True if the product is Jetpack Social, false otherwise. */ export function isJetpackBoost( product ) { return JETPACK_BOOST_PRODUCTS.includes( product ); @@ -533,7 +533,7 @@ export function isJetpackBoost( product ) { * Determines if a product is Jetpack AI. * * @param {string} product - The product id. - * @returns {boolean} True if the product is Jetpack AI, false otherwise. + * @return {boolean} True if the product is Jetpack AI, false otherwise. */ export function isJetpackAI( product ) { return JETPACK_AI_PRODUCTS.includes( product ); @@ -543,7 +543,7 @@ export function isJetpackAI( product ) { * Determines if a product is Jetpack Stats. * * @param {string} product - The product id. - * @returns {boolean} True if the product is Jetpack Stats, false otherwise. + * @return {boolean} True if the product is Jetpack Stats, false otherwise. */ export function isJetpackStats( product ) { return JETPACK_STATS_PRODUCTS.includes( product ); @@ -553,7 +553,7 @@ export function isJetpackStats( product ) { * Determines if a product is Jetpack Creator. * * @param {string} product - The product id. - * @returns {boolean} True if the product is Jetpack Creator, false otherwise. + * @return {boolean} True if the product is Jetpack Creator, false otherwise. */ export function isJetpackCreator( product ) { return JETPACK_CREATOR_PRODUCTS.includes( product ); @@ -563,7 +563,7 @@ export function isJetpackCreator( product ) { * Checks if a product slug is a Jetpack product. * * @param {string} product - The product id. - * @returns {boolean} True if the product is Jetpack product. + * @return {boolean} True if the product is Jetpack product. */ export function isJetpackProduct( product ) { return ( @@ -584,7 +584,7 @@ export function isJetpackProduct( product ) { * Checks if the product slug is a Jetpack bundle. * * @param {string} product - The product slug - * @returns {boolean} True if the product is Jetpack bundle + * @return {boolean} True if the product is Jetpack bundle */ export function isJetpackBundle( product ) { return JETPACK_BUNDLES.includes( product ); @@ -594,7 +594,7 @@ export function isJetpackBundle( product ) { * Checks if the product slug is a Jetpack Starter bundle. * * @param {string} product - The product slug - * @returns {boolean} True if the product is Jetpack Starter bundle + * @return {boolean} True if the product is Jetpack Starter bundle */ export function isJetpackStarterBundle( product ) { return JETPACK_STARTER_BUNDLES.includes( product ); @@ -604,7 +604,7 @@ export function isJetpackStarterBundle( product ) { * Determine if the given product is a Security Bundle. * * @param {number} product - productId to check - * @returns {boolean} if the given product is a Security Bundle + * @return {boolean} if the given product is a Security Bundle */ export function isJetpackSecurityBundle( product ) { return JETPACK_SECURITY_BUNDLES.includes( product ); @@ -614,7 +614,7 @@ export function isJetpackSecurityBundle( product ) { * Checks if the product slug is a legacy Jetpack plan. * * @param {string} product - The product slug - * @returns {boolean} True if the product is a legacy Jetpack plan + * @return {boolean} True if the product is a legacy Jetpack plan */ export function isJetpackLegacyPlan( product ) { return JETPACK_LEGACY_PLANS.includes( product ); @@ -624,7 +624,7 @@ export function isJetpackLegacyPlan( product ) { * Identify legacy plans that contain features comparable to a security bundle * * @param {string} product - The product id. - * @returns {boolean} True if the product is a legacy Jetpack plan with security features, false otherwise. + * @return {boolean} True if the product is a legacy Jetpack plan with security features, false otherwise. */ export function isSecurityComparableJetpackLegacyPlan( product ) { return JETPACK_LEGACY_PLANS_WITH_SECURITY_FEATURES.includes( product ); @@ -634,7 +634,7 @@ export function isSecurityComparableJetpackLegacyPlan( product ) { * Retrieves the upsell for a feature. * * @param {string} feature - The feature slug. - * @returns {string} The product slug required for the feature. + * @return {string} The product slug required for the feature. */ export function getJetpackProductUpsellByFeature( feature ) { return JETPACK_FEATURE_PRODUCT_UPSELL_MAP[ feature ]; @@ -644,7 +644,7 @@ export function getJetpackProductUpsellByFeature( feature ) { * Gets the CSS class to use for the plans section, given the plan slug. * * @param {string} plan - The plan slug. - * @returns {string} The CSS class to use. + * @return {string} The CSS class to use. */ export function getPlanClass( plan ) { switch ( plan ) { @@ -789,7 +789,7 @@ export function getPlanClass( plan ) { * Retrieve the monthly equivalent of a yearly plan. * * @param {string} plan - The plan slug of the yearly plan. - * @returns {string} The monthly plan if it exists, otherwise, an empty string. + * @return {string} The monthly plan if it exists, otherwise, an empty string. */ export function getMonthlyPlanByYearly( plan ) { switch ( plan ) { @@ -825,7 +825,7 @@ export function getMonthlyPlanByYearly( plan ) { * Determines if the plan or product is a special gifted offering. * * @param {string} planOrProductSlug - A plan or product slug. - * @returns {boolean} True if the plan or product is a special gifted offering, false otherwise. + * @return {boolean} True if the plan or product is a special gifted offering, false otherwise. */ export function containsGiftedPlanOrProduct( planOrProductSlug ) { return [ PLAN_JETPACK_GOLDEN_TOKEN_LIFETIME ].includes( planOrProductSlug ); @@ -835,7 +835,7 @@ export function containsGiftedPlanOrProduct( planOrProductSlug ) { * Determines if the plan class contains backup daily. * * @param {string} planClass - A plan class. - * @returns {boolean} True if the plan class contains backup daily, false otherwise. + * @return {boolean} True if the plan class contains backup daily, false otherwise. */ // DEPRECATED: Daily and Real-time variations will soon be retired. // Remove after all customers are migrated to new products. @@ -852,7 +852,7 @@ export function containsBackupDaily( planClass ) { * Determines if the plan class contains backup realtime. * * @param {string} planClass - A plan class. - * @returns {boolean} True if the plan class contains backup realtime, false otherwise. + * @return {boolean} True if the plan class contains backup realtime, false otherwise. */ export function containsBackupRealtime( planClass ) { return [ diff --git a/projects/plugins/jetpack/_inc/client/lib/touch-detect/index.js b/projects/plugins/jetpack/_inc/client/lib/touch-detect/index.js index 44ff568c60131..9a99d26380385 100644 --- a/projects/plugins/jetpack/_inc/client/lib/touch-detect/index.js +++ b/projects/plugins/jetpack/_inc/client/lib/touch-detect/index.js @@ -6,7 +6,7 @@ * @license See CREDITS.md. * @see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.js * - * @returns {Boolean} whether touch screen is available + * @return {Boolean} whether touch screen is available */ export function hasTouch() { /* global DocumentTouch:true */ diff --git a/projects/plugins/jetpack/_inc/client/main.jsx b/projects/plugins/jetpack/_inc/client/main.jsx index 2f38880c19e80..a46348b9bcc66 100644 --- a/projects/plugins/jetpack/_inc/client/main.jsx +++ b/projects/plugins/jetpack/_inc/client/main.jsx @@ -274,7 +274,7 @@ class Main extends React.Component { * Render the main navigation bar. * * @param {string} route - The current page route. - * @returns {React.ReactElement|null} - The navigation component or `null` if not available. + * @return {React.ReactElement|null} - The navigation component or `null` if not available. */ renderMainNav = route => { if ( this.shouldShowWooConnectionScreen() ) { @@ -731,7 +731,7 @@ class Main extends React.Component { /** * Checks if this is the main connection screen page. * - * @returns {boolean} Whether this is the main connection screen page. + * @return {boolean} Whether this is the main connection screen page. */ isMainConnectScreen() { return false === this.props.siteConnectionStatus && this.props.userCanConnectSite; @@ -740,7 +740,7 @@ class Main extends React.Component { /** * Checks if this is the user connection screen page. * - * @returns {boolean} Whether this is the user connection screen page. + * @return {boolean} Whether this is the user connection screen page. */ isUserConnectScreen() { return ( @@ -752,7 +752,7 @@ class Main extends React.Component { /** * Checks whether we should show the Woo Connection screen page. * - * @returns {boolean} Whether we should show the Woo connection screen page. + * @return {boolean} Whether we should show the Woo connection screen page. */ shouldShowWooConnectionScreen() { return '/woo-setup' === this.props.location.pathname; @@ -761,7 +761,7 @@ class Main extends React.Component { /** * Check if the user connection has been triggered. * - * @returns {boolean} Whether the user connection has been triggered. + * @return {boolean} Whether the user connection has been triggered. */ shouldConnectUser() { return this.props.isConnectingUser; @@ -778,7 +778,7 @@ class Main extends React.Component { /** * Checks if this is a licensing screen page. * - * @returns {boolean} Whether this is a licensing screen page. + * @return {boolean} Whether this is a licensing screen page. */ isLicensingScreen() { return this.props.location.pathname.startsWith( '/license' ); @@ -787,7 +787,7 @@ class Main extends React.Component { /** * Check if the connection flow should get triggered automatically. * - * @returns {boolean} Whether to trigger the connection flow automatically. + * @return {boolean} Whether to trigger the connection flow automatically. */ shouldAutoTriggerConnection() { return ( @@ -960,14 +960,69 @@ export default connect( } )( withRouter( Main ) ) ); +// eslint-disable-next-line jsdoc/require-returns-check +/** + * Determines the page order of My Jetpack, Activity Log, Dashboard, and Settings in the left sidebar. + * @return {object} Object with keys for each page and values for the order of the page in the sidebar. + */ +function jetpackPageOrder() { + const jetpackParentMenu = document.querySelector( '#toplevel_page_jetpack' ); + const pageOrder = {}; + + if ( jetpackParentMenu ) { + const jetpackSubMenu = jetpackParentMenu.querySelector( '.wp-submenu' ); + + if ( jetpackSubMenu ) { + const subMenuItems = jetpackSubMenu.querySelectorAll( 'li:not(.wp-submenu-head) a' ); + + const urlPatterns = [ + { + key: 'dashboard', + pattern: '/wp-admin/admin.php?page=jetpack#/dashboard', + matchType: 'end', + }, + { + key: 'activityLog', + pattern: 'https://jetpack.com/redirect/?source=cloud-activity-log-wp-menu', + matchType: 'start', + }, + { + key: 'settings', + pattern: '/wp-admin/admin.php?page=jetpack#/settings', + matchType: 'end', + }, + ]; + + const findIndex = ( urlPattern, matchType ) => { + let foundIndex = -1; + subMenuItems.forEach( ( item, index ) => { + const href = item.href; + if ( + ( matchType === 'end' && href.endsWith( urlPattern ) ) || + ( matchType === 'start' && href.startsWith( urlPattern ) ) + ) { + foundIndex = index + 1; + } + } ); + return foundIndex; + }; + + urlPatterns.forEach( ( { key, pattern, matchType } ) => { + const index = findIndex( pattern, matchType ); + pageOrder[ key ] = index; + } ); + return pageOrder; + } + } +} + /** * Manages changing the visuals of the sub-nav items on the left sidebar when the React app changes routes * - * @param pageOrder */ -window.wpNavMenuClassChange = function ( - pageOrder = { myJetpack: 1, activityLog: 2, dashboard: 3, settings: 4 } -) { +window.wpNavMenuClassChange = function () { + const pageOrder = jetpackPageOrder(); + let hash = window.location.hash; let page = new URLSearchParams( window.location.search ); diff --git a/projects/plugins/jetpack/_inc/client/my-plan/my-plan-body.jsx b/projects/plugins/jetpack/_inc/client/my-plan/my-plan-body.jsx index 21fa1e054fffc..672051c8b0ad2 100644 --- a/projects/plugins/jetpack/_inc/client/my-plan/my-plan-body.jsx +++ b/projects/plugins/jetpack/_inc/client/my-plan/my-plan-body.jsx @@ -302,6 +302,11 @@ class MyPlanBody extends React.Component { }; switch ( planClass ) { + // DEPRECATED: Daily and Real-time variations will soon be retired. + // Remove after all customers are migrated to new products. + case 'is-daily-security-plan': + case 'is-realtime-security-plan': + // fall through case 'is-personal-plan': case 'is-premium-plan': case 'is-jetpack-starter-plan': @@ -309,10 +314,6 @@ class MyPlanBody extends React.Component { case 'is-security-t2-plan': case 'is-business-plan': case 'is-complete-plan': - // DEPRECATED: Daily and Real-time variations will soon be retired. - // Remove after all customers are migrated to new products. - case 'is-daily-security-plan': - case 'is-realtime-security-plan': planCard = (
{ 'is-personal-plan' === planClass && getRewindVaultPressCard() } @@ -623,6 +624,11 @@ class MyPlanBody extends React.Component { ); break; + // DEPRECATED: Daily and Real-time variations will soon be retired. + // Remove after all customers are migrated to new products. + case 'is-daily-backup-plan': + case 'is-realtime-backup-plan': + // fall through case 'is-free-plan': case 'is-backup-t0-plan': case 'is-backup-t1-plan': @@ -632,10 +638,6 @@ class MyPlanBody extends React.Component { case 'is-free-search-plan': case 'is-jetpack-creator-plan': case 'offline': - // DEPRECATED: Daily and Real-time variations will soon be retired. - // Remove after all customers are migrated to new products. - case 'is-daily-backup-plan': - case 'is-realtime-backup-plan': planCard = (
{ jetpackBackupCard } diff --git a/projects/plugins/jetpack/_inc/client/my-plan/my-plan-header/index.js b/projects/plugins/jetpack/_inc/client/my-plan/my-plan-header/index.js index c56e33c070b7b..143488476c643 100644 --- a/projects/plugins/jetpack/_inc/client/my-plan/my-plan-header/index.js +++ b/projects/plugins/jetpack/_inc/client/my-plan/my-plan-header/index.js @@ -532,7 +532,7 @@ class MyPlanHeader extends React.Component { * Renders license related actions * * @param {'header'|'footer'} position - Whether the actions are for header or footer - * @returns {React.ReactElement} The licence actions + * @return {React.ReactElement} The licence actions */ renderLicensingActions = ( position = 'header' ) => { const { diff --git a/projects/plugins/jetpack/_inc/client/newsletter/email-settings.jsx b/projects/plugins/jetpack/_inc/client/newsletter/email-settings.jsx index 2cdde7d4fa56e..b1287f70c6cd8 100644 --- a/projects/plugins/jetpack/_inc/client/newsletter/email-settings.jsx +++ b/projects/plugins/jetpack/_inc/client/newsletter/email-settings.jsx @@ -360,8 +360,19 @@ const EmailSettings = props => { disableInSiteConnectionMode module={ subscriptionsModule } className="newsletter-group" + support={ { + link: getRedirectUrl( 'jetpack-support-subscriptions', { + anchor: 'reply-to-email-address', + } ), + text: __( + "Sets the reply to email address for your newsletter emails. It's the email where subscribers send their replies.", + 'jetpack' + ), + } } > - { __( 'Sender name', 'jetpack' ) } + + { __( 'Sender name and reply-to settings', 'jetpack' ) } +

{ __( "This is the name that appears in subscribers' inboxes. It's usually the name of your newsletter or the author.", @@ -387,35 +398,8 @@ const EmailSettings = props => { { __( 'Save', 'jetpack' ) } - - { sprintf( - /* translators: 1. placeholder is the user entered value for From Name, 2. is the example email */ - __( 'Example: %1$s <%2$s>', 'jetpack' ), - fromNameState.value || siteName, - getExampleEmail( subscriptionReplyTo ) - ) } - - - - - { __( 'Reply-to email', 'jetpack' ) } - -

+

{ __( 'Choose who receives emails when subscribers reply to your newsletter.', 'jetpack' @@ -453,6 +437,16 @@ const EmailSettings = props => { ] } onChange={ handleSubscriptionReplyToChange } /> + + + { sprintf( + /* translators: 1. Site name or user entered replacement value 2. is the example email */ + __( 'Preview: %1$s <%2$s>', 'jetpack' ), + fromNameState.value || siteName, + getExampleEmail( subscriptionReplyTo ) + ) } + + ); diff --git a/projects/plugins/jetpack/_inc/client/newsletter/index.jsx b/projects/plugins/jetpack/_inc/client/newsletter/index.jsx index 7f7da029691ae..ebb620bbde9ed 100644 --- a/projects/plugins/jetpack/_inc/client/newsletter/index.jsx +++ b/projects/plugins/jetpack/_inc/client/newsletter/index.jsx @@ -17,7 +17,7 @@ import './style.scss'; * Newsletter Section. * * @param {object} props - Component props. - * @returns {React.Component} Newsletter settings component. + * @return {React.Component} Newsletter settings component. */ function Subscriptions( props ) { const { active, isModuleFound, searchTerm, siteRawUrl, blogID } = props; diff --git a/projects/plugins/jetpack/_inc/client/newsletter/newsletter-categories.jsx b/projects/plugins/jetpack/_inc/client/newsletter/newsletter-categories.jsx index d7dbf4c0394e7..6618def65cd21 100644 --- a/projects/plugins/jetpack/_inc/client/newsletter/newsletter-categories.jsx +++ b/projects/plugins/jetpack/_inc/client/newsletter/newsletter-categories.jsx @@ -34,7 +34,7 @@ const mapCategoriesIds = category => { * NewsletterCategories settings component. * * @param {object} props - Component props. - * @returns {React.Component} Subscription settings component. + * @return {React.Component} Subscription settings component. */ function NewsletterCategories( props ) { const { diff --git a/projects/plugins/jetpack/_inc/client/newsletter/newsletter.jsx b/projects/plugins/jetpack/_inc/client/newsletter/newsletter.jsx index 48159eda50034..d080c8365daec 100644 --- a/projects/plugins/jetpack/_inc/client/newsletter/newsletter.jsx +++ b/projects/plugins/jetpack/_inc/client/newsletter/newsletter.jsx @@ -21,7 +21,7 @@ const trackViewSubsClick = () => { * Newsletter component. * * @param {object} props - Component props. - * @returns {React.Component} Newsletter component. + * @return {React.Component} Newsletter component. */ function Newsletter( props ) { const { diff --git a/projects/plugins/jetpack/_inc/client/newsletter/paid-newsletter.jsx b/projects/plugins/jetpack/_inc/client/newsletter/paid-newsletter.jsx index fb6e76d02e2e0..2489985dd4c3a 100644 --- a/projects/plugins/jetpack/_inc/client/newsletter/paid-newsletter.jsx +++ b/projects/plugins/jetpack/_inc/client/newsletter/paid-newsletter.jsx @@ -15,7 +15,7 @@ import { SUBSCRIPTIONS_MODULE_NAME } from './constants'; * Paid Newsletter component. * * @param {object} props - Component props. - * @returns {React.Component} Paid Newsletter component. + * @return {React.Component} Paid Newsletter component. */ function PaidNewsletter( props ) { const { isSubscriptionsActive, setupPaymentPlansUrl, subscriptionsModule } = props; diff --git a/projects/plugins/jetpack/_inc/client/newsletter/style.scss b/projects/plugins/jetpack/_inc/client/newsletter/style.scss index 4d1edaf7cdafa..57d5e34bdf826 100644 --- a/projects/plugins/jetpack/_inc/client/newsletter/style.scss +++ b/projects/plugins/jetpack/_inc/client/newsletter/style.scss @@ -68,7 +68,6 @@ .sender-name-example { font-size: var(--font-body-small); - color: var(--jp-gray-20); margin-top: 8px; } @@ -123,9 +122,11 @@ position: relative; margin-right: -48px; } + .jp-form-settings-group .email-settings__gravatar .jp-support-info { top: 3px; } + .email-settings__gravatar-image { width: 60px; height: 60px; @@ -140,3 +141,7 @@ #jp-settings-subscriptions .dops-textarea { field-sizing: content; } + +.newsletter-group .reply-to { + margin-top: 16px; +} \ No newline at end of file diff --git a/projects/plugins/jetpack/_inc/client/newsletter/subscriptions-settings.jsx b/projects/plugins/jetpack/_inc/client/newsletter/subscriptions-settings.jsx index 4c8d49adadae2..fdc7d7e3620db 100644 --- a/projects/plugins/jetpack/_inc/client/newsletter/subscriptions-settings.jsx +++ b/projects/plugins/jetpack/_inc/client/newsletter/subscriptions-settings.jsx @@ -22,7 +22,7 @@ import { SUBSCRIPTIONS_MODULE_NAME } from './constants'; * Subscription settings component. * * @param {object} props - Component props. - * @returns {React.Component} Subscription settings component. + * @return {React.Component} Subscription settings component. */ function SubscriptionsSettings( props ) { const { diff --git a/projects/plugins/jetpack/_inc/client/notices/index.js b/projects/plugins/jetpack/_inc/client/notices/index.js index 74ad2cc3e2ac1..0733afc616c2b 100644 --- a/projects/plugins/jetpack/_inc/client/notices/index.js +++ b/projects/plugins/jetpack/_inc/client/notices/index.js @@ -14,9 +14,9 @@ const notices = { /** * Creates a new notice * @private - * @param {String} text the text to show - * @param {Object} options options for the notice - * @param {String} status the classname to affect the notice color. + * @param {String} text the text to show + * @param {Object} options options for the notice + * @param {String} status the classname to affect the notice color. * @return {object} notice */ new: function ( text, options, status ) { @@ -65,8 +65,8 @@ const notices = { /** * Helper function for creating a new "Success" notice * @public - * @param {String} text the text to show - * @param {Object} options options for the notice + * @param {String} text the text to show + * @param {Object} options options for the notice * @return {object} notice */ success: function ( text, options ) { @@ -77,8 +77,8 @@ const notices = { /** * Helper function for creating a new "Error" notice * @public - * @param {String} text the text to show - * @param {Object} options options for the notice + * @param {String} text the text to show + * @param {Object} options options for the notice * @return {object} notice */ error: function ( text, options ) { @@ -89,8 +89,8 @@ const notices = { /** * Helper function for creating a new general "Info" notice * @public - * @param {String} text the text to show - * @param {Object} options options for the notice + * @param {String} text the text to show + * @param {Object} options options for the notice * @return {object} notice */ info: function ( text, options ) { @@ -101,8 +101,8 @@ const notices = { /** * Helper function for creating a new general "Info" notice * @public - * @param {String} text the text to show - * @param {Object} options options for the notice + * @param {String} text the text to show + * @param {Object} options options for the notice * @return {object} notice */ warning: function ( text, options ) { @@ -117,7 +117,7 @@ const notices = { /** * Removes a specific notice when you click its `X` button - * @param {object} notice The data that was originally used to create the notice + * @param {object} notice The data that was originally used to create the notice */ removeNotice: function ( notice ) { if ( ! notice.container ) { @@ -136,8 +136,8 @@ const notices = { /** * Callback handler to clear notices when a user leaves current page * @public - * @param {*} context Not used ? - * @param {Function} next next callback to execute + * @param {*} context Not used ? + * @param {Function} next next callback to execute */ clearNoticesOnNavigation: function ( context, next ) { debug( 'clearNoticesOnNavigation' ); @@ -175,7 +175,7 @@ const notices = { * Clear all notices at once for a given container * @public * - * @param {string} container DOM ID of notices container to clear + * @param {string} container DOM ID of notices container to clear */ clearNotices: function ( container ) { list[ container ] = []; diff --git a/projects/plugins/jetpack/_inc/client/performance/search.jsx b/projects/plugins/jetpack/_inc/client/performance/search.jsx index ba05e6a004742..a058ef806ed5d 100644 --- a/projects/plugins/jetpack/_inc/client/performance/search.jsx +++ b/projects/plugins/jetpack/_inc/client/performance/search.jsx @@ -24,8 +24,8 @@ const SEARCH_SUPPORT = __( 'Search supports many customizations. ', 'jetpack' ); /** * Search settings component to be used within the Performance section. * - * @param {object} props - Component properties. - * @returns {React.Component} Search settings component. + * @param {object} props - Component properties. + * @return {React.Component} Search settings component. */ function Search( props ) { const { failedToEnableSearch, hasInstantSearch, updateOptions } = props; diff --git a/projects/plugins/jetpack/_inc/client/performance/test/fixtures.js b/projects/plugins/jetpack/_inc/client/performance/test/fixtures.js index 6e865361c887a..4cac4b432feea 100644 --- a/projects/plugins/jetpack/_inc/client/performance/test/fixtures.js +++ b/projects/plugins/jetpack/_inc/client/performance/test/fixtures.js @@ -1,7 +1,7 @@ /** * Build site data. * - * @returns {object} - Site data. + * @return {object} - Site data. */ function siteDataFixture() { return { @@ -22,9 +22,9 @@ function siteDataFixture() { /** * Build an object that can be used as a Redux store initial state. * - * @param {object} options - Options + * @param {object} options - Options * @param {boolean} options.themeSupportsWidgets - whether the current theme supports widgets - * @returns {object} – initial Redux state + * @return {object} – initial Redux state */ export function buildInitialState( { themeSupportsWidgets = false } = {} ) { return { diff --git a/projects/plugins/jetpack/_inc/client/portals/plugin-deactivation.jsx b/projects/plugins/jetpack/_inc/client/portals/plugin-deactivation.jsx index 4e523c37a146f..aca868cdb4128 100644 --- a/projects/plugins/jetpack/_inc/client/portals/plugin-deactivation.jsx +++ b/projects/plugins/jetpack/_inc/client/portals/plugin-deactivation.jsx @@ -20,12 +20,12 @@ import PortalSidecar from './utilities/portal-sidecar'; /** * Component that loads on the plugins page and manages presenting the disconnection modal. * - * @param {object} props - The props object for the component. - * @param {string} props.apiRoot - Root URL for the API, which is required by the component. - * @param {string} props.apiNonce - Nonce value for the API, which is required by the component. - * @param {Array} props.siteBenefits - An array of benefits provided by Jetpack. - * @param {string} props.pluginUrl - The URL of the plugin directory. - * @returns {React.Component} - The PluginDeactivation component. + * @param {object} props - The props object for the component. + * @param {string} props.apiRoot - Root URL for the API, which is required by the component. + * @param {string} props.apiNonce - Nonce value for the API, which is required by the component. + * @param {Array} props.siteBenefits - An array of benefits provided by Jetpack. + * @param {string} props.pluginUrl - The URL of the plugin directory. + * @return {React.Component} - The PluginDeactivation component. */ const PluginDeactivation = props => { const { diff --git a/projects/plugins/jetpack/_inc/client/pro-status/index.jsx b/projects/plugins/jetpack/_inc/client/pro-status/index.jsx index 76b52ca21c114..8afa74cd5381e 100644 --- a/projects/plugins/jetpack/_inc/client/pro-status/index.jsx +++ b/projects/plugins/jetpack/_inc/client/pro-status/index.jsx @@ -29,7 +29,7 @@ import { isFetchingPluginsData, isPluginActive, isPluginInstalled } from 'state/ * * @param {string} type - Status of a certain feature. * @param {string} feature - Slug of plugin or service. - * @returns {undefined} + * @return {undefined} */ const trackProStatusClick = ( type, feature ) => analytics.tracks.recordJetpackClick( { @@ -43,7 +43,7 @@ const trackProStatusClick = ( type, feature ) => * * @param {string} type - Status of a certain feature. * @param {string} feature - Slug of plugin or service. - * @returns {Function} Function to track a click. + * @return {Function} Function to track a click. */ const handleClickForTracking = ( type, feature ) => () => trackProStatusClick( type, feature ); @@ -138,7 +138,7 @@ class ProStatus extends React.Component { * Return a button to Set Up a feature. * * @param {string} feature - Slug of the feature to set up. - * @returns {React.ReactElement} A Button component. + * @return {React.ReactElement} A Button component. */ getSetUpButton = feature => { return ( diff --git a/projects/plugins/jetpack/_inc/client/product-descriptions/index.jsx b/projects/plugins/jetpack/_inc/client/product-descriptions/index.jsx index c4fc3eb864be5..6c5134ada0ea2 100644 --- a/projects/plugins/jetpack/_inc/client/product-descriptions/index.jsx +++ b/projects/plugins/jetpack/_inc/client/product-descriptions/index.jsx @@ -24,7 +24,7 @@ const ProductDescriptions = props => { if ( ! isLoading ) { Object.values( SUPPORTED_PRODUCTS ).forEach( function ( key ) { - if ( ! products.hasOwnProperty( key ) ) { + if ( ! Object.hasOwn( products, key ) ) { return; } diff --git a/projects/plugins/jetpack/_inc/client/product-descriptions/product-description/index.jsx b/projects/plugins/jetpack/_inc/client/product-descriptions/product-description/index.jsx index a86bd48175946..57a41fa2f9f76 100644 --- a/projects/plugins/jetpack/_inc/client/product-descriptions/product-description/index.jsx +++ b/projects/plugins/jetpack/_inc/client/product-descriptions/product-description/index.jsx @@ -27,7 +27,7 @@ const getRelatedProductPlan = ( product, availableProductsAndPlans ) => { if ( isEmpty( product.includedInPlans ) || - ! availableProductsAndPlans.hasOwnProperty( upsellPlan ) || + ! Object.hasOwn( availableProductsAndPlans, upsellPlan ) || ! product.includedInPlans.includes( upsellPlan ) ) { return false; @@ -38,7 +38,7 @@ const getRelatedProductPlan = ( product, availableProductsAndPlans ) => { const renderProduct = ( product, offers, priority, hasRelatedPlan ) => { const illustration = - ! hasRelatedPlan && productIllustrations.hasOwnProperty( product.key ) + ! hasRelatedPlan && Object.hasOwn( productIllustrations, product.key ) ? productIllustrations[ product.key ] : undefined; let cta, icon; diff --git a/projects/plugins/jetpack/_inc/client/product-descriptions/product-description/test/fixtures.js b/projects/plugins/jetpack/_inc/client/product-descriptions/product-description/test/fixtures.js index 6ecb8ec30b0ba..c08724587eb5e 100644 --- a/projects/plugins/jetpack/_inc/client/product-descriptions/product-description/test/fixtures.js +++ b/projects/plugins/jetpack/_inc/client/product-descriptions/product-description/test/fixtures.js @@ -1,7 +1,7 @@ /** * Build the Redux initial state. * - * @returns {object} - State. + * @return {object} - State. */ export function buildInitialState() { return { diff --git a/projects/plugins/jetpack/_inc/client/product-descriptions/utils.js b/projects/plugins/jetpack/_inc/client/product-descriptions/utils.js index 76d34f2da2157..8c333c3576290 100644 --- a/projects/plugins/jetpack/_inc/client/product-descriptions/utils.js +++ b/projects/plugins/jetpack/_inc/client/product-descriptions/utils.js @@ -7,7 +7,7 @@ import { productDescriptionRoutes, myJetpackRoutes } from './constants'; * * Todo: Make it return true once we fully ship and enable new search pricing. * - * @returns {boolean} Whether new search pricing and free plan is forced by URL parameter. + * @return {boolean} Whether new search pricing and free plan is forced by URL parameter. */ export const isSearchNewPricingLaunched202208 = () => URLSearchParams && !! new URLSearchParams( window.location?.search ).get( 'new_pricing_202208' ); @@ -18,9 +18,9 @@ export const isSearchNewPricingLaunched202208 = () => * A product key differs from slugs since "jetpack-backup-daily" => "backups". * We follow these to keep support for existing redirects / tracks. * - * @param {object} state - The site state + * @param {object} state - The site state * @param {string} productKey - Product key to redirect to. - * @returns {string} URL for a product or the . + * @return {string} URL for a product or the . */ export const getProductDescriptionUrl = ( state, productKey ) => { const baseUrl = `${ getSiteAdminUrl( state ) }admin.php?page=jetpack#`; diff --git a/projects/plugins/jetpack/_inc/client/recommendations/feature-summary/primary.tsx b/projects/plugins/jetpack/_inc/client/recommendations/feature-summary/primary.tsx index 1f2c2db9f93f0..7ba3fc63c34c1 100644 --- a/projects/plugins/jetpack/_inc/client/recommendations/feature-summary/primary.tsx +++ b/projects/plugins/jetpack/_inc/client/recommendations/feature-summary/primary.tsx @@ -21,7 +21,7 @@ const SummaryTextLink = ( { href, label, isHidden, onClick }: SummaryTextLinkPro target="_blank" href={ href } onClick={ onClick } - className={ clsx( 'jp-summary-text-link', { [ 'is-hidden' ]: isHidden } ) } + className={ clsx( 'jp-summary-text-link', { 'is-hidden': isHidden } ) } > { label } diff --git a/projects/plugins/jetpack/_inc/client/recommendations/product-purchased/index.jsx b/projects/plugins/jetpack/_inc/client/recommendations/product-purchased/index.jsx index 1c205bb4ecf20..f468fe4fd5976 100644 --- a/projects/plugins/jetpack/_inc/client/recommendations/product-purchased/index.jsx +++ b/projects/plugins/jetpack/_inc/client/recommendations/product-purchased/index.jsx @@ -44,11 +44,9 @@ const getPurchasedSuggestion = ( { if ( isArray( activePurchases ) ) { const matchingProduct = suggestions.find( suggestion => { - if ( - activePurchases.find( activePurchase => suggestion.slug === activePurchase.product_slug ) - ) { - return suggestion; - } + return activePurchases.find( + activePurchase => suggestion.slug === activePurchase.product_slug + ); } ); if ( matchingProduct ) { diff --git a/projects/plugins/jetpack/_inc/client/recommendations/product-purchased/test/component.js b/projects/plugins/jetpack/_inc/client/recommendations/product-purchased/test/component.js index aea9f6598c701..825fcf25aba02 100644 --- a/projects/plugins/jetpack/_inc/client/recommendations/product-purchased/test/component.js +++ b/projects/plugins/jetpack/_inc/client/recommendations/product-purchased/test/component.js @@ -22,9 +22,9 @@ describe( 'Recommendations – Product Purchased', () => { expect( screen.getByText( 'You now have access to these benefits:' ) ).toBeInTheDocument(); // Shows dynamic features checkboxes. - productSuggestion.features.map( feature => { + for ( const feature of productSuggestion.features ) { expect( screen.getByText( feature ) ).toBeInTheDocument(); - } ); + } } ); it( 'track landing on the purchase step', () => { diff --git a/projects/plugins/jetpack/_inc/client/recommendations/prompts/feature-prompt/test/component.js b/projects/plugins/jetpack/_inc/client/recommendations/prompts/feature-prompt/test/component.js index d79eecf094b58..cff929c5a28d9 100644 --- a/projects/plugins/jetpack/_inc/client/recommendations/prompts/feature-prompt/test/component.js +++ b/projects/plugins/jetpack/_inc/client/recommendations/prompts/feature-prompt/test/component.js @@ -10,9 +10,9 @@ import { FeaturePrompt } from '../index'; /** * Build initial state. * - * @param {object} _ - Dummy positional parameter. + * @param {object} _ - Dummy positional parameter. * @param {string} _.recommendationsStep - Value for jetpack.recommendations.step. - * @returns {object} - State. + * @return {object} - State. */ function buildInitialState( { recommendationsStep } = {} ) { return { diff --git a/projects/plugins/jetpack/_inc/client/recommendations/prompts/product-suggestions/test/fixtures.js b/projects/plugins/jetpack/_inc/client/recommendations/prompts/product-suggestions/test/fixtures.js index dfa0250b675bf..5f7019bbb6921 100644 --- a/projects/plugins/jetpack/_inc/client/recommendations/prompts/product-suggestions/test/fixtures.js +++ b/projects/plugins/jetpack/_inc/client/recommendations/prompts/product-suggestions/test/fixtures.js @@ -1,7 +1,7 @@ /** * Build the Redux initial state. * - * @returns {object} - State. + * @return {object} - State. */ export function buildInitialState() { return { diff --git a/projects/plugins/jetpack/_inc/client/recommendations/prompts/resource-prompt/index.jsx b/projects/plugins/jetpack/_inc/client/recommendations/prompts/resource-prompt/index.jsx index 37a82ecd15918..f059ba8311454 100644 --- a/projects/plugins/jetpack/_inc/client/recommendations/prompts/resource-prompt/index.jsx +++ b/projects/plugins/jetpack/_inc/client/recommendations/prompts/resource-prompt/index.jsx @@ -29,7 +29,7 @@ import { PromptLayout } from '../prompt-layout'; * * @param {object} props - Component props. * @function Object() { [native code] } - * @returns {Element} - A react component. + * @return {Element} - A react component. */ const ResourcePromptComponent = props => { const { diff --git a/projects/plugins/jetpack/_inc/client/recommendations/prompts/site-type/test/component.js b/projects/plugins/jetpack/_inc/client/recommendations/prompts/site-type/test/component.js index ab22f1ad6aca3..8b0cc6f430d7a 100644 --- a/projects/plugins/jetpack/_inc/client/recommendations/prompts/site-type/test/component.js +++ b/projects/plugins/jetpack/_inc/client/recommendations/prompts/site-type/test/component.js @@ -9,7 +9,7 @@ import { SiteTypeQuestion } from '../index'; /** * Build initial state. * - * @returns {object} State. + * @return {object} State. */ function buildInitialState() { return { diff --git a/projects/plugins/jetpack/_inc/client/recommendations/summary/test/fixtures.js b/projects/plugins/jetpack/_inc/client/recommendations/summary/test/fixtures.js index e8b2dd6578963..5520ecbe019e7 100644 --- a/projects/plugins/jetpack/_inc/client/recommendations/summary/test/fixtures.js +++ b/projects/plugins/jetpack/_inc/client/recommendations/summary/test/fixtures.js @@ -2,7 +2,7 @@ * Build the Rewind fixture object. * * @param {object} rewindStatus - – rewind status of the site - * @returns {object} Status. + * @return {object} Status. */ function rewindFixture( rewindStatus ) { return { @@ -15,10 +15,10 @@ function rewindFixture( rewindStatus ) { /** * Build the site data fixture object. * - * @param {object} options - Options - * @param {string} options.productSlug - – product slug of the site's plan - * @param {Array} options.sitePurchases - mocked site purchases - * @returns {object} Fixture. + * @param {object} options - Options + * @param {string} options.productSlug - – product slug of the site's plan + * @param {Array} options.sitePurchases - mocked site purchases + * @return {object} Fixture. */ function siteDataFixture( { productSlug, sitePurchases } ) { return { @@ -41,7 +41,7 @@ function siteDataFixture( { productSlug, sitePurchases } ) { /** * Build the intro offers fixture object. * - * @returns {object} Fixture. + * @return {object} Fixture. */ function introOffersFixture() { return { @@ -76,9 +76,9 @@ function introOffersFixture() { /** * Build the upsell fixture object. * - * @param {object} options - Options. + * @param {object} options - Options. * @param {boolean} options.hideUpsell - Whether to hide the upsell. - * @returns {object} Fixture. + * @return {object} Fixture. */ function upsellFixture( { hideUpsell } ) { return { @@ -105,16 +105,16 @@ function upsellFixture( { hideUpsell } ) { /** * Build an object that can be use as a Redux store initial state. * - * @param {object} options - Options. - * @param {boolean} options.hideUpsell - – whether to show the upsell product card - * @param {string} options.productSlug - – product slug of the site's plan - * @param {object} options.rewindStatus - – rewind status of the site - * @param {object} options.enabledRecommendations - Enabled recommendations. - * @param {object} options.skippedRecommendations - Skipped recommendations. - * @param {string} options.onboardingActive - Active onboarding name. - * @param {Array} options.onboardingViewed - Viewed onboarding names. - * @param {Array} options.sitePurchases - Mocked Site Purchases. - * @returns {object} – initial Redux state + * @param {object} options - Options. + * @param {boolean} options.hideUpsell - – whether to show the upsell product card + * @param {string} options.productSlug - – product slug of the site's plan + * @param {object} options.rewindStatus - – rewind status of the site + * @param {object} options.enabledRecommendations - Enabled recommendations. + * @param {object} options.skippedRecommendations - Skipped recommendations. + * @param {string} options.onboardingActive - Active onboarding name. + * @param {Array} options.onboardingViewed - Viewed onboarding names. + * @param {Array} options.sitePurchases - Mocked Site Purchases. + * @return {object} – initial Redux state */ export function buildInitialState( { enabledRecommendations = {}, diff --git a/projects/plugins/jetpack/_inc/client/recommendations/utils/compute-max-suggested-discount.js b/projects/plugins/jetpack/_inc/client/recommendations/utils/compute-max-suggested-discount.js index f17be755535c3..7e8cd987ef8fa 100644 --- a/projects/plugins/jetpack/_inc/client/recommendations/utils/compute-max-suggested-discount.js +++ b/projects/plugins/jetpack/_inc/client/recommendations/utils/compute-max-suggested-discount.js @@ -1,10 +1,10 @@ /** * Return the highest discount amongst all suggested products. * - * @param {object} discountData - Informations about the discount - * @param {object[]} introOffers - Set of product offering information - * @param {object[]} suggestions - Suggested products - * @returns {number|undefined} Max discount + * @param {object} discountData - Informations about the discount + * @param {object[]} introOffers - Set of product offering information + * @param {object[]} suggestions - Suggested products + * @return {number|undefined} Max discount */ export const computeMaxSuggestedDiscount = ( discountData, introOffers, suggestions ) => { if ( ! discountData || ! introOffers || ! suggestions ) { diff --git a/projects/plugins/jetpack/_inc/client/recommendations/utils/generate-checkout-link.js b/projects/plugins/jetpack/_inc/client/recommendations/utils/generate-checkout-link.js index 8c53fdbd5643b..7f3cbcd8dbcc8 100644 --- a/projects/plugins/jetpack/_inc/client/recommendations/utils/generate-checkout-link.js +++ b/projects/plugins/jetpack/_inc/client/recommendations/utils/generate-checkout-link.js @@ -3,12 +3,12 @@ import { getRedirectUrl } from '@automattic/jetpack-components'; /** * Return the URL of the checkout page with a given product in cart, for a specific site. * - * @param {string} productSlug - Slug of the product to order + * @param {string} productSlug - Slug of the product to order * @param {string} siteAdminUrl - Site admin URL - * @param {string} siteRawUrl - Site URL - * @param {string} couponCode - Coupon code - * @param {string} blogID - Site URL - * @returns {string} Checkout URL + * @param {string} siteRawUrl - Site URL + * @param {string} couponCode - Coupon code + * @param {string} blogID - Site URL + * @return {string} Checkout URL */ export const generateCheckoutLink = ( productSlug, diff --git a/projects/plugins/jetpack/_inc/client/recommendations/utils/is-coupon-valid.js b/projects/plugins/jetpack/_inc/client/recommendations/utils/is-coupon-valid.js index cfbf441824a33..cbabf65740202 100644 --- a/projects/plugins/jetpack/_inc/client/recommendations/utils/is-coupon-valid.js +++ b/projects/plugins/jetpack/_inc/client/recommendations/utils/is-coupon-valid.js @@ -2,7 +2,7 @@ * Check if coupon is valid. * * @param {object} data - Coupon information. - * @returns {boolean} Whether coupon is valid. + * @return {boolean} Whether coupon is valid. */ export const isCouponValid = data => { if ( 'object' !== typeof data ) { diff --git a/projects/plugins/jetpack/_inc/client/security/allowList.jsx b/projects/plugins/jetpack/_inc/client/security/allowList.jsx index a0073c961321e..8928f062c815d 100644 --- a/projects/plugins/jetpack/_inc/client/security/allowList.jsx +++ b/projects/plugins/jetpack/_inc/client/security/allowList.jsx @@ -18,7 +18,7 @@ const AllowList = class extends Component { /** * Get options for initial state. * - * @returns {object} + * @return {object} */ state = { ipAllowListEnabled: this.props.settings?.ipAllowListEnabled, @@ -44,7 +44,7 @@ const AllowList = class extends Component { /** * Handle settings updates. * - * @returns {void} + * @return {void} */ onSubmit = () => { this.props.removeNotice( 'module-setting-update' ); diff --git a/projects/plugins/jetpack/_inc/client/security/index.jsx b/projects/plugins/jetpack/_inc/client/security/index.jsx index 056948fa997c3..a6c1b4893c3c3 100644 --- a/projects/plugins/jetpack/_inc/client/security/index.jsx +++ b/projects/plugins/jetpack/_inc/client/security/index.jsx @@ -27,7 +27,7 @@ export class Security extends Component { /** * Check if Akismet plugin is being searched and matched. * - * @returns {boolean} False if the plugin is inactive or if the search doesn't match it. True otherwise. + * @return {boolean} False if the plugin is inactive or if the search doesn't match it. True otherwise. */ isAkismetFound = () => { if ( ! this.props.isPluginActive( 'akismet/akismet.php' ) ) { diff --git a/projects/plugins/jetpack/_inc/client/security/sso.jsx b/projects/plugins/jetpack/_inc/client/security/sso.jsx index 422f87b216966..55d31668c31da 100644 --- a/projects/plugins/jetpack/_inc/client/security/sso.jsx +++ b/projects/plugins/jetpack/_inc/client/security/sso.jsx @@ -89,7 +89,7 @@ export const SSO = withModuleSettingsFormHelpers( /** * Get options for initial state. * - * @returns {{jetpack_sso_match_by_email: *, jetpack_sso_require_two_step: *}} + * @return {{jetpack_sso_match_by_email: *, jetpack_sso_require_two_step: *}} */ state = { jetpack_sso_match_by_email: this.props.getOptionValue( diff --git a/projects/plugins/jetpack/_inc/client/security/waf.jsx b/projects/plugins/jetpack/_inc/client/security/waf.jsx index 1bd7646c98d62..c9437c5aa202d 100644 --- a/projects/plugins/jetpack/_inc/client/security/waf.jsx +++ b/projects/plugins/jetpack/_inc/client/security/waf.jsx @@ -8,6 +8,8 @@ import { FormFieldset } from 'components/forms'; import { createNotice, removeNotice } from 'components/global-notices/state/notices/actions'; import JetpackBanner from 'components/jetpack-banner'; import { withModuleSettingsFormHelpers } from 'components/module-settings/with-module-settings-form-helpers'; +import SimpleNotice from 'components/notice'; +import NoticeAction from 'components/notice/notice-action'; import SettingsCard from 'components/settings-card'; import SettingsGroup from 'components/settings-group'; import { @@ -45,7 +47,7 @@ export const Waf = class extends Component { /** * Get options for initial state. * - * @returns {object} + * @return {object} */ state = { automaticRulesEnabled: this.props.settings?.automaticRulesEnabled, @@ -78,7 +80,7 @@ export const Waf = class extends Component { * Get a custom error message based on the error code. * * @param {object} error - Error object. - * @returns {string|boolean} Custom error message or false if no custom message exists. + * @return {string|boolean} Custom error message or false if no custom message exists. */ getCustomErrorMessage = error => { switch ( error.code ) { @@ -94,7 +96,7 @@ export const Waf = class extends Component { /** * Handle settings updates. * - * @returns {void} + * @return {void} */ onSubmit = () => { this.props.removeNotice( 'module-setting-update' ); @@ -499,6 +501,18 @@ export const Waf = class extends Component { hideButton={ true } > { isWafActive && } + + + { __( 'Get Jetpack Protect', 'jetpack' ) } + + isPluginActive( state, pluginFile ) ), + getProtectUrl: `${ getSiteAdminUrl( state ) }admin.php?page=my-jetpack#/add-protect`, isFetchingSettings: isFetchingWafSettings( state ), isUpdatingWafSettings: isUpdatingWafSettings( state ), settings: getWafSettings( state ), diff --git a/projects/plugins/jetpack/_inc/client/sharing/share-buttons.jsx b/projects/plugins/jetpack/_inc/client/sharing/share-buttons.jsx index b2312fad07de6..ef0ebfb0638dc 100644 --- a/projects/plugins/jetpack/_inc/client/sharing/share-buttons.jsx +++ b/projects/plugins/jetpack/_inc/client/sharing/share-buttons.jsx @@ -45,7 +45,7 @@ export const ShareButtons = withModuleSettingsFormHelpers( * - Is the site in offline mode? * - Is the site using the classic admin interface? * - * @returns {React.ReactNode} A card with the sharing configuration link. + * @return {React.ReactNode} A card with the sharing configuration link. */ const configCard = () => { const cardProps = { @@ -74,7 +74,7 @@ export const ShareButtons = withModuleSettingsFormHelpers( * If the sharing block is available, * we suggest to use it instead of the legacy module. * - * @returns {React.ReactNode} A module toggle. + * @return {React.ReactNode} A module toggle. */ const moduleToggle = () => { const toggle = ( diff --git a/projects/plugins/jetpack/_inc/client/state/at-a-glance/reducer.js b/projects/plugins/jetpack/_inc/client/state/at-a-glance/reducer.js index f5a85ff7bcc0d..ab8d4fc51d4b9 100644 --- a/projects/plugins/jetpack/_inc/client/state/at-a-glance/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/at-a-glance/reducer.js @@ -204,8 +204,8 @@ export const dashboard = combineReducers( { /** * Returns string of active Stats tab in At A Glance section * - * @param {object} state - Global state tree - * @returns {string} Which Stats tab is open. + * @param {object} state - Global state tree + * @return {string} Which Stats tab is open. */ export function getActiveStatsTab( state ) { return state.jetpack.dashboard.activeStatsTab; @@ -214,8 +214,8 @@ export function getActiveStatsTab( state ) { /** * Returns true if currently requesting Stats data. * - * @param {object} state - Global state tree - * @returns {boolean} Whether Stats data is being requested + * @param {object} state - Global state tree + * @return {boolean} Whether Stats data is being requested */ export function isFetchingStatsData( state ) { return !! state.jetpack.dashboard.requests.fetchingStatsData; @@ -224,8 +224,8 @@ export function isFetchingStatsData( state ) { /** * Returns object with Stats data. * - * @param {object} state - Global state tree - * @returns {object} Stats data. + * @param {object} state - Global state tree + * @return {object} Stats data. */ export function getStatsData( state ) { return state.jetpack.dashboard.statsData; @@ -234,8 +234,8 @@ export function getStatsData( state ) { /** * Returns true if currently requesting Akismet data * - * @param {object} state - Global state tree - * @returns {boolean} Whether Akismet data is being requested + * @param {object} state - Global state tree + * @return {boolean} Whether Akismet data is being requested */ export function isFetchingAkismetData( state ) { return !! state.jetpack.dashboard.requests.fetchingAkismetData; @@ -244,8 +244,8 @@ export function isFetchingAkismetData( state ) { /** * Returns int of protect count of blocked attempts. * - * @param {object} state - Global state tree - * @returns {number | string} Number of comments blocked by Akismet or error code: 'not_active', 'not_installed', 'invalid_key' + * @param {object} state - Global state tree + * @return {number | string} Number of comments blocked by Akismet or error code: 'not_active', 'not_installed', 'invalid_key' */ export function getAkismetData( state ) { return state.jetpack.dashboard.akismetData; @@ -254,8 +254,8 @@ export function getAkismetData( state ) { /** * Returns true if currently checking Akismet API key for validity. * - * @param {object} state - Global state tree - * @returns {boolean} Whether Akismet API key is being checked. + * @param {object} state - Global state tree + * @return {boolean} Whether Akismet API key is being checked. */ export function isCheckingAkismetKey( state ) { return !! state.jetpack.dashboard.requests.checkingAkismetKey; @@ -264,8 +264,8 @@ export function isCheckingAkismetKey( state ) { /** * Checks if the Akismet key is valid. * - * @param {object} state - Global state tree - * @returns {boolean} True if Akismet API key is valid. + * @param {object} state - Global state tree + * @return {boolean} True if Akismet API key is valid. */ export function isAkismetKeyValid( state ) { return get( state.jetpack.dashboard, [ 'akismet', 'validKey' ], false ); @@ -274,8 +274,8 @@ export function isAkismetKeyValid( state ) { /** * Returns true if currently requesting Protect data * - * @param {object} state - Global state tree - * @returns {boolean} Whether Protect data is being requested + * @param {object} state - Global state tree + * @return {boolean} Whether Protect data is being requested */ export function isFetchingProtectData( state ) { return !! state.jetpack.dashboard.requests.fetchingProtectData; @@ -284,8 +284,8 @@ export function isFetchingProtectData( state ) { /** * Returns int of protect count of blocked attempts. * - * @param {object} state - Global state tree - * @returns {number} Number of blocked brute force login attempts + * @param {object} state - Global state tree + * @return {number} Number of blocked brute force login attempts */ export function getProtectCount( state ) { return state.jetpack.dashboard.protectCount; @@ -295,8 +295,8 @@ export function getProtectCount( state ) { * Returns true if a fetch to VaultPress data has completed. * Both success and error states will set hasLoadedVaultPressData = true. * - * @param {object} state - Global state tree. - * @returns {boolean} Whether a VaultPress data fetch has finished. + * @param {object} state - Global state tree. + * @return {boolean} Whether a VaultPress data fetch has finished. */ export function hasLoadedVaultPressData( state ) { return !! state.jetpack.dashboard.requests.hasLoadedVaultPressData; @@ -305,8 +305,8 @@ export function hasLoadedVaultPressData( state ) { /** * Returns true if currently requesting VaultPress data * - * @param {object} state - Global state tree - * @returns {boolean} Whether VaultPress data is being requested + * @param {object} state - Global state tree + * @return {boolean} Whether VaultPress data is being requested */ export function isFetchingVaultPressData( state ) { return !! state.jetpack.dashboard.requests.fetchingVaultPressData; @@ -316,8 +316,8 @@ export function isFetchingVaultPressData( state ) { * * Returns all VaultPress data as an object. * - * @param {object} state - Global state tree - * @returns {object} All VaultPress configuration/status data + * @param {object} state - Global state tree + * @return {object} All VaultPress configuration/status data */ export function getVaultPressData( state ) { return state.jetpack.dashboard.vaultPressData; @@ -327,8 +327,8 @@ export function getVaultPressData( state ) { * * Returns number of VaultPress Scan threats found. * - * @param {object} state - Global state tree - * @returns {number} The number of current security threats found by VaultPress + * @param {object} state - Global state tree + * @return {number} The number of current security threats found by VaultPress */ export function getVaultPressScanThreatCount( state ) { return get( state.jetpack.dashboard.vaultPressData, 'data.security.notice_count', 0 ); @@ -337,8 +337,8 @@ export function getVaultPressScanThreatCount( state ) { /** * Returns true if currently requesting Plugin Updates * - * @param {object} state - Global state tree - * @returns {boolean} Whether Plugin Updates are being requested + * @param {object} state - Global state tree + * @return {boolean} Whether Plugin Updates are being requested */ export function isFetchingPluginUpdates( state ) { return !! state.jetpack.dashboard.requests.fetchingPluginUpdates; @@ -347,8 +347,8 @@ export function isFetchingPluginUpdates( state ) { /** * Returns int of plugin updates * - * @param {object} state - Global state tree - * @returns {number} Number of plugin updates currently available + * @param {object} state - Global state tree + * @return {number} Number of plugin updates currently available */ export function getPluginUpdates( state ) { return state.jetpack.dashboard.pluginUpdates; @@ -357,8 +357,8 @@ export function getPluginUpdates( state ) { /** * Returns true if currently requesting plugins data. * - * @param {object} state - Global state tree - * @returns {boolean} Whether plugins data is being requested + * @param {object} state - Global state tree + * @return {boolean} Whether plugins data is being requested */ export function isFetchingPluginsData( state ) { return !! state.jetpack.pluginsData.requests.isFetchingPluginsData; @@ -368,8 +368,8 @@ export function isFetchingPluginsData( state ) { * Returns the plugins data items object, with key being the plugin basepath * and value being an object containing plugin details * - * @param {object} state - Global state tree - * @returns {object} The plugins data items + * @param {object} state - Global state tree + * @return {object} The plugins data items */ export function getPluginItems( state ) { return state.jetpack.pluginsData.items || {}; @@ -378,8 +378,8 @@ export function getPluginItems( state ) { /** * Returns the last backup undo even from the Activity Log. * - * @param {object} state - Global state tree - * @returns {object} The last backup undo event + * @param {object} state - Global state tree + * @return {object} The last backup undo event */ export function getBackupUndoEvent( state ) { return state.jetpack.dashboard.backupUndoEvent; @@ -388,8 +388,8 @@ export function getBackupUndoEvent( state ) { /** * Returns true if currently requesting backup undo event. * - * @param {object} state - Global state tree - * @returns {boolean} Whether backup undo event is being requested + * @param {object} state - Global state tree + * @return {boolean} Whether backup undo event is being requested */ export function isFetchingBackupUndoEvent( state ) { return state.jetpack.dashboard.backupUndoEvent.isFetching; @@ -398,8 +398,8 @@ export function isFetchingBackupUndoEvent( state ) { /** * Returns true if backup undo event has been loaded. * - * @param {object} state - Global state tree - * @returns {boolean} Whether backup undo event has been loaded + * @param {object} state - Global state tree + * @return {boolean} Whether backup undo event has been loaded */ export function hasLoadedBackupUndoEvent( state ) { return state.jetpack.dashboard.backupUndoEvent.loaded; diff --git a/projects/plugins/jetpack/_inc/client/state/connection/reducer.js b/projects/plugins/jetpack/_inc/client/state/connection/reducer.js index 706afbd15c1f0..3062aaff5c056 100644 --- a/projects/plugins/jetpack/_inc/client/state/connection/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/connection/reducer.js @@ -163,8 +163,8 @@ export const reducer = combineReducers( { /** * Get the whole connection status object. * - * @param {object} state - Global state tree - * @returns {object} Connection status object. + * @param {object} state - Global state tree + * @return {object} Connection status object. */ export function getConnectionStatus( state ) { return 'object' === typeof state.jetpack.connection.status.siteConnected @@ -175,7 +175,7 @@ export function getConnectionStatus( state ) { /** * Returns true if site is connected to WordPress.com * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {bool|string} True if site is connected, False if it is not, 'offline' if site is in offline mode. */ export function getSiteConnectionStatus( state ) { @@ -191,7 +191,7 @@ export function getSiteConnectionStatus( state ) { /** * Checks if the site is connected to WordPress.com. Unlike getSiteConnectionStatus, this one returns only a boolean. * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {boolean} True if site is connected to WordPress.com. False if site is in Offline Mode or there's no connection data. */ export function isSiteConnected( state ) { @@ -208,7 +208,7 @@ export function isSiteConnected( state ) { * Checks if the site is registered with WordPress.com. * * @param {object} state -- Global state tree - * @returns {boolean} True if site is registered WordPress.com (has blog token). False if site is in Offline Mode or there's no connection data. + * @return {boolean} True if site is registered WordPress.com (has blog token). False if site is in Offline Mode or there's no connection data. */ export function isSiteRegistered( state ) { if ( @@ -223,7 +223,7 @@ export function isSiteRegistered( state ) { /** * Returns an object with information about the Offline Mode. * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {bool|object} False if site is not in Offline Mode. If it is, returns an object with information about the Offline Mode. */ export function getSiteOfflineMode( state ) { @@ -236,7 +236,7 @@ export function getSiteOfflineMode( state ) { /** * Returns string/URL to make a connection to WordPress.com * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {String} URL for connecting to WordPress.com */ export function getConnectUrl( state ) { @@ -246,7 +246,7 @@ export function getConnectUrl( state ) { /** * Returns an object with information about the WP.com connected user * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {object} Returns an object with information about the connected user */ export function getConnectedWpComUser( state ) { @@ -256,7 +256,7 @@ export function getConnectedWpComUser( state ) { /** * Returns true if currently disconnecting the site * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {bool} True if site is being disconnected */ export function isDisconnectingSite( state ) { @@ -266,7 +266,7 @@ export function isDisconnectingSite( state ) { /** * Returns true if currently fetching connectUrl * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {bool} true if currently fetching connectUrl, false otherwise */ export function isFetchingConnectUrl( state ) { @@ -276,7 +276,7 @@ export function isFetchingConnectUrl( state ) { /** * Returns true if currently unlinking the user * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {bool} true if currently unlinking a user, false otherwise */ export function isUnlinkingUser( state ) { @@ -286,8 +286,8 @@ export function isUnlinkingUser( state ) { /** * Returns true if currently linking the user * - * @param {object} state - Global state tree - * @returns {bool} true if currently linking a user, false otherwise + * @param {object} state - Global state tree + * @return {bool} true if currently linking a user, false otherwise */ export function isConnectingUser( state ) { return !! state.jetpack.connection.requests.connectingUser; @@ -296,11 +296,11 @@ export function isConnectingUser( state ) { /** * Returns the feature label the user connection where initiated from, if any. * - * @param {object} state - Global state tree - * @returns {string|null} string if feature label exists, false otherwise. + * @param {object} state - Global state tree + * @return {string|null} string if feature label exists, false otherwise. */ export function getConnectingUserFeatureLabel( state ) { - return state.jetpack.connection.requests.hasOwnProperty( 'connectingUserFeatureLabel' ) + return Object.hasOwn( state.jetpack.connection.requests, 'connectingUserFeatureLabel' ) ? state.jetpack.connection.requests.connectingUserFeatureLabel : null; } @@ -308,11 +308,11 @@ export function getConnectingUserFeatureLabel( state ) { /** * Returns the "from" value the user connection where initiated from, if any. * - * @param {object} state - Global state tree - * @returns {string|null} string if "from" value exists, false otherwise. + * @param {object} state - Global state tree + * @return {string|null} string if "from" value exists, false otherwise. */ export function getConnectingUserFrom( state ) { - return state.jetpack.connection.requests.hasOwnProperty( 'connectingUserFrom' ) + return Object.hasOwn( state.jetpack.connection.requests, 'connectingUserFrom' ) ? state.jetpack.connection.requests.connectingUserFrom : null; } @@ -320,7 +320,7 @@ export function getConnectingUserFrom( state ) { /** * Returns true if currently fetching user data * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {bool} true if currently fetching user data, false otherwise */ export function isFetchingUserData( state ) { @@ -330,7 +330,7 @@ export function isFetchingUserData( state ) { /** * Returns true if current user is linked to WordPress.com * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {bool} true if the current user is connected to WP.com, false otherwise */ export function isCurrentUserLinked( state ) { @@ -340,7 +340,7 @@ export function isCurrentUserLinked( state ) { /** * Returns true if current user is connection owner. * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {bool} true if the current user is connection owner, false otherwise */ export function isConnectionOwner( state ) { @@ -350,8 +350,8 @@ export function isConnectionOwner( state ) { /** * Returns true if the site has a connected owner. * - * @param {object} state - Global state tree - * @returns {boolean} true if the site has an owner connected, false otherwise + * @param {object} state - Global state tree + * @return {boolean} true if the site has an owner connected, false otherwise */ export function hasConnectedOwner( state ) { return get( state.jetpack.connection.status, [ 'siteConnected', 'hasConnectedOwner' ], false ); @@ -360,7 +360,7 @@ export function hasConnectedOwner( state ) { /** * Checks if the site is currently in offline mode. * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {boolean} True if site is in offline mode. False otherwise. */ export function isOfflineMode( state ) { @@ -370,7 +370,7 @@ export function isOfflineMode( state ) { /** * Checks if the site is currently in an Identity Crisis. * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {boolean} True if site is in IDC. False otherwise. */ export function isInIdentityCrisis( state ) { @@ -380,8 +380,8 @@ export function isInIdentityCrisis( state ) { /** * Checks if the module requires connection. * - * @param {Object} state Global state tree - * @param {String} slug Module slug. + * @param {Object} state Global state tree + * @param {String} slug Module slug. * @return {boolean} True if module requires connection. */ export function requiresConnection( state, slug ) { @@ -391,8 +391,8 @@ export function requiresConnection( state, slug ) { /** * Checks if the current module is unavailable in offline mode. * - * @param {Object} state Global state tree - * @param {String} module Module slug. + * @param {Object} state Global state tree + * @param {String} module Module slug. * @return {boolean} True if site is in offline mode and module requires connection. False otherwise. */ export function isUnavailableInOfflineMode( state, module ) { @@ -402,9 +402,9 @@ export function isUnavailableInOfflineMode( state, module ) { /** * Checks if the module requires user to be connected. * - * @param {object} state - Global state tree - * @param {string} slug - Module slug. - * @returns {boolean} True if module requires connection. + * @param {object} state - Global state tree + * @param {string} slug - Module slug. + * @return {boolean} True if module requires connection. */ export function requiresUserConnection( state, slug ) { return includes( getModulesThatRequireUserConnection( state ), slug ); @@ -413,9 +413,9 @@ export function requiresUserConnection( state, slug ) { /** * Checks if the current module is unavailable in Site Connection mode. * - * @param {object} state - Global state tree - * @param {string} module - Module slug. - * @returns {boolean} True if site is in Site Connection mode and module requires connection. False otherwise. + * @param {object} state - Global state tree + * @param {string} module - Module slug. + * @return {boolean} True if site is in Site Connection mode and module requires connection. False otherwise. */ export function isUnavailableInSiteConnectionMode( state, module ) { return ! hasConnectedOwner( state ) && requiresUserConnection( state, module ); @@ -424,7 +424,7 @@ export function isUnavailableInSiteConnectionMode( state, module ) { /** * Checks if the JETPACK__SANDBOX_DOMAIN is set * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {string} Value of the JETPACK__SANDBOX_DOMAIN constant. Empty string if not sandboxed - url if so. */ export function getSandboxDomain( state ) { @@ -434,7 +434,7 @@ export function getSandboxDomain( state ) { /** * Check if the reconnect requested. * - * @param {Object} state Global state tree. + * @param {Object} state Global state tree. * @return {boolean} True if the reconnecting is required, false otherwise. */ export function isReconnectingSite( state ) { @@ -445,7 +445,7 @@ export function isReconnectingSite( state ) { * Check if `hasSeenWCConnectionModal` (Jetpack option) is true. * * @param {object} state - Global state tree. - * @returns {boolean} If true, the site has already displayed the WooCommerce Connection Modal. + * @return {boolean} If true, the site has already displayed the WooCommerce Connection Modal. */ export function getHasSeenWCConnectionModal( state ) { return !! state.jetpack.connection.hasSeenWCConnectionModal; diff --git a/projects/plugins/jetpack/_inc/client/state/dev-version/reducer.js b/projects/plugins/jetpack/_inc/client/state/dev-version/reducer.js index 2ef651095884f..ae617c83cd865 100644 --- a/projects/plugins/jetpack/_inc/client/state/dev-version/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/dev-version/reducer.js @@ -19,7 +19,7 @@ export const reducer = combineReducers( { /** * Determines if the DevCard should be displayed. - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Boolean} whether the devCard can be displayed */ export function canDisplayDevCard( state ) { diff --git a/projects/plugins/jetpack/_inc/client/state/disconnect-survey/reducer.js b/projects/plugins/jetpack/_inc/client/state/disconnect-survey/reducer.js index 551ae75832342..0252f2f7dce9b 100644 --- a/projects/plugins/jetpack/_inc/client/state/disconnect-survey/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/disconnect-survey/reducer.js @@ -39,7 +39,7 @@ export const reducer = combineReducers( { /** * Returns true if currently trying to send a login email * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Boolean} Whether email is being sent */ export function isSubmittingDisconnectSurvey( state ) { @@ -49,7 +49,7 @@ export function isSubmittingDisconnectSurvey( state ) { /** * Returns true if a login email has been sent in the current state of the application. * - * @param {Object} state Global state tree. + * @param {Object} state Global state tree. * @return {Boolean} Whether email has been sent. */ export function hasSubmittedDisconnectSurvey( state ) { @@ -59,7 +59,7 @@ export function hasSubmittedDisconnectSurvey( state ) { /** * Returns an error object for the last magic login link or null. * - * @param {Object} state Global state tree. + * @param {Object} state Global state tree. * @return {Object|null} The error object if there is one. */ export function getDisconnectSurveySubmitError( state ) { diff --git a/projects/plugins/jetpack/_inc/client/state/initial-state/reducer.js b/projects/plugins/jetpack/_inc/client/state/initial-state/reducer.js index d9783f0ad1ad1..2ae0caf2a9f54 100644 --- a/projects/plugins/jetpack/_inc/client/state/initial-state/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/initial-state/reducer.js @@ -22,7 +22,7 @@ export const initialState = ( state = window.Initial_State, action ) => { * Returns bool if current version is Dev version * Which means -alpha, -beta, etc... * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {bool} true if dev version */ export function isDevVersion( state ) { @@ -33,7 +33,7 @@ export function isDevVersion( state ) { * Returns a string of the current Jetpack version defined * by JETPACK__VERSION * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {string} Version number. Empty string if the data is not yet available. */ export function getCurrentVersion( state ) { @@ -51,8 +51,8 @@ export function getInitialStateStatsData( state ) { /** * Returns an object of plugins that are using the Jetpack connection. * - * @param {object} state - Global state tree - * @returns {object} Plugins that are using the Jetpack connection. + * @param {object} state - Global state tree + * @return {object} Plugins that are using the Jetpack connection. */ export function getInitialStateConnectedPlugins( state ) { return get( state.jetpack.initialState, 'connectedPlugins', {} ); @@ -61,8 +61,8 @@ export function getInitialStateConnectedPlugins( state ) { /** * Returns the email address of the connected user if they are the current user. * - * @param {object} state - Global state tree - * @returns {string} The email address of the current user. . + * @param {object} state - Global state tree + * @return {string} The email address of the current user. . */ export function getAdminEmailAddress( state ) { return get( state.jetpack.initialState, [ 'userData', 'currentUser', 'wpcomUser', 'email' ] ); @@ -71,8 +71,8 @@ export function getAdminEmailAddress( state ) { /** * Returns the current users email address. * - * @param {object} state - Global state tree - * @returns {string} The email address of the current user. . + * @param {object} state - Global state tree + * @return {string} The email address of the current user. . */ export function getCurrenUserEmailAddress( state ) { return get( state.jetpack.initialState, [ 'userData', 'currentUser', 'email' ] ); @@ -161,7 +161,7 @@ export function userCanConnectSite( state ) { * * @param {object} state - Global state tree * - * @returns {boolean} Whether current user can connect their WordPress.com account. + * @return {boolean} Whether current user can connect their WordPress.com account. */ export function userCanConnectAccount( state ) { return get( state.jetpack.initialState.userData.currentUser.permissions, 'connect_user', false ); @@ -170,7 +170,7 @@ export function userCanConnectAccount( state ) { /** * Returns true if current user is connection owner. * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {bool} true if the current user is connection owner, false otherwise * * @deprecated 9.3.0 @@ -187,7 +187,7 @@ export function getUserWpComLogin( state ) { * Returns the WPCOM ID of the connected user. * * @param {object} state - Global state tree - * @returns {number} the ID of the user + * @return {number} the ID of the user */ export function getUserWpComId( state ) { return get( state.jetpack.initialState.userData.currentUser, [ 'wpcomUser', 'ID' ], '' ); @@ -211,7 +211,7 @@ export function getUsername( state ) { /** * Gets the current user display name. * @param {object} state - Global state tree - * @returns {string} The user display name. + * @return {string} The user display name. */ export function getDisplayName( state ) { const displayName = get( state.jetpack.initialState.userData.currentUser, [ 'displayName' ] ); @@ -224,7 +224,7 @@ export function getDisplayName( state ) { /** * Gets the current wp-admin user id * @param {Object} state Global state tree - * @returns {int} The user id in wp-admin + * @return {int} The user id in wp-admin */ export function getUserId( state ) { return get( state.jetpack.initialState.userData.currentUser, 'id', '' ); @@ -238,7 +238,7 @@ export function userCanViewStats( state ) { * Returns the WPCOM ID of a connected site. * * @param {object} state - Global state tree - * @returns {number} the ID of the site + * @return {number} the ID of the site */ export function getSiteId( state ) { return get( state.jetpack.initialState.siteData, [ 'blog_id' ] ); @@ -270,7 +270,7 @@ export function isSiteVisibleToSearchEngines( state ) { * Returns the site's boost speed scores from the last time it was checked * * @param {object} state - Global state tree - * @returns {object} the boost speed scores and timestamp + * @return {object} the boost speed scores and timestamp */ export function getLatestBoostSpeedScores( state ) { return get( state.jetpack.initialState.siteData, [ 'latestBoostSpeedScores' ] ); @@ -288,7 +288,7 @@ export function getApiRootUrl( state ) { * Returns the registration nonce. * * @param {object} state - Global state tree - * @returns {string} The registration nonce + * @return {string} The registration nonce */ export function getRegistrationNonce( state ) { return get( state.jetpack.initialState, 'registrationNonce' ); @@ -298,7 +298,7 @@ export function getRegistrationNonce( state ) { * Returns the plugin base URL. * * @param {object} state - Global state tree - * @returns {string} The registration nonce + * @return {string} The registration nonce */ export function getPluginBaseUrl( state ) { return get( state.jetpack.initialState, 'pluginBaseUrl' ); @@ -309,7 +309,7 @@ export function getPluginBaseUrl( state ) { * * @param {object} state - Global state tree * - * @returns {string|boolean} purchase token or false if not the connection owner. + * @return {string|boolean} purchase token or false if not the connection owner. */ export function getPurchaseToken( state ) { return get( state.jetpack.initialState, 'purchaseToken' ); @@ -320,7 +320,7 @@ export function getPurchaseToken( state ) { * * @param {object} state - Global state tree * - * @returns {string} Calypso environment name. + * @return {string} Calypso environment name. */ export function getCalypsoEnv( state ) { return get( state.jetpack.initialState, 'calypsoEnv' ); @@ -362,7 +362,7 @@ export function arePromotionsActive( state ) { * @todo Deprecated soon for isWoASite(); * @param {object} state - Global state tree. * - * @returns {boolean} True if this is an WoA site, false otherwise. + * @return {boolean} True if this is an WoA site, false otherwise. */ export function isAtomicSite( state ) { return get( state.jetpack.initialState.siteData, 'isAtomicSite', false ); @@ -372,7 +372,7 @@ export function isAtomicSite( state ) { * Check if the site is a WordPress.com-on-Atomic site. * * @param {object} state - Global state tree. - * @returns {boolean} True if this is an WoA site, false otherwise. + * @return {boolean} True if this is an WoA site, false otherwise. */ export function isWoASite( state ) { return get( state.jetpack.initialState.siteData, 'isWoASite', false ); @@ -382,7 +382,7 @@ export function isWoASite( state ) { * Check if the site is an Atomic-hosted site. * * @param {object} state - Global state tree. - * @returns {boolean} True if this is an Atomic-hosted site, false otherwise. + * @return {boolean} True if this is an Atomic-hosted site, false otherwise. */ export function isAtomicPlatform( state ) { return get( state.jetpack.initialState.siteData, 'isAtomicPlatform', false ); @@ -392,7 +392,7 @@ export function isAtomicPlatform( state ) { * Get the current theme's stylesheet (slug). * * @param {object} state - Global state tree. - * @returns {string} theme stylesheet, e.g. twentytwentythree. + * @return {string} theme stylesheet, e.g. twentytwentythree. */ export function currentThemeStylesheet( state ) { return get( state.jetpack.initialState.themeData, 'stylesheet' ); @@ -414,7 +414,7 @@ export function currentThemeSupports( state, feature ) { * Check that the current theme is a block theme. * * @param {object} state - Global state tree. - * @returns {boolean} True if the current theme is a block theme, false otherwise. + * @return {boolean} True if the current theme is a block theme, false otherwise. */ export function currentThemeIsBlockTheme( state ) { return get( state.jetpack.initialState.themeData, [ 'isBlockTheme' ], false ); @@ -436,7 +436,7 @@ export function showBackups( state ) { * * @param {object} state - Global state tree * - * @returns {boolean} True if the Jetpack Recommendations should be displayed, false otherwise. + * @return {boolean} True if the Jetpack Recommendations should be displayed, false otherwise. */ export function showRecommendations( state ) { return get( state.jetpack.initialState.siteData, 'showRecommendations', false ); @@ -446,7 +446,7 @@ export function showRecommendations( state ) { * Determines if My Jetpack should be referenced. * * @param {object} state - Global state tree - * @returns {boolean} True if the My Jetpack should be referenced, false otherwise. + * @return {boolean} True if the My Jetpack should be referenced, false otherwise. */ export function showMyJetpack( state ) { return get( state.jetpack.initialState.siteData, 'showMyJetpack', true ); @@ -456,7 +456,7 @@ export function showMyJetpack( state ) { * Get an array of new recommendations for this site * * @param {object} state - Global state tree - * @returns {Array} - Array of recommendation slugs + * @return {Array} - Array of recommendation slugs */ export function getNewRecommendations( state ) { return get( state.jetpack.initialState, 'newRecommendations', [] ); @@ -466,7 +466,7 @@ export function getNewRecommendations( state ) { * Get a count of new recommendations for this site * * @param {object} state - Global state tree - * @returns {number} - Count of recommendations + * @return {number} - Count of recommendations */ export function getNewRecommendationsCount( state ) { return getNewRecommendations( state ).length; @@ -477,7 +477,7 @@ export function getNewRecommendationsCount( state ) { * * @param {object} state - Global state tree * - * @returns {boolean} True if the Jetpack Licensing UI should be displayed, false otherwise. + * @return {boolean} True if the Jetpack Licensing UI should be displayed, false otherwise. */ export function showLicensingUi( state ) { return get( state.jetpack.initialState.licensing, 'showLicensingUi', false ); @@ -531,7 +531,7 @@ export function getPartnerSubsidiaryId( state ) { * Returns the partner coupon associated with this site, if any. * * @param {object} state - Global state tree - * @returns {object|boolean} partner coupon if exists or false. + * @return {object|boolean} partner coupon if exists or false. */ export function getPartnerCoupon( state ) { return get( state.jetpack.initialState, 'partnerCoupon' ); @@ -540,9 +540,9 @@ export function getPartnerCoupon( state ) { /** * Return an upgrade URL * - * @param {object} state - Global state tree - * @param {string} source - Context where this URL is clicked. - * @param {string} userId - Current user id. + * @param {object} state - Global state tree + * @param {string} source - Context where this URL is clicked. + * @param {string} userId - Current user id. * @param {boolean} planDuration - Add plan duration to the URL. * * @return {string} Upgrade URL with source, site, and affiliate code added. @@ -592,7 +592,7 @@ export const getUpgradeUrl = ( state, source, userId = '', planDuration = false * Returns the list of products that are available for purchase in the initial state. * * @param {object} state - Global state tree - * @returns {Array} - Array of Products that you can purchase. + * @return {Array} - Array of Products that you can purchase. */ export function getStaticProductsForPurchase( state ) { return get( state.jetpack.initialState, 'products', {} ); @@ -638,7 +638,7 @@ export function getProductsForPurchase( state ) { * * @param {*} state - Global state tree. * - * @returns {string} The current Recommendations step. + * @return {string} The current Recommendations step. */ export function getInitialRecommendationsStep( state ) { return get( state.jetpack.initialState, 'recommendationsStep', '' ); @@ -647,19 +647,19 @@ export function getInitialRecommendationsStep( state ) { /** * Get the connection errors. * - * @param {Object} state Global state tree. - * @returns {Array} Connection errors. + * @param {Object} state Global state tree. + * @return {Array} Connection errors. */ export function getConnectionErrors( state ) { return get( state.jetpack.initialState, [ 'connectionStatus', 'errors' ], [] ).filter( error => - error.hasOwnProperty( 'action' ) + Object.hasOwn( error, 'action' ) ); } /** * Check if the user is on Safari browser. * - * @param {Object} state Global state tree. + * @param {Object} state Global state tree. * * @return {boolean} True the user is on Safari browser. */ @@ -670,7 +670,7 @@ export function isSafari( state ) { /** * Check if the `JETPACK_SHOULD_NOT_USE_CONNECTION_IFRAME` constant is true. * - * @param {Object} state Global state tree. + * @param {Object} state Global state tree. * * @return {boolean} True, the `JETPACK_SHOULD_NOT_USE_CONNECTION_IFRAME` constant is true. */ @@ -682,7 +682,7 @@ export function doNotUseConnectionIframe( state ) { * Check if WooCommerce is currently installed and active * * @param {object} state - Global state tree. - * @returns {boolean} True, the plugin is installed and active + * @return {boolean} True, the plugin is installed and active */ export function isWooCommerceActive( state ) { return !! state.jetpack.initialState.isWooCommerceActive; @@ -692,8 +692,8 @@ export function isWooCommerceActive( state ) { * Returns the Jetpack Cloud URL for the specified resource for the current site. * * @param {object} state - Global state tree. - * @param {string} slug - Jetpack Cloud resource slug. - * @returns {string} The valid Jetpack Cloud URL + * @param {string} slug - Jetpack Cloud resource slug. + * @return {string} The valid Jetpack Cloud URL */ export function getJetpackCloudUrl( state, slug ) { return `https://cloud.jetpack.com/${ slug }/${ getSiteRawUrl( state ) }`; @@ -703,7 +703,7 @@ export function getJetpackCloudUrl( state, slug ) { * Returns if the new Stats experience is enabled. * * @param {object} state - Global state tree. - * @returns {boolean} True if the new Stats experience is enabled. + * @return {boolean} True if the new Stats experience is enabled. */ export function isOdysseyStatsEnabled( state ) { return !! state.jetpack.initialState.isOdysseyStatsEnabled; @@ -713,7 +713,7 @@ export function isOdysseyStatsEnabled( state ) { * Returns true if Blaze can be used on the site. * * @param {object} state - Global state tree. - * @returns {boolean} True if Blaze is available on the site. + * @return {boolean} True if Blaze is available on the site. */ export function shouldInitializeBlaze( state ) { return !! state.jetpack.initialState.shouldInitializeBlaze; @@ -723,7 +723,7 @@ export function shouldInitializeBlaze( state ) { * Returns true if the wp-admin Blaze dashboard is enabled. * * @param {object} state - Global state tree. - * @returns {boolean} True if the Blaze dashboard is enabled. + * @return {boolean} True if the Blaze dashboard is enabled. */ export function isBlazeDashboardEnabled( state ) { return !! state.jetpack.initialState.isBlazeDashboardEnabled; @@ -733,7 +733,7 @@ export function isBlazeDashboardEnabled( state ) { * Check if the Sharing block is available on the site. * * @param {object} state - Global state tree. - * @returns {boolean} True if the Sharing block is available on the site. + * @return {boolean} True if the Sharing block is available on the site. */ export function isSharingBlockAvailable( state ) { return !! state.jetpack.initialState.siteData.isSharingBlockAvailable; @@ -743,7 +743,7 @@ export function isSharingBlockAvailable( state ) { * Get the Jetpack Manage info * * @param {object} state - Global state tree. - * @returns {object} Jetpack Manage info + * @return {object} Jetpack Manage info */ export function getJetpackManageInfo( state ) { return state.jetpack.initialState.jetpackManage; @@ -753,7 +753,7 @@ export function getJetpackManageInfo( state ) { * Returns true if Subscription Site feature is enabled on the site. * * @param {object} state - Global state tree. - * @returns {boolean} True if Subscription Site feature is enabled on the site. + * @return {boolean} True if Subscription Site feature is enabled on the site. */ export function isSubscriptionSiteEnabled( state ) { return !! state.jetpack.initialState.isSubscriptionSiteEnabled; @@ -763,7 +763,7 @@ export function isSubscriptionSiteEnabled( state ) { * returns the newletter date example. * * @param {object} state - Global state tree. - * @returns {string} Newsletter date example. + * @return {string} Newsletter date example. */ export function getNewsetterDateExample( state ) { return state.jetpack.initialState.newsletterDateExample; @@ -773,7 +773,7 @@ export function getNewsetterDateExample( state ) { * Returns true if Subscription Site editing feature is supported. * * @param {object} state - Global state tree. - * @returns {boolean} True if Subscription Site editing feature is supported. + * @return {boolean} True if Subscription Site editing feature is supported. */ export function subscriptionSiteEditSupported( state ) { return !! state.jetpack.initialState.subscriptionSiteEditSupported; @@ -783,7 +783,7 @@ export function subscriptionSiteEditSupported( state ) { * Get the Jetpack Social Initial State * * @param {object} state - Global state tree. - * @returns {object} Jetpack Social Initial State + * @return {object} Jetpack Social Initial State */ export function getSocialInitiaState( state ) { return state.jetpack.initialState.socialInitialState ?? {}; diff --git a/projects/plugins/jetpack/_inc/client/state/intro-offers/reducer.js b/projects/plugins/jetpack/_inc/client/state/intro-offers/reducer.js index b88e1974c5837..0c6d965169140 100644 --- a/projects/plugins/jetpack/_inc/client/state/intro-offers/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/intro-offers/reducer.js @@ -34,8 +34,8 @@ export const reducer = combineReducers( { /** * Returns true if currently requesting site intro offers. Otherwise false. * - * @param {object} state - Global state tree - * @returns {boolean} Whether intro offers are being requested + * @param {object} state - Global state tree + * @return {boolean} Whether intro offers are being requested */ export function isFetchingIntroOffers( state ) { return !! state.jetpack.introOffers.requests.isFetching; @@ -44,8 +44,8 @@ export function isFetchingIntroOffers( state ) { /** * Returns intro offers. * - * @param {object} state - Global state tree - * @returns {object} Intro offers + * @param {object} state - Global state tree + * @return {object} Intro offers */ export function getIntroOffers( state ) { return state.jetpack.introOffers.data; diff --git a/projects/plugins/jetpack/_inc/client/state/jetpack-notices/reducer.js b/projects/plugins/jetpack/_inc/client/state/jetpack-notices/reducer.js index 9f7e606d0c315..91b56466056a3 100644 --- a/projects/plugins/jetpack/_inc/client/state/jetpack-notices/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/jetpack-notices/reducer.js @@ -41,7 +41,7 @@ export const reducer = combineReducers( { /** * Returns any Jetpack notice hooked onto 'jetpack_notices' in PHP * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {bool|string} False if no notice, string if there is. */ export function getJetpackNotices( state ) { @@ -51,7 +51,7 @@ export function getJetpackNotices( state ) { /** * Returns any Jetpack notice error code hooked onto 'jetpack_notices' in PHP * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {number} An error code. */ export function getJetpackStateNoticesErrorCode( state ) { @@ -61,7 +61,7 @@ export function getJetpackStateNoticesErrorCode( state ) { /** * Returns any Jetpack notice message code hooked onto 'jetpack_notices' in PHP * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {number} A message code. */ export function getJetpackStateNoticesMessageCode( state ) { @@ -81,7 +81,7 @@ export function getJetpackStateNoticesMessageContent( state ) { /** * Returns any Jetpack notice error description hooked onto 'jetpack_notices' in PHP * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {string} An error description. */ export function getJetpackStateNoticesErrorDescription( state ) { @@ -91,8 +91,8 @@ export function getJetpackStateNoticesErrorDescription( state ) { /** * Returns whether or not a Jetpack notice has been dismissed. * - * @param {Object} state Global state tree - * @param {String} notice_name Name of the jetpack notice to check for. + * @param {Object} state Global state tree + * @param {String} notice_name Name of the jetpack notice to check for. * @return {bool} False if notice is still active, True if it's been dismissed. */ export function isNoticeDismissed( state, notice_name ) { diff --git a/projects/plugins/jetpack/_inc/client/state/licensing/reducer.js b/projects/plugins/jetpack/_inc/client/state/licensing/reducer.js index 9e887976973e7..2fd7daa95d7ce 100644 --- a/projects/plugins/jetpack/_inc/client/state/licensing/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/licensing/reducer.js @@ -29,9 +29,9 @@ export const error = ( state = window.Initial_State.licensing.error, action ) => /** * "user" licenses counts reducer. * - * @param {number} state - Global state tree + * @param {number} state - Global state tree * @param {object} action - The action - * @returns {object} - The counts of user licenses + * @return {object} - The counts of user licenses */ export const userCounts = ( state = window.Initial_State.licensing.userCounts ?? {}, action ) => { switch ( action.type ) { @@ -46,9 +46,9 @@ export const userCounts = ( state = window.Initial_State.licensing.userCounts ?? /** * "user"-licenses activation notice dismissal info. * - * @param {number} state - Global state tree + * @param {number} state - Global state tree * @param {object} action - The action - * @returns {object} - The 'last_detached_count' and 'last_dismissed_time' + * @return {object} - The 'last_detached_count' and 'last_dismissed_time' */ export const activationNoticeDismiss = ( state = window.Initial_State.licensing.activationNoticeDismiss ?? { @@ -69,9 +69,9 @@ export const activationNoticeDismiss = ( /** * "user"-licenses. * - * @param {number} state - Global state tree + * @param {number} state - Global state tree * @param {object} action - The action - * @returns {object} - The 'items' and 'loading' state + * @return {object} - The 'items' and 'loading' state */ export const licenses = ( state = window.Initial_State.licensing.licenses ?? { @@ -116,7 +116,7 @@ export const reducer = combineReducers( { * Get the latest licensing error, if any. * * @param {Object} state - Global state tree. - * @returns {string} - Error message or an empty string. + * @return {string} - Error message or an empty string. */ export function getLicensingError( state ) { return get( state.jetpack.licensing, [ 'error' ], '' ); @@ -126,7 +126,7 @@ export function getLicensingError( state ) { * Determines if the user has detached "user" licenses available for product activation. * * @param {object} state - Global state tree. - * @returns {boolean} - True if the user has detached user licenses, false otherwise. + * @return {boolean} - True if the user has detached user licenses, false otherwise. */ export function hasDetachedUserLicenses( state ) { return !! get( state.jetpack.licensing.userCounts, [ 'detached' ], 0 ); @@ -136,7 +136,7 @@ export function hasDetachedUserLicenses( state ) { * Get the licenses * * @param {object} state - Global state tree. - * @returns {Array} - An array containing all the detached licenses + * @return {Array} - An array containing all the detached licenses */ export function getDetachedLicenses( state ) { const allLicenses = get( state.jetpack.licensing.licenses, [ 'items' ], {} ); @@ -147,7 +147,7 @@ export function getDetachedLicenses( state ) { * Get the license loading info * * @param {object} state - Global state tree. - * @returns {boolean} - A boolean value of loading state of licenses + * @return {boolean} - A boolean value of loading state of licenses */ export function getDetachedLicensesLoadingInfo( state ) { return get( state.jetpack.licensing.licenses, [ 'loading' ], false ); @@ -157,7 +157,7 @@ export function getDetachedLicensesLoadingInfo( state ) { * Get the user's number of detached licenses. * * @param {object} state - Global state tree. - * @returns {number} - Number of detached licenses. + * @return {number} - Number of detached licenses. */ export function getDetachedLicensesCount( state ) { return get( state.jetpack.licensing.userCounts, [ 'detached' ], 0 ); @@ -167,7 +167,7 @@ export function getDetachedLicensesCount( state ) { * Get the license activation notice dismiss info. * * @param {object} state - Global state tree. - * @returns {object} - An object containing last_detached_count and last_dismissed_time. + * @return {object} - An object containing last_detached_count and last_dismissed_time. */ export function getActivationNoticeDismissInfo( state ) { return get( state.jetpack.licensing, [ 'activationNoticeDismiss' ], {} ); diff --git a/projects/plugins/jetpack/_inc/client/state/modules/reducer.js b/projects/plugins/jetpack/_inc/client/state/modules/reducer.js index f213fa6069f1d..5599dc44292ba 100644 --- a/projects/plugins/jetpack/_inc/client/state/modules/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/modules/reducer.js @@ -117,7 +117,7 @@ export const reducer = combineReducers( { * Returns true if currently requesting modules lists or false * otherwise. * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Boolean} Whether modules are being requested */ export function isFetchingModulesList( state ) { @@ -127,8 +127,8 @@ export function isFetchingModulesList( state ) { /** * Returns true if we are currently making a request to activate a module * - * @param {Object} state Global state tree - * @param {String} name module name + * @param {Object} state Global state tree + * @param {String} name module name * @return {Boolean} Whether module is being activated */ export function isActivatingModule( state, name ) { @@ -138,8 +138,8 @@ export function isActivatingModule( state, name ) { /** * Returns true if we are currently making a request to deactivate a module * - * @param {Object} state Global state tree - * @param {String} name module name + * @param {Object} state Global state tree + * @param {String} name module name * @return {Boolean} Whether module is being deactivated */ export function isDeactivatingModule( state, name ) { @@ -149,9 +149,9 @@ export function isDeactivatingModule( state, name ) { /** * Returns true if we are currently making a request to update a module's option * - * @param {Object} state Global state tree - * @param {String} module_slug slug of the module to check - * @param {String} option_name option key to check if currently updating + * @param {Object} state Global state tree + * @param {String} module_slug slug of the module to check + * @param {String} option_name option key to check if currently updating * @return {Boolean} Whether option is being updated on the module */ export function isUpdatingModuleOption( state, module_slug, option_name ) { @@ -170,9 +170,9 @@ export function getModuleOption( state, module_slug, option_name ) { /** * Return a list of key & value pairs admitted. * - * @param {Object} state Global state tree. - * @param {String} group Slug of the set of settings to check. - * @param {String} setting Setting to check for valid values. + * @param {Object} state Global state tree. + * @param {String} group Slug of the set of settings to check. + * @param {String} setting Setting to check for valid values. * @return {Array} The list of key => value pairs. */ export function getModuleOptionValidValues( state, group, setting ) { @@ -181,7 +181,7 @@ export function getModuleOptionValidValues( state, group, setting ) { /** * Returns an object with jetpack modules descriptions keyed by module name - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Object} Modules keyed by module name */ export function getModules( state ) { @@ -191,8 +191,8 @@ export function getModules( state ) { /** * Returns an array of module slugs for all active modules on the site. * - * @param {object} state - Global state tree - * @returns {Array} Array of module slugs. + * @param {object} state - Global state tree + * @return {Array} Array of module slugs. */ export function getActiveModules( state ) { return Object.keys( state.jetpack.modules.items ).filter( @@ -202,8 +202,8 @@ export function getActiveModules( state ) { /** * Returns a module object by its name as present in the state - * @param {Object} state Global state tree - * @param {String} name module name + * @param {Object} state Global state tree + * @param {String} name module name * @return {Object} Module description */ export function getModule( state, name ) { @@ -215,8 +215,8 @@ export function getModule( state, name ) { * * Module features are defined in the module's header comments * - * @param {Object} state Global state tree - * @param {String} feature Feature to select + * @param {Object} state Global state tree + * @param {String} feature Feature to select * @return {Array} Array of modules that match the feature. */ export function getModulesByFeature( state, feature ) { @@ -230,7 +230,7 @@ export function getModulesByFeature( state, feature ) { * * The module's header comments indicates if it requires connection or not. * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Array} Array of modules that require connection. */ export function getModulesThatRequireConnection( state ) { @@ -244,8 +244,8 @@ export function getModulesThatRequireConnection( state ) { * * The module's header comments indicates if it requires user connection or not. * - * @param {object} state - Global state tree - * @returns {Array} Array of modules that require user connection. + * @param {object} state - Global state tree + * @return {Array} Array of modules that require user connection. */ export function getModulesThatRequireUserConnection( state ) { return Object.keys( state.jetpack.modules.items ).filter( @@ -256,8 +256,8 @@ export function getModulesThatRequireUserConnection( state ) { /** * Check that the module list includes at least one of these modules. * - * @param {Object} state Global state tree - * @param {array} modules Modules that are probably included in the module list. + * @param {Object} state Global state tree + * @param {array} modules Modules that are probably included in the module list. * * @return {boolean} True if at least one of the modules is included in the list. */ @@ -269,9 +269,9 @@ export function hasAnyOfTheseModules( state, modules = [] ) { /** * Check that the site has any of the performance features available. * - * @param {object} state - Global state tree + * @param {object} state - Global state tree * - * @returns {boolean} True if at least one of the performance features is available + * @return {boolean} True if at least one of the performance features is available */ export function hasAnyPerformanceFeature( state ) { return hasAnyOfTheseModules( state, [ @@ -286,7 +286,7 @@ export function hasAnyPerformanceFeature( state ) { /** * Check that the site has any of the security features available. * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * * @return {boolean} True if at least one of the security features is available. */ @@ -298,8 +298,8 @@ export function hasAnySecurityFeature( state ) { } /** * Returns true if the module is activated - * @param {Object} state Global state tree - * @param {String} name A module's name + * @param {Object} state Global state tree + * @param {String} name A module's name * @return {Boolean} Weather a module is activated */ export function isModuleActivated( state, name ) { @@ -308,8 +308,8 @@ export function isModuleActivated( state, name ) { /** * Returns true if the module is available. - * @param {Object} state Global state tree. - * @param {String} moduleSlug The slug of a module. + * @param {Object} state Global state tree. + * @param {String} moduleSlug The slug of a module. * @return {Boolean} Whether a module is available to be displayed in the dashboard. */ export function isModuleAvailable( state, moduleSlug ) { @@ -333,8 +333,8 @@ export function getModuleOverride( state, name ) { /** * Returns true if the module is forced to be active. - * @param {Object} state Global state tree - * @param {String} name A module's name + * @param {Object} state Global state tree + * @param {String} name A module's name * @return {Boolean} Whether the module is forced to be active. */ export function isModuleForcedActive( state, name ) { @@ -343,8 +343,8 @@ export function isModuleForcedActive( state, name ) { /** * Returns true if the module is forced to be inactive. - * @param {Object} state Global state tree - * @param {String} name A module's name + * @param {Object} state Global state tree + * @param {String} name A module's name * @return {Boolean} Whether the module is forced to be inactive. */ export function isModuleForcedInactive( state, name ) { diff --git a/projects/plugins/jetpack/_inc/client/state/plans/reducer.js b/projects/plugins/jetpack/_inc/client/state/plans/reducer.js index e2c3c61682367..f1ab6dc05863b 100644 --- a/projects/plugins/jetpack/_inc/client/state/plans/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/plans/reducer.js @@ -17,7 +17,7 @@ export const reducer = combineReducers( { /** * Determines if the DevCard should be displayed. - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Boolean} whether the devCard can be displayed */ export function getPlanDuration( state ) { diff --git a/projects/plugins/jetpack/_inc/client/state/products/reducer.js b/projects/plugins/jetpack/_inc/client/state/products/reducer.js index d51e2ccdd612c..a9126d5e5b30c 100644 --- a/projects/plugins/jetpack/_inc/client/state/products/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/products/reducer.js @@ -40,7 +40,7 @@ export const reducer = combineReducers( { /** * Returns true if currently requesting products. Otherwise false. * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Boolean} Whether products are being requested */ export function isFetchingProducts( state ) { @@ -49,7 +49,7 @@ export function isFetchingProducts( state ) { /** * Returns WP.com products that are relevant to Jetpack. - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Object} Products */ export function getProducts( state ) { diff --git a/projects/plugins/jetpack/_inc/client/state/publicize/reducer.js b/projects/plugins/jetpack/_inc/client/state/publicize/reducer.js index 8e0ba80617816..7250b567bac1d 100644 --- a/projects/plugins/jetpack/_inc/client/state/publicize/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/publicize/reducer.js @@ -18,8 +18,8 @@ export const reducer = combineReducers( { /** * Return a connect url for a given service name. * - * @param {Object} state Global state tree. - * @param {String} serviceName Name of the external service. + * @param {Object} state Global state tree. + * @param {String} serviceName Name of the external service. * @return {String} Url to connect to the service or null. */ export function getExternalServiceConnectUrl( state, serviceName ) { diff --git a/projects/plugins/jetpack/_inc/client/state/recommendations/onboarding-utils.ts b/projects/plugins/jetpack/_inc/client/state/recommendations/onboarding-utils.ts index 9ba4f779b5417..7e4096115fb84 100644 --- a/projects/plugins/jetpack/_inc/client/state/recommendations/onboarding-utils.ts +++ b/projects/plugins/jetpack/_inc/client/state/recommendations/onboarding-utils.ts @@ -4,7 +4,7 @@ import { ONBOARDING_NAME_BY_PRODUCT_SLUG, ONBOARDING_ORDER } from '../../recomme * Function to get an onboarding for the specific product * * @param {string} productSlug - slug of the product - * @returns {string} onboarding name or null if onboarding not found + * @return {string} onboarding name or null if onboarding not found */ export function getOnboardingNameByProductSlug( productSlug: string ) { const foundIndex = Object.values( ONBOARDING_NAME_BY_PRODUCT_SLUG ).findIndex( slugs => @@ -22,7 +22,7 @@ export function getOnboardingNameByProductSlug( productSlug: string ) { * Function to get an onboarding priority * * @param {string} name - onboarding name - * @returns {number} the onboarding priority + * @return {number} the onboarding priority * @throws exception when the requested onboarding is not in the ONBOARDING_ORDER array. */ function getOnboardingPriority( name: string ) { @@ -40,7 +40,7 @@ function getOnboardingPriority( name: string ) { * * @param {string} a - left Onboarding name to compare * @param {string} b - right Onboarding name to compare - * @returns {number} Value ( -1, 0, 1) to sort array in descending order + * @return {number} Value ( -1, 0, 1) to sort array in descending order */ export function sortByOnboardingPriority( a: string, b: string ) { return getOnboardingPriority( a ) - getOnboardingPriority( b ); diff --git a/projects/plugins/jetpack/_inc/client/state/redux-store-minimal.js b/projects/plugins/jetpack/_inc/client/state/redux-store-minimal.js index 5b9fcc0871b3f..2d734210352ec 100644 --- a/projects/plugins/jetpack/_inc/client/state/redux-store-minimal.js +++ b/projects/plugins/jetpack/_inc/client/state/redux-store-minimal.js @@ -7,7 +7,7 @@ export default createJetpackStore(); /** * Creates redux store * - * @returns {object} store + * @return {object} store */ function createJetpackStore() { const finalCreateStore = compose( diff --git a/projects/plugins/jetpack/_inc/client/state/redux-store.js b/projects/plugins/jetpack/_inc/client/state/redux-store.js index 228373ab0fd21..aba3ce16c4d3a 100644 --- a/projects/plugins/jetpack/_inc/client/state/redux-store.js +++ b/projects/plugins/jetpack/_inc/client/state/redux-store.js @@ -7,7 +7,7 @@ export default createJetpackStore(); /** * Creates redux store * - * @returns {object} store + * @return {object} store */ function createJetpackStore() { const finalCreateStore = compose( diff --git a/projects/plugins/jetpack/_inc/client/state/rewind/preflight/selectors.js b/projects/plugins/jetpack/_inc/client/state/rewind/preflight/selectors.js index aaf9c6aa1d469..10b827c0372da 100644 --- a/projects/plugins/jetpack/_inc/client/state/rewind/preflight/selectors.js +++ b/projects/plugins/jetpack/_inc/client/state/rewind/preflight/selectors.js @@ -3,7 +3,7 @@ import { PreflightTestStatus } from './constants'; /** * Returns the current status of the preflight tests. * @param {object} state - State tree - * @returns {Array} Preflight statuses + * @return {Array} Preflight statuses */ export const getPreflightStatus = state => { if ( ! state.jetpack.rewind.preflight.featureEnabled ) { @@ -16,8 +16,8 @@ export const getPreflightStatus = state => { /** * Returns true if currently requesting preflight tests. * - * @param {object} state - State tree - * @returns {boolean} Whether preflight status is being requested + * @param {object} state - State tree + * @return {boolean} Whether preflight status is being requested */ export function isFetchingPreflightStatus( state ) { return state.jetpack.rewind.preflight.isFetching; @@ -26,8 +26,8 @@ export function isFetchingPreflightStatus( state ) { /** * Returns true if preflight tests has loaded. * - * @param {object} state - State tree - * @returns {boolean} Whether preflight status has been loaded + * @param {object} state - State tree + * @return {boolean} Whether preflight status has been loaded */ export function hasLoadedPreflightStatus( state ) { return state.jetpack.rewind.preflight.hasLoaded; diff --git a/projects/plugins/jetpack/_inc/client/state/rewind/preflight/utils.js b/projects/plugins/jetpack/_inc/client/state/rewind/preflight/utils.js index 7c16a1f47b4bb..b5aecb4f9e800 100644 --- a/projects/plugins/jetpack/_inc/client/state/rewind/preflight/utils.js +++ b/projects/plugins/jetpack/_inc/client/state/rewind/preflight/utils.js @@ -9,7 +9,7 @@ import { PreflightTestStatus } from './constants'; * - If all tests are successful, the overall status is SUCCESS. * - If none of the above conditions are met, the overall status defaults to PENDING. * @param {Array} tests - An array of PreflightTest objects. - * @returns {string} The overall status as a string. + * @return {string} The overall status as a string. */ export const calculateOverallStatus = tests => { // If there are no tests, the overall status is PENDING. diff --git a/projects/plugins/jetpack/_inc/client/state/rewind/reducer.js b/projects/plugins/jetpack/_inc/client/state/rewind/reducer.js index 0d589c1bed996..40ed4074c8fda 100644 --- a/projects/plugins/jetpack/_inc/client/state/rewind/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/rewind/reducer.js @@ -49,7 +49,7 @@ export const reducer = combineReducers( { * Returns true if currently requesting rewind status. Otherwise false. * otherwise. * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Boolean} Whether rewind status is being requested */ export function isFetchingRewindStatus( state ) { @@ -58,7 +58,7 @@ export function isFetchingRewindStatus( state ) { /** * Returns the current status of rewind - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Object} Features */ export function getRewindStatus( state ) { diff --git a/projects/plugins/jetpack/_inc/client/state/scan/reducer.js b/projects/plugins/jetpack/_inc/client/state/scan/reducer.js index 854af6873cb3c..c65df3255ad96 100644 --- a/projects/plugins/jetpack/_inc/client/state/scan/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/scan/reducer.js @@ -51,8 +51,8 @@ export const reducer = combineReducers( { /** * Returns true if currently requesting scan. status. Otherwise false. * - * @param {object} state - Global state tree - * @returns {boolean} Whether rewind status is being requested + * @param {object} state - Global state tree + * @return {boolean} Whether rewind status is being requested */ export function isFetchingScanStatus( state ) { return !! state.jetpack.scan.requests.isFetchingScanStatus; @@ -61,8 +61,8 @@ export function isFetchingScanStatus( state ) { /** * Returns the current status of scan. * - * @param {object} state - Global state tree - * @returns {object} Features + * @param {object} state - Global state tree + * @return {object} Features */ export function getScanStatus( state ) { return get( state.jetpack.scan, [ 'data', 'status' ], {} ); diff --git a/projects/plugins/jetpack/_inc/client/state/search/reducer.js b/projects/plugins/jetpack/_inc/client/state/search/reducer.js index 989ac1d2d23b4..0f9cd32ffc9ec 100644 --- a/projects/plugins/jetpack/_inc/client/state/search/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/search/reducer.js @@ -19,7 +19,7 @@ export const reducer = combineReducers( { /** * Returns the Search Term * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {string} The current term being searched */ export function getSearchTerm( state ) { @@ -29,8 +29,8 @@ export function getSearchTerm( state ) { /** * Returns the module found status * - * @param {Object} state Global state tree - * @param {String} module The module slug + * @param {Object} state Global state tree + * @param {String} module The module slug * @return {Boolean} Whether the module should be in the search results */ export function isModuleFound( state, module ) { diff --git a/projects/plugins/jetpack/_inc/client/state/settings/actions.js b/projects/plugins/jetpack/_inc/client/state/settings/actions.js index 693e5806dea12..31f7de3637794 100644 --- a/projects/plugins/jetpack/_inc/client/state/settings/actions.js +++ b/projects/plugins/jetpack/_inc/client/state/settings/actions.js @@ -171,9 +171,9 @@ export const updateSettings = ( newOptionValues, noticeMessages = {} ) => { /** * Maps the response from the API for handling special cases * like with regeneration of Post By Email where we need the new address from the response - * @param {object} success The JSON response from the API + * @param {object} success The JSON response from the API * @param {object} requestedValues The object holding the requested value changes for settings. - * @returns {object} The mapped object. + * @return {object} The mapped object. */ function mapUpdateSettingsResponseFromApi( success, requestedValues ) { let values = requestedValues; diff --git a/projects/plugins/jetpack/_inc/client/state/settings/reducer.js b/projects/plugins/jetpack/_inc/client/state/settings/reducer.js index 04657b62668dc..bb6f2d05225f6 100644 --- a/projects/plugins/jetpack/_inc/client/state/settings/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/settings/reducer.js @@ -88,7 +88,7 @@ export const reducer = combineReducers( { /** * Returns an object with Jetpack settings keyed by setting name. - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Object} Settings keyed by setting name */ export function getSettings( state ) { @@ -97,10 +97,10 @@ export function getSettings( state ) { /** * Returns a value of a certain setting - * @param {Object} state Global state tree - * @param {String} key Name of setting or module option to return. - * @param {String} moduleName If present, it will check if the module is active before returning it. - * @param {boolean} ignoreDisabledModules - Whether to ignore settings for disabled modules. + * @param {Object} state Global state tree + * @param {String} key Name of setting or module option to return. + * @param {String} moduleName If present, it will check if the module is active before returning it. + * @param {boolean} ignoreDisabledModules - Whether to ignore settings for disabled modules. * @return {undefined|*} Settings value or undefined if a module was specified and it wasn't active. */ export function getSetting( state, key, moduleName = '', ignoreDisabledModules = true ) { @@ -118,7 +118,7 @@ export function getSetting( state, key, moduleName = '', ignoreDisabledModules = * Returns true if currently requesting settings lists or false * otherwise. * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Boolean} Whether settings are being requested */ export function isFetchingSettingsList( state ) { @@ -128,8 +128,8 @@ export function isFetchingSettingsList( state ) { /** * Returns true if we are currently making a request to update a setting's option * - * @param {Object} state Global state tree - * @param {String|Array} settings Single or multiple settings to check if they're being saved or not. + * @param {Object} state Global state tree + * @param {String|Array} settings Single or multiple settings to check if they're being saved or not. * @return {Boolean} Whether option is being updated on the setting */ export function isUpdatingSetting( state, settings = '' ) { @@ -147,8 +147,8 @@ export function isUpdatingSetting( state, settings = '' ) { /** * Returns true if we successfully updated a setting * - * @param {Object} state Global state tree - * @param {String} setting A setting name + * @param {Object} state Global state tree + * @param {String} setting A setting name * @return {Boolean|undefined} Whether the option has been updated successfully. Undefined if an attempt has not yet been made. */ export function hasUpdatedSetting( state, setting = '' ) { @@ -157,8 +157,8 @@ export function hasUpdatedSetting( state, setting = '' ) { /** * Returns true if the setting is "checked". - * @param {Object} state Global state tree - * @param {String} name A setting's name + * @param {Object} state Global state tree + * @param {String} name A setting's name * @return {Boolean} Whether a setting is checked */ export function isSettingActivated( state, name ) { @@ -167,8 +167,8 @@ export function isSettingActivated( state, name ) { /** * Returns true if the setting is "checked". - * @param {Object} state Global state tree - * @param {String} name A setting's name + * @param {Object} state Global state tree + * @param {String} name A setting's name * @return {Boolean} Whether a setting is checked */ export function toggleSetting( state, name ) { @@ -177,7 +177,7 @@ export function toggleSetting( state, name ) { /** * Returns true if there are unsaved settings. - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Boolean} Whether there are unsaved settings */ export function areThereUnsavedSettings( state ) { @@ -186,7 +186,7 @@ export function areThereUnsavedSettings( state ) { /** * Returns true if Empty Stats card has been dismissed. - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Boolean} Whether the card has been dismissed */ export function emptyStatsCardDismissed( state ) { @@ -196,8 +196,8 @@ export function emptyStatsCardDismissed( state ) { /** * Returns true if Backup Getting Started card has been dismissed. * - * @param {Object} state - Global state tree - * @returns {boolean} Whether the card has been dismissed + * @param {Object} state - Global state tree + * @return {boolean} Whether the card has been dismissed */ export function backupGettingStartedDismissed( state ) { return get( state.jetpack.settings.items, 'dismiss_dash_backup_getting_started', false ); @@ -207,7 +207,7 @@ export function backupGettingStartedDismissed( state ) { * Returns true if Agencies Learn More card has been dismissed. * * @param {Object} state - Global state tree - * @returns {boolean} Whether the card has been dismissed + * @return {boolean} Whether the card has been dismissed */ export function agenciesLearnMoreDismissed( state ) { return get( state.jetpack.settings.items, 'dismiss_dash_agencies_learn_more', false ); diff --git a/projects/plugins/jetpack/_inc/client/state/site-products/reducer.js b/projects/plugins/jetpack/_inc/client/state/site-products/reducer.js index 09ed4b6f13f75..1f02885d9e52c 100644 --- a/projects/plugins/jetpack/_inc/client/state/site-products/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/site-products/reducer.js @@ -34,8 +34,8 @@ export const reducer = combineReducers( { /** * Returns true if currently requesting site products. Otherwise false. * - * @param {object} state - Global state tree - * @returns {boolean} Whether site products are being requested + * @param {object} state - Global state tree + * @return {boolean} Whether site products are being requested */ export function isFetchingSiteProducts( state ) { return !! state.jetpack.siteProducts.requests.isFetching; @@ -44,8 +44,8 @@ export function isFetchingSiteProducts( state ) { /** * Returns WP.com site products that are relevant to Jetpack. * - * @param {object} state - Global state tree - * @returns {object} Site products + * @param {object} state - Global state tree + * @return {object} Site products */ export function getSiteProducts( state ) { return state.jetpack.siteProducts.items; @@ -54,9 +54,9 @@ export function getSiteProducts( state ) { /** * Returns a Jetpack product if it exists in the state. * - * @param {object} state - Global state tree - * @param {string} slug - Product slug - * @returns {object} Product + * @param {object} state - Global state tree + * @param {string} slug - Product slug + * @return {object} Product */ export function getSiteProduct( state, slug ) { return state.jetpack.siteProducts.items?.[ slug ]; @@ -67,9 +67,9 @@ export function getSiteProduct( state, slug ) { * * @see pbNhbs-53E-p2 * @todo Fix how we calculate the price in the future. - * @param {object} state - Global state tree - * @param {string} slug - Product slug - * @returns {number} Monthly cost of a product + * @param {object} state - Global state tree + * @param {string} slug - Product slug + * @return {number} Monthly cost of a product */ export function getSiteProductMonthlyCost( state, slug ) { const product = getSiteProduct( state, slug ); @@ -81,9 +81,9 @@ export function getSiteProductMonthlyCost( state, slug ) { /** * Returns the discount of a product price. It bases the discount on intro offers with a yearly interval * - * @param {object} state - Global state tree - * @param {string} slug - Product slug - * @returns {number} Discount of a product price or 0 if there is no discount + * @param {object} state - Global state tree + * @param {string} slug - Product slug + * @return {number} Discount of a product price or 0 if there is no discount */ export function getSiteProductYearlyDiscount( state, slug ) { const product = getSiteProduct( state, slug ); diff --git a/projects/plugins/jetpack/_inc/client/state/site-verify/reducer.js b/projects/plugins/jetpack/_inc/client/state/site-verify/reducer.js index 0cf748b341881..cbf90c131e644 100644 --- a/projects/plugins/jetpack/_inc/client/state/site-verify/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/site-verify/reducer.js @@ -65,7 +65,7 @@ export const reducer = combineReducers( { * Returns true if currently requesting settings lists or false * otherwise. * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Boolean} Whether settings are being requested */ export function isFetchingGoogleSiteVerify( state ) { @@ -76,7 +76,7 @@ export function isFetchingGoogleSiteVerify( state ) { * Returns true if currently verifying a site or false * otherwise. * - * @param {Object} state Global state tree + * @param {Object} state Global state tree * @return {Boolean} Whether settings is being verified */ export function isVerifyingGoogleSite( state ) { diff --git a/projects/plugins/jetpack/_inc/client/state/site/plugins/reducer.js b/projects/plugins/jetpack/_inc/client/state/site/plugins/reducer.js index d4d3873735065..3ae0fc97c1c2c 100644 --- a/projects/plugins/jetpack/_inc/client/state/site/plugins/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/site/plugins/reducer.js @@ -46,7 +46,7 @@ export const reducer = combineReducers( { * otherwise. * * @param {object} state - Global state tree - * @returns {boolean} - Whether plugin data is being requested + * @return {boolean} - Whether plugin data is being requested */ export function isFetchingPluginsData( state ) { return !! state.jetpack.pluginsData.requests.isFetchingPluginsData; @@ -56,7 +56,7 @@ export function isFetchingPluginsData( state ) { * Returns the site plugins data * * @param {object} state - Global state tree - * @returns {boolean} - The plugins data + * @return {boolean} - The plugins data */ export function getPluginsData( state ) { return state.jetpack.pluginsData.items; @@ -65,9 +65,9 @@ export function getPluginsData( state ) { /** * Returns whether the plugin is active or not. * - * @param {object} state - Global state tree - * @param {string} plugin - Slug of plugin to check. - * @returns {boolean} True if plugin is active, false otherwise. + * @param {object} state - Global state tree + * @param {string} plugin - Slug of plugin to check. + * @return {boolean} True if plugin is active, false otherwise. */ export function isPluginActive( state, plugin ) { return ( @@ -78,9 +78,9 @@ export function isPluginActive( state, plugin ) { /** * Returns whether the plugin is installed or not. * - * @param {object} state - Global state tree - * @param {string} plugin - Slug of plugin to check. - * @returns {boolean} True if plugin is installed, false otherwise. + * @param {object} state - Global state tree + * @param {string} plugin - Slug of plugin to check. + * @return {boolean} True if plugin is installed, false otherwise. */ export function isPluginInstalled( state, plugin ) { return !! state.jetpack.pluginsData.items[ plugin ]; diff --git a/projects/plugins/jetpack/_inc/client/state/site/reducer.js b/projects/plugins/jetpack/_inc/client/state/site/reducer.js index c7fd41dba09d6..d74135abe1cd5 100644 --- a/projects/plugins/jetpack/_inc/client/state/site/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/site/reducer.js @@ -47,6 +47,7 @@ export const data = ( state = {}, action ) => { if ( action.siteDiscount?.code ) { return merge( {}, state, { site: { discount: action.siteDiscount } } ); } + return state; case JETPACK_SITE_CONNECTED_PLUGINS_FETCH_RECEIVE: return merge( {}, state, { site: { connectedPlugins: action.connectedPlugins } } ); case JETPACK_SITE_FEATURES_FETCH_RECEIVE: @@ -166,14 +167,14 @@ export const errors = ( state = {}, action ) => { } return assign( {}, state, { - message: action.error.hasOwnProperty( 'response' ) + message: Object.hasOwn( action.error, 'response' ) ? action.error.response.message : defaultErrorMessage, action: resolveAction, - code: action.error.hasOwnProperty( 'response' ) + code: Object.hasOwn( action.error, 'response' ) ? action.error.response.code : 'fetch_site_data_fail_other', - data: action.error.hasOwnProperty( 'response' ) ? action.error.response.data : {}, + data: Object.hasOwn( action.error, 'response' ) ? action.error.response.data : {}, } ); default: return state; @@ -189,8 +190,8 @@ export const reducer = combineReducers( { /** * Returns an object of the siteData errors * - * @param {object} state - Global state tree - * @returns {object} Error object + * @param {object} state - Global state tree + * @return {object} Error object */ export function getSiteDataErrors( state ) { return [ get( state.jetpack.siteData, [ 'errors' ], [] ) ]; @@ -199,8 +200,8 @@ export function getSiteDataErrors( state ) { /** * Returns true if currently requesting site data. Otherwise false. * - * @param {object} state - Global state tree - * @returns {boolean} Whether site data is being requested + * @param {object} state - Global state tree + * @return {boolean} Whether site data is being requested */ export function isFetchingSiteData( state ) { return !! ( @@ -214,8 +215,8 @@ export function isFetchingSiteData( state ) { /** * Returns true if currently requesting site benefits. Otherwise false. * - * @param {object} state - Global state tree - * @returns {boolean} Whether benefits are being requested + * @param {object} state - Global state tree + * @return {boolean} Whether benefits are being requested */ export function isFetchingSiteBenefits( state ) { return !! state.jetpack.siteData.requests.isFetchingSiteBenefits; @@ -224,8 +225,8 @@ export function isFetchingSiteBenefits( state ) { /** * Returns true if currently requesting site discount. Otherwise false. * - * @param {object} state - Global state tree - * @returns {boolean} Whether discount is being requested + * @param {object} state - Global state tree + * @return {boolean} Whether discount is being requested */ export function isFetchingSiteDiscount( state ) { return !! state.jetpack.siteData.requests.isFetchingSiteDiscount; @@ -234,8 +235,8 @@ export function isFetchingSiteDiscount( state ) { /** * Returns true if currently requesting connected plugins. Otherwise false. * - * @param {object} state - Global state tree - * @returns {boolean} Whether connected plugins are being requested + * @param {object} state - Global state tree + * @return {boolean} Whether connected plugins are being requested */ export function isFetchingConnectedPlugins( state ) { return !! state.jetpack.siteData.requests.isFetchingConnectedPlugins; @@ -244,8 +245,8 @@ export function isFetchingConnectedPlugins( state ) { /** * Returns true if the connected plugins request has finished (even if it returned an error). Otherwise false. * - * @param {object} state - Global state tree - * @returns {boolean} Whether connected plugins request is completed. + * @param {object} state - Global state tree + * @return {boolean} Whether connected plugins request is completed. */ export function isDoneFetchingConnectedPlugins( state ) { return !! state.jetpack.siteData.requests.isDoneFetchingConnectedPlugins; @@ -254,8 +255,8 @@ export function isDoneFetchingConnectedPlugins( state ) { /** * Returns true if currently requesting site purchases. Otherwise false. * - * @param {object} state - Global state tree - * @returns {boolean} Whether site purchases are being requested + * @param {object} state - Global state tree + * @return {boolean} Whether site purchases are being requested */ export function isFetchingSitePurchases( state ) { return !! state.jetpack.siteData.requests.isFetchingSitePurchases; @@ -264,8 +265,8 @@ export function isFetchingSitePurchases( state ) { /** * Returns the products of this site. * - * @param {object} state - Global state tree - * @returns {Array} Site products + * @param {object} state - Global state tree + * @return {Array} Site products */ export function getSiteProducts( state ) { return get( state.jetpack.siteData, [ 'data', 'products' ], [] ); @@ -274,8 +275,8 @@ export function getSiteProducts( state ) { /** * Returns the plan of this site. * - * @param {object} state - Global state tree - * @returns {object} Site plan + * @param {object} state - Global state tree + * @return {object} Site plan */ export function getSitePlan( state ) { return get( state.jetpack.siteData, [ 'data', 'plan' ], {} ); @@ -285,7 +286,7 @@ export function getSitePlan( state ) { * Returns the VideoPress storage used for this site. * * @param {object} state - Argv object for an install command. Must contain project and root at least. - * @returns {number|null} Storage used in megabytes or null if not found. + * @return {number|null} Storage used in megabytes or null if not found. */ export function getVideoPressStorageUsed( state ) { return get( state.jetpack.siteData, [ 'data', 'options', 'videopress_storage_used' ], null ); @@ -294,8 +295,8 @@ export function getVideoPressStorageUsed( state ) { /** * Returns benefits provided to the site by Jetpack. * - * @param {object} state - Global state tree - * @returns {object} Benefits + * @param {object} state - Global state tree + * @return {object} Benefits */ export function getSiteBenefits( state ) { return get( state.jetpack.siteData, [ 'data', 'site', 'benefits' ], null ); @@ -304,8 +305,8 @@ export function getSiteBenefits( state ) { /** * Returns discount provided to the site by Jetpack. * - * @param {object} state - Global state tree - * @returns {object} Discount + * @param {object} state - Global state tree + * @return {object} Discount */ export function getSiteDiscount( state ) { return get( state.jetpack.siteData, [ 'data', 'site', 'discount' ], {} ); @@ -314,8 +315,8 @@ export function getSiteDiscount( state ) { /** * Returns features that are available on any plan. * - * @param {object} state - Global state tree - * @returns {object} Features + * @param {object} state - Global state tree + * @return {object} Features */ export function getAvailableFeatures( state ) { return get( state.jetpack.siteData, [ 'data', 'site', 'features', 'available' ], {} ); @@ -324,8 +325,8 @@ export function getAvailableFeatures( state ) { /** * Returns features that are available for current plan. * - * @param {object} state - Global state tree - * @returns {object} Features + * @param {object} state - Global state tree + * @return {object} Features */ export function getActiveFeatures( state ) { return get( state.jetpack.siteData, [ 'data', 'site', 'features', 'active' ], [] ); @@ -334,9 +335,9 @@ export function getActiveFeatures( state ) { /** * Check if the feature is active on the site. * - * @param {object} state - Global state tree - * @param {string} featureId - The feature to check. - * @returns {boolean} True if the feature is active. Otherwise, False. + * @param {object} state - Global state tree + * @param {string} featureId - The feature to check. + * @return {boolean} True if the feature is active. Otherwise, False. */ export function siteHasFeature( state, featureId ) { const siteFeatures = getActiveFeatures( state ); @@ -347,8 +348,8 @@ export function siteHasFeature( state, featureId ) { /** * Check if the site's admin interface style is set to wp-admin. * - * @param {object} state - Global state tree - * @returns {boolean} Whether the admin interface style is set to wp-admin. + * @param {object} state - Global state tree + * @return {boolean} Whether the admin interface style is set to wp-admin. */ export function siteUsesWpAdminInterface( state ) { return ( @@ -360,7 +361,7 @@ export function siteUsesWpAdminInterface( state ) { * Returns the purchase data for a site * * @param {object} state - Global state tree - * @returns {Array} Purchases for the site + * @return {Array} Purchases for the site */ export function getSitePurchases( state ) { return get( state.jetpack.siteData, [ 'data', 'sitePurchases' ], [] ); @@ -370,7 +371,7 @@ export function getSitePurchases( state ) { * Returns the active purchases for a site * * @param {object} state - Global state tree - * @returns {Array} Active purchases for the site + * @return {Array} Active purchases for the site */ export function getActiveSitePurchases( state ) { return getSitePurchases( state ).filter( purchase => '1' === purchase.active ); @@ -380,7 +381,7 @@ export function getActiveSitePurchases( state ) { * Returns the active product purchases for a site * * @param {object} state - Global state tree - * @returns {Array} Active product purchases for the site + * @return {Array} Active product purchases for the site */ export function getActiveProductPurchases( state ) { return getActiveSitePurchases( state ).filter( purchase => @@ -392,7 +393,7 @@ export function getActiveProductPurchases( state ) { * Determines if the site has an active product purchase * * @param {object} state - Global state tree - * @returns {boolean} True if the site has an active product purchase, false otherwise. + * @return {boolean} True if the site has an active product purchase, false otherwise. */ export function hasActiveProductPurchase( state ) { return getActiveProductPurchases( state ).length > 0; @@ -402,7 +403,7 @@ export function hasActiveProductPurchase( state ) { * Return any active security bundles on the site * * @param {object} state - Global state tree - * @returns {object} A active security bundle on the site, undefined otherwise + * @return {object} A active security bundle on the site, undefined otherwise */ export function getActiveSecurityPurchase( state ) { return find( getActiveSitePurchases( state ), purchase => @@ -414,7 +415,7 @@ export function getActiveSecurityPurchase( state ) { * Determines if the site has an active security or complete plan * * @param {object} state - Global state tree - * @returns {boolean} True if the site has an active security or complete plan, false otherwise. + * @return {boolean} True if the site has an active security or complete plan, false otherwise. */ export function hasActiveSecurityPurchase( state ) { return ( @@ -427,7 +428,7 @@ export function hasActiveSecurityPurchase( state ) { * Determines if the site has an active Jetpack Complete plan * * @param {object} state - Global state tree - * @returns {boolean} True if the site has an active Jetpack Complete plan, false otherwise. + * @return {boolean} True if the site has an active Jetpack Complete plan, false otherwise. */ export function hasActiveCompletePurchase( state ) { return 'is-complete-plan' === getPlanClass( getSitePlan( state ).product_slug ); @@ -437,7 +438,7 @@ export function hasActiveCompletePurchase( state ) { * Searches active products for Search product * * @param {object} state - Global state tree - * @returns {object} An active Search product if one was found, undefined otherwise. + * @return {object} An active Search product if one was found, undefined otherwise. */ export function getActiveSearchPurchase( state ) { return find( getActiveProductPurchases( state ), product => @@ -449,7 +450,7 @@ export function getActiveSearchPurchase( state ) { * Determines if the site has an active Search product purchase * * @param {object} state - Global state tree - * @returns {boolean} True if the site has an active Search product purchase, false otherwise. + * @return {boolean} True if the site has an active Search product purchase, false otherwise. */ export function hasActiveSearchPurchase( state ) { return ( @@ -462,7 +463,7 @@ export function hasActiveSearchPurchase( state ) { * Searches active products for Creator product * * @param {object} state - Global state tree - * @returns {object} An active Creator product if one was found, undefined otherwise. + * @return {object} An active Creator product if one was found, undefined otherwise. */ export function getActiveCreatorPurchase( state ) { return find( getActiveProductPurchases( state ), product => @@ -474,7 +475,7 @@ export function getActiveCreatorPurchase( state ) { * Determines if the site has an active Creator product purchase * * @param {object} state - Global state tree - * @returns {boolean} True if the site has an active Creator product purchase, false otherwise. + * @return {boolean} True if the site has an active Creator product purchase, false otherwise. */ export function hasActiveCreatorPurchase( state ) { return ( @@ -487,7 +488,7 @@ export function hasActiveCreatorPurchase( state ) { * Searches active products for an active Anti-Spam product. * * @param {object} state - Global state tree - * @returns {object} An active Anti-Spam product if one was found, undefined otherwise. + * @return {object} An active Anti-Spam product if one was found, undefined otherwise. */ export function getActiveAntiSpamPurchase( state ) { return find( getActiveProductPurchases( state ), product => @@ -499,7 +500,7 @@ export function getActiveAntiSpamPurchase( state ) { * Determines if the site has an active Anti-Spam product purchase * * @param {object} state - Global state tree - * @returns {boolean} True if the site has an active Anti-Spam product purchase, false otherwise. + * @return {boolean} True if the site has an active Anti-Spam product purchase, false otherwise. */ export function hasActiveAntiSpamPurchase( state ) { return !! getActiveAntiSpamPurchase( state ); @@ -509,7 +510,7 @@ export function hasActiveAntiSpamPurchase( state ) { * Searches active products for an active Boost product. * * @param {object} state - Global state tree - * @returns {object} An active Boost product if one was found, undefined otherwise. + * @return {object} An active Boost product if one was found, undefined otherwise. */ export function getActiveBoostPurchase( state ) { return find( getActiveProductPurchases( state ), product => @@ -521,7 +522,7 @@ export function getActiveBoostPurchase( state ) { * Determines if the site has an active Boost product purchase * * @param {object} state - Global state tree - * @returns {boolean} True if the site has an active Boost product purchase, false otherwise. + * @return {boolean} True if the site has an active Boost product purchase, false otherwise. */ export function hasActiveBoostPurchase( state ) { return !! getActiveBoostPurchase( state ); @@ -531,7 +532,7 @@ export function hasActiveBoostPurchase( state ) { * Searches active products for an active Backup product. * * @param {object} state - Global state tree - * @returns {object} An active backup product if one was found, undefined otherwise. + * @return {object} An active backup product if one was found, undefined otherwise. */ export function getActiveBackupPurchase( state ) { return find( getActiveProductPurchases( state ), product => @@ -543,7 +544,7 @@ export function getActiveBackupPurchase( state ) { * Determines if the site has an active social product purchase * * @param {object} state - Global state tree - * @returns {boolean} True if the site has an active backup product purchase, false otherwise. + * @return {boolean} True if the site has an active backup product purchase, false otherwise. */ export function getActiveSocialPurchase( state ) { return find( getActiveProductPurchases( state ), product => @@ -555,7 +556,7 @@ export function getActiveSocialPurchase( state ) { * Determines if the site has an active backup product purchase * * @param {object} state - Global state tree - * @returns {boolean} True if the site has an active backup product purchase, false otherwise. + * @return {boolean} True if the site has an active backup product purchase, false otherwise. */ export function hasActiveBackupPurchase( state ) { return !! getActiveBackupPurchase( state ); @@ -565,7 +566,7 @@ export function hasActiveBackupPurchase( state ) { * Searches active products for an active Social product. * * @param {object} state - Global state tree - * @returns {object} An active Social product if one was found, undefined otherwise. + * @return {object} An active Social product if one was found, undefined otherwise. */ export function hasActiveSocialPurchase( state ) { return !! getActiveSocialPurchase( state ); @@ -575,7 +576,7 @@ export function hasActiveSocialPurchase( state ) { * Searches active products for a legacy Jetpack plan with security features. * * @param {object} state - Global state tree - * @returns {object} An active legacy plan with security features if one was found, undefined otherwise. + * @return {object} An active legacy plan with security features if one was found, undefined otherwise. */ export function getSecurityComparableLegacyPlan( state ) { return find( getActiveProductPurchases( state ), product => @@ -587,7 +588,7 @@ export function getSecurityComparableLegacyPlan( state ) { * Determines if the site has an active Jetpack legacy plan with security features * * @param {object} state - Global state tree - * @returns {boolean} True if the site has a legacy Jetpack plan with security features, false otherwise. + * @return {boolean} True if the site has a legacy Jetpack plan with security features, false otherwise. */ export function hasSecurityComparableLegacyPlan( state ) { return !! getSecurityComparableLegacyPlan( state ); @@ -596,8 +597,8 @@ export function hasSecurityComparableLegacyPlan( state ) { /** * Returns the site ID * - * @param {object} state - Global state tree - * @returns {number} Site ID + * @param {object} state - Global state tree + * @return {number} Site ID */ export function getSiteID( state ) { return get( state.jetpack.siteData, [ 'data', 'ID' ] ); @@ -606,8 +607,8 @@ export function getSiteID( state ) { /** * Returns plugins that use the Jetpack connection * - * @param {object} state - Global state tree - * @returns {object} Connected plugins + * @param {object} state - Global state tree + * @return {object} Connected plugins */ export function getConnectedPlugins( state ) { if ( ! isDoneFetchingConnectedPlugins( state ) ) { @@ -622,8 +623,8 @@ export function getConnectedPlugins( state ) { * Returns Jetpack connected plugins converted to obj keyed by slug * [ { name, slug }, ... ] -> { slug: { name }, ... } * - * @param {object} state - Global state tree - * @returns {object} Connected plugins + * @param {object} state - Global state tree + * @return {object} Connected plugins */ export function getConnectedPluginsMap( state ) { const plugins = getConnectedPlugins( state ); diff --git a/projects/plugins/jetpack/_inc/client/state/tracking/reducer.js b/projects/plugins/jetpack/_inc/client/state/tracking/reducer.js index 49d916455342c..6b61f49076c08 100644 --- a/projects/plugins/jetpack/_inc/client/state/tracking/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/tracking/reducer.js @@ -64,7 +64,7 @@ export const reducer = combineReducers( { /** * Returns tracking settings. * - * @param {Object} state Global state tree. + * @param {Object} state Global state tree. * @return {Object} Settings keyed by name. */ export function getTrackingSettings( state ) { @@ -74,7 +74,7 @@ export function getTrackingSettings( state ) { /** * Returns true if currently requesting settings. * - * @param {Object} state Global state tree. + * @param {Object} state Global state tree. * @return {Boolean} Whether settings are being fetched. */ export function isFetchingTrackingSettingsList( state ) { @@ -84,7 +84,7 @@ export function isFetchingTrackingSettingsList( state ) { /** * Returns true if currently updating settings. * - * @param {Object} state Global state tree. + * @param {Object} state Global state tree. * @return {Boolean} Whether settings are being updated. */ export function isUpdatingTrackingSettings( state ) { diff --git a/projects/plugins/jetpack/_inc/client/state/waf/actions.js b/projects/plugins/jetpack/_inc/client/state/waf/actions.js index 1db0885638aea..6b327034db0a0 100644 --- a/projects/plugins/jetpack/_inc/client/state/waf/actions.js +++ b/projects/plugins/jetpack/_inc/client/state/waf/actions.js @@ -41,7 +41,7 @@ export const fetchWafSettings = () => { * @param {string} newSettings.ipBlockList - The IP block list. * @param {boolean} newSettings.shareData - Whether to share data. * @param {boolean} newSettings.shareDebugData - Whether to share detailed data. - * @returns {Function} - The action. + * @return {Function} - The action. */ export const updateWafSettings = newSettings => { return dispatch => { diff --git a/projects/plugins/jetpack/_inc/client/state/waf/reducer.js b/projects/plugins/jetpack/_inc/client/state/waf/reducer.js index 06f1fca2cace5..f408c38a6cce5 100644 --- a/projects/plugins/jetpack/_inc/client/state/waf/reducer.js +++ b/projects/plugins/jetpack/_inc/client/state/waf/reducer.js @@ -69,7 +69,7 @@ export const reducer = combineReducers( { * Returns true if currently requesting the firewall settings. Otherwise false. * * @param {object} state - Global state tree - * @returns {boolean} Whether the firewall settings are being requested + * @return {boolean} Whether the firewall settings are being requested */ export function isFetchingWafSettings( state ) { return !! state.jetpack.waf.requests.isFetchingWafSettings; @@ -78,8 +78,8 @@ export function isFetchingWafSettings( state ) { /** * Returns true if currently updating the firewall settings. Otherwise false. * - * @param {object} state - Global state tree - * @returns {boolean} Whether the firewall settings are being requested + * @param {object} state - Global state tree + * @return {boolean} Whether the firewall settings are being requested */ export function isUpdatingWafSettings( state ) { return !! state.jetpack.waf.requests.isUpdatingWafSettings; @@ -89,7 +89,7 @@ export function isUpdatingWafSettings( state ) { * Returns the firewall's settings. * * @param {object} state - Global state tree - * @returns {string} File path to bootstrap.php + * @return {string} File path to bootstrap.php */ export function getWafSettings( state ) { return get( state.jetpack.waf, [ 'data' ], {} ); @@ -99,7 +99,7 @@ export function getWafSettings( state ) { * Returns true if the firewall has automatic rules available. * * @param {object} state - Global state tree - * @returns {boolean} Whether the firewall has automatic rules available + * @return {boolean} Whether the firewall has automatic rules available */ export function getAutomaticRulesAvailable( state ) { return get( state.jetpack.waf, [ 'data', 'automaticRulesAvailable' ], false ); diff --git a/projects/plugins/jetpack/_inc/client/test/test-utils.js b/projects/plugins/jetpack/_inc/client/test/test-utils.js index 4295fd10a2d5a..c53c6bbda8615 100644 --- a/projects/plugins/jetpack/_inc/client/test/test-utils.js +++ b/projects/plugins/jetpack/_inc/client/test/test-utils.js @@ -9,7 +9,7 @@ import thunk from 'redux-thunk'; * Reducer that does nothing. * * @param {object} state - Current state. - * @returns {object} - New state, same as the old state. + * @return {object} - New state, same as the old state. */ function doNothingReducer( state = {} ) { return state; @@ -18,13 +18,13 @@ function doNothingReducer( state = {} ) { /** * Render a React element. * - * @param {React.ReactElement} ui - React element to render. - * @param {object} _ - Options. - * @param {*} _.initialState - Initial Redux state. - * @param {Function} _.reducer - Redux reducer. - * @param {Store} _.store - Redux store. Overrides `initialState` and `reducer`. - * @param {...} _.renderOptions - Additional options to pass to `@testing-library/react`'s `render()`. - * @returns {RenderResult} - Render result. + * @param {React.ReactElement} ui - React element to render. + * @param {object} _ - Options. + * @param {*} _.initialState - Initial Redux state. + * @param {Function} _.reducer - Redux reducer. + * @param {Store} _.store - Redux store. Overrides `initialState` and `reducer`. + * @param {...} _.renderOptions - Additional options to pass to `@testing-library/react`'s `render()`. + * @return {RenderResult} - Render result. */ function render( ui, diff --git a/projects/plugins/jetpack/_inc/client/traffic/blaze.jsx b/projects/plugins/jetpack/_inc/client/traffic/blaze.jsx index 08e4515705736..90715ebf065eb 100644 --- a/projects/plugins/jetpack/_inc/client/traffic/blaze.jsx +++ b/projects/plugins/jetpack/_inc/client/traffic/blaze.jsx @@ -24,7 +24,7 @@ const trackDashboardClick = () => { * Blaze settings component. * * @param {object} props - Component props. - * @returns {React.Component} Blaze settings component. + * @return {React.Component} Blaze settings component. */ function Blaze( props ) { const { diff --git a/projects/plugins/jetpack/_inc/client/traffic/related-posts.jsx b/projects/plugins/jetpack/_inc/client/traffic/related-posts.jsx index eb53bf8cb982f..e38648eb50454 100644 --- a/projects/plugins/jetpack/_inc/client/traffic/related-posts.jsx +++ b/projects/plugins/jetpack/_inc/client/traffic/related-posts.jsx @@ -14,7 +14,7 @@ class RelatedPostsComponent extends React.Component { /** * Get options for initial state. * - * @returns {{show_headline: boolean, show_thumbnails: boolean}} Initial state object. + * @return {{show_headline: boolean, show_thumbnails: boolean}} Initial state object. */ state = { show_headline: this.props.getOptionValue( 'show_headline', 'related-posts' ), diff --git a/projects/plugins/jetpack/_inc/client/traffic/seo/custom-seo-titles.jsx b/projects/plugins/jetpack/_inc/client/traffic/seo/custom-seo-titles.jsx index becebe0fcb8f8..5eff02b5e4227 100644 --- a/projects/plugins/jetpack/_inc/client/traffic/seo/custom-seo-titles.jsx +++ b/projects/plugins/jetpack/_inc/client/traffic/seo/custom-seo-titles.jsx @@ -37,8 +37,8 @@ export const customSeoTitleFormats = { * for storage into the `advanced_seo_title_formats` option. * * @param {string} inputValue - The value of an input for one of the custom SEO title inputs/pageTypes. - * @param {string} pageType - Type of page the title is being customized for (e.g front_page, archives) - * @returns {Array} An array of token/string objects and their values. + * @param {string} pageType - Type of page the title is being customized for (e.g front_page, archives) + * @return {Array} An array of token/string objects and their values. */ export const stringToTokenizedArray = ( inputValue, pageType ) => { const inputArray = inputValue.split( @@ -46,18 +46,14 @@ export const stringToTokenizedArray = ( inputValue, pageType ) => { ); return inputArray - .filter( value => { - if ( value ) { - return value; - } - } ) + .filter( value => value ) .map( value => { let matchedToken = null; - Object.keys( customSeoTitleFormats.insertableTokens ).map( token => { + for ( const token of Object.keys( customSeoTitleFormats.insertableTokens ) ) { if ( value === `[${ token }]` ) { matchedToken = token; } - } ); + } if ( matchedToken && @@ -81,7 +77,7 @@ export const stringToTokenizedArray = ( inputValue, pageType ) => { * Objects with type of 'token' have their values enclosed by '[]' * * @param {Array} arr - An array of token/string objects and their values. - * @returns {string} A concatenated string of values from the token/string objects supplied. + * @return {string} A concatenated string of values from the token/string objects supplied. */ export const tokenizedArrayToString = arr => { if ( Array.isArray( arr ) ) { @@ -222,7 +218,7 @@ const CustomSeoTitleInput = ( { * Renders the `advanced_seo_title_formats` inputs. * * @param {object} props - Parent props. - * @returns {object} React component. + * @return {object} React component. */ const CustomSeoTitles = props => { const [ customSeoTitleInputRefs ] = useState( { diff --git a/projects/plugins/jetpack/_inc/client/traffic/seo/yoast-jetpack-logos.svg b/projects/plugins/jetpack/_inc/client/traffic/seo/yoast-jetpack-logos.svg index 255c92fc37ca4..bd530673889d6 100644 --- a/projects/plugins/jetpack/_inc/client/traffic/seo/yoast-jetpack-logos.svg +++ b/projects/plugins/jetpack/_inc/client/traffic/seo/yoast-jetpack-logos.svg @@ -1 +1,6 @@ - \ No newline at end of file + + + + + + diff --git a/projects/plugins/jetpack/_inc/client/traffic/site-stats.jsx b/projects/plugins/jetpack/_inc/client/traffic/site-stats.jsx index 0cc0bfb041ae6..754e3e60a3b86 100644 --- a/projects/plugins/jetpack/_inc/client/traffic/site-stats.jsx +++ b/projects/plugins/jetpack/_inc/client/traffic/site-stats.jsx @@ -203,13 +203,10 @@ class SiteStatsComponent extends React.Component { ? __( 'Unavailable in Offline Mode', 'jetpack' ) : createInterpolateElement( __( - ' to see page views, likes, followers, subscribers, and more! Learn More', + 'Activate Jetpack Stats to see page views, likes, followers, subscribers, and more! Learn More', 'jetpack' ), { - Button: ( - -

- ) } -
- ); - }; - - const customizerLink = () => { - return ( -
- { createInterpolateElement( - __( - 'Additional CSS can be added from the Customizer. Enable the enhanced Custom CSS feature below to add additional features. Access the Customizer here.', - 'jetpack' - ), - { - a: , - } - ) } -
- ); - }; - - const toggleModule = () => { - // If we're using a block theme and the feature is disabled, we don't want to show the toggle. - if ( isBlockThemeActive && ! customCssActive ) { - return null; - } - - return ( - - - { __( 'Enhance CSS customization panel', 'jetpack' ) } - - - ); - }; - - const supportText = () => { - if ( isBlockThemeActive ) { - return {}; - } - - return { - text: description, - link: getRedirectUrl( 'jetpack-support-custom-css' ), - }; - }; - - return ( - - { name } - { options?.replace && ( - - { ' ' } - - ) } - { isBlockThemeActive && recommendSiteEditor() } - { ! isBlockThemeActive && customizerLink() } - { toggleModule() } - - ); -} - -export default withModuleSettingsFormHelpers( - connect( ( state, ownProps ) => { - return { - customCssActive: ownProps.getOptionValue( 'custom-css' ), - customCssModule: getModule( state, 'custom-css' ), - isBlockThemeActive: currentThemeIsBlockTheme( state ), - siteAdminUrl: getSiteAdminUrl( state ), - }; - } )( CustomCss ) -); diff --git a/projects/plugins/jetpack/_inc/client/writing/index.jsx b/projects/plugins/jetpack/_inc/client/writing/index.jsx index 0ba27d6ca320d..0a62e77f137eb 100644 --- a/projects/plugins/jetpack/_inc/client/writing/index.jsx +++ b/projects/plugins/jetpack/_inc/client/writing/index.jsx @@ -15,7 +15,6 @@ import { isModuleFound } from 'state/search'; import { getSettings } from 'state/settings'; import Composing from './composing'; import CustomContentTypes from './custom-content-types'; -import { Masterbar } from './masterbar'; import PostByEmail from './post-by-email'; import ThemeEnhancements from './theme-enhancements'; import Widgets from './widgets'; @@ -37,7 +36,6 @@ export class Writing extends React.Component { const found = [ 'carousel', 'copy-post', - 'custom-css', 'latex', 'masterbar', 'markdown', @@ -92,9 +90,6 @@ export class Writing extends React.Component { userCanManageModules={ this.props.userCanManageModules } /> ) } - { this.props.isModuleFound( 'masterbar' ) && ! this.props.masterbarIsAlwaysActive && ( - - ) } { ! showComposing && ! showPostByEmail && ( { __( diff --git a/projects/plugins/jetpack/_inc/client/writing/masterbar.jsx b/projects/plugins/jetpack/_inc/client/writing/masterbar.jsx deleted file mode 100644 index 5fd9cd9c154d1..0000000000000 --- a/projects/plugins/jetpack/_inc/client/writing/masterbar.jsx +++ /dev/null @@ -1,65 +0,0 @@ -import { getRedirectUrl } from '@automattic/jetpack-components'; -import { __, _x } from '@wordpress/i18n'; -import ConnectUserBar from 'components/connect-user-bar'; -import { withModuleSettingsFormHelpers } from 'components/module-settings/with-module-settings-form-helpers'; -import { ModuleToggle } from 'components/module-toggle'; -import SettingsCard from 'components/settings-card'; -import SettingsGroup from 'components/settings-group'; -import React, { Component } from 'react'; - -export const Masterbar = withModuleSettingsFormHelpers( - class extends Component { - render() { - const isActive = this.props.getOptionValue( 'masterbar' ), - unavailableInOfflineMode = this.props.isUnavailableInOfflineMode( 'masterbar' ); - - return ( - - -

- { __( - 'The WordPress.com toolbar replaces the default WordPress admin toolbar. It offers one-click access to notifications, your WordPress.com profile and your other Jetpack and WordPress.com websites. You can also catch up on the sites you follow in the Reader.', - 'jetpack' - ) } -

- - - { __( 'Enable the WordPress.com toolbar', 'jetpack' ) } - - -
- - { ! this.props.isUnavailableInOfflineMode( 'masterbar' ) && ! this.props.isLinked && ( - - ) } -
- ); - } - } -); diff --git a/projects/plugins/jetpack/_inc/client/writing/style.scss b/projects/plugins/jetpack/_inc/client/writing/style.scss index afa37f8f3c365..e69de29bb2d1d 100644 --- a/projects/plugins/jetpack/_inc/client/writing/style.scss +++ b/projects/plugins/jetpack/_inc/client/writing/style.scss @@ -1,57 +0,0 @@ -@import '../scss/calypso-colors'; - -/* Custom CSS settings */ -.jp-custom-css-site-editor { - @include breakpoint('>660px') { - display: flex; - flex-wrap: nowrap; - flex-direction: row; - align-items: center; - } -} - -.jp-custom-css-site-editor__text { - font-size: $font-body-small; - line-height: 1.5; - letter-spacing: -0.3px; - color: $gray-80; - flex-grow: 1; - - @include breakpoint('<660px') { - padding: 0 0 rem(16px); - } - - @include breakpoint('>660px') { - flex-basis: 50%; - padding: 0 rem(16px) 0 0; - } -} - -.jp-custom-css-site-editor__button { - text-align: left; - - button.dops-button.is-primary { - padding: 4px 20px; - font-size: $font-body-small; - - &:focus { - border: 1px solid $white; - box-shadow: 0 0 0 1px $black; - } - } - - @include breakpoint('>660px') { - flex-grow: 0; - margin-left: 64px; - } -} - -.jp-custom-css__module-toggle { - @include breakpoint('>660px') { - padding: rem(16px) 0 0; - } -} - -.jp-custom-css__deprecation-warning { - margin-bottom: 1rem; -} diff --git a/projects/plugins/jetpack/_inc/client/writing/theme-enhancements.jsx b/projects/plugins/jetpack/_inc/client/writing/theme-enhancements.jsx index 913d1eb3ece10..a6c58586402c3 100644 --- a/projects/plugins/jetpack/_inc/client/writing/theme-enhancements.jsx +++ b/projects/plugins/jetpack/_inc/client/writing/theme-enhancements.jsx @@ -11,13 +11,12 @@ import { connect } from 'react-redux'; import { currentThemeSupports } from 'state/initial-state'; import { getModule } from 'state/modules'; import { isModuleFound } from 'state/search'; -import CustomCss from './custom-css'; class ThemeEnhancements extends React.Component { /** * Translate Infinite Scroll module and option status into our three values for the options. * - * @returns {string} Check the Infinite Scroll and its mode and translate into a string. + * @return {string} Check the Infinite Scroll and its mode and translate into a string. */ getInfiniteMode = () => { if ( ! this.props.getOptionValue( 'infinite-scroll' ) ) { @@ -64,7 +63,7 @@ class ThemeEnhancements extends React.Component { * Update state so toggles are updated. * * @param {string} optionName - option slug - * @param {string} module - module slug + * @param {string} module - module slug */ updateOptions = ( optionName, module ) => { this.setState( @@ -86,7 +85,7 @@ class ThemeEnhancements extends React.Component { /** * Get options for initial state. * - * @returns {object} {{ + * @return {object} {{ * infinite_scroll: * * }} */ @@ -99,10 +98,9 @@ class ThemeEnhancements extends React.Component { }; render() { - const foundInfiniteScroll = this.props.isModuleFound( 'infinite-scroll' ), - foundCustomCSS = this.props.isModuleFound( 'custom-css' ); + const foundInfiniteScroll = this.props.isModuleFound( 'infinite-scroll' ); - if ( ! foundInfiniteScroll && ! foundCustomCSS ) { + if ( ! foundInfiniteScroll ) { return null; } @@ -185,7 +183,6 @@ class ThemeEnhancements extends React.Component { ) } ) } - { foundCustomCSS && } ); } diff --git a/projects/plugins/jetpack/_inc/client/writing/writing-media.jsx b/projects/plugins/jetpack/_inc/client/writing/writing-media.jsx index a93ffd4d8e4e9..bd76bb0038f63 100644 --- a/projects/plugins/jetpack/_inc/client/writing/writing-media.jsx +++ b/projects/plugins/jetpack/_inc/client/writing/writing-media.jsx @@ -14,7 +14,7 @@ import { isModuleFound as _isModuleFound } from 'state/search'; * Renders controls to activate the carousel and additional settings. * * @param {object} props - Component properties. - * @returns {object} - Controls for carousel. + * @return {object} - Controls for carousel. */ function WritingMedia( props ) { const foundCarousel = props.isModuleFound( 'carousel' ); @@ -38,11 +38,11 @@ function WritingMedia( props ) { /** * Render a toggle. For example the toggle for EXIF data. * - * @param {string} checked - Current state of the toggle. - * @param {string} optionName - Name of the option that the toggle state will be saved to. + * @param {string} checked - Current state of the toggle. + * @param {string} optionName - Name of the option that the toggle state will be saved to. * @param {Function} onChangeHandler - Method to call when the toggle is clicked. - * @param {string} label - Description for the toggle. - * @returns {object} A compact toggle component. + * @param {string} label - Description for the toggle. + * @return {object} A compact toggle component. */ const renderToggle = ( checked, optionName, onChangeHandler, label ) => ( \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/projects/plugins/jetpack/_inc/genericons/genericons/Genericons.svg b/projects/plugins/jetpack/_inc/genericons/genericons/Genericons.svg index 5ba8e5bfca0ad..47406858fbfc0 100644 --- a/projects/plugins/jetpack/_inc/genericons/genericons/Genericons.svg +++ b/projects/plugins/jetpack/_inc/genericons/genericons/Genericons.svg @@ -1 +1,537 @@ - \ No newline at end of file + + + + + +Created by FontForge 20150618 at Fri Sep 18 10:24:13 2015 + By Joen Asmussen +Copyright (c) 2015, Joen Asmussen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/plugins/jetpack/_inc/lib/admin-pages/class-jetpack-redux-state-helper.php b/projects/plugins/jetpack/_inc/lib/admin-pages/class-jetpack-redux-state-helper.php index f7a4dba2ca5fb..73307ad810473 100644 --- a/projects/plugins/jetpack/_inc/lib/admin-pages/class-jetpack-redux-state-helper.php +++ b/projects/plugins/jetpack/_inc/lib/admin-pages/class-jetpack-redux-state-helper.php @@ -248,7 +248,7 @@ public static function get_initial_state() { 'isSubscriptionSiteEnabled' => apply_filters( 'jetpack_subscription_site_enabled', false ), 'newsletterDateExample' => gmdate( get_option( 'date_format' ), time() ), 'subscriptionSiteEditSupported' => $current_theme->is_block_theme(), - 'isGoogleAnalyticsActive' => ( new Modules() )->is_active( 'google-analytics', false ), + 'isMasterbarActive' => ( new Modules() )->is_active( 'masterbar', false ), ); } diff --git a/projects/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-react-page.php b/projects/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-react-page.php index 56b96499d14a4..428108f4dcf3d 100644 --- a/projects/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-react-page.php +++ b/projects/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-react-page.php @@ -1,5 +1,6 @@ is_offline_mode() + || Jetpack::is_connection_ready() + ) { + remove_submenu_page( 'jetpack', 'jetpack' ); + } + } + /** * Add Jetpack Dashboard sub-link and point it to AAG if the user can view stats, manage modules or if Protect is active. * @@ -86,8 +102,14 @@ public function add_page_actions( $hook ) { */ public function jetpack_add_dashboard_sub_nav_item() { if ( ( new Status() )->is_offline_mode() || Jetpack::is_connection_ready() ) { - add_submenu_page( 'jetpack', __( 'Dashboard', 'jetpack' ), __( 'Dashboard', 'jetpack' ), 'jetpack_admin_page', 'jetpack#/dashboard', '__return_null', 1 ); - remove_submenu_page( 'jetpack', 'jetpack' ); + Admin_Menu::add_menu( + __( 'Dashboard', 'jetpack' ), + __( 'Dashboard', 'jetpack' ), + 'jetpack_admin_page', + Jetpack::admin_url( array( 'page' => 'jetpack#/dashboard' ) ), + null, // @phan-suppress-current-line PhanTypeMismatchArgumentProbablyReal -- See https://core.trac.wordpress.org/ticket/52539. + 14 + ); } } @@ -165,7 +187,14 @@ private function can_access_settings() { */ public function jetpack_add_settings_sub_nav_item() { if ( $this->can_access_settings() ) { - add_submenu_page( 'jetpack', __( 'Settings', 'jetpack' ), __( 'Settings', 'jetpack' ), 'jetpack_admin_page', 'jetpack#/settings', '__return_null' ); + Admin_Menu::add_menu( + __( 'Settings', 'jetpack' ), + __( 'Settings', 'jetpack' ), + 'jetpack_admin_page', + Jetpack::admin_url( array( 'page' => 'jetpack#/settings' ) ), + null, // @phan-suppress-current-line PhanTypeMismatchArgumentProbablyReal -- See https://core.trac.wordpress.org/ticket/52539. + 13 + ); } } diff --git a/projects/plugins/jetpack/_inc/lib/class-jetpack-top-posts-helper.php b/projects/plugins/jetpack/_inc/lib/class-jetpack-top-posts-helper.php index 28325c3d67e9b..bb002d44cfa38 100644 --- a/projects/plugins/jetpack/_inc/lib/class-jetpack-top-posts-helper.php +++ b/projects/plugins/jetpack/_inc/lib/class-jetpack-top-posts-helper.php @@ -44,6 +44,14 @@ public static function get_top_posts( $period, $items_count = null, $types = nul $data = array( 'summary' => array( 'postviews' => array() ) ); } + // Remove posts that have subsequently been deleted. + $data['summary']['postviews'] = array_filter( + $data['summary']['postviews'], + function ( $item ) { + return get_post_status( $item['id'] ) === 'publish'; + } + ); + $posts_retrieved = is_countable( $data['summary']['postviews'] ) ? count( $data['summary']['postviews'] ) : 0; // Fallback to random posts if user does not have enough top content. diff --git a/projects/plugins/jetpack/_inc/lib/class.color.php b/projects/plugins/jetpack/_inc/lib/class.color.php index 4d1d0941db2b1..d4c398c2ed106 100644 --- a/projects/plugins/jetpack/_inc/lib/class.color.php +++ b/projects/plugins/jetpack/_inc/lib/class.color.php @@ -36,6 +36,8 @@ class Jetpack_Color { * One of hex (default), rgb, hsl, int. */ public function __construct( $color = null, $type = 'hex' ) { + _deprecated_function( 'Jetpack_Color::__construct', 'jetpack-13.8' ); + if ( $color ) { switch ( $type ) { case 'hex': diff --git a/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-admin-menu.php b/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-admin-menu.php index 75885fee98be1..c139cbe556363 100644 --- a/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-admin-menu.php +++ b/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-admin-menu.php @@ -6,8 +6,6 @@ * @since 9.1.0 */ -use Automattic\Jetpack\Status\Host; - /** * Class WPCOM_REST_API_V2_Endpoint_Admin_Menu */ @@ -85,9 +83,6 @@ public function get_item_permissions_check( $request ) { // phpcs:ignore Generic * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter, VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable - if ( ! ( new Host() )->is_wpcom_platform() && get_option( 'wpcom_admin_interface' ) !== 'wp-admin' ) { - require_once JETPACK__PLUGIN_DIR . 'jetpack_vendor/automattic/jetpack-masterbar/src/admin-menu/load.php'; - } // All globals need to be declared for menu items to properly register. global $admin_page_hooks, $menu, $menu_order, $submenu, $_wp_menu_nopriv, $_wp_submenu_nopriv; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable @@ -119,8 +114,11 @@ private function hide_customizer_menu_on_block_theme() { remove_action( 'customize_register', array( 'Jetpack_Fonts_Typekit', 'maybe_override_for_advanced_mode' ), 20 ); - remove_action( 'customize_register', 'Automattic\Jetpack\Masterbar\register_css_nudge_control' ); + if ( class_exists( 'Automattic\Jetpack\Masterbar' ) ) { + remove_action( 'customize_register', 'Automattic\Jetpack\Masterbar\register_css_nudge_control' ); + } + // @phan-suppress-next-line PhanUndeclaredClassInCallable remove_action( 'customize_register', array( 'Jetpack_Custom_CSS_Enhancements', 'customize_register' ) ); } } diff --git a/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php b/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php index a4927ce04a879..53dd76731b96d 100644 --- a/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php +++ b/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php @@ -122,6 +122,16 @@ public function get_mailchimp_groups() { 403 ); } + + // Do not attempt to fetch groups if Mailchimp is not connected. + if ( ! $this->is_connected() ) { + return new WP_Error( + 'mailchimp_not_connected', + __( 'Your site is not connected to Mailchimp yet.', 'jetpack' ), + 403 + ); + } + $path = sprintf( '/sites/%d/mailchimp/groups', absint( $site_id ) ); $request = Client::wpcom_json_api_request_as_blog( $path ); $body = wp_remote_retrieve_body( $request ); diff --git a/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-profile.php b/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-profile.php new file mode 100644 index 0000000000000..14ed4b8f4cf37 --- /dev/null +++ b/projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-profile.php @@ -0,0 +1,72 @@ +namespace = 'wpcom/v2'; + $this->rest_base = 'profile'; + add_action( 'rest_api_init', array( $this, 'register_routes' ) ); + } + + /** + * Register routes. + */ + public function register_routes() { + register_rest_route( + $this->namespace, + $this->rest_base . '/', + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_item' ), + 'permission_callback' => array( $this, 'get_item_permissions_check' ), + ), + ) + ); + } + + /** + * Checks if a given request has access to user profile. + * + * @param WP_REST_Request $request Full details about the request. + * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. + */ + public function get_item_permissions_check( $request ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter, VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + if ( ! current_user_can( 'read' ) ) { + return new WP_Error( + 'rest_forbidden', + __( 'Sorry, you are not allowed to view your user profile on this site.', 'jetpack' ), + array( 'status' => rest_authorization_required_code() ) + ); + } + + return true; + } + + /** + * Retrieves the user profile. + * + * @param WP_REST_Request $request Full details about the request. + * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. + */ + public function get_item( $request ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter, VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + return rest_ensure_response( + array( + 'admin_color' => get_user_option( 'admin_color' ), + 'locale' => get_user_locale(), + ) + ); + } +} + +wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Profile' ); diff --git a/projects/plugins/jetpack/_inc/lib/tonesque.php b/projects/plugins/jetpack/_inc/lib/tonesque.php index 245170f314645..ec19049c43de4 100644 --- a/projects/plugins/jetpack/_inc/lib/tonesque.php +++ b/projects/plugins/jetpack/_inc/lib/tonesque.php @@ -38,6 +38,8 @@ class Tonesque { * @param string $image_url Image URL. */ public function __construct( $image_url ) { + _deprecated_function( 'Tonesque::__construct', 'jetpack-13.8' ); + if ( ! class_exists( 'Jetpack_Color' ) ) { require_once JETPACK__PLUGIN_DIR . '/_inc/lib/class.color.php'; } @@ -66,6 +68,8 @@ public function __construct( $image_url ) { * @return object|bool Image object or false if the image could not be loaded. */ public static function imagecreatefromurl( $image_url ) { + _deprecated_function( 'Tonesque::imagecreatefromurl', 'jetpack-13.8' ); + $data = null; // If it's a URL. diff --git a/projects/plugins/jetpack/changelog/update-paywall-block-styles-3 b/projects/plugins/jetpack/changelog/add-brief-retry-event similarity index 52% rename from projects/plugins/jetpack/changelog/update-paywall-block-styles-3 rename to projects/plugins/jetpack/changelog/add-brief-retry-event index e221fc719fa83..b3fe9a1cfacad 100644 --- a/projects/plugins/jetpack/changelog/update-paywall-block-styles-3 +++ b/projects/plugins/jetpack/changelog/add-brief-retry-event @@ -1,4 +1,4 @@ Significance: minor Type: other -Paywall Block: improve styles +Add retry event for Brief diff --git a/projects/plugins/jetpack/changelog/add-content-options-to-classic-theme-helper-package b/projects/plugins/jetpack/changelog/add-content-options-to-classic-theme-helper-package new file mode 100644 index 0000000000000..98a5718d8ad3b --- /dev/null +++ b/projects/plugins/jetpack/changelog/add-content-options-to-classic-theme-helper-package @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +Content Options: Moving content to Classic Theme Helper package. diff --git a/projects/plugins/jetpack/changelog/add-jetpack-ai-guidelines-link b/projects/plugins/jetpack/changelog/add-jetpack-ai-guidelines-link new file mode 100644 index 0000000000000..6b4e6ad90cacc --- /dev/null +++ b/projects/plugins/jetpack/changelog/add-jetpack-ai-guidelines-link @@ -0,0 +1,4 @@ +Significance: minor +Type: other + +AI Assistant: add AI Guidelines link to the AI Assistant sidebar panel diff --git a/projects/plugins/jetpack/changelog/add-monetize-add-wpcom-currencies b/projects/plugins/jetpack/changelog/add-monetize-add-wpcom-currencies new file mode 100644 index 0000000000000..7d1631b31d4b2 --- /dev/null +++ b/projects/plugins/jetpack/changelog/add-monetize-add-wpcom-currencies @@ -0,0 +1,4 @@ +Significance: minor +Type: other + +Monetize: support more currencies diff --git a/projects/plugins/jetpack/changelog/add-more-eslint-rules b/projects/plugins/jetpack/changelog/add-more-eslint-rules new file mode 100644 index 0000000000000..0f8d7bc5efd93 --- /dev/null +++ b/projects/plugins/jetpack/changelog/add-more-eslint-rules @@ -0,0 +1,5 @@ +Significance: patch +Type: other +Comment: Fix new eslint sniffs. Should be no change in functionality. + + diff --git a/projects/plugins/jetpack/changelog/add-new-sync-active-modules-callable b/projects/plugins/jetpack/changelog/add-new-sync-active-modules-callable deleted file mode 100644 index 4859735e1cc59..0000000000000 --- a/projects/plugins/jetpack/changelog/add-new-sync-active-modules-callable +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: other - -Sync: Add a new callable for Sync Active Modules diff --git a/projects/plugins/jetpack/changelog/add-require-social-links-classic-theme-helper-package b/projects/plugins/jetpack/changelog/add-require-social-links-classic-theme-helper-package deleted file mode 100644 index da3854f6af4fc..0000000000000 --- a/projects/plugins/jetpack/changelog/add-require-social-links-classic-theme-helper-package +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: other - -Social Links: Requiring feature from Classic Theme Helper package instead of Jetpack module. diff --git a/projects/plugins/jetpack/changelog/add-require-social-links-classic-theme-helper-package#2 b/projects/plugins/jetpack/changelog/add-require-social-links-classic-theme-helper-package#2 deleted file mode 100644 index a1c1831fa1ef7..0000000000000 --- a/projects/plugins/jetpack/changelog/add-require-social-links-classic-theme-helper-package#2 +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: other -Comment: Updated composer.lock. - - diff --git a/projects/plugins/jetpack/changelog/add-site-breadcrumbs-to-classic-theme-helper-package b/projects/plugins/jetpack/changelog/add-site-breadcrumbs-to-classic-theme-helper-package deleted file mode 100644 index 6b8c2b9f497c6..0000000000000 --- a/projects/plugins/jetpack/changelog/add-site-breadcrumbs-to-classic-theme-helper-package +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: other - -Site Breadcrumbs: Wrapping functions in function_exists as part of functionality move to package diff --git a/projects/plugins/jetpack/changelog/change-ai-image-generation-unlimited-plan-hard-limit b/projects/plugins/jetpack/changelog/change-ai-image-generation-unlimited-plan-hard-limit new file mode 100644 index 0000000000000..28255fb70ecb6 --- /dev/null +++ b/projects/plugins/jetpack/changelog/change-ai-image-generation-unlimited-plan-hard-limit @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +Jetpack AI: remove hardcoded limit on image generation, it's handled by backend diff --git a/projects/plugins/jetpack/changelog/change-jetpack-ai-sidebar-hide-usage-panel-on-plans b/projects/plugins/jetpack/changelog/change-jetpack-ai-sidebar-hide-usage-panel-on-plans new file mode 100644 index 0000000000000..10a3084411675 --- /dev/null +++ b/projects/plugins/jetpack/changelog/change-jetpack-ai-sidebar-hide-usage-panel-on-plans @@ -0,0 +1,4 @@ +Significance: minor +Type: other + +Jetpack AI: hide usagepanel when tier plans are disabled. Show QuotaExceededMessage instead of nudges diff --git a/projects/plugins/jetpack/changelog/fix-breve-dismiss b/projects/plugins/jetpack/changelog/fix-breve-dismiss deleted file mode 100644 index bf3f7e14232b3..0000000000000 --- a/projects/plugins/jetpack/changelog/fix-breve-dismiss +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: other - -Allow dismiss suggestion in all states diff --git a/projects/plugins/jetpack/changelog/fix-comment-redirect b/projects/plugins/jetpack/changelog/fix-comment-redirect new file mode 100644 index 0000000000000..9df54534a9c2e --- /dev/null +++ b/projects/plugins/jetpack/changelog/fix-comment-redirect @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +Fix redirecting after comment when subscription modal is disabled diff --git a/projects/plugins/jetpack/changelog/fix-hide-customizer-menu-on-simple b/projects/plugins/jetpack/changelog/fix-hide-customizer-menu-on-simple deleted file mode 100644 index 5f56a859dccba..0000000000000 --- a/projects/plugins/jetpack/changelog/fix-hide-customizer-menu-on-simple +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: bugfix - -Hide the Customizer link on Simple site diff --git a/projects/plugins/jetpack/changelog/fix-incorrect-next-version-tokens b/projects/plugins/jetpack/changelog/fix-incorrect-next-version-tokens deleted file mode 100644 index 26b00c0c77e0f..0000000000000 --- a/projects/plugins/jetpack/changelog/fix-incorrect-next-version-tokens +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: other -Comment: Fix incorrect next-version tokens in php `@since` and/or `@deprecated` docs. - - diff --git a/projects/plugins/jetpack/changelog/update-email-preview-improvements b/projects/plugins/jetpack/changelog/fix-install-instructions similarity index 50% rename from projects/plugins/jetpack/changelog/update-email-preview-improvements rename to projects/plugins/jetpack/changelog/fix-install-instructions index 024602784feaa..cf13959481ea3 100644 --- a/projects/plugins/jetpack/changelog/update-email-preview-improvements +++ b/projects/plugins/jetpack/changelog/fix-install-instructions @@ -1,4 +1,4 @@ Significance: patch Type: other -small change under feature flag +Update Quick Start instructions diff --git a/projects/plugins/jetpack/changelog/fix-jetpack-ai-breve-animation-name b/projects/plugins/jetpack/changelog/fix-jetpack-ai-breve-animation-name deleted file mode 100644 index ae140d7effef2..0000000000000 --- a/projects/plugins/jetpack/changelog/fix-jetpack-ai-breve-animation-name +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: other - -AI Assistant: Remove unique-id sass function call from animation name diff --git a/projects/plugins/jetpack/changelog/fix-jetpack-ai-breve-remove-popover-on-disable b/projects/plugins/jetpack/changelog/fix-jetpack-ai-breve-remove-popover-on-disable deleted file mode 100644 index 396d5480dfa7c..0000000000000 --- a/projects/plugins/jetpack/changelog/fix-jetpack-ai-breve-remove-popover-on-disable +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: other - -AI Assistant: Remove Breve highlight popover when feature is disabled diff --git a/projects/plugins/jetpack/changelog/fix-jetpack-comment-endpoint-warnings b/projects/plugins/jetpack/changelog/fix-jetpack-comment-endpoint-warnings new file mode 100644 index 0000000000000..cd8d8e645371b --- /dev/null +++ b/projects/plugins/jetpack/changelog/fix-jetpack-comment-endpoint-warnings @@ -0,0 +1,4 @@ +Significance: patch +Type: bugfix + +REST API: Avoid PHP warnings in comment endpoint when the parent comment does not exist. diff --git a/projects/plugins/jetpack/changelog/fix-mailchimp-groups-not-connected b/projects/plugins/jetpack/changelog/fix-mailchimp-groups-not-connected new file mode 100644 index 0000000000000..e70deb4971983 --- /dev/null +++ b/projects/plugins/jetpack/changelog/fix-mailchimp-groups-not-connected @@ -0,0 +1,4 @@ +Significance: patch +Type: bugfix + +Mailchimp block: do not attempt to fetch groups when a site is not connected to Mailchimp yet. diff --git a/projects/plugins/jetpack/changelog/fix-map-block-selection b/projects/plugins/jetpack/changelog/fix-map-block-selection new file mode 100644 index 0000000000000..989aae81cfcda --- /dev/null +++ b/projects/plugins/jetpack/changelog/fix-map-block-selection @@ -0,0 +1,4 @@ +Significance: patch +Type: enhancement + +Map block: Allow maps on WordPress.com to be selectable. diff --git a/projects/plugins/jetpack/changelog/fix-send-test-email-modal-layout b/projects/plugins/jetpack/changelog/fix-send-test-email-modal-layout deleted file mode 100644 index 2a331892765c1..0000000000000 --- a/projects/plugins/jetpack/changelog/fix-send-test-email-modal-layout +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: other - -Email preview: ensure the email is visible diff --git a/projects/plugins/jetpack/changelog/fix-slideshow-shortcode-jquery-remove b/projects/plugins/jetpack/changelog/fix-slideshow-shortcode-jquery-remove new file mode 100644 index 0000000000000..ad7c1caaf791c --- /dev/null +++ b/projects/plugins/jetpack/changelog/fix-slideshow-shortcode-jquery-remove @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +Slideshow shortcode: Remove deprecated JS functionality and remove majority of jQuery. diff --git a/projects/plugins/jetpack/changelog/fix-subscribe-block-paragraph-styles b/projects/plugins/jetpack/changelog/fix-subscribe-block-paragraph-styles deleted file mode 100644 index 83d7dcce1359c..0000000000000 --- a/projects/plugins/jetpack/changelog/fix-subscribe-block-paragraph-styles +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: other - -Subscribe block: p tag styles leaking in from theme diff --git a/projects/plugins/jetpack/changelog/update-newsletter-plugin-3 b/projects/plugins/jetpack/changelog/init-release-cycle similarity index 57% rename from projects/plugins/jetpack/changelog/update-newsletter-plugin-3 rename to projects/plugins/jetpack/changelog/init-release-cycle index c2a0c4e4755b8..fdd0d1aa51dd2 100644 --- a/projects/plugins/jetpack/changelog/update-newsletter-plugin-3 +++ b/projects/plugins/jetpack/changelog/init-release-cycle @@ -1,4 +1,5 @@ Significance: patch Type: other +Comment: Init 13.8-a.8 + -just refactoring code diff --git a/projects/plugins/jetpack/changelog/remove-custom-css-warnings b/projects/plugins/jetpack/changelog/remove-custom-css-warnings new file mode 100644 index 0000000000000..46af7496437a3 --- /dev/null +++ b/projects/plugins/jetpack/changelog/remove-custom-css-warnings @@ -0,0 +1,4 @@ +Significance: major +Type: major + +Jetpack Custom CSS: remove feature in favor of WordPress core implementation diff --git a/projects/plugins/jetpack/changelog/renovate-definitelytyped b/projects/plugins/jetpack/changelog/renovate-npm-webpack-vulnerability similarity index 100% rename from projects/plugins/jetpack/changelog/renovate-definitelytyped rename to projects/plugins/jetpack/changelog/renovate-npm-webpack-vulnerability diff --git a/projects/plugins/jetpack/changelog/renovate-wordpress-monorepo#2 b/projects/plugins/jetpack/changelog/renovate-wordpress-monorepo#2 deleted file mode 100644 index e9f58d1083de4..0000000000000 --- a/projects/plugins/jetpack/changelog/renovate-wordpress-monorepo#2 +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: other -Comment: Fix unit test for loader recursion inside `@wordpress/components`. - - diff --git a/projects/plugins/jetpack/changelog/try-no-version-bumps-in-trunk b/projects/plugins/jetpack/changelog/try-no-version-bumps-in-trunk new file mode 100644 index 0000000000000..12a34c0b4acba --- /dev/null +++ b/projects/plugins/jetpack/changelog/try-no-version-bumps-in-trunk @@ -0,0 +1,5 @@ +Significance: patch +Type: other +Comment: Un-bump version numbers in trunk. The build will now update the version numbers as needed for mirrors. + + diff --git a/projects/plugins/jetpack/changelog/update-allow-list-settings-access b/projects/plugins/jetpack/changelog/update-allow-list-settings-access deleted file mode 100644 index 2f1c77879b246..0000000000000 --- a/projects/plugins/jetpack/changelog/update-allow-list-settings-access +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: other - -Makes allow list settings always accessible diff --git a/projects/plugins/jetpack/changelog/update-audit-usage-of-extensions-when-blocks-disabled b/projects/plugins/jetpack/changelog/update-audit-usage-of-extensions-when-blocks-disabled new file mode 100644 index 0000000000000..5d17a625c878e --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-audit-usage-of-extensions-when-blocks-disabled @@ -0,0 +1,4 @@ +Significance: minor +Type: other + +Blocks: Ensure function is loaded even if blocks aren't enabled diff --git a/projects/plugins/jetpack/changelog/update-breve-highlight-ux b/projects/plugins/jetpack/changelog/update-breve-highlight-ux deleted file mode 100644 index 53d62013d686c..0000000000000 --- a/projects/plugins/jetpack/changelog/update-breve-highlight-ux +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: other - -Add general improvements in Breve UX diff --git a/projects/plugins/jetpack/changelog/update-connection-initial-state b/projects/plugins/jetpack/changelog/update-connection-initial-state deleted file mode 100644 index a1c1831fa1ef7..0000000000000 --- a/projects/plugins/jetpack/changelog/update-connection-initial-state +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: other -Comment: Updated composer.lock. - - diff --git a/projects/plugins/jetpack/changelog/update-contact-form-block-api b/projects/plugins/jetpack/changelog/update-contact-form-block-api new file mode 100644 index 0000000000000..98d3e28b9dc5a --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-contact-form-block-api @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +Button Block: update to Block API v3 diff --git a/projects/plugins/jetpack/changelog/update-email-preview-improvements-2 b/projects/plugins/jetpack/changelog/update-email-preview-improvements-2 deleted file mode 100644 index 533ad5c5e9bb8..0000000000000 --- a/projects/plugins/jetpack/changelog/update-email-preview-improvements-2 +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: other - -featured flagged feature diff --git a/projects/plugins/jetpack/changelog/update-fediverse-og-better-compat-check b/projects/plugins/jetpack/changelog/update-fediverse-og-better-compat-check deleted file mode 100644 index 1c73b77c5cd8b..0000000000000 --- a/projects/plugins/jetpack/changelog/update-fediverse-og-better-compat-check +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: other - -OG Tags: check if the Open Graph integration in the ActivityPub plugin is active instead of checking for the class. diff --git a/projects/plugins/jetpack/changelog/update-fediverse-og-no-simple b/projects/plugins/jetpack/changelog/update-fediverse-og-no-simple deleted file mode 100644 index a59cd90ed7c98..0000000000000 --- a/projects/plugins/jetpack/changelog/update-fediverse-og-no-simple +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: other - -Open Graph Meta Tags: do not display Fediverse tag on WordPress.com Simple. diff --git a/projects/plugins/jetpack/changelog/update-newsletter-plugin-2 b/projects/plugins/jetpack/changelog/update-jetpack-13.7-backport similarity index 64% rename from projects/plugins/jetpack/changelog/update-newsletter-plugin-2 rename to projects/plugins/jetpack/changelog/update-jetpack-13.7-backport index 6d89556e38b3d..38112c3078868 100644 --- a/projects/plugins/jetpack/changelog/update-newsletter-plugin-2 +++ b/projects/plugins/jetpack/changelog/update-jetpack-13.7-backport @@ -1,4 +1,4 @@ Significance: patch Type: other -feature flagged +Updated versions. diff --git a/projects/plugins/jetpack/changelog/update-jetpack-ai-add-beta-flag-for-keywords-on-title-optimization b/projects/plugins/jetpack/changelog/update-jetpack-ai-add-beta-flag-for-keywords-on-title-optimization deleted file mode 100644 index 5a2a28fa536b1..0000000000000 --- a/projects/plugins/jetpack/changelog/update-jetpack-ai-add-beta-flag-for-keywords-on-title-optimization +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: other - -Jetpack AI: register the ai-title-optimization-keywords-support beta flag. diff --git a/projects/plugins/jetpack/changelog/update-jetpack-ai-add-fair-usage-message-on-extension-ai-control b/projects/plugins/jetpack/changelog/update-jetpack-ai-add-fair-usage-message-on-extension-ai-control new file mode 100644 index 0000000000000..729bf31f35b9b --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-jetpack-ai-add-fair-usage-message-on-extension-ai-control @@ -0,0 +1,4 @@ +Significance: minor +Type: other + +Jetpack AI: support fair usage messaging on the Extension AI Control component. diff --git a/projects/plugins/jetpack/changelog/update-jetpack-ai-add-renewal-date-to-fair-usage-messaging b/projects/plugins/jetpack/changelog/update-jetpack-ai-add-renewal-date-to-fair-usage-messaging new file mode 100644 index 0000000000000..1f740b48e3724 --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-jetpack-ai-add-renewal-date-to-fair-usage-messaging @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +Jetpack AI: add usage policy link and renewal date to fair usage messaging. diff --git a/projects/plugins/jetpack/changelog/add-new-sync-active-modules-callable#2 b/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-a8c-dictionary similarity index 50% rename from projects/plugins/jetpack/changelog/add-new-sync-active-modules-callable#2 rename to projects/plugins/jetpack/changelog/update-jetpack-ai-breve-a8c-dictionary index a1c1831fa1ef7..9c01f54e8372b 100644 --- a/projects/plugins/jetpack/changelog/add-new-sync-active-modules-callable#2 +++ b/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-a8c-dictionary @@ -1,5 +1,4 @@ Significance: patch Type: other -Comment: Updated composer.lock. - +AI Assistant: Add A8c dictionary diff --git a/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-add-to-dictionary b/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-add-to-dictionary new file mode 100644 index 0000000000000..b510dc00269c1 --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-add-to-dictionary @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +AI Assistant: Add option to add word to spelling dictionary diff --git a/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-add-to-dictionary-without-flickering b/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-add-to-dictionary-without-flickering new file mode 100644 index 0000000000000..e6181dd6d8f45 --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-add-to-dictionary-without-flickering @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +AI Assistant: Fix flickering when adding word to Breve dictionary diff --git a/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-anchorless-popover b/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-anchorless-popover new file mode 100644 index 0000000000000..b04e8b78a7564 --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-anchorless-popover @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +AI Assistant: Limit popover height and fix anchorless popover diff --git a/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-clean b/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-clean new file mode 100644 index 0000000000000..a0a449db0a03f --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-clean @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +AI Assistant: Remove dead Breve code diff --git a/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-special-symbols b/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-special-symbols new file mode 100644 index 0000000000000..6d50d150202ad --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-special-symbols @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +AI Assistant: Do not mark words starting with special characters as spelling mistakes diff --git a/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-type-detection b/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-type-detection deleted file mode 100644 index af51abc13d1e3..0000000000000 --- a/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-type-detection +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: other - -AI Assistant: Change Breve type markup and restrict types diff --git a/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-typo-flag b/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-typo-flag deleted file mode 100644 index 01b9aaed70715..0000000000000 --- a/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-typo-flag +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: other - -AI Assistant: Add flag for Breve typo detection support diff --git a/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-typo-local b/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-typo-local deleted file mode 100644 index 9f77a091a391d..0000000000000 --- a/projects/plugins/jetpack/changelog/update-jetpack-ai-breve-typo-local +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: other - -AI Assistant: Add spelling mistake detection to Breve diff --git a/projects/plugins/jetpack/changelog/update-jetpack-ai-handle-fair-usage-quota-messaging b/projects/plugins/jetpack/changelog/update-jetpack-ai-handle-fair-usage-quota-messaging new file mode 100644 index 0000000000000..2e8da6cbdde15 --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-jetpack-ai-handle-fair-usage-quota-messaging @@ -0,0 +1,4 @@ +Significance: minor +Type: other + +Jetpack AI: handle fair usage limit messaging on the UI. diff --git a/projects/plugins/jetpack/changelog/update-jetpack-ai-update-sidebar-fair-usage-messaging b/projects/plugins/jetpack/changelog/update-jetpack-ai-update-sidebar-fair-usage-messaging new file mode 100644 index 0000000000000..68a0489bb624c --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-jetpack-ai-update-sidebar-fair-usage-messaging @@ -0,0 +1,4 @@ +Significance: minor +Type: other + +Jetpack AI: update fair usage messaging on the sidebar. diff --git a/projects/plugins/jetpack/changelog/update-jetpack-menu-item-order b/projects/plugins/jetpack/changelog/update-jetpack-menu-item-order new file mode 100644 index 0000000000000..c96aa7333e16a --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-jetpack-menu-item-order @@ -0,0 +1,4 @@ +Significance: patch +Type: enhancement + +Admin menu: Change order of Jetpack sub-menu items diff --git a/projects/plugins/jetpack/changelog/update-newsletter-plugin b/projects/plugins/jetpack/changelog/update-newsletter-plugin deleted file mode 100644 index 533ad5c5e9bb8..0000000000000 --- a/projects/plugins/jetpack/changelog/update-newsletter-plugin +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: other - -featured flagged feature diff --git a/projects/plugins/jetpack/changelog/update-notification-locale-source b/projects/plugins/jetpack/changelog/update-notification-locale-source new file mode 100644 index 0000000000000..b42711e0c5db4 --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-notification-locale-source @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +Notifications: Use profile locale to match menu language diff --git a/projects/plugins/jetpack/changelog/update-socia-render-share-status-modal-globally b/projects/plugins/jetpack/changelog/update-socia-render-share-status-modal-globally new file mode 100644 index 0000000000000..b6cc3bbd1e742 --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-socia-render-share-status-modal-globally @@ -0,0 +1,4 @@ +Significance: minor +Type: other + +Social: Updated the share status modal to render it globally diff --git a/projects/plugins/jetpack/changelog/update-tiled-galleries-enqueue b/projects/plugins/jetpack/changelog/update-tiled-galleries-enqueue deleted file mode 100644 index cd980722fb7cb..0000000000000 --- a/projects/plugins/jetpack/changelog/update-tiled-galleries-enqueue +++ /dev/null @@ -1,4 +0,0 @@ -Significance: patch -Type: enhancement - -Tiled Galleries: defer loading of the Tiled Gallery script for improved performance. diff --git a/projects/plugins/jetpack/changelog/update-title-optimization-keywords-section b/projects/plugins/jetpack/changelog/update-title-optimization-keywords-section deleted file mode 100644 index a714ec297f246..0000000000000 --- a/projects/plugins/jetpack/changelog/update-title-optimization-keywords-section +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: other - -Title Optimization: Add keywords section to UI and make it send the keywords on the request. diff --git a/projects/plugins/jetpack/changelog/update-title-optimization-update-ui-copy b/projects/plugins/jetpack/changelog/update-title-optimization-update-ui-copy deleted file mode 100644 index c2ede39c07c2f..0000000000000 --- a/projects/plugins/jetpack/changelog/update-title-optimization-update-ui-copy +++ /dev/null @@ -1,4 +0,0 @@ -Significance: minor -Type: other - -AI Title Optimization: change UI labels when keywords beta flag is enabled. diff --git a/projects/plugins/jetpack/changelog/update-videopress-tus-client-lib b/projects/plugins/jetpack/changelog/update-videopress-tus-client-lib deleted file mode 100644 index a1c1831fa1ef7..0000000000000 --- a/projects/plugins/jetpack/changelog/update-videopress-tus-client-lib +++ /dev/null @@ -1,5 +0,0 @@ -Significance: patch -Type: other -Comment: Updated composer.lock. - - diff --git a/projects/plugins/jetpack/class.jetpack-admin.php b/projects/plugins/jetpack/class.jetpack-admin.php index 73e437c1d83f3..60e1af1fd3747 100644 --- a/projects/plugins/jetpack/class.jetpack-admin.php +++ b/projects/plugins/jetpack/class.jetpack-admin.php @@ -64,6 +64,7 @@ private function __construct() { add_action( 'admin_init', array( $jetpack_react, 'react_redirects' ), 0 ); add_action( 'admin_menu', array( $jetpack_react, 'add_actions' ), 998 ); + add_action( 'admin_menu', array( $jetpack_react, 'remove_jetpack_menu' ), 2000 ); add_action( 'jetpack_admin_menu', array( $jetpack_react, 'jetpack_add_dashboard_sub_nav_item' ) ); add_action( 'jetpack_admin_menu', array( $jetpack_react, 'jetpack_add_settings_sub_nav_item' ) ); add_action( 'jetpack_admin_menu', array( $this, 'admin_menu_debugger' ) ); diff --git a/projects/plugins/jetpack/class.jetpack.php b/projects/plugins/jetpack/class.jetpack.php index fa0a279635a60..11ac2ae9c2b26 100644 --- a/projects/plugins/jetpack/class.jetpack.php +++ b/projects/plugins/jetpack/class.jetpack.php @@ -159,9 +159,6 @@ class Jetpack { array( 'grunion-contact-form/grunion-contact-form.php', 'Grunion Contact Form' ), array( 'mullet/mullet-contact-form.php', 'Mullet Contact Form' ), ), - 'custom-css' => array( - array( 'safecss/safecss.php', 'WordPress.com Custom CSS' ), - ), 'gravatar-hovercards' => array( array( 'jetpack-gravatar-hovercards/gravatar-hovercards.php', 'Jetpack Gravatar Hovercards' ), ), diff --git a/projects/plugins/jetpack/composer.json b/projects/plugins/jetpack/composer.json index bd46755d43bec..bada036b838f3 100644 --- a/projects/plugins/jetpack/composer.json +++ b/projects/plugins/jetpack/composer.json @@ -57,7 +57,7 @@ "automattic/jetpack-changelogger": "@dev", "automattic/patchwork-redefine-exit": "@dev", "johnkary/phpunit-speedtrap": "^4.0.0 || ^2.0.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "scripts": { "build-production": [ @@ -102,7 +102,7 @@ "platform": { "ext-intl": "0.0.0" }, - "autoloader-suffix": "f11009ded9fc4592b6a05b61ce272b3c_jetpackⓥ13_8_a_2", + "autoloader-suffix": "f11009ded9fc4592b6a05b61ce272b3c_jetpackⓥ13_8_a_7", "allow-plugins": { "automattic/jetpack-autoloader": true, "automattic/jetpack-composer-plugin": true diff --git a/projects/plugins/jetpack/composer.lock b/projects/plugins/jetpack/composer.lock index 75d74bdadebf4..6537628420f92 100644 --- a/projects/plugins/jetpack/composer.lock +++ b/projects/plugins/jetpack/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fa4fcbac69cbb7823ffc581413e98ffc", + "content-hash": "123885af37389b4c687c46a31399b7d6", "packages": [ { "name": "automattic/jetpack-a8c-mc-stats", @@ -12,14 +12,14 @@ "dist": { "type": "path", "url": "../../packages/a8c-mc-stats", - "reference": "29e2de602fcb803984eed4229ffa60a2f96a53f9" + "reference": "1608695e54d44f088960b6a7bfa0c5779c372ee6" }, "require": { "php": ">=7.0" }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -62,7 +62,7 @@ "dist": { "type": "path", "url": "../../packages/admin-ui", - "reference": "b191c34a0e21f625069eab0c054d8827b9542dfa" + "reference": "7330d0d7b9011e4b516c62a87c10d64f1a168eb7" }, "require": { "php": ">=7.0" @@ -71,7 +71,7 @@ "automattic/jetpack-changelogger": "@dev", "automattic/jetpack-logo": "@dev", "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -124,7 +124,7 @@ "dist": { "type": "path", "url": "../../packages/assets", - "reference": "9a9e8b6703e074750408f276c14011262b388ddc" + "reference": "58de4ea5a64ffa0899cd5903840499c76d253f4b" }, "require": { "automattic/jetpack-constants": "@dev", @@ -134,7 +134,7 @@ "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", "wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -190,7 +190,7 @@ "dist": { "type": "path", "url": "../../packages/autoloader", - "reference": "6bb097db25b5b249079fcb03ff39d493f59076a6" + "reference": "8e9867c7b1f5bac0c5652f87946fd2cd41a88f70" }, "require": { "composer-plugin-api": "^1.1 || ^2.0", @@ -199,7 +199,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "composer/composer": "^1.1 || ^2.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "type": "composer-plugin", "extra": { @@ -254,7 +254,7 @@ "dist": { "type": "path", "url": "../../packages/backup", - "reference": "d974148c9be257d174de2f6afc99b768ef5ab1d5" + "reference": "952a01e67d1f63be1f900fb8bcb1869b1c53133a" }, "require": { "automattic/jetpack-admin-ui": "@dev", @@ -272,7 +272,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -341,7 +341,7 @@ "dist": { "type": "path", "url": "../../packages/backup-helper-script-manager", - "reference": "ec1665a5730b66aad2b6b5744c884056de856f58" + "reference": "460d4932cc27b84f375cb04f47691faeb57d67ad" }, "require": { "php": ">=7.0" @@ -349,7 +349,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -398,7 +398,7 @@ "dist": { "type": "path", "url": "../../packages/blaze", - "reference": "2c21c40f16815e3a4db4a846577544ad9ada1660" + "reference": "7c5abfdb2bf223c8789349a31dde316983d1709d" }, "require": { "automattic/jetpack-assets": "@dev", @@ -413,7 +413,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -476,7 +476,7 @@ "dist": { "type": "path", "url": "../../packages/blocks", - "reference": "f2e9d1750729b4645c78cb1988112c3a838e1bce" + "reference": "2d1b34d2e22edcee8f156d75a0d5782e4c29d9a2" }, "require": { "automattic/jetpack-constants": "@dev", @@ -486,7 +486,7 @@ "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -535,7 +535,7 @@ "dist": { "type": "path", "url": "../../packages/boost-core", - "reference": "402efb3188837598621d70876c3c2cd085df93a8" + "reference": "254e450eefc86995a797518cc1cbc041f1509222" }, "require": { "automattic/jetpack-connection": "@dev", @@ -544,7 +544,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -600,7 +600,7 @@ "dist": { "type": "path", "url": "../../packages/boost-speed-score", - "reference": "6ab34e20ce114b8ad71262ab2ad7f547d69b7784" + "reference": "6d24ca9aca1b0cda4e925bbe6dcaad4bbd3a16be" }, "require": { "automattic/jetpack-boost-core": "@dev", @@ -609,7 +609,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "^2.6", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -673,7 +673,7 @@ "dist": { "type": "path", "url": "../../packages/classic-theme-helper", - "reference": "2a143c5d437250ba07b2c633257be1cb616dd4ff" + "reference": "2ef40dc91652b8370108a7d3cb358947e43b0218" }, "require": { "automattic/jetpack-assets": "@dev", @@ -682,7 +682,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -778,7 +778,7 @@ "dist": { "type": "path", "url": "../../packages/composer-plugin", - "reference": "9dd2a092b3de5ed00ee778f1f40704f7d913a836" + "reference": "b6fe2427cac6dd3bbef0a7e915c16bef55ad7c9b" }, "require": { "composer-plugin-api": "^2.1.0", @@ -787,7 +787,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "composer/composer": "^2.2 || ^2.4", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "type": "composer-plugin", "extra": { @@ -907,7 +907,7 @@ "dist": { "type": "path", "url": "../../packages/connection", - "reference": "2e4a3b9a72cb4f590de3ffcbd5ea0146d584483e" + "reference": "61beeb1eadc51c94a4ba35310bed89a1f15702e3" }, "require": { "automattic/jetpack-a8c-mc-stats": "@dev", @@ -925,7 +925,7 @@ "automattic/jetpack-sync": "@dev", "automattic/wordbless": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -993,7 +993,7 @@ "dist": { "type": "path", "url": "../../packages/constants", - "reference": "3fd2bf1d1ba0bb374918e6b7dd670735ce554c2b" + "reference": "e58ffa801a8e816c562f15bdc4731824f8f9c64a" }, "require": { "php": ">=7.0" @@ -1001,7 +1001,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1044,14 +1044,14 @@ "dist": { "type": "path", "url": "../../packages/device-detection", - "reference": "a6696f57f2f6f29f4a6930727ae5063c4e89fab4" + "reference": "d97d4ed63b8e702834bb60496f02e99d30197619" }, "require": { "php": ">=7.0" }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1094,14 +1094,14 @@ "dist": { "type": "path", "url": "../../packages/error", - "reference": "dfee9d42c99adb520d5ca9924f3afde48926369a" + "reference": "6fa9bb23ca4fe24284149ca750e6148621139517" }, "require": { "php": ">=7.0" }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1144,7 +1144,7 @@ "dist": { "type": "path", "url": "../../packages/explat", - "reference": "04730c821356389b213b361f33a2fc696826ad77" + "reference": "d53b06a5550c6f8c2f009c183b5ab037e6c648c5" }, "require": { "automattic/jetpack-connection": "@dev", @@ -1152,7 +1152,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1216,7 +1216,7 @@ "dist": { "type": "path", "url": "../../packages/forms", - "reference": "602d117040022dd07dacac0bf9da6f3d542bc9cf" + "reference": "14fabd3459819457087533a4404afcb8616ef65e" }, "require": { "automattic/jetpack-assets": "@dev", @@ -1231,7 +1231,7 @@ "automattic/jetpack-changelogger": "@dev", "automattic/jetpack-connection": "@dev", "automattic/wordbless": "^0.4.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1297,7 +1297,7 @@ "dist": { "type": "path", "url": "../../packages/image-cdn", - "reference": "fdd9e3c288c7ada8ddcc70fb46ff4ae1426b3309" + "reference": "a5b2d15b86d745342dc1de2ed0478e07e29df4ef" }, "require": { "automattic/jetpack-assets": "@dev", @@ -1307,7 +1307,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1360,7 +1360,7 @@ "dist": { "type": "path", "url": "../../packages/import", - "reference": "78099ea25f5e3d214e3845ce4a069d1c83e2c3fa" + "reference": "5b2ce5d8cf7f355b792b2bfd8fa2e0cd4ec9a83d" }, "require": { "automattic/jetpack-connection": "@dev", @@ -1370,7 +1370,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1429,7 +1429,7 @@ "dist": { "type": "path", "url": "../../packages/ip", - "reference": "b696350993b7f42257788add260e0efa7c9934f4" + "reference": "5f9e9900d766e6f2aa25f6b80f6da591e02af8c5" }, "require": { "php": ">=7.0" @@ -1437,7 +1437,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1484,7 +1484,7 @@ "dist": { "type": "path", "url": "../../packages/jitm", - "reference": "c21ef5f64d44c453e7a7dddbe13202c41aecb942" + "reference": "695db30039999154283059f6b2fe34fff746cd25" }, "require": { "automattic/jetpack-a8c-mc-stats": "@dev", @@ -1499,7 +1499,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1556,7 +1556,7 @@ "dist": { "type": "path", "url": "../../packages/licensing", - "reference": "4b35f767b1121c4691abc75e17ea650d6539d046" + "reference": "2507ac1d1f2bbc7a12e8dddb1cb9fa3f9423d8d7" }, "require": { "automattic/jetpack-connection": "@dev", @@ -1565,7 +1565,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1615,14 +1615,14 @@ "dist": { "type": "path", "url": "../../packages/logo", - "reference": "e152a4c83d1f952442d40260c559c4880757b298" + "reference": "0cbca46f49b19ea8f252cba7a7c67cf2b222824f" }, "require": { "php": ">=7.0" }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1665,7 +1665,7 @@ "dist": { "type": "path", "url": "../../packages/masterbar", - "reference": "9f21b1d7607b21df7becfcdb49002d310d891440" + "reference": "4d37336caa7e0c30dde20741f27a1785d65a8cb0" }, "require": { "automattic/jetpack-assets": "@dev", @@ -1684,7 +1684,7 @@ "automattic/patchwork-redefine-exit": "@dev", "automattic/wordbless": "dev-master", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1693,7 +1693,7 @@ "extra": { "autotagger": true, "branch-alias": { - "dev-trunk": "0.6.x-dev" + "dev-trunk": "0.8.x-dev" }, "changelogger": { "link-template": "https://github.com/Automattic/jetpack-masterbar/compare/v${old}...v${new}" @@ -1744,7 +1744,7 @@ "dist": { "type": "path", "url": "../../packages/my-jetpack", - "reference": "2c06449483ed175f949e69ba407e6e92363c3b84" + "reference": "df3217bf04a3c78de203fadcd4a1b796f21a5b60" }, "require": { "automattic/jetpack-admin-ui": "@dev", @@ -1761,7 +1761,6 @@ "automattic/jetpack-redirect": "@dev", "automattic/jetpack-status": "@dev", "automattic/jetpack-sync": "@dev", - "automattic/jetpack-waf": "@dev", "php": ">=7.0" }, "require-dev": { @@ -1769,7 +1768,7 @@ "automattic/jetpack-search": "@dev", "automattic/jetpack-videopress": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1783,7 +1782,7 @@ "link-template": "https://github.com/Automattic/jetpack-my-jetpack/compare/${old}...${new}" }, "branch-alias": { - "dev-trunk": "4.32.x-dev" + "dev-trunk": "4.33.x-dev" }, "version-constants": { "::PACKAGE_VERSION": "src/class-initializer.php" @@ -1846,7 +1845,7 @@ "dist": { "type": "path", "url": "../../packages/password-checker", - "reference": "16182898ae3faae3eb6ca9e5d2c490fd0b844243" + "reference": "b10057021f5d77cc3617afaa2672044e1e8ce1d5" }, "require": { "php": ">=7.0" @@ -1854,7 +1853,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1904,7 +1903,7 @@ "dist": { "type": "path", "url": "../../packages/plans", - "reference": "572028d8755c1c303f0643b2d3663b555e5ce87b" + "reference": "5b2084083304385b29ab96840abf799afd0f79c2" }, "require": { "automattic/jetpack-connection": "@dev", @@ -1914,7 +1913,7 @@ "automattic/jetpack-changelogger": "@dev", "automattic/jetpack-status": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -1969,7 +1968,7 @@ "dist": { "type": "path", "url": "../../packages/plugins-installer", - "reference": "c244721eaf5c40706e6275ce995a1f64931d6cd8" + "reference": "94f77ef5fa17584be1cf6ff0f3157c78ca888e31" }, "require": { "automattic/jetpack-a8c-mc-stats": "@dev", @@ -1978,7 +1977,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -2022,7 +2021,7 @@ "dist": { "type": "path", "url": "../../packages/post-list", - "reference": "d163b29e9f11af83ba2995fcec0106df86345c7e" + "reference": "31b15eb96fcb892ced260b76d1b861a0d23165e7" }, "require": { "automattic/jetpack-assets": "@dev", @@ -2031,7 +2030,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -2084,7 +2083,7 @@ "dist": { "type": "path", "url": "../../packages/protect-models", - "reference": "7acb119f496f32361379b236b6dbbcca68680d4d" + "reference": "de2bfbb992d4877826018aca7bd808072b34c62f" }, "require": { "php": ">=7.0" @@ -2092,7 +2091,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "0.4.2", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -2151,7 +2150,7 @@ "dist": { "type": "path", "url": "../../packages/protect-status", - "reference": "297c3a5f7826a8e4c76f9bc992d2bc3417a1b669" + "reference": "813bfcce0178120e2fe389bf2223a3c5b8802163" }, "require": { "automattic/jetpack-connection": "@dev", @@ -2164,7 +2163,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -2223,7 +2222,7 @@ "dist": { "type": "path", "url": "../../packages/publicize", - "reference": "9dbb115acd62d66dc4548594fc28442a298476d0" + "reference": "a93a6a56a70e7f1aa7fc965efaecd0000804f0f4" }, "require": { "automattic/jetpack-assets": "@dev", @@ -2237,7 +2236,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "0.4.2", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -2251,7 +2250,7 @@ "link-template": "https://github.com/Automattic/jetpack-publicize/compare/v${old}...v${new}" }, "branch-alias": { - "dev-trunk": "0.49.x-dev" + "dev-trunk": "0.50.x-dev" } }, "autoload": { @@ -2301,7 +2300,7 @@ "dist": { "type": "path", "url": "../../packages/redirect", - "reference": "effd6fdea78e9c3cb1bebf479474b4a9262444a1" + "reference": "3a861643edfc325a9150008bbde9a13d3aa77bb6" }, "require": { "automattic/jetpack-status": "@dev", @@ -2310,7 +2309,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -2353,7 +2352,7 @@ "dist": { "type": "path", "url": "../../packages/roles", - "reference": "0ac6d02e8ef2adb058f8f52e80a4924a33fa9b86" + "reference": "f89c7b97f2a26162f238096d290765510b387458" }, "require": { "php": ">=7.0" @@ -2361,7 +2360,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -2404,7 +2403,7 @@ "dist": { "type": "path", "url": "../../packages/search", - "reference": "166bd6f8bca2ec2da8ca3960b8cffe19983c095d" + "reference": "bc62920b3bcc3604c7275bc8d7812913522bf5d9" }, "require": { "automattic/jetpack-assets": "@dev", @@ -2419,7 +2418,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "0.4.2", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -2489,7 +2488,7 @@ "dist": { "type": "path", "url": "../../packages/stats", - "reference": "51130b6feb1e67769587bd503d52f17207303c6a" + "reference": "d532b2e0e9034ea1bedf2be0f16b2eb69d776713" }, "require": { "automattic/jetpack-connection": "@dev", @@ -2500,7 +2499,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -2553,7 +2552,7 @@ "dist": { "type": "path", "url": "../../packages/stats-admin", - "reference": "ff4b8867ed6377bbbef67e778b08eac0ccbe635c" + "reference": "8cb039727b34a6e18d6683f33ee1bfeb19f16358" }, "require": { "automattic/jetpack-connection": "@dev", @@ -2567,7 +2566,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "dev-master", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -2623,7 +2622,7 @@ "dist": { "type": "path", "url": "../../packages/status", - "reference": "782aceefdf8ebfcf4d24049700da9409628bf4de" + "reference": "7ff2e0454b5d9dafdd6ddd7c1917065f739408e0" }, "require": { "automattic/jetpack-constants": "@dev", @@ -2635,7 +2634,7 @@ "automattic/jetpack-ip": "@dev", "automattic/jetpack-plans": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -2684,7 +2683,7 @@ "dist": { "type": "path", "url": "../../packages/sync", - "reference": "1647bd686ed11800513f14aa1c93956e16a3b7f5" + "reference": "64ed9303f16e3377d99091c67842f3c4b07b71eb" }, "require": { "automattic/jetpack-connection": "@dev", @@ -2700,7 +2699,7 @@ "automattic/jetpack-search": "@dev", "automattic/jetpack-waf": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -2717,7 +2716,7 @@ "link-template": "https://github.com/Automattic/jetpack-sync/compare/v${old}...v${new}" }, "branch-alias": { - "dev-trunk": "3.6.x-dev" + "dev-trunk": "3.8.x-dev" }, "dependencies": { "test-only": [ @@ -2759,7 +2758,7 @@ "dist": { "type": "path", "url": "../../packages/videopress", - "reference": "a2141cef5a8cad5d00f4040f6474f08538d0d1d2" + "reference": "d1d13e7078cf764ebd17b136992f2f575930df33" }, "require": { "automattic/jetpack-admin-ui": "@dev", @@ -2773,7 +2772,7 @@ "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev", "brain/monkey": "2.6.1", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -2839,7 +2838,7 @@ "dist": { "type": "path", "url": "../../packages/waf", - "reference": "6e2fd903a4dc024db95b51904989506f65013e0e" + "reference": "d770cb6a3baeaf0455d09ee5c443f46a18b19f75" }, "require": { "automattic/jetpack-connection": "@dev", @@ -2852,7 +2851,7 @@ "require-dev": { "automattic/jetpack-changelogger": "@dev", "automattic/wordbless": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -2910,7 +2909,7 @@ "dist": { "type": "path", "url": "../../packages/wordads", - "reference": "91cca4ee789f1d49c018ded2637ad0f2066bcace" + "reference": "d401d5dee453857997f670c11352a6c85e62ee3d" }, "require": { "automattic/jetpack-assets": "@dev", @@ -2922,7 +2921,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -2986,7 +2985,7 @@ "dist": { "type": "path", "url": "../../packages/woocommerce-analytics", - "reference": "1f2950cc7f0b34e4406a6973886a5f88c08a77b6" + "reference": "595f8f553e413545332fc516dfe8503f2fc6fb97" }, "require": { "automattic/jetpack-connection": "@dev", @@ -2995,7 +2994,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "suggest": { "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." @@ -3229,7 +3228,7 @@ "dist": { "type": "path", "url": "../../packages/changelogger", - "reference": "d945e0cd8dec218ab24445d5ddc95894c9f24534" + "reference": "8489a82ca328626854da99e29f3cb0f017529cb5" }, "require": { "php": ">=7.0", @@ -3238,7 +3237,7 @@ }, "require-dev": { "wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "bin": [ "bin/changelogger" @@ -3303,7 +3302,7 @@ "dist": { "type": "path", "url": "../../packages/patchwork-redefine-exit", - "reference": "14e4719ada9d517ef6d15334f583fbdb65312eab" + "reference": "8746e7b07685991b1b6e8dbc37c8a6f7f13e013d" }, "require": { "antecedent/patchwork": "^2.1", @@ -3311,7 +3310,7 @@ }, "require-dev": { "automattic/jetpack-changelogger": "@dev", - "yoast/phpunit-polyfills": "1.1.0" + "yoast/phpunit-polyfills": "^1.1.1" }, "type": "library", "extra": { @@ -5910,16 +5909,16 @@ }, { "name": "yoast/phpunit-polyfills", - "version": "1.1.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/Yoast/PHPUnit-Polyfills.git", - "reference": "224e4a1329c03d8bad520e3fc4ec980034a4b212" + "reference": "a0f7d708794a738f328d7b6c94380fd1d6c40446" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/224e4a1329c03d8bad520e3fc4ec980034a4b212", - "reference": "224e4a1329c03d8bad520e3fc4ec980034a4b212", + "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/a0f7d708794a738f328d7b6c94380fd1d6c40446", + "reference": "a0f7d708794a738f328d7b6c94380fd1d6c40446", "shasum": "" }, "require": { @@ -5927,7 +5926,9 @@ "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, "require-dev": { - "yoast/yoastcs": "^2.3.0" + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "yoast/yoastcs": "^3.1.0" }, "type": "library", "extra": { @@ -5964,9 +5965,10 @@ ], "support": { "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues", + "security": "https://github.com/Yoast/PHPUnit-Polyfills/security/policy", "source": "https://github.com/Yoast/PHPUnit-Polyfills" }, - "time": "2023-08-19T14:25:08+00:00" + "time": "2024-04-05T16:01:51+00:00" } ], "aliases": [], diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/ai-assistant-toolbar-dropdown/dropdown-content.tsx b/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/ai-assistant-toolbar-dropdown/dropdown-content.tsx index 5f18abffe663b..37a612b506eba 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/ai-assistant-toolbar-dropdown/dropdown-content.tsx +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/ai-assistant-toolbar-dropdown/dropdown-content.tsx @@ -181,7 +181,7 @@ type AiAssistantToolbarDropdownContentProps = { /** * The React UI content of the dropdown. * @param {AiAssistantToolbarDropdownContentProps} props - The props. - * @returns {ReactElement} The React content of the dropdown. + * @return {ReactElement} The React content of the dropdown. */ export default function AiAssistantToolbarDropdownContent( { blockType, diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/ai-assistant-toolbar-dropdown/index.tsx b/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/ai-assistant-toolbar-dropdown/index.tsx index 913884be98d20..b006bc86575a1 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/ai-assistant-toolbar-dropdown/index.tsx +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/ai-assistant-toolbar-dropdown/index.tsx @@ -35,7 +35,7 @@ type AiAssistantBlockToolbarDropdownContentProps = { /** * The dropdown component with logic for the AI Assistant block. * @param {AiAssistantBlockToolbarDropdownContentProps} props - The props. - * @returns {ReactElement} The React content of the dropdown. + * @return {ReactElement} The React content of the dropdown. */ function AiAssistantBlockToolbarDropdownContent( { onClose, @@ -162,7 +162,7 @@ type AiAssistantBlockToolbarDropdownProps = { /** * The AI Assistant dropdown component. * @param {AiAssistantBlockToolbarDropdownProps} props - The props. - * @returns {ReactElement} The AI Assistant dropdown component. + * @return {ReactElement} The AI Assistant dropdown component. */ export default function AiAssistantBlockToolbarDropdown( { blockType, diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/connect-prompt/index.tsx b/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/connect-prompt/index.tsx index b4542db1a7b18..a09c7e233010d 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/connect-prompt/index.tsx +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/connect-prompt/index.tsx @@ -18,7 +18,7 @@ const ConnectPrompt = () => { return ( { + const { usagePeriod } = useAiFeature(); + + const getFormattedUsagePeriodStartDate = planUsagePeriod => { + if ( ! planUsagePeriod?.nextStart ) { + return null; + } + + const nextUsagePeriodStartDate = new Date( planUsagePeriod.nextStart ); + return ( + nextUsagePeriodStartDate.toLocaleString( 'default', { month: 'long' } ) + + ' ' + + nextUsagePeriodStartDate.getDate() + ); + }; + + const getFairUsageNoticeMessage = resetDateString => { + const fairUsageMessage = __( + "You've reached this month's request limit, per our fair usage policy.", + 'jetpack' + ); + + if ( ! resetDateString ) { + return fairUsageMessage; + } + + // Translators: %s is the date when the requests will reset. + const dateMessage = __( 'Requests will reset on %s.', 'jetpack' ); + const formattedDateMessage = sprintf( dateMessage, resetDateString ); + + return `${ fairUsageMessage } ${ formattedDateMessage }`; + }; + + const nextUsagePeriodStartDateString = getFormattedUsagePeriodStartDate( usagePeriod ); + + // Get the proper template based on the presence of the next usage period start date. + const fairUsageNoticeMessage = getFairUsageNoticeMessage( nextUsagePeriodStartDateString ); + + const fairUsageNoticeMessageElement = createInterpolateElement( fairUsageNoticeMessage, { + link: ( + + ), + } ); + + return fairUsageNoticeMessageElement; +}; + /** * The default upgrade prompt for the AI Assistant block, containing the Upgrade button and linking * to the checkout page or the Jetpack AI interstitial page. * - * @param {UpgradePromptProps} props - Component props. - * @returns {ReactElement} the Nudge component with the prompt. + * @param {QuotaExceededMessageProps} props - Component props. + * @return {ReactElement} the Nudge component with the prompt. */ const DefaultUpgradePrompt = ( { placement = null, description = null, useLightNudge = false, -}: UpgradePromptProps ): ReactElement => { +}: QuotaExceededMessageProps ): ReactElement => { const Nudge = useLightNudge ? LightNudge : StandardNudge; const { checkoutUrl } = useAICheckout(); @@ -170,10 +227,10 @@ const DefaultUpgradePrompt = ( { * The VIP upgrade prompt, with a single text message recommending that the user reach * out to their VIP account team. * - * @param {object} props - Component props. - * @param {string} props.description - The description to display in the prompt. + * @param {object} props - Component props. + * @param {string} props.description - The description to display in the prompt. * @param {boolean} props.useLightNudge - Wheter to use the light variant of the nudge, or the standard one. - * @returns {ReactElement} the Nudge component with the prompt. + * @return {ReactElement} the Nudge component with the prompt. */ const VIPUpgradePrompt = ( { description = null, @@ -209,8 +266,45 @@ const VIPUpgradePrompt = ( { ); }; -const UpgradePrompt = props => { - const { upgradeType } = useAiFeature(); +type FairUsageNoticeProps = { + variant?: 'error' | 'muted'; +}; + +/** + * The fair usage notice component. + * @param {FairUsageNoticeProps} props - Fair usage notice component props. + * @param {FairUsageNoticeProps.variant} props.variant - The variant of the notice to render. + * @return {ReactElement} the Notice component with the fair usage message. + */ +export const FairUsageNotice = ( { variant = 'error' }: FairUsageNoticeProps ) => { + const useFairUsageNoticeMessageElement = useFairUsageNoticeMessage(); + + if ( variant === 'muted' ) { + return ( + + { useFairUsageNoticeMessageElement } + + ); + } + + if ( variant === 'error' ) { + return ( + + { useFairUsageNoticeMessageElement } + + ); + } + + return null; +}; + +const QuotaExceededMessage = props => { + const { upgradeType, currentTier } = useAiFeature(); + + // Return notice component for the fair usage limit message, on unlimited plans. + if ( currentTier?.value === 1 ) { + return ; + } // If the user is on a VIP site, show the VIP upgrade prompt. if ( upgradeType === 'vip' ) { @@ -223,4 +317,4 @@ const UpgradePrompt = props => { return DefaultUpgradePrompt( props ); }; -export default UpgradePrompt; +export default QuotaExceededMessage; diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/upgrade-prompt/light-nudge.tsx b/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/quota-exceeded-message/light-nudge.tsx similarity index 100% rename from projects/plugins/jetpack/extensions/blocks/ai-assistant/components/upgrade-prompt/light-nudge.tsx rename to projects/plugins/jetpack/extensions/blocks/ai-assistant/components/quota-exceeded-message/light-nudge.tsx diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/upgrade-prompt/style.scss b/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/quota-exceeded-message/style.scss similarity index 53% rename from projects/plugins/jetpack/extensions/blocks/ai-assistant/components/upgrade-prompt/style.scss rename to projects/plugins/jetpack/extensions/blocks/ai-assistant/components/quota-exceeded-message/style.scss index 5e04a8e519ec1..35b21b5ec6713 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/upgrade-prompt/style.scss +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/components/quota-exceeded-message/style.scss @@ -12,3 +12,24 @@ } } } + +.jetpack-ai-fair-usage-notice-muted-variant { + line-height: 1.4; + margin: 0px; + text-wrap: pretty; + font-size: calc(13px); + font-weight: normal; + color: #757575; + + a { + color: #757575; + } +} + +.jetpack-ai-fair-usage-notice { + color: #1E1E1E; + + a { + color: #1E1E1E; + } +} diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/edit.js b/projects/plugins/jetpack/extensions/blocks/ai-assistant/edit.js index 841e0cb169a88..f2bed94f0106d 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/edit.js +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/edit.js @@ -26,11 +26,11 @@ import clsx from 'clsx'; */ import UsagePanel from '../../plugins/ai-assistant-plugin/components/usage-panel'; import { USAGE_PANEL_PLACEMENT_BLOCK_SETTINGS_SIDEBAR } from '../../plugins/ai-assistant-plugin/components/usage-panel/types'; -import { PLAN_TYPE_FREE, usePlanType } from '../../shared/use-plan-type'; +import { PLAN_TYPE_FREE, PLAN_TYPE_UNLIMITED, usePlanType } from '../../shared/use-plan-type'; import ConnectPrompt from './components/connect-prompt'; import FeedbackControl from './components/feedback-control'; +import QuotaExceededMessage, { FairUsageNotice } from './components/quota-exceeded-message'; import ToolbarControls from './components/toolbar-controls'; -import UpgradePrompt from './components/upgrade-prompt'; import { getStoreBlockId } from './extensions/ai-assistant/with-ai-assistant'; import useAIAssistant from './hooks/use-ai-assistant'; import useAICheckout from './hooks/use-ai-checkout'; @@ -61,6 +61,7 @@ export default function AIAssistantEdit( { attributes, setAttributes, clientId, requestsLimit, currentTier, loading: loadingAiFeature, + tierPlansEnabled, } = useAiFeature(); const requestsRemaining = Math.max( requestsLimit - requestsCount, 0 ); @@ -207,7 +208,6 @@ export default function AIAssistantEdit( { attributes, setAttributes, clientId, const handleGetSuggestion = ( ...args ) => { getSuggestionFromOpenAI( ...args ); focusOnBlock(); - return; }; const handleChange = value => { @@ -304,7 +304,7 @@ export default function AIAssistantEdit( { attributes, setAttributes, clientId, const banner = ( <> - { isOverLimit && isSelected && } + { isOverLimit && isSelected && } { ! connected && } ); @@ -323,6 +323,10 @@ export default function AIAssistantEdit( { attributes, setAttributes, clientId, ); + const fairUsageNotice = ( + <>{ isOverLimit && planType === PLAN_TYPE_UNLIMITED && } + ); + const trackUpgradeClick = useCallback( event => { event.preventDefault(); @@ -354,6 +358,12 @@ export default function AIAssistantEdit( { attributes, setAttributes, clientId,
) } + { fairUsageNotice && ( +
+ + { fairUsageNotice } +
+ ) } { /* Mock BlockCard component styles to keep alignment */ }
@@ -361,11 +371,14 @@ export default function AIAssistantEdit( { attributes, setAttributes, clientId, { __( 'Discover all features', 'jetpack' ) }
- - - - - + { ( planType === PLAN_TYPE_FREE || + ( tierPlansEnabled && planType !== PLAN_TYPE_UNLIMITED ) ) && ( + + + + + + ) } diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/extensions/ai-assistant/index.ts b/projects/plugins/jetpack/extensions/blocks/ai-assistant/extensions/ai-assistant/index.ts index e364f96b90f5f..9ab83d3cb5b52 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/extensions/ai-assistant/index.ts +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/extensions/ai-assistant/index.ts @@ -106,7 +106,7 @@ type BlockSettingsProps = { /** * Check if it is possible to extend the block. * - * @returns {boolean} True if it is possible to extend the block. + * @return {boolean} True if it is possible to extend the block. */ export function isPossibleToExtendBlock(): boolean { const isBlockRegistered = getBlockType( metadata.name ); @@ -149,8 +149,8 @@ export function isPossibleToExtendBlock(): boolean { * Add jetpack/ai support to the extended blocks. * * @param {BlockSettingsProps} settings - Block settings. - * @param {ExtendedBlockProp} name - Block name. - * @returns {BlockSettingsProps} Block settings. + * @param {ExtendedBlockProp} name - Block name. + * @return {BlockSettingsProps} Block settings. */ function addJetpackAISupport( settings: BlockSettingsProps, diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/extensions/jetpack-contact-form/components/ai-assistant-bar/index.tsx b/projects/plugins/jetpack/extensions/blocks/ai-assistant/extensions/jetpack-contact-form/components/ai-assistant-bar/index.tsx index 6ad31b73ee74c..75fbb13963429 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/extensions/jetpack-contact-form/components/ai-assistant-bar/index.tsx +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/extensions/jetpack-contact-form/components/ai-assistant-bar/index.tsx @@ -24,7 +24,7 @@ import React from 'react'; * Internal dependencies */ import ConnectPrompt from '../../../../components/connect-prompt'; -import UpgradePrompt from '../../../../components/upgrade-prompt'; +import QuotaExceededMessage from '../../../../components/quota-exceeded-message'; import useAiFeature from '../../../../hooks/use-ai-feature'; import { isUserConnected } from '../../../../lib/connection'; import { getJetpackFormCustomPrompt } from '../../../../lib/prompt'; @@ -49,7 +49,7 @@ const BREAKPOINTS = { * Return the serialized content from the childrens block. * * @param {string} clientId - The block client ID. - * @returns {string} The serialized content. + * @return {string} The serialized content. */ function getSerializedContentFromBlock( clientId: string ): string { if ( ! clientId?.length ) { @@ -267,7 +267,7 @@ export default function AiAssistantBar( { } ) } tabIndex={ -1 } > - { siteRequireUpgrade && } + { siteRequireUpgrade && } { ! connected && } * * @param {object} settings - The block settings. * @param {string} name - The block name. - * @returns {object} The block settings. + * @return {object} The block settings. */ function jetpackFormWithAiSupport( settings, name: string ) { // Only extend Jetpack Form block type. diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/extensions/jetpack-contact-form/ui-handler/with-ui-handler-data-provider.tsx b/projects/plugins/jetpack/extensions/blocks/ai-assistant/extensions/jetpack-contact-form/ui-handler/with-ui-handler-data-provider.tsx index f3d51dd96fb42..10bd22ede26b2 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/extensions/jetpack-contact-form/ui-handler/with-ui-handler-data-provider.tsx +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/extensions/jetpack-contact-form/ui-handler/with-ui-handler-data-provider.tsx @@ -39,9 +39,9 @@ type CoreEditorSelect = { * based on the block client ID. * Then, run the function passed as parameter (optional). * - * @param {string} clientId - The block client ID. - * @param {Function} fn - The function to run after selecting the block. - * @returns {void} + * @param {string} clientId - The block client ID. + * @param {Function} fn - The function to run after selecting the block. + * @return {void} */ export function selectFormBlock( clientId: string, fn: () => void ): void { const blockEditorDispatch = dispatch( 'core/block-editor' ); @@ -83,7 +83,7 @@ const withUiHandlerDataProvider = createHigherOrderComponent( BlockListBlock => /** * Show the AI Assistant * - * @returns {void} + * @return {void} */ const show = useCallback( () => { setAssistantVisibility( true ); @@ -92,7 +92,7 @@ const withUiHandlerDataProvider = createHigherOrderComponent( BlockListBlock => /** * Hide the AI Assistant * - * @returns {void} + * @return {void} */ const hide = useCallback( () => { setAssistantVisibility( false ); @@ -101,7 +101,7 @@ const withUiHandlerDataProvider = createHigherOrderComponent( BlockListBlock => /** * Toggle the AI Assistant visibility * - * @returns {void} + * @return {void} */ const toggle = useCallback( () => { setAssistantVisibility( ! isVisible ); @@ -122,7 +122,7 @@ const withUiHandlerDataProvider = createHigherOrderComponent( BlockListBlock => * Show the error notice * * @param {RequestingErrorProps} suggestionError - * @returns {void} + * @return {void} */ const showSuggestionError = useCallback( ( { severity, message, code }: RequestingErrorProps ) => { diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/hooks/use-ai-feature/index.ts b/projects/plugins/jetpack/extensions/blocks/ai-assistant/hooks/use-ai-feature/index.ts index 6a75e66bc5326..db84bbd4577c7 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/hooks/use-ai-feature/index.ts +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/hooks/use-ai-feature/index.ts @@ -2,11 +2,7 @@ * External dependencies */ import { useDispatch, useSelect } from '@wordpress/data'; -import { - PLAN_TYPE_FREE, - PLAN_TYPE_TIERED, - usePlanType as getPlanType, -} from '../../../../shared/use-plan-type'; +import { PLAN_TYPE_FREE, usePlanType as getPlanType } from '../../../../shared/use-plan-type'; import type { WordPressPlansSelectors } from 'extensions/store/wordpress-com'; export default function useAiFeature() { @@ -26,10 +22,11 @@ export default function useAiFeature() { const planType = getPlanType( currentTier ); + const currentTierLimit = currentTier?.limit || freeRequestsLimit; + const actualRequestsCount = - planType === PLAN_TYPE_TIERED ? usagePeriod?.requestsCount : allTimeRequestsCount; - const actualRequestsLimit = - planType === PLAN_TYPE_FREE ? freeRequestsLimit : currentTier?.limit; + planType === PLAN_TYPE_FREE ? allTimeRequestsCount : usagePeriod?.requestsCount; + const actualRequestsLimit = planType === PLAN_TYPE_FREE ? freeRequestsLimit : currentTierLimit; return { data: featureData, diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/hooks/use-selected-blocks/index.ts b/projects/plugins/jetpack/extensions/blocks/ai-assistant/hooks/use-selected-blocks/index.ts index 512017c8fb954..89b0427903695 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/hooks/use-selected-blocks/index.ts +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/hooks/use-selected-blocks/index.ts @@ -23,7 +23,7 @@ export type GetSelectedBlocksProps = { /** * Returns all selected blocks. * - * @returns {GetSelectedBlocksProps} The text content. + * @return {GetSelectedBlocksProps} The text content. */ export default function useSelectedBlocks(): GetSelectedBlocksProps { diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/components/ai-assistant-input/index.tsx b/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/components/ai-assistant-input/index.tsx index 0c8eceb89c2a6..90356810fd123 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/components/ai-assistant-input/index.tsx +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/components/ai-assistant-input/index.tsx @@ -76,6 +76,13 @@ export default function AiAssistantInput( { [ requireUpgrade, requestingState ] ); + /** + * Show the fair usage message when the site is on the unlimited tier and was flagged as requireUpgrade. + */ + const showFairUsageMessage = useMemo( () => { + return requireUpgrade && currentTier?.value === 1; + }, [ requireUpgrade, currentTier ] ); + const handleSend = useCallback( () => { tracks.recordEvent( 'jetpack_ai_assistant_extension_generate', { block_type: blockType, @@ -165,6 +172,7 @@ export default function AiAssistantInput( { error={ requestingError } requestsRemaining={ requestsRemaining } showUpgradeMessage={ showUpgradeMessage } + showFairUsageMessage={ showFairUsageMessage } upgradeUrl={ checkoutUrl } onChange={ setValue } onSend={ handleSend } diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/components/ai-assistant-toolbar-dropdown/index.tsx b/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/components/ai-assistant-toolbar-dropdown/index.tsx index e9591e20e2840..6909cae078180 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/components/ai-assistant-toolbar-dropdown/index.tsx +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/components/ai-assistant-toolbar-dropdown/index.tsx @@ -34,7 +34,7 @@ type AiAssistantExtensionToolbarDropdownContentProps = { /** * The dropdown component with logic for the AI Assistant block. * @param {AiAssistantExtensionToolbarDropdownContentProps} props - The props. - * @returns {ReactElement} The React content of the dropdown. + * @return {ReactElement} The React content of the dropdown. */ function AiAssistantExtensionToolbarDropdownContent( { blockType, diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/get-block-handler.tsx b/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/get-block-handler.tsx index fedee978c64b6..529ebdd77b73a 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/get-block-handler.tsx +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/get-block-handler.tsx @@ -44,8 +44,8 @@ export const InlineExtensionsContext = createContext( {} ); * Gets the block handler based on the block type. * The block handler is used to handle the request suggestions. * @param {ExtendedInlineBlockProp} blockType - The block type. - * @param {string} clientId - The block client ID. - * @returns {IBlockHandler} The block handler. + * @param {string} clientId - The block client ID. + * @return {IBlockHandler} The block handler. */ export function getBlockHandler( blockType: ExtendedInlineBlockProp, diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/lib/is-possible-to-extend-block.ts b/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/lib/is-possible-to-extend-block.ts index efa1f849f5550..9fbc5c12e0069 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/lib/is-possible-to-extend-block.ts +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/lib/is-possible-to-extend-block.ts @@ -11,7 +11,7 @@ import { EXTENDED_INLINE_BLOCKS, isAiAssistantSupportEnabled } from '../../exten /** * Check if it is possible to extend the block as an inline extension. * @param {string} blockName - The block name. - * @returns {boolean} Whether it is possible to extend the block. + * @return {boolean} Whether it is possible to extend the block. */ export function isPossibleToExtendBlock( blockName: string ): boolean { // Check if the AI Assistant block is registered. If not, we understand that Jetpack AI is not active. diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/with-ai-extension.tsx b/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/with-ai-extension.tsx index 633093e5617b7..9f01338eeb817 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/with-ai-extension.tsx +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/inline-extensions/with-ai-extension.tsx @@ -543,7 +543,7 @@ const blockEditWithAiComponents = createHigherOrderComponent( BlockEdit => { * Populates the block edit component with the AI Assistant bar and button. * @param {object} settings - The block settings. * @param {string} name - The block name. - * @returns {object} The extended block settings. + * @return {object} The extended block settings. */ function blockWithInlineExtension( settings, name: ExtendedInlineBlockProp ) { // Only extend the allowed block types and when AI is enabled diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/connection/index.ts b/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/connection/index.ts index abcdd8fd863bd..63d273fa1e093 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/connection/index.ts +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/connection/index.ts @@ -18,7 +18,7 @@ const debugOnce = content => { /** * Return the initial connection status. * - * @returns {boolean} true if the user is connected, false otherwise. + * @return {boolean} true if the user is connected, false otherwise. */ export function isUserConnected(): boolean { if ( isSimpleSite() ) { diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/prompt/backend-prompt.ts b/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/prompt/backend-prompt.ts index 4af0bb6876cd1..594ccf877e59f 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/prompt/backend-prompt.ts +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/prompt/backend-prompt.ts @@ -30,7 +30,7 @@ const SUBJECT_DEFAULT = null; * system prompt. * * @param {PromptTypeProp} promptType - The internal type of the prompt. - * @returns {PromptItemProps} The initial message. + * @return {PromptItemProps} The initial message. */ export function buildInitialMessageForBackendPrompt( promptType: PromptTypeProp ): PromptItemProps { // The basic template for the message. @@ -47,8 +47,8 @@ export function buildInitialMessageForBackendPrompt( promptType: PromptTypeProp * Builds the relevant content message, if applicable. * * @param {boolean} isContentGenerated - Whether the current content was generated. - * @param {string} relevantContent - The relevant content. - * @returns {PromptItemProps} The initial message. + * @param {string} relevantContent - The relevant content. + * @return {PromptItemProps} The initial message. */ export function buildRelevantContentMessageForBackendPrompt( isContentGenerated?: boolean, @@ -72,7 +72,7 @@ export function buildRelevantContentMessageForBackendPrompt( * based on the type of prompt. * * @param {BuildPromptProps} options - The prompt options. - * @returns {Array< PromptItemProps >} The prompt. + * @return {Array< PromptItemProps >} The prompt. */ export function buildMessagesForBackendPrompt( { generatedContent, @@ -145,10 +145,10 @@ export function buildMessagesForBackendPrompt( { /** * Gets the subject of the prompt. * - * @param {boolean} isGeneratingTitle - Whether the action is to generate a title. + * @param {boolean} isGeneratingTitle - Whether the action is to generate a title. * @param {boolean} isContentGenerated - Whether the current content was generated. - * @param {boolean} isFromExtension - Whether the content is from the extension. - * @returns {string} The subject. + * @param {boolean} isFromExtension - Whether the content is from the extension. + * @return {string} The subject. */ function getSubject( isGeneratingTitle?: boolean, @@ -170,7 +170,7 @@ function getSubject( * and the options of the prompt. * * @param {BuildPromptProps} options - The prompt options. - * @returns {object} The context. + * @return {object} The context. */ export function buildMessageContextForUserPrompt( { options, @@ -205,8 +205,8 @@ export function buildMessageContextForUserPrompt( { * Maps the internal prompt type to the backend prompt type. * * @param {PromptTypeProp} promptType - The internal type of the prompt. - * @param {string} extension - The extension of the prompt, if any. - * @returns {string} The backend type of the prompt. + * @param {string} extension - The extension of the prompt, if any. + * @return {string} The backend type of the prompt. */ export function mapInternalPromptTypeToBackendPromptType( promptType: PromptTypeProp, diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/prompt/index.ts b/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/prompt/index.ts index d2a9b99eaeca5..6a9f181c0d82e 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/prompt/index.ts +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/prompt/index.ts @@ -123,7 +123,7 @@ export type BuildPromptProps = { * Meant for use by the block, not the extensions. * * @param {BuildPromptProps} options - The prompt options. - * @returns {Array< PromptItemProps >} The prompt. + * @return {Array< PromptItemProps >} The prompt. * @throws {Error} If the type is not recognized. */ export function buildPromptForBlock( { diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/utils/block-content.ts b/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/utils/block-content.ts index 51afd871975f4..aef31f9561d5b 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/utils/block-content.ts +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/utils/block-content.ts @@ -13,7 +13,7 @@ import { select } from '@wordpress/data'; * to the current block, based on the given block clientId. * * @param {string} clientId - The current block clientId. - * @returns {string} The partial content. + * @return {string} The partial content. */ export function getPartialContentToBlock( clientId: string ): string { if ( ! clientId ) { @@ -35,7 +35,7 @@ export function getPartialContentToBlock( clientId: string ): string { * Returns content from all blocks, * by inspecting the blocks `content` attributes * - * @returns {string} The content. + * @return {string} The content. */ export function getContentFromBlocks(): string { const editor = select( 'core/block-editor' ); @@ -51,7 +51,7 @@ export function getContentFromBlocks(): string { /** * Given a list of blocks, it returns their content as a string. * @param {Array} blocks - The list of blocks. - * @returns {string} The content of the blocks as a string. + * @return {string} The content of the blocks as a string. */ export function getBlocksContent( blocks ) { return blocks @@ -64,7 +64,7 @@ export function getBlocksContent( blocks ) { * Returns the text content of the inner blocks of a block. * * @param {string} clientId - The block clientId. - * @returns {string} The text content. + * @return {string} The text content. */ export function getTextContentFromInnerBlocks( clientId: string ) { const block = select( 'core/block-editor' ).getBlock( clientId ); @@ -79,7 +79,7 @@ export function getTextContentFromInnerBlocks( clientId: string ) { * Extract raw text from HTML content * * @param {string} htmlString - The HTML content. - * @returns {string} The raw text. + * @return {string} The raw text. */ export function getRawTextFromHTML( htmlString: string ): string { // Removes all continuous whitespace from the start to check if the string is empty diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/utils/compare-blocks.ts b/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/utils/compare-blocks.ts index 5fffcc4cc9d26..f912beff9d7cf 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/utils/compare-blocks.ts +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/lib/utils/compare-blocks.ts @@ -21,7 +21,7 @@ const copyBlockWithoutClientId = ( block: Block ) => omitClientId( copyBlock( bl * * @param {Block} blockA - The first block to compare. * @param {Block} blockB - The second block to compare. - * @returns {boolean} Whether the two blocks are equal. + * @return {boolean} Whether the two blocks are equal. */ export function compareBlocks( blockA: Block, blockB: Block ): boolean { const aCopy = copyBlockWithoutClientId( blockA ); diff --git a/projects/plugins/jetpack/extensions/blocks/ai-assistant/transforms/index.tsx b/projects/plugins/jetpack/extensions/blocks/ai-assistant/transforms/index.tsx index 48c2b68d24ff6..468158dbdc40c 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-assistant/transforms/index.tsx +++ b/projects/plugins/jetpack/extensions/blocks/ai-assistant/transforms/index.tsx @@ -23,8 +23,8 @@ const from: unknown[] = []; * Return an AI Assistant block instance from a given block type. * * @param {ExtendedBlockProp} blockType - Block type. - * @param {object} attrs - Block attributes. - * @returns {object} AI Assistant block instance. + * @param {object} attrs - Block attributes. + * @return {object} AI Assistant block instance. */ export function transformToAIAssistantBlock( blockType: ExtendedBlockProp | ExtendedInlineBlockProp, diff --git a/projects/plugins/jetpack/extensions/blocks/ai-chat/question-answer.js b/projects/plugins/jetpack/extensions/blocks/ai-chat/question-answer.js index 1c7bb156d67a3..dd409c4f0aa49 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-chat/question-answer.js +++ b/projects/plugins/jetpack/extensions/blocks/ai-chat/question-answer.js @@ -65,15 +65,15 @@ function ShowLittleByLittle( { html, showAnimation, onAnimationDone } ) { /** * Primary question-answer. * - * @param {object} props - Component props. - * @param {string} props.askButtonLabel - Ask button label. - * @param {number} props.blogId - Blog ID. - * @param {string} props.blogType - Blog type (wpcom|jetpack) for wpcom simple and jetpack/atomic. - * @param {string} props.placeholder - Input placeholder. - * @param {boolean} props.settingShowCopy - Show copy button. + * @param {object} props - Component props. + * @param {string} props.askButtonLabel - Ask button label. + * @param {number} props.blogId - Blog ID. + * @param {string} props.blogType - Blog type (wpcom|jetpack) for wpcom simple and jetpack/atomic. + * @param {string} props.placeholder - Input placeholder. + * @param {boolean} props.settingShowCopy - Show copy button. * @param {boolean} props.settingShowFeedback - Show feedback (thumbs up/down) buttons. - * @param {boolean} props.settingShowSources - Show references (the list of URLs). - * @returns {QuestionAnswer} component. + * @param {boolean} props.settingShowSources - Show references (the list of URLs). + * @return {QuestionAnswer} component. */ export default function QuestionAnswer( { askButtonLabel = DEFAULT_ASK_BUTTON_LABEL, diff --git a/projects/plugins/jetpack/extensions/blocks/ai-paragraph/edit.js b/projects/plugins/jetpack/extensions/blocks/ai-paragraph/edit.js index f249ef56a387d..a079507a1decd 100644 --- a/projects/plugins/jetpack/extensions/blocks/ai-paragraph/edit.js +++ b/projects/plugins/jetpack/extensions/blocks/ai-paragraph/edit.js @@ -127,7 +127,7 @@ export default function Edit( { attributes, setAttributes, clientId } ) { if ( ! category ) { // Data is not yet loaded loading = true; - return; + return undefined; } return category; @@ -149,7 +149,7 @@ export default function Edit( { attributes, setAttributes, clientId } ) { if ( ! tag ) { // Data is not yet loaded loading = true; - return; + return undefined; } return tag; diff --git a/projects/plugins/jetpack/extensions/blocks/blogging-prompt/bloganuary-icon.svg b/projects/plugins/jetpack/extensions/blocks/blogging-prompt/bloganuary-icon.svg index b85805cd2a0a0..7e1091f8065a7 100644 --- a/projects/plugins/jetpack/extensions/blocks/blogging-prompt/bloganuary-icon.svg +++ b/projects/plugins/jetpack/extensions/blocks/blogging-prompt/bloganuary-icon.svg @@ -1 +1,13 @@ - \ No newline at end of file + + + + \ No newline at end of file diff --git a/projects/plugins/jetpack/extensions/blocks/blogging-prompt/icon.svg b/projects/plugins/jetpack/extensions/blocks/blogging-prompt/icon.svg index a129fd688644e..5b7ad0f235352 100644 --- a/projects/plugins/jetpack/extensions/blocks/blogging-prompt/icon.svg +++ b/projects/plugins/jetpack/extensions/blocks/blogging-prompt/icon.svg @@ -1 +1,6 @@ - \ No newline at end of file + + + diff --git a/projects/plugins/jetpack/extensions/blocks/blogroll/placeholder-site-icon.svg b/projects/plugins/jetpack/extensions/blocks/blogroll/placeholder-site-icon.svg index cc34e50db2036..707f0fa8492e1 100644 --- a/projects/plugins/jetpack/extensions/blocks/blogroll/placeholder-site-icon.svg +++ b/projects/plugins/jetpack/extensions/blocks/blogroll/placeholder-site-icon.svg @@ -1 +1,44 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/plugins/jetpack/extensions/blocks/button/edit.js b/projects/plugins/jetpack/extensions/blocks/button/edit.js index 40b991494d7c5..c1d57607b21c3 100644 --- a/projects/plugins/jetpack/extensions/blocks/button/edit.js +++ b/projects/plugins/jetpack/extensions/blocks/button/edit.js @@ -3,6 +3,7 @@ import { RichText, __experimentalUseGradient as useGradient, // eslint-disable-line @wordpress/no-unsafe-wp-apis withColors, + useBlockProps, } from '@wordpress/block-editor'; import { compose } from '@wordpress/compose'; import { __ } from '@wordpress/i18n'; @@ -36,7 +37,9 @@ export function ButtonEdit( props ) { : {}; /* eslint-enable react-hooks/rules-of-hooks */ - const blockClasses = clsx( 'wp-block-button', className ); + const blockProps = useBlockProps( { + className: clsx( 'wp-block-button', className ), + } ); const buttonClasses = clsx( 'wp-block-button__link', { 'has-background': backgroundColor.color || gradientValue, @@ -61,7 +64,7 @@ export function ButtonEdit( props ) { }; return ( -
+
+
{ 'blockEditor.useSetting.before', 'extensions/blocks/button/test/controls', ( value, path ) => { - if ( overrideSettings.hasOwnProperty( path ) ) { + if ( Object.hasOwn( overrideSettings, path ) ) { return overrideSettings[ path ]; } return value; diff --git a/projects/plugins/jetpack/extensions/blocks/button/test/edit.js b/projects/plugins/jetpack/extensions/blocks/button/test/edit.js index e70f4a2f43933..b33ee865addff 100644 --- a/projects/plugins/jetpack/extensions/blocks/button/test/edit.js +++ b/projects/plugins/jetpack/extensions/blocks/button/test/edit.js @@ -55,7 +55,7 @@ beforeEach( () => { * Render the button. * * @param {object} props - Props. - * @returns {HTMLElement} Button. + * @return {HTMLElement} Button. */ function renderButton( props ) { const { container } = render( ); diff --git a/projects/plugins/jetpack/extensions/blocks/contact-info/address/edit.js b/projects/plugins/jetpack/extensions/blocks/contact-info/address/edit.js index e44e65a465819..3a2acc2188a11 100644 --- a/projects/plugins/jetpack/extensions/blocks/contact-info/address/edit.js +++ b/projects/plugins/jetpack/extensions/blocks/contact-info/address/edit.js @@ -15,7 +15,6 @@ class AddressEdit extends Component { preventEnterKey( event ) { if ( event.key === 'Enter' ) { event.preventDefault(); - return; } } diff --git a/projects/plugins/jetpack/extensions/blocks/contact-info/class-jetpack-contact-info-block.php b/projects/plugins/jetpack/extensions/blocks/contact-info/class-jetpack-contact-info-block.php index 691302c530da3..9c961dc8e2f2d 100644 --- a/projects/plugins/jetpack/extensions/blocks/contact-info/class-jetpack-contact-info-block.php +++ b/projects/plugins/jetpack/extensions/blocks/contact-info/class-jetpack-contact-info-block.php @@ -22,7 +22,7 @@ class Jetpack_Contact_Info_Block { * @return string */ public static function render( $attr, $content ) { - Jetpack_Gutenberg::load_styles_as_required( __DIR__ ); + Jetpack_Gutenberg::load_assets_as_required( __DIR__ ); return str_replace( 'class="wp-block-jetpack-contact-info', // Closing " intentionally ommited to that the user can also add the className as expected. 'itemprop="location" itemscope itemtype="http://schema.org/Organization" class="wp-block-jetpack-contact-info', diff --git a/projects/plugins/jetpack/extensions/blocks/cookie-consent/edit.js b/projects/plugins/jetpack/extensions/blocks/cookie-consent/edit.js index be0e2c6b08174..c3888dde0b75e 100644 --- a/projects/plugins/jetpack/extensions/blocks/cookie-consent/edit.js +++ b/projects/plugins/jetpack/extensions/blocks/cookie-consent/edit.js @@ -8,11 +8,11 @@ import { useSaveCookieConsentSettings } from './use-save-cookie-consent-settings /** * Cookie Consent Edit Component. * - * @param {object} props - Component props. - * @param {string} props.clientId - Block id - * @param {object} props.attributes - {object} Block attributes. + * @param {object} props - Component props. + * @param {string} props.clientId - Block id + * @param {object} props.attributes - {object} Block attributes. * @param {Function} props.setAttributes - Set block attributes. - * @returns {object} Element to render. + * @return {object} Element to render. */ function CookieConsentBlockEdit( { clientId, attributes, setAttributes } ) { const { consentExpiryDays, align, text = DEFAULT_TEXT } = attributes; diff --git a/projects/plugins/jetpack/extensions/blocks/cookie-consent/save.js b/projects/plugins/jetpack/extensions/blocks/cookie-consent/save.js index f1587866f3e17..70d9ed864769a 100644 --- a/projects/plugins/jetpack/extensions/blocks/cookie-consent/save.js +++ b/projects/plugins/jetpack/extensions/blocks/cookie-consent/save.js @@ -12,10 +12,10 @@ import { DEFAULT_TEXT } from './constants'; * be combined into the final markup, which is then serialized by the block * editor into `post_content`. * - * @param {object} props - Save props. + * @param {object} props - Save props. * @param {object} props.attributes - Block attributes. * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#save - * @returns {object} Element to render. + * @return {object} Element to render. */ export default function save( { attributes } ) { const blockProps = useBlockProps.save(); diff --git a/projects/plugins/jetpack/extensions/blocks/donations/amount.js b/projects/plugins/jetpack/extensions/blocks/donations/amount.js index 800580d347320..2aedd36086b39 100644 --- a/projects/plugins/jetpack/extensions/blocks/donations/amount.js +++ b/projects/plugins/jetpack/extensions/blocks/donations/amount.js @@ -21,20 +21,23 @@ const Amount = ( { const richTextRef = useRef( null ); const setAmount = useCallback( - amount => { - setEditedValue( amount ); + ( amount, shouldSync ) => { + setEditedValue( currentAmount => { + // Validate the amount only when it changes. + if ( amount !== currentAmount ) { + const parsedAmount = parseAmount( amount, currency ); + if ( parsedAmount && parsedAmount >= minimumTransactionAmountForCurrency( currency ) ) { + setIsInvalid( false ); + if ( shouldSync ) { + onChange?.( parsedAmount ); + } + } else { + setIsInvalid( true ); + } + } - if ( ! onChange ) { - return; - } - - const parsedAmount = parseAmount( amount, currency ); - if ( parsedAmount && parsedAmount >= minimumTransactionAmountForCurrency( currency ) ) { - onChange( parsedAmount ); - setIsInvalid( false ); - } else { - setIsInvalid( true ); - } + return amount; + } ); }, [ currency, onChange ] ); @@ -76,12 +79,12 @@ const Amount = ( { return; } setEditedValue( formatCurrency( value, currency, { symbol: '' } ) ); - }, [ currency, isFocused, isInvalid, setAmount, value ] ); + }, [ currency, isFocused, isInvalid, value ] ); useEffect( () => { setAmount( formatCurrency( value, currency, { symbol: '' } ) ); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ value ] ); + }, [ currency, value ] ); return (
setAmount( amount ) } + onChange={ amount => setAmount( amount, true ) } placeholder={ formatCurrency( defaultValue, currency, { symbol: '' } ) } ref={ richTextRef } value={ editedValue } diff --git a/projects/plugins/jetpack/extensions/blocks/donations/donations.php b/projects/plugins/jetpack/extensions/blocks/donations/donations.php index f450d64244582..b59b63f760733 100644 --- a/projects/plugins/jetpack/extensions/blocks/donations/donations.php +++ b/projects/plugins/jetpack/extensions/blocks/donations/donations.php @@ -39,6 +39,18 @@ function register_block() { function render_block( $attr, $content ) { // Keep content as-is if rendered in other contexts than frontend (i.e. feed, emails, API, etc.). if ( ! jetpack_is_frontend() ) { + $parsed = parse_blocks( $content ); + if ( ! empty( $parsed[0] ) ) { + // Inject the link of the current post from the server side as the fallback link to make sure the donations block + // points to the correct post when it's inserted from the synced pattern (aka “My Pattern”). + $post_link = get_permalink(); + $parsed[0]['attrs']['fallbackLinkUrl'] = $post_link; + $content = \render_block( $parsed[0] ); + if ( preg_match( '/ { const { lockPostSaving, unlockPostSaving } = useDispatch( 'core/editor' ); const post = useSelect( select => select( 'core/editor' ).getCurrentPost(), [] ); + const isPostSavingLocked = useSelect( + select => select( 'core/editor' ).isPostSavingLocked(), + [] + ); const stripeConnectUrl = useSelect( - select => select( membershipProductsStore ).getConnectUrl(), - '' + select => select( membershipProductsStore ).getConnectUrl() || '', + [] ); const { setConnectUrl, setConnectedAccountDefaultCurrency } = useDispatch( MEMBERSHIPS_PRODUCTS_STORE ); - useEffect( () => { - setAttributes( { fallbackLinkUrl: post.link } ); - }, [ post.link, setAttributes ] ); - const stripeDefaultCurrency = useSelect( select => select( MEMBERSHIPS_PRODUCTS_STORE ).getConnectedAccountDefaultCurrency() ); useEffect( () => { - if ( ! currency && stripeDefaultCurrency ) { + if ( ! currency && stripeDefaultCurrency && ! isPostSavingLocked ) { const uppercasedStripeCurrency = stripeDefaultCurrency.toUpperCase(); const isCurrencySupported = !! SUPPORTED_CURRENCIES[ uppercasedStripeCurrency ]; if ( isCurrencySupported ) { @@ -53,7 +53,7 @@ const Edit = props => { setAttributes( { currency: 'USD' } ); } } - }, [ currency, stripeDefaultCurrency, setAttributes ] ); + }, [ currency, stripeDefaultCurrency, isPostSavingLocked, setAttributes ] ); const apiError = message => { setLoadingError( message ); @@ -120,6 +120,8 @@ const Edit = props => { unlockPostSaving( 'donations' ); }, apiError ); } + + unlockPostSaving( 'donations' ); }, apiError ); }, [ lockPostSaving, diff --git a/projects/plugins/jetpack/extensions/blocks/donations/utils.js b/projects/plugins/jetpack/extensions/blocks/donations/utils.js index 2fae1ed7d8d92..e02b90f1d2764 100644 --- a/projects/plugins/jetpack/extensions/blocks/donations/utils.js +++ b/projects/plugins/jetpack/extensions/blocks/donations/utils.js @@ -2,7 +2,7 @@ * Return the default texts defined in `donations.php` and injected client side by assigning them * to the `Jetpack_DonationsBlock` attribute of the window object. * - * @returns {object} Defaut texts for the block. + * @return {object} Defaut texts for the block. */ export function getDefaultTexts() { if ( 'undefined' === typeof window ) { diff --git a/projects/plugins/jetpack/extensions/blocks/eventbrite/deprecated/v1/index.js b/projects/plugins/jetpack/extensions/blocks/eventbrite/deprecated/v1/index.js index 52bcebe6f5437..df4ba29d55f0d 100644 --- a/projects/plugins/jetpack/extensions/blocks/eventbrite/deprecated/v1/index.js +++ b/projects/plugins/jetpack/extensions/blocks/eventbrite/deprecated/v1/index.js @@ -30,8 +30,8 @@ const deprecatedButtonAttributes = [ * * Uses a "button" element rather than "a", since the button opens a modal rather than * an external link. - * @param { object } attributes - Eventbrite block attributes. - * @returns { string } - Button markup to save. + * @param { object } attributes - Eventbrite block attributes. + * @return { string } - Button markup to save. */ function saveButton( attributes ) { const { diff --git a/projects/plugins/jetpack/extensions/blocks/eventbrite/utils.js b/projects/plugins/jetpack/extensions/blocks/eventbrite/utils.js index b86b36b889487..41c497f8cb9b8 100644 --- a/projects/plugins/jetpack/extensions/blocks/eventbrite/utils.js +++ b/projects/plugins/jetpack/extensions/blocks/eventbrite/utils.js @@ -16,8 +16,8 @@ export function convertToLink( url, onReplace ) { /** * Extracts an event id from an Eventbrite URL. * - * @param {string} url - Eventbrite URL. - * @returns {?number} - Event id. + * @param {string} url - Eventbrite URL. + * @return {?number} - Event id. */ export function eventIdFromUrl( url ) { if ( ! url ) { @@ -31,8 +31,8 @@ export function eventIdFromUrl( url ) { /** * Returns a normalized URL string from raw input. For now we're just trimming to avoid broken URLs. * - * @param {string} url - Eventbrite URL string. - * @returns {?string} - Normalized string. + * @param {string} url - Eventbrite URL string. + * @return {?string} - Normalized string. */ export function normalizeUrlInput( url = '' ) { if ( ! url || typeof url !== 'string' ) { diff --git a/projects/plugins/jetpack/extensions/blocks/gif/test/use-fetch-giphy-data.js b/projects/plugins/jetpack/extensions/blocks/gif/test/use-fetch-giphy-data.js index 2d1c7263e3d8b..722dd19427b10 100644 --- a/projects/plugins/jetpack/extensions/blocks/gif/test/use-fetch-giphy-data.js +++ b/projects/plugins/jetpack/extensions/blocks/gif/test/use-fetch-giphy-data.js @@ -54,7 +54,7 @@ const GIPHY_MULTIPLE_RESPONSE = { * Mock return value for a successful fetch JSON return value. * * @param {*} resolvedFetchPromiseResponse - JSON return value. - * @returns {Promise} Mock return value. + * @return {Promise} Mock return value. */ function getFetchMockReturnValue( resolvedFetchPromiseResponse ) { const resolvedFetchPromise = Promise.resolve( resolvedFetchPromiseResponse ); diff --git a/projects/plugins/jetpack/extensions/blocks/google-calendar/utils.js b/projects/plugins/jetpack/extensions/blocks/google-calendar/utils.js index 7b94f92e71cb7..0da29ed433863 100644 --- a/projects/plugins/jetpack/extensions/blocks/google-calendar/utils.js +++ b/projects/plugins/jetpack/extensions/blocks/google-calendar/utils.js @@ -17,8 +17,8 @@ const ATTRIBUTE_REGEX = /\s+(\w+)=(["'])(.*?)\2/gi; * * to an embed URL. * - * @param {string} shareableUrl - The Google Calendar shareable URL - * @returns {string|undefined} The embed URL or undefined if the conversion fails + * @param {string} shareableUrl - The Google Calendar shareable URL + * @return {string|undefined} The embed URL or undefined if the conversion fails */ export function convertShareableUrl( shareableUrl ) { const parsedUrl = SHAREABLE_REGEX.exec( shareableUrl ); @@ -33,8 +33,8 @@ export function convertShareableUrl( shareableUrl ) { /** * Given an