merge changes
This commit is contained in:
commit
4fa634ee0e
|
@ -25,7 +25,7 @@ Closes # .
|
|||
- [ ] Have you added an explanation of what your changes do and why you'd like us to include them?
|
||||
- [ ] Have you written new tests for your changes, as applicable?
|
||||
- [ ] Have you successfully run tests with your changes locally?
|
||||
- [ ] Have you created a changelog file for each project being changed, ie `pnpm nx changelog <project>`?
|
||||
- [ ] Have you created a changelog file for each project being changed, ie `pnpm changelog add --filter=<project>`?
|
||||
|
||||
<!-- Mark completed items with an [x] -->
|
||||
|
||||
|
|
|
@ -17,14 +17,9 @@ runs:
|
|||
- name: Install dependencies
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.working_directory }}
|
||||
run: pnpm install
|
||||
|
||||
- name: Install Composer dependencies
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.working_directory }}
|
||||
run: pnpm nx composer-install-no-dev woocommerce
|
||||
run: COMPOSER_NO_DEV=1 pnpm install
|
||||
|
||||
- name: Run build
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.working_directory }}
|
||||
run: pnpm nx build woocommerce
|
||||
run: pnpm exec turbo run build --filter=woocommerce
|
||||
|
|
|
@ -63,7 +63,7 @@ jobs:
|
|||
uses: ./.github/actions/install-build
|
||||
|
||||
- name: Build Admin feature config
|
||||
run: pnpm nx build:feature-config woocommerce
|
||||
run: pnpm build:feature-config --filter=woocommerce
|
||||
|
||||
- name: Add PHP8 Compatibility.
|
||||
run: |
|
||||
|
@ -75,7 +75,7 @@ jobs:
|
|||
composer bin phpunit config repositories.0 '{"type": "path", "url": "/tmp/phpunit-7.5-fork/phpunit-add-compatibility-with-php8-to-phpunit-7", "options": {"symlink": false}}'
|
||||
composer bin phpunit require --dev -W phpunit/phpunit:@dev --ignore-platform-reqs
|
||||
rm -rf ./vendor/phpunit/
|
||||
pnpm nx composer-dump-autoload woocommerce
|
||||
composer dump-autoload
|
||||
fi
|
||||
|
||||
- name: Init DB and WP
|
||||
|
@ -83,4 +83,4 @@ jobs:
|
|||
run: ./tests/bin/install.sh woo_test root root 127.0.0.1 ${{ matrix.wp }}
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm nx test-unit woocommerce
|
||||
run: pnpm exec turbo run test --filter=woocommerce
|
||||
|
|
|
@ -49,14 +49,16 @@ jobs:
|
|||
|
||||
- name: Build Admin feature config
|
||||
run: |
|
||||
pnpm nx build:feature-config woocommerce
|
||||
pnpm build:feature-config --filter=woocommerce
|
||||
|
||||
- name: Init DB and WP
|
||||
run: pnpm nx install-unit-test-db woocommerce
|
||||
working-directory: plugins/woocommerce
|
||||
run: bash tests/bin/install.sh woo_test root root 127.0.0.1 latest
|
||||
|
||||
- name: Run unit tests with code coverage. Allow to fail.
|
||||
working-directory: plugins/woocommerce
|
||||
run: |
|
||||
pnpm nx test-code-coverage woocommerce
|
||||
RUN_CODE_COVERAGE=1 bash tests/bin/phpunit.sh
|
||||
exit 0
|
||||
|
||||
- name: Send code coverage to Codecov.
|
||||
|
|
|
@ -12,13 +12,15 @@ jobs:
|
|||
- name: Install prerequisites
|
||||
run: |
|
||||
npm install -g pnpm@^6.24.2
|
||||
npm -g i @wordpress/env
|
||||
pnpm install
|
||||
pnpm build:feature-config --filter=woocommerce
|
||||
- name: Run analyzer
|
||||
id: run
|
||||
run: ./tools/code-analyzer/bin/dev analyzer "$GITHUB_HEAD_REF" -o github
|
||||
- name: Print results
|
||||
id: results
|
||||
run: echo "::set-output name=results::${{ steps.run.outputs.templates }}${{ steps.run.outputs.wphooks }}"
|
||||
run: echo "::set-output name=results::${{ steps.run.outputs.templates }}${{ steps.run.outputs.wphooks }}${{ steps.run.outputs.schema }}${{ steps.run.outputs.database }}"
|
||||
comment:
|
||||
name: Add comment to hightlight changes
|
||||
needs: analyze
|
||||
|
@ -29,7 +31,7 @@ jobs:
|
|||
id: find-comment
|
||||
with:
|
||||
issue-number: ${{ github.event.number }}
|
||||
comment-author: woocommercebot
|
||||
body-includes: New hook, template, or database changes in this PR
|
||||
- name: Add comment
|
||||
if: ${{ needs.analyze.outputs.results && (steps.find-comment.outputs.comment-id == '') }}
|
||||
uses: actions/github-script@v5
|
||||
|
@ -40,7 +42,7 @@ jobs:
|
|||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: '## New hook or template changes in this PR${{ needs.analyze.outputs.results }}'
|
||||
body: '## New hook, template, or database changes in this PR${{ needs.analyze.outputs.results }}'
|
||||
})
|
||||
- name: Update comment
|
||||
if: ${{ needs.analyze.outputs.results && steps.find-comment.outputs.comment-id }}
|
||||
|
@ -52,15 +54,19 @@ jobs:
|
|||
comment_id: ${{ steps.find-comment.outputs.comment-id }},
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: '## New hook or template changes in this PR${{ needs.analyze.outputs.results }}'
|
||||
body: '## New hook, template, or database changes in this PR${{ needs.analyze.outputs.results }}'
|
||||
})
|
||||
- name: Delete comment
|
||||
if: ${{ !needs.analyze.outputs.results && steps.find-comment.outputs.comment-id }}
|
||||
uses: izhangzhihao/delete-comment@master
|
||||
uses: actions/github-script@v5
|
||||
with:
|
||||
github_token: ${{ secrets.WC_BOT_TRIAGE_TOKEN }}
|
||||
delete_user_name: woocommercebot
|
||||
issue_number: ${{ github.event.number }}
|
||||
github-token: ${{ secrets.WC_BOT_TRIAGE_TOKEN }}
|
||||
script: |
|
||||
github.rest.issues.deleteComment({
|
||||
comment_id: ${{ steps.find-comment.outputs.comment-id }},
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo
|
||||
})
|
||||
- name: Add label
|
||||
if: ${{ needs.analyze.outputs.results }}
|
||||
uses: actions/github-script@v5
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
name: Run lint checks potentially affecting projects across the monorepo
|
||||
on: pull_request
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- 'trunk'
|
||||
concurrency:
|
||||
group: changelogger-${{ github.event_name }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
|
|
@ -35,13 +35,7 @@ jobs:
|
|||
uses: ./.github/actions/install-build
|
||||
|
||||
- name: Lint
|
||||
run: |
|
||||
pnpm nx build woocommerce-admin
|
||||
pnpm nx lint woocommerce-admin
|
||||
pnpm nx lint:js-packages woocommerce-admin
|
||||
run: pnpm exec turbo run lint --filter='@woocommerce/admin-library...' --filter='!@woocommerce/e2e*' --filter='!@woocommerce/api'
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
pnpm nx build woocommerce-admin
|
||||
pnpm nx test woocommerce-admin
|
||||
pnpm nx test:packages woocommerce-admin
|
||||
run: pnpm exec turbo run test --filter='@woocommerce/admin-library...' --filter='!@woocommerce/e2e*' --filter='!@woocommerce/api'
|
||||
|
|
|
@ -60,7 +60,7 @@ jobs:
|
|||
|
||||
- name: Build Admin feature config
|
||||
run: |
|
||||
pnpm nx build:feature-config woocommerce
|
||||
pnpm build:feature-config --filter=woocommerce
|
||||
|
||||
- name: Add PHP8 Compatibility.
|
||||
run: |
|
||||
|
@ -72,7 +72,7 @@ jobs:
|
|||
composer bin phpunit config repositories.0 '{"type": "path", "url": "/tmp/phpunit-7.5-fork/phpunit-add-compatibility-with-php8-to-phpunit-7", "options": {"symlink": false}}'
|
||||
composer bin phpunit require --dev -W phpunit/phpunit:@dev --ignore-platform-reqs
|
||||
rm -rf ./vendor/phpunit/
|
||||
pnpm nx composer-dump-autoload woocommerce
|
||||
composer dump-autoload
|
||||
fi
|
||||
|
||||
- name: Init DB and WP
|
||||
|
@ -80,4 +80,4 @@ jobs:
|
|||
run: ./tests/bin/install.sh woo_test root root 127.0.0.1 ${{ matrix.wp }}
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm nx test-unit woocommerce
|
||||
run: pnpm exec turbo run test --filter=woocommerce
|
||||
|
|
|
@ -20,14 +20,14 @@ $release_day_of_month = (int) date( 'j', $release_time );
|
|||
// If 26 days from now isn't the second Tuesday, then it's not code freeze day.
|
||||
if ( 'Tuesday' !== $release_day_of_week || $release_day_of_month < 8 || $release_day_of_month > 14 ) {
|
||||
echo 'Info: Today is not the Thursday of the code freeze.' . PHP_EOL;
|
||||
return;
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
$latest_version_with_release = get_latest_version_with_release();
|
||||
|
||||
if ( empty( $latest_version_with_release ) ) {
|
||||
echo '*** Error: Unable to get latest version with release' . PHP_EOL;
|
||||
return;
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
// Because we go from 5.9 to 6.0, we can get the next major_minor by adding 0.1 and formatting appropriately.
|
||||
|
@ -60,6 +60,8 @@ if ( create_github_branch_from_branch( 'trunk', $release_branch_to_create ) ) {
|
|||
} else if ( '422' === $github_api_response_code ) {
|
||||
// The release branch already existed when GitHub returns a 422 status.
|
||||
echo "Notice: Unable to create {$release_branch_to_create} branch. Maybe it already exists? Skipping..." . PHP_EOL;
|
||||
exit( 1 );
|
||||
} else {
|
||||
echo "*** Error: Unable to create {$release_branch_to_create}" . PHP_EOL;
|
||||
exit( 1 );
|
||||
}
|
||||
|
|
|
@ -177,7 +177,7 @@ jobs:
|
|||
|
||||
- name: Load docker images and start containers.
|
||||
working-directory: package/woocommerce
|
||||
run: pnpm nx docker-up woocommerce
|
||||
run: pnpm docker:up --filter=woocommerce
|
||||
|
||||
- name: Run tests command.
|
||||
working-directory: package/woocommerce/plugins/woocommerce
|
||||
|
|
|
@ -109,7 +109,7 @@ jobs:
|
|||
working-directory: package/woocommerce
|
||||
env:
|
||||
LATEST_WP_VERSION_MINUS: ${{ matrix.wp }}
|
||||
run: pnpm nx docker-up woocommerce
|
||||
run: pnpm docker:up --filter=woocommerce
|
||||
|
||||
- name: Run tests command.
|
||||
working-directory: package/woocommerce/plugins/woocommerce
|
||||
|
@ -188,7 +188,7 @@ jobs:
|
|||
working-directory: package/woocommerce
|
||||
env:
|
||||
LATEST_WP_VERSION_MINUS: ${{ matrix.wp }}
|
||||
run: pnpm nx docker-up woocommerce
|
||||
run: pnpm docker:up --filter=woocommerce
|
||||
|
||||
- name: Run tests command.
|
||||
working-directory: package/woocommerce/plugins/woocommerce
|
||||
|
|
|
@ -92,3 +92,6 @@ allure-results
|
|||
/plugins/woocommerce/e2e/output
|
||||
/plugins/woocommerce/e2e/report
|
||||
/plugins/woocommerce/e2e/storage
|
||||
|
||||
# Turborepo
|
||||
.turbo
|
||||
|
|
|
@ -2,4 +2,3 @@
|
|||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
pnpm install
|
||||
pnpm nx affected --target="composer-install" --base=ORIG_HEAD --head=HEAD
|
||||
|
|
|
@ -34,14 +34,7 @@ The port # might be different depending on your `.wp-env.override.json` configur
|
|||
Once you have WP-ENV container up, we need to run a few commands to start developing.
|
||||
|
||||
1. Run `pnpm install` to install npm modules.
|
||||
2. Run `pnpm nx build woocommerce` to build core.
|
||||
3. Run `pnpm nx composer-install woocommerce` to install PHP dependencies.
|
||||
|
||||
If you don't have Composer available locally, run the following command. It runs the command in WP-ENV container.
|
||||
|
||||
`wp-env run composer composer install`
|
||||
|
||||
You might also want to run `pnpm start` to watch your CSS and JS changes if you are working on the frontend.
|
||||
2. Run `pnpm exec turbo run build --filter=woocommerce` to build core.
|
||||
|
||||
You're now ready to develop!
|
||||
|
||||
|
|
72
README.md
72
README.md
|
@ -1,24 +1,55 @@
|
|||
<p align="center"><a href="https://woocommerce.com/"><img src="https://woocommerce.com/wp-content/themes/woo/images/logo-woocommerce@2x.png" alt="WooCommerce"></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://packagist.org/packages/woocommerce/woocommerce"><img src="https://poser.pugx.org/woocommerce/woocommerce/license" alt="license"></a>
|
||||
<a href="https://packagist.org/packages/woocommerce/woocommerce"><img src="https://poser.pugx.org/woocommerce/woocommerce/v/stable" alt="Latest Stable Version"></a>
|
||||
<img src="https://img.shields.io/wordpress/plugin/dt/woocommerce.svg" alt="WordPress.org downloads">
|
||||
<img src="https://img.shields.io/wordpress/plugin/r/woocommerce.svg" alt="WordPress.org rating">
|
||||
<a href="https://github.com/woocommerce/woocommerce/actions/workflows/ci.yml"><img src="https://github.com/woocommerce/woocommerce/actions/workflows/ci.yml/badge.svg?branch=trunk" alt="Build Status"></a>
|
||||
<a href="https://codecov.io/gh/woocommerce/woocommerce"><img src="https://codecov.io/gh/woocommerce/woocommerce/branch/trunk/graph/badge.svg" alt="codecov"></a>
|
||||
</p>
|
||||
Welcome to the WooCommerce Monorepo on GitHub. Here you can find all of the packages, plugins, and tools used in the development of the core WooCommerce plugin as well as WooCommerce extensions. You can browse the source, look at open issues, contribute code, and keep tracking of ongoing development.
|
||||
|
||||
Welcome to the WooCommerce repository on GitHub. Here you can browse the source, look at open issues and keep track of development. We recommend all developers to follow the [WooCommerce development blog](https://woocommerce.wordpress.com/) to stay up to date about everything happening in the project. You can also [follow @DevelopWC](https://twitter.com/DevelopWC) on Twitter for the latest development updates.
|
||||
We recommend all developers to follow the [WooCommerce development blog](https://woocommerce.wordpress.com/) to stay up to date about everything happening in the project. You can also [follow @DevelopWC](https://twitter.com/DevelopWC) on Twitter for the latest development updates.
|
||||
|
||||
If you are not a developer, please use the [WooCommerce plugin page](https://wordpress.org/plugins/woocommerce/) on WordPress.org.
|
||||
## Repository Structure
|
||||
|
||||
## Documentation
|
||||
* [WooCommerce Documentation](https://docs.woocommerce.com/)
|
||||
* [WooCommerce Developer Documentation](https://github.com/woocommerce/woocommerce/wiki)
|
||||
* [WooCommerce Code Reference](https://docs.woocommerce.com/wc-apidocs/)
|
||||
* [WooCommerce REST API Docs](https://woocommerce.github.io/woocommerce-rest-api-docs/)
|
||||
* [Setting up a development environment](https://github.com/woocommerce/woocommerce/wiki/How-to-set-up-WooCommerce-development-environment)
|
||||
* [**Plugins**](plugins): Our repository contains plugins that relate to or otherwise aid in the development of WooCommerce.
|
||||
* [**WooCommerce Core**](plugins/woocommerce): The core WooCommerce plugin is available in the plugins directory.
|
||||
* [**Packages**](packages): Contained within the packages directory are all of the [PHP](packages/php) and [JavaScript](packages/js) provided for the community. Some of these are internal dependencies and are marked with an `internal-` prefix.
|
||||
* [**Tools**](tools): We also have a growing number of tools within our repository. Many of these are intended to be utilities and scripts for use in the monorepo, but, this directory may also contain external tools.
|
||||
|
||||
## Getting Started
|
||||
|
||||
To get up and running within the WooCommerce Monorepo, you will need to make sure that you have installed all of the prerequisites.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
* [NVM](https://github.com/nvm-sh/nvm#installing-and-updating): While you can always install Node through other means, we recommend using NVM to ensure you're aligned with the version used by our development teams. Our repository contains [an `.nvmrc` file](.nvmrc) which helps ensure you are using the correct version of Node.
|
||||
* [PNPM](https://pnpm.io/installation): Our repository utilizes PNPM to manage project dependencies and run various scripts involved in building and testing projects.
|
||||
* [PHP 7.2+](https://www.php.net/manual/en/install.php): WooCommerce Core currently features a minimum PHP version of 7.2. While you don't need to use it to run a local development environment, you will need it to utilize Composer.
|
||||
* [Composer](https://getcomposer.org/doc/00-intro.md): We use Composer to manage all of the dependencies for PHP packages and plugins.
|
||||
|
||||
Once you've installed all of the prerequisites, you can run the following commands.
|
||||
|
||||
```bash
|
||||
# Ensure that you're using the correct version of Node
|
||||
nvm use
|
||||
# Install all of the NPM and Composer dependencies within the Monorepo
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### Building, Linting, and Testing
|
||||
|
||||
Our repository uses [Turborepo](https://turborepo.org) for running `build`, `lint`, `test`, and `e2e` commands. This tool ensures that all dependencies of a package, plugin, or tool are prepared before running a command. It also provides caching for command outputs in order to ensure that work is not performed unnecessarily.
|
||||
|
||||
Without any additional flags, running a command will execute it against every project in the monorepo. For example, `pnpm exec turbo run build` will build all of the projects within the monorepo. `pnpm exec turbo run test` will run unit tests for all of the projects within the monorepo.
|
||||
|
||||
This behavior can be desireable, as the cache should ensure anything that has not changed is not rebuilt. There are times, however, that you may want to explicitly run a command against a specific project.
|
||||
|
||||
This can be done using the `--filter` flag. For example, running `pnpm exec turbo run build --filter=woocommerce` will build the WooCommerce plugin, as well as all of the dependencies required for the plugin to function.
|
||||
|
||||
The `--filter` syntax also supports paths, such as `--filter='./plugins/**'` to build all of the plugins in the monorepo. [You can read more about the filtering syntax in Turborepo's documentation](https://turborepo.org/docs/core-concepts/filtering).
|
||||
|
||||
### Project-Specific Commands
|
||||
|
||||
Outside of the above `turbo` commands, there may be times where you want to run a command on a specific project. This can _also_ be done using the `--filter` syntax, however, you will run these commands using `pnpm`. For example, `pnpm postinstall --filter=woocommerce` will run the `"postinstall"` script from `plugins/woocommerce/package.json`.
|
||||
|
||||
## Development Environments
|
||||
|
||||
Our repository makes use of [the `@wordpress/env` package](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/) for providing development environments out-of-the-box. Once you have installed the package and its related dependencies, you should be able to run `wp-env start` in any of the `plugins/` folders. This will start a development environment and provide you with a URL to begin testing code using.
|
||||
|
||||
## Reporting Security Issues
|
||||
To disclose a security issue to our team, [please submit a report via HackerOne here](https://hackerone.com/automattic/).
|
||||
|
@ -33,12 +64,3 @@ This repository is not suitable for support. Please don't use our issue tracker
|
|||
* For customizations, you may want to check our list of [WooExperts](https://woocommerce.com/experts/) or [Codeable](https://codeable.io/).
|
||||
|
||||
Support requests in issues on this repository will be closed on sight.
|
||||
|
||||
## Contributing to WooCommerce
|
||||
If you have a patch or have stumbled upon an issue with WooCommerce core, you can contribute this back to the code. Please read our [contributor guidelines](https://github.com/woocommerce/woocommerce/blob/trunk/.github/CONTRIBUTING.md) for more information how you can do this.
|
||||
|
||||
<p align="center">
|
||||
<br/><br/>
|
||||
Made with 💜 by <a href="https://woocommerce.com/">WooCommerce</a>.<br/>
|
||||
<a href="https://woocommerce.com/careers/">We're hiring</a>! Come work with us!
|
||||
</p>
|
||||
|
|
34
nx.json
34
nx.json
|
@ -1,34 +0,0 @@
|
|||
{
|
||||
"extends": "@nrwl/workspace/presets/npm.json",
|
||||
"npmScope": "woocommerce-monorepo",
|
||||
"tasksRunnerOptions": {
|
||||
"default": {
|
||||
"runner": "@nrwl/workspace/tasks-runners/default",
|
||||
"options": {
|
||||
"cacheableOperations": [
|
||||
"build",
|
||||
"test",
|
||||
"lint",
|
||||
"package"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"targetDependencies": {
|
||||
"build": [
|
||||
{
|
||||
"target": "build",
|
||||
"projects": "dependencies"
|
||||
}
|
||||
],
|
||||
"package": [
|
||||
{
|
||||
"target": "package",
|
||||
"projects": "dependencies"
|
||||
}
|
||||
]
|
||||
},
|
||||
"affected": {
|
||||
"defaultBase": "trunk"
|
||||
}
|
||||
}
|
|
@ -23,15 +23,8 @@
|
|||
"create-extension": "node ./tools/create-extension/index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@automattic/nx-composer": "^0.1.0",
|
||||
"@babel/preset-env": "^7.16.11",
|
||||
"@babel/runtime": "^7.17.2",
|
||||
"@nrwl/cli": "^13.3.4",
|
||||
"@nrwl/devkit": "^13.1.4",
|
||||
"@nrwl/linter": "^13.3.4",
|
||||
"@nrwl/tao": "13.3.4",
|
||||
"@nrwl/web": "^13.3.4",
|
||||
"@nrwl/workspace": "^13.3.4",
|
||||
"@storybook/addon-a11y": "^6.4.19",
|
||||
"@storybook/addon-actions": "^6.4.19",
|
||||
"@storybook/addon-console": "^1.2.3",
|
||||
|
@ -72,6 +65,7 @@
|
|||
"request": "^2.88.2",
|
||||
"sass": "^1.49.9",
|
||||
"sass-loader": "^10.2.1",
|
||||
"turbo": "^1.2.9",
|
||||
"typescript": "4.2.4",
|
||||
"url-loader": "^1.1.2",
|
||||
"webpack": "^5.70.0"
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"build": "tsc --build",
|
||||
"start": "tsc --build --watch",
|
||||
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/admin-e2e-tests",
|
||||
"sourceRoot": "packages/js/admin-e2e-tests/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"build-watch": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "start"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test"
|
||||
}
|
||||
},
|
||||
"clean": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "clean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ For local setup, create a `.env` file in this folder with the three required val
|
|||
Alternatively, these values can be passed in via the command line. For example:
|
||||
|
||||
```shell
|
||||
BASE_URL=http://localhost:8084 USER_KEY=admin USER_SECRET=password npm run test:api
|
||||
BASE_URL=http://localhost:8084 USER_KEY=admin USER_SECRET=password npm run e2e:api
|
||||
```
|
||||
|
||||
When using a username and password combination instead of a consumer secret and consumer key, make sure to have the [JSON Basic Authentication plugin](https://github.com/WP-API/Basic-Auth) installed and activated on the test site.
|
||||
|
@ -43,7 +43,7 @@ The following optional variables can be set in your local `.env` file:
|
|||
To verify that everything is configured correctly, the following test script is available:
|
||||
|
||||
```shell
|
||||
npm run test:hello
|
||||
npm run e2e:hello
|
||||
```
|
||||
|
||||
This tests connectivity to the API by validating connection to the following:
|
||||
|
@ -56,7 +56,7 @@ This tests connectivity to the API by validating connection to the following:
|
|||
To run all of the API tests, you can use the following command:
|
||||
|
||||
```shell
|
||||
npm run test:api
|
||||
npm run e2e:api
|
||||
```
|
||||
|
||||
### Running groups of tests
|
||||
|
@ -66,7 +66,7 @@ To run a specific group of tests, you can use the `npm test -- --group=` command
|
|||
For example, if you wanted to only run the orders API tests, you can use the following:
|
||||
|
||||
```shell
|
||||
npm test -- --group=orders
|
||||
npm e2e -- --group=orders
|
||||
```
|
||||
|
||||
Alternatively, you can use `jest` to run test groups:
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
"description": "API tests for WooCommerce",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"test:api": "jest --group=api",
|
||||
"test:hello": "jest --group=hello",
|
||||
"e2e": "jest",
|
||||
"e2e:api": "jest --group=api",
|
||||
"e2e:hello": "jest --group=hello",
|
||||
"make:collection": "node utils/api-collection/build-collection.js",
|
||||
"report": "allure generate --clean && allure serve",
|
||||
"lint": "eslint data endpoints tests utils --ext=js,ts,tsx",
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/api-core-tests/",
|
||||
"sourceRoot": "packages/js/api-core-tests",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/api-core-tests"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test"
|
||||
}
|
||||
},
|
||||
"test-hello": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test:hello"
|
||||
}
|
||||
},
|
||||
"make-collection": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "make:collection"
|
||||
}
|
||||
},
|
||||
"test-api": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test:api"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@
|
|||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"clean": "rm -rf ./dist ./tsconfig.tsbuildinfo",
|
||||
"compile": "tsc -b",
|
||||
"build": "pnpm run clean && npm run compile",
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/api/",
|
||||
"sourceRoot": "packages/js/api/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/api"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"clean": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "clean"
|
||||
}
|
||||
},
|
||||
"compile": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "compile"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "lint"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Add tour kit component
|
|
@ -26,7 +26,9 @@
|
|||
],
|
||||
"types": "build-types",
|
||||
"dependencies": {
|
||||
"@automattic/calypso-color-schemes": "^2.1.1",
|
||||
"@automattic/interpolate-components": "^1.2.0",
|
||||
"@automattic/tour-kit": "^1.0.0",
|
||||
"@woocommerce/csv-export": "workspace:*",
|
||||
"@woocommerce/currency": "workspace:*",
|
||||
"@woocommerce/data": "workspace:*",
|
||||
|
@ -93,6 +95,7 @@
|
|||
"@testing-library/jest-dom": "^5.16.2",
|
||||
"@testing-library/react": "^12.1.3",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@types/wordpress__viewport": "^2.5.4",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"@woocommerce/internal-style-build": "workspace:*",
|
||||
"@wordpress/browserslist-config": "^4.1.1",
|
||||
|
@ -112,6 +115,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"build": "pnpm run build:js && pnpm run build:css",
|
||||
"build:js": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
|
||||
"build:css": "webpack",
|
||||
|
@ -120,9 +124,8 @@
|
|||
"lint:fix": "eslint src --ext=js,ts,tsx --fix",
|
||||
"prepack": "pnpm run clean && pnpm run build",
|
||||
"start": "concurrently \"tsc --build ./tsconfig.json --watch\" \"webpack --watch\"",
|
||||
"test": "pnpm run build && pnpm run test:nobuild",
|
||||
"test:nobuild": "jest --config ./jest.config.json",
|
||||
"test:update-snapshots": "pnpm run test:nobuild -- --updateSnapshot",
|
||||
"test": "jest --config ./jest.config.json",
|
||||
"test:update-snapshots": "pnpm run test -- --updateSnapshot",
|
||||
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
|
||||
},
|
||||
"lint-staged": {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/components",
|
||||
"sourceRoot": "packages/js/components/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/components"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"build-watch": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "start"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -58,3 +58,5 @@ export { default as ViewMoreList } from './view-more-list';
|
|||
export { default as WebPreview } from './web-preview';
|
||||
export { Badge } from './badge';
|
||||
export { DynamicForm } from './dynamic-form';
|
||||
export { default as TourKit } from './tour-kit';
|
||||
export * as TourKitTypes from './tour-kit/types';
|
|
@ -1,3 +1,8 @@
|
|||
/**
|
||||
* External Dependencies
|
||||
*/
|
||||
@import '@automattic/tour-kit/dist/esm/styles.scss';
|
||||
|
||||
/**
|
||||
* Internal Dependencies
|
||||
*/
|
||||
|
@ -38,3 +43,4 @@
|
|||
@import 'web-preview/style.scss';
|
||||
@import 'badge/style.scss';
|
||||
@import 'dynamic-form/style.scss';
|
||||
@import 'tour-kit/style.scss';
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
# tour-kit
|
||||
|
||||
A Woocommerce Tour Kit variant based on [@automattic/tour-kit](https://github.com/Automattic/wp-calypso/blob/trunk/packages/tour-kit/README.md) for configurable guided tours. Contains some optional effects (like spotlight and overlay) that can be enabled/disabled depending on the desired use..
|
||||
|
||||
Uses [Popper.js](https://popper.js.org/) underneath (also customizable via tour configuration).
|
||||
|
||||
## Usage
|
||||
|
||||
A typical expected workflow builds around:
|
||||
|
||||
1. Define the criteria for showing a tour.
|
||||
2. Define a configuration for the tour, passing along a handler for closing.
|
||||
3. Render it (or not).
|
||||
|
||||
### Sample
|
||||
|
||||
```jsx
|
||||
import { TourKit } from '@woocommerce/components';
|
||||
|
||||
function Tour() {
|
||||
// 1. Define the criteria for showing a tour:
|
||||
const [ showTour, setShowTour ] = useState( true );
|
||||
|
||||
// 2. Define a configuration for the tour, passing along a handler for closing.
|
||||
const config = {
|
||||
steps: [
|
||||
{
|
||||
referenceElements: {
|
||||
desktop: '.render-step-near-me',
|
||||
},
|
||||
meta: {
|
||||
heading: 'Lorem ipsum dolor sit amet.',
|
||||
descriptions: {
|
||||
desktop: 'Lorem ipsum dolor sit amet.',
|
||||
},
|
||||
primaryButtonText: "Done"
|
||||
},
|
||||
},
|
||||
],
|
||||
closeHandler: () => setShowTour( false ),
|
||||
options: {},
|
||||
};
|
||||
|
||||
// 3. Render it (or not):
|
||||
|
||||
if ( ! showTour ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <TourKit config={ config } />;
|
||||
}
|
||||
```
|
||||
|
||||
## Accessibility
|
||||
|
||||
### Keyboard Navigation
|
||||
|
||||
When a tour is rendered and focused, the following functionality exists:
|
||||
|
||||
- Close the tour on `ESC` key (in minimized view)
|
||||
- Go to previous/next step on `left/right` arrow keys (in step view)
|
||||
|
||||
## Configuration
|
||||
|
||||
The main API for configuring a tour is the config object. See example usage and [types.ts](./types.ts) for the full definition.
|
||||
|
||||
`config.steps`: An array of objects that define the content we wish to render on the page. Each step defined by:
|
||||
|
||||
- `referenceElements` (optional): A set of `desktop` & `mobile` selectors to render the step near.
|
||||
- `focusElement` (optional): A set of `desktop` & `mobile` & `iframe` selectors to automatically focus.
|
||||
- `meta`: Arbitrary object that encloses the content we want to render for each step.
|
||||
- `classNames` (optional): An array or CSV of CSS classes applied to a step.
|
||||
|
||||
`config.closeHandler`: The callback responsible for closing the tour.
|
||||
|
||||
- `tourStep`: A React component that will be called to render each step. Receives the following properties:
|
||||
|
||||
- `steps`: The steps defined for the tour.
|
||||
- `currentStepIndex`
|
||||
- `onDismiss`: Handler that dismissed/closes the tour.
|
||||
- `onNext`: Handler that progresses the tour to the next step.
|
||||
- `onPrevious`: Handler that takes the tour to the previous step.
|
||||
- `onMinimize`: Handler that minimizes the tour (passes rendering to `tourMinimized`).
|
||||
- `setInitialFocusedElement`: A dispatcher that assigns an element to be initially focused when a step renders (see examples).
|
||||
- `onGoToStep`: Handler that progresses the tour to a given step index.
|
||||
|
||||
- `tourMinimized`: A React component that will be called to render a minimized view for the tour. Receives the following properties:
|
||||
- `steps`: The steps defined for the tour.
|
||||
- `currentStepIndex`
|
||||
- `onDismiss`: Handler that dismissed/closes the tour.
|
||||
- `onMaximize`: Handler that expands the tour (passes rendering to `tourStep`).
|
||||
|
||||
`config.options` (optional):
|
||||
|
||||
- `classNames` (optional): An array or CSV of CSS classes to enclose the main tour frame with.
|
||||
|
||||
- `effects`: An object to enable/disable/combine various tour effects:
|
||||
|
||||
- `spotlight`: Adds a semi-transparent overlay and highlights the reference element when provided with a transparent box over it. Expects an object with optional styles to override the default highlight/spotlight behavior when provided (default: spotlight wraps the entire reference element).
|
||||
- `interactivity`: An object that configures whether the user is allowed to interact with the referenced element during the tour
|
||||
- `styles`: CSS properties that configures the styles applied to the spotlight overlay
|
||||
- `arrowIndicator`: Adds an arrow tip pointing at the reference element when provided.
|
||||
- `overlay`: Includes the semi-transparent overlay for all the steps (also blocks interactions with the rest of the page)
|
||||
- `autoScroll`: The page scrolls up and down automatically such that the step target element is visible to the user.
|
||||
|
||||
- `callbacks`: An object of callbacks to handle side effects from various interactions (see [types.ts](./src/types.ts)).
|
||||
|
||||
- `popperModifiers`: The tour uses Popper to position steps near reference elements (and for other effects). An implementation can pass its own modifiers to tailor the functionality further e.g. more offset or padding from the reference element.
|
||||
- `tourRating` (optional - only in WPCOM Tour Kit variant):
|
||||
- `enabled`: Whether to show rating in last step.
|
||||
- `useTourRating`: (optional) A hook to provide the rating from an external source/state (see [types.ts](./src/types.ts)).
|
||||
- `onTourRate`: (optional) A callback to fire off when a rating is submitted.
|
||||
|
||||
- `portalElementId`: A string that lets you customize under which DOM element the Tour will be appended.
|
||||
|
||||
`placement` (Optional) : Describes the preferred placement of the popper. Possible values are left-start, left, left-end, top-start, top, top-end, right-start, right, right-end, bottom-start, bottom, and bottom-end.
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Button, Flex, Icon } from '@wordpress/components';
|
||||
import { closeSmall } from '@wordpress/icons';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { createElement } from '@wordpress/element';
|
||||
import { TourStepRendererProps } from '@automattic/tour-kit';
|
||||
|
||||
interface Props {
|
||||
onDismiss: TourStepRendererProps[ 'onDismiss' ];
|
||||
}
|
||||
|
||||
const StepControls: React.FunctionComponent< Props > = ( { onDismiss } ) => {
|
||||
return (
|
||||
<Flex className="woocommerce-tour-kit-step-controls" justify="flex-end">
|
||||
<Button
|
||||
className="woocommerce-tour-kit-step-controls__close-btn"
|
||||
label={ __( 'Close Tour', 'woocommerce' ) }
|
||||
icon={ <Icon icon={ closeSmall } viewBox="6 4 12 14" /> }
|
||||
iconSize={ 16 }
|
||||
size={ 16 }
|
||||
onClick={ onDismiss( 'close-btn' ) }
|
||||
></Button>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default StepControls;
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Button } from '@wordpress/components';
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
import { createElement } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import type { WooTourStepRendererProps } from '../types';
|
||||
|
||||
type Props = Omit<
|
||||
WooTourStepRendererProps,
|
||||
'onMinimize' | 'setInitialFocusedElement'
|
||||
>;
|
||||
|
||||
const StepNavigation: React.FunctionComponent< Props > = ( {
|
||||
currentStepIndex,
|
||||
onNextStep,
|
||||
onPreviousStep,
|
||||
onDismiss,
|
||||
steps,
|
||||
} ) => {
|
||||
const isFirstStep = currentStepIndex === 0;
|
||||
const isLastStep = currentStepIndex === steps.length - 1;
|
||||
const { primaryButton = { text: '', isDisabled: false } } = steps[
|
||||
currentStepIndex
|
||||
].meta;
|
||||
|
||||
const NextButton = (
|
||||
<Button
|
||||
className="woocommerce-tour-kit-step-navigation__next-btn"
|
||||
isPrimary
|
||||
disabled={ primaryButton.isDisabled }
|
||||
onClick={ onNextStep }
|
||||
>
|
||||
{ primaryButton.text || __( 'Next', 'woocommerce' ) }
|
||||
</Button>
|
||||
);
|
||||
|
||||
const BackButton = (
|
||||
<Button
|
||||
className="woocommerce-tour-kit-step-navigation__back-btn"
|
||||
isSecondary
|
||||
onClick={ onPreviousStep }
|
||||
>
|
||||
{ __( 'Back', 'woocommerce' ) }
|
||||
</Button>
|
||||
);
|
||||
|
||||
const renderButtons = () => {
|
||||
if ( isFirstStep ) {
|
||||
return <div>{ NextButton }</div>;
|
||||
}
|
||||
|
||||
if ( isLastStep ) {
|
||||
return (
|
||||
<div>
|
||||
{ BackButton }
|
||||
<Button
|
||||
isPrimary
|
||||
disabled={ primaryButton.isDisabled }
|
||||
className="woocommerce-tour-kit-step-navigation__done-btn"
|
||||
onClick={ onDismiss( 'done-btn' ) }
|
||||
>
|
||||
{ primaryButton.text || __( 'Done', 'woocommerce' ) }
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{ BackButton }
|
||||
{ NextButton }
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="woocommerce-tour-kit-step-navigation">
|
||||
<div className="woocommerce-tour-kit-step-navigation__step">
|
||||
{ sprintf(
|
||||
/* translators: current progress in tour, eg: "Step 2 of 4" */
|
||||
__( 'Step %1$d of %2$d', 'woocommerce' ),
|
||||
currentStepIndex + 1,
|
||||
steps.length
|
||||
) }
|
||||
</div>
|
||||
{ renderButtons() }
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default StepNavigation;
|
|
@ -0,0 +1,115 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { withViewportMatch } from '@wordpress/viewport';
|
||||
import { Card, CardBody, CardFooter, CardHeader } from '@wordpress/components';
|
||||
import { createElement, useEffect } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import StepNavigation from './step-navigation';
|
||||
import StepControls from './step-controls';
|
||||
import type { WooTourStepRendererProps } from '../types';
|
||||
|
||||
const getFocusElement = (
|
||||
focusElementSelector: string | null,
|
||||
iframeSelector: string | null
|
||||
) => {
|
||||
if ( ! focusElementSelector ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( iframeSelector ) {
|
||||
const iframeElement = document.querySelector< HTMLIFrameElement >(
|
||||
iframeSelector
|
||||
);
|
||||
if ( ! iframeElement ) {
|
||||
return null;
|
||||
}
|
||||
const innerDoc =
|
||||
iframeElement.contentDocument ||
|
||||
( iframeElement.contentWindow &&
|
||||
iframeElement.contentWindow.document );
|
||||
|
||||
if ( ! innerDoc ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return innerDoc.querySelector< HTMLElement >( focusElementSelector );
|
||||
}
|
||||
|
||||
return document.querySelector< HTMLElement >( focusElementSelector );
|
||||
};
|
||||
|
||||
const Step: React.FunctionComponent<
|
||||
WooTourStepRendererProps & {
|
||||
isViewportMobile: boolean;
|
||||
}
|
||||
> = ( {
|
||||
steps,
|
||||
currentStepIndex,
|
||||
onDismiss,
|
||||
onNextStep,
|
||||
onPreviousStep,
|
||||
setInitialFocusedElement,
|
||||
onGoToStep,
|
||||
isViewportMobile,
|
||||
} ) => {
|
||||
const { descriptions, heading } = steps[ currentStepIndex ].meta;
|
||||
const description =
|
||||
descriptions[ isViewportMobile ? 'mobile' : 'desktop' ] ??
|
||||
descriptions.desktop;
|
||||
|
||||
const focusElementSelector =
|
||||
steps[ currentStepIndex ].focusElement?.[
|
||||
isViewportMobile ? 'mobile' : 'desktop'
|
||||
] || null;
|
||||
|
||||
const iframeSelector =
|
||||
steps[ currentStepIndex ].focusElement?.iframe || null;
|
||||
|
||||
const focusElement = getFocusElement(
|
||||
focusElementSelector,
|
||||
iframeSelector
|
||||
);
|
||||
|
||||
/*
|
||||
* Focus the element when step renders.
|
||||
*/
|
||||
useEffect( () => {
|
||||
if ( focusElement ) {
|
||||
setInitialFocusedElement( focusElement );
|
||||
}
|
||||
}, [ focusElement, setInitialFocusedElement ] );
|
||||
|
||||
return (
|
||||
<Card className="woocommerce-tour-kit-step" isElevated>
|
||||
<CardHeader isBorderless={ true } size="small">
|
||||
<StepControls onDismiss={ onDismiss } />
|
||||
</CardHeader>
|
||||
<CardBody className="woocommerce-tour-kit-step__body" size="small">
|
||||
<h2 className="woocommerce-tour-kit-step__heading">
|
||||
{ heading }
|
||||
</h2>
|
||||
<p className="woocommerce-tour-kit-step__description">
|
||||
{ description }
|
||||
</p>
|
||||
</CardBody>
|
||||
<CardFooter isBorderless={ true } size="small">
|
||||
<StepNavigation
|
||||
currentStepIndex={ currentStepIndex }
|
||||
onGoToStep={ onGoToStep }
|
||||
onNextStep={ onNextStep }
|
||||
onPreviousStep={ onPreviousStep }
|
||||
onDismiss={ onDismiss }
|
||||
steps={ steps }
|
||||
></StepNavigation>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default withViewportMatch( {
|
||||
isViewportMobile: '< medium',
|
||||
} )( Step );
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
|
||||
import { createElement } from '@wordpress/element';
|
||||
import TourKit, { TourStepRenderer } from '@automattic/tour-kit';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import TourKitStep from './components/step';
|
||||
import type { WooConfig } from './types';
|
||||
|
||||
interface Props {
|
||||
config: WooConfig;
|
||||
}
|
||||
|
||||
const defaultOptions = {
|
||||
effects: { spotlight: {}, arrowIndicator: true },
|
||||
};
|
||||
|
||||
const WooTourKit: React.FunctionComponent< Props > = ( { config } ) => {
|
||||
return (
|
||||
<TourKit
|
||||
__temp__className={ 'woocommerce-tour-kit' }
|
||||
config={ {
|
||||
options: {
|
||||
...defaultOptions,
|
||||
...config.options,
|
||||
},
|
||||
...config,
|
||||
renderers: {
|
||||
tourStep: TourKitStep as TourStepRenderer,
|
||||
// Disable minimize feature for woo tour kit.
|
||||
tourMinimized: () => null,
|
||||
},
|
||||
} }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default WooTourKit;
|
|
@ -0,0 +1,212 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { createElement, useState } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './style.scss';
|
||||
import '../style.scss';
|
||||
|
||||
import WooTourKit from '..';
|
||||
import type { WooConfig, WooOptions } from '../types';
|
||||
|
||||
export default {
|
||||
title: 'WooCommerce Admin/components/TourKit',
|
||||
component: WooTourKit,
|
||||
};
|
||||
|
||||
const References = () => {
|
||||
return (
|
||||
<div className={ 'storybook__tourkit-references' }>
|
||||
<div className={ 'storybook__tourkit-references-container' }>
|
||||
<div className={ 'storybook__tourkit-references-a' }>
|
||||
<p>Reference A</p>
|
||||
</div>
|
||||
<div className={ 'storybook__tourkit-references-b' }>
|
||||
<p>Reference B</p>
|
||||
<div style={ { display: 'grid', placeItems: 'center' } }>
|
||||
<input
|
||||
style={ { margin: 'auto', display: 'block' } }
|
||||
></input>
|
||||
</div>
|
||||
</div>
|
||||
<div className={ 'storybook__tourkit-references-c' }>
|
||||
<p>Reference C</p>
|
||||
</div>
|
||||
<div className={ 'storybook__tourkit-references-d' }>
|
||||
<p>Reference D</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Tour = ( {
|
||||
onClose,
|
||||
options,
|
||||
placement,
|
||||
}: {
|
||||
onClose: () => void;
|
||||
options?: WooOptions;
|
||||
placement?: WooConfig[ 'placement' ];
|
||||
} ) => {
|
||||
const config: WooConfig = {
|
||||
placement,
|
||||
steps: [
|
||||
{
|
||||
referenceElements: {
|
||||
desktop: '.storybook__tourkit-references-a',
|
||||
mobile: '.storybook__tourkit-references-a',
|
||||
},
|
||||
meta: {
|
||||
heading: 'Change content',
|
||||
descriptions: {
|
||||
desktop:
|
||||
'You can change the content and add any relevant links.',
|
||||
mobile:
|
||||
'You can change the content and add any relevant links.',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
referenceElements: {
|
||||
desktop: '.storybook__tourkit-references-b',
|
||||
mobile: '.storybook__tourkit-references-b',
|
||||
},
|
||||
focusElement: {
|
||||
desktop: '.storybook__tourkit-references-b input',
|
||||
},
|
||||
meta: {
|
||||
heading: 'Shipping zones',
|
||||
descriptions: {
|
||||
desktop:
|
||||
'We added a few shipping zones for you based on your location, but you can manage them at any time.',
|
||||
mobile:
|
||||
'A shipping zone is a geographic area where a certain set of shipping methods are offered.',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
referenceElements: {
|
||||
desktop: '.storybook__tourkit-references-c',
|
||||
mobile: '.storybook__tourkit-references-c',
|
||||
},
|
||||
meta: {
|
||||
heading: 'Shipping methods',
|
||||
descriptions: {
|
||||
desktop:
|
||||
'We defaulted to some recommended shipping methods based on your store location, but you can manage them at any time within each shipping zone settings. ',
|
||||
mobile:
|
||||
'We defaulted to some recommended shipping methods based on your store location, but you can manage them at any time within each shipping zone settings. ',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
referenceElements: {
|
||||
desktop: '.storybook__tourkit-references-d',
|
||||
mobile: '.storybook__tourkit-references-d',
|
||||
},
|
||||
meta: {
|
||||
heading: 'Laura 4',
|
||||
descriptions: {
|
||||
desktop: 'Lorem ipsum dolor sit amet.',
|
||||
mobile: 'Lorem ipsum dolor sit amet.',
|
||||
},
|
||||
primaryButton: {
|
||||
isDisabled: true,
|
||||
text: 'Keep editing',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
closeHandler: onClose,
|
||||
options: {
|
||||
classNames: [ 'mytour' ],
|
||||
...options,
|
||||
},
|
||||
};
|
||||
|
||||
return <WooTourKit config={ config } />;
|
||||
};
|
||||
|
||||
const StoryTour = ( {
|
||||
options = {},
|
||||
placement,
|
||||
}: {
|
||||
options?: WooConfig[ 'options' ];
|
||||
placement?: WooConfig[ 'placement' ];
|
||||
} ) => {
|
||||
const [ showTour, setShowTour ] = useState( false );
|
||||
|
||||
return (
|
||||
<div className="storybook__tourkit">
|
||||
<References />
|
||||
{ ! showTour && (
|
||||
<button onClick={ () => setShowTour( true ) }>
|
||||
Start Tour
|
||||
</button>
|
||||
) }
|
||||
{ showTour && (
|
||||
<Tour
|
||||
placement={ placement }
|
||||
onClose={ () => setShowTour( false ) }
|
||||
options={ options }
|
||||
/>
|
||||
) }
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const NoEffects = () => (
|
||||
<StoryTour
|
||||
options={ {
|
||||
effects: {},
|
||||
} }
|
||||
/>
|
||||
);
|
||||
export const Spotlight = () => (
|
||||
<StoryTour
|
||||
options={ {
|
||||
effects: { arrowIndicator: true, spotlight: {} },
|
||||
} }
|
||||
/>
|
||||
);
|
||||
export const Overlay = () => (
|
||||
<StoryTour
|
||||
options={ {
|
||||
effects: { arrowIndicator: true, overlay: true },
|
||||
} }
|
||||
/>
|
||||
);
|
||||
export const SpotlightInteractivity = () => (
|
||||
<StoryTour
|
||||
options={ {
|
||||
effects: {
|
||||
spotlight: {
|
||||
interactivity: {
|
||||
rootElementSelector: '#root',
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
} }
|
||||
/>
|
||||
);
|
||||
export const AutoScroll = () => (
|
||||
<>
|
||||
<div style={ { height: '10vh' } }></div>
|
||||
<StoryTour
|
||||
options={ {
|
||||
effects: {
|
||||
autoScroll: {
|
||||
behavior: 'smooth',
|
||||
},
|
||||
},
|
||||
} }
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
export const Placement = () => <StoryTour placement={ 'left' } />;
|
|
@ -0,0 +1,73 @@
|
|||
.storybook__tourkit {
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
.storybook__tourkit-step,
|
||||
.storybook__tourkit-minimized {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.storybook__tourkit-step {
|
||||
min-height: 150px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.storybook__tourkit-step-controls,
|
||||
.storybook__tourkit-minimized-controls {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.storybook__tourkit-references {
|
||||
height: 400px;
|
||||
margin-bottom: 30px;
|
||||
overflow: auto;
|
||||
resize: auto;
|
||||
|
||||
.storybook__tourkit-references-container {
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
||||
grid-template-rows: 1fr 1fr 1fr 1fr;
|
||||
gap: 0 0;
|
||||
grid-auto-flow: row;
|
||||
grid-template-areas:
|
||||
'Ref-A Ref-B Ref-B Ref-B Ref-D'
|
||||
'Ref-A Ref-B Ref-B Ref-B Ref-D'
|
||||
'Ref-A Ref-C Ref-C Ref-C Ref-D'
|
||||
'Ref-A Ref-C Ref-C Ref-C Ref-D';
|
||||
}
|
||||
|
||||
.storybook__tourkit-references-a,
|
||||
.storybook__tourkit-references-b,
|
||||
.storybook__tourkit-references-c,
|
||||
.storybook__tourkit-references-d {
|
||||
display: grid;
|
||||
> p {
|
||||
align-self: center;
|
||||
justify-self: center;
|
||||
}
|
||||
}
|
||||
|
||||
.storybook__tourkit-references-a {
|
||||
background-color: silver;
|
||||
grid-area: Ref-A;
|
||||
}
|
||||
|
||||
.storybook__tourkit-references-b {
|
||||
background-color: orange;
|
||||
grid-area: Ref-B;
|
||||
}
|
||||
|
||||
.storybook__tourkit-references-c {
|
||||
background-color: palevioletred;
|
||||
grid-area: Ref-C;
|
||||
}
|
||||
|
||||
.storybook__tourkit-references-d {
|
||||
background-color: gainsboro;
|
||||
grid-area: Ref-D;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
.woocommerce-tour-kit{
|
||||
box-shadow: 0 0 8px rgba( 0, 0, 0, 0.15 );
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
|
||||
.woocommerce-tour-kit-step {
|
||||
width: 350px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.woocommerce-tour-kit-step__body {
|
||||
padding-top: 0;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.woocommerce-tour-kit-step__heading {
|
||||
color: $studio-gray-100;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
letter-spacing: -0.1px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.woocommerce-tour-kit-step__description {
|
||||
color: $studio-gray-80;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
letter-spacing: -0.24px;
|
||||
margin: 4px 0 0;
|
||||
}
|
||||
|
||||
.woocommerce-tour-kit-step-controls__close-btn {
|
||||
height: 16px;
|
||||
min-width: 16px;
|
||||
padding: 0;
|
||||
svg {
|
||||
fill: #1e1e1e;
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-tour-kit-step-navigation {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
|
||||
button {
|
||||
margin-left: $gap;
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-tour-kit-step-navigation__step {
|
||||
color: $studio-gray-60;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.tour-kit-frame__arrow, .tour-kit-frame__arrow::before {
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { createElement } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import TourKit from '..';
|
||||
|
||||
jest.mock( '@automattic/calypso-config' );
|
||||
|
||||
const config = {
|
||||
steps: [
|
||||
{
|
||||
referenceElements: {
|
||||
desktop: '.render-step-near-me',
|
||||
},
|
||||
meta: {
|
||||
heading: 'Step1',
|
||||
descriptions: {
|
||||
desktop: 'Description',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
referenceElements: {
|
||||
desktop: '.render-step-near-me',
|
||||
},
|
||||
meta: {
|
||||
heading: 'Step2',
|
||||
descriptions: {
|
||||
desktop: 'Description',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
closeHandler: () => jest.fn(),
|
||||
options: {},
|
||||
};
|
||||
|
||||
describe( 'TourKit', () => {
|
||||
it( 'should render TourKit', () => {
|
||||
const { queryByText } = render( <TourKit config={ config } /> );
|
||||
expect( queryByText( 'Step1' ) ).toBeInTheDocument();
|
||||
} );
|
||||
|
||||
it( 'should go to next step and show a back button', async () => {
|
||||
const { queryByText, getByRole } = render(
|
||||
<TourKit config={ config } />
|
||||
);
|
||||
userEvent.click( getByRole( 'button', { name: 'Next' } ) );
|
||||
|
||||
await waitFor( () =>
|
||||
expect( queryByText( 'Step2' ) ).toBeInTheDocument()
|
||||
);
|
||||
expect( getByRole( 'button', { name: 'Back' } ) ).toBeInTheDocument();
|
||||
} );
|
||||
} );
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import {
|
||||
Step,
|
||||
Options,
|
||||
Config,
|
||||
TourStepRendererProps,
|
||||
} from '@automattic/tour-kit';
|
||||
|
||||
export interface WooStep extends Step {
|
||||
meta: {
|
||||
heading: string | null;
|
||||
descriptions: {
|
||||
desktop: string | React.ReactElement | null;
|
||||
mobile?: string | React.ReactElement | null;
|
||||
};
|
||||
primaryButton?: {
|
||||
/** Set a text for the button. Default to "Done" for the last step and "Next" for the other steps */
|
||||
text?: string;
|
||||
/** Disable the button or not. Default to False */
|
||||
isDisabled?: boolean;
|
||||
};
|
||||
};
|
||||
/** Auto apply the focus state for the element. Default to null */
|
||||
focusElement?: {
|
||||
desktop?: string;
|
||||
mobile?: string;
|
||||
/** Iframe HTML selector. Default to null. If set, it will find the focus element in the iframe */
|
||||
iframe?: string;
|
||||
};
|
||||
}
|
||||
export type WooOptions = Options;
|
||||
|
||||
export interface WooConfig extends Omit< Config, 'renderers' | 'isMinimized' > {
|
||||
steps: WooStep[];
|
||||
options?: WooOptions;
|
||||
}
|
||||
|
||||
export interface WooTourStepRendererProps extends TourStepRendererProps {
|
||||
steps: WooStep[];
|
||||
}
|
|
@ -30,14 +30,14 @@
|
|||
},
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
|
||||
"build": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
|
||||
"start": "tsc --build --watch",
|
||||
"prepack": "pnpm run clean && pnpm run build",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"test": "pnpm run build && pnpm run test:nobuild",
|
||||
"test:nobuild": "jest --config ./jest.config.json",
|
||||
"test": "jest --config ./jest.config.json",
|
||||
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/csv-export",
|
||||
"sourceRoot": "packages/js/csv-export/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/csv-export"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"build-watch": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "start"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,14 +33,14 @@
|
|||
},
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
|
||||
"build": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
|
||||
"start": "tsc --build --watch",
|
||||
"prepack": "pnpm run clean && pnpm run build",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"test": "pnpm run build && pnpm run test:nobuild",
|
||||
"test:nobuild": "jest --config ./jest.config.json",
|
||||
"test": "jest --config ./jest.config.json",
|
||||
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/currency",
|
||||
"sourceRoot": "packages/js/currency/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/currency"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"build-watch": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "start"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -62,6 +62,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
|
||||
"build": "pnpm run build:js && pnpm run build:css",
|
||||
"build:js": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
|
||||
|
@ -70,8 +71,7 @@
|
|||
"prepack": "pnpm run clean && pnpm run build",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"test": "pnpm run build && pnpm run test:nobuild",
|
||||
"test:nobuild": "jest --config ./jest.config.json",
|
||||
"test": "jest --config ./jest.config.json",
|
||||
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
|
||||
},
|
||||
"lint-staged": {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/customer-effort-score",
|
||||
"sourceRoot": "packages/js/customer-effort-score/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/customer-effort-score"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"build-watch": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "start"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Add create product actions in products data store #33278
|
|
@ -70,14 +70,14 @@
|
|||
},
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
|
||||
"build": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
|
||||
"start": "tsc --build --watch",
|
||||
"prepack": "pnpm run clean && pnpm run build",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"test": "pnpm run build && pnpm run test:nobuild",
|
||||
"test:nobuild": "jest --config ./jest.config.json",
|
||||
"test": "jest --config ./jest.config.json",
|
||||
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
|
||||
},
|
||||
"lint-staged": {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/data",
|
||||
"sourceRoot": "packages/js/data/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/data"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"build-watch": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "start"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -155,3 +155,4 @@ export interface WCDataSelector {
|
|||
|
||||
// Other exports
|
||||
export { ActionDispatchers as PluginsStoreActions } from './plugins/actions';
|
||||
export { ActionDispatchers as ProductsStoreActions } from './products/actions';
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
export enum TYPES {
|
||||
CREATE_PRODUCT_ERROR = 'CREATE_PRODUCT_ERROR',
|
||||
CREATE_PRODUCT_SUCCESS = 'CREATE_PRODUCT_SUCCESS',
|
||||
GET_PRODUCT_SUCCESS = 'GET_PRODUCT_SUCCESS',
|
||||
GET_PRODUCT_ERROR = 'GET_PRODUCT_ERROR',
|
||||
GET_PRODUCTS_SUCCESS = 'GET_PRODUCTS_SUCCESS',
|
||||
|
|
|
@ -1,8 +1,20 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { apiFetch } from '@wordpress/data-controls';
|
||||
import { DispatchFromMap } from '@automattic/data-stores';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import TYPES from './action-types';
|
||||
import { PartialProduct, ProductQuery } from './types';
|
||||
import {
|
||||
MutableProperties,
|
||||
PartialProduct,
|
||||
Product,
|
||||
ProductQuery,
|
||||
} from './types';
|
||||
import { WC_PRODUCT_NAMESPACE } from './constants';
|
||||
|
||||
export function getProductSuccess( id: number, product: PartialProduct ) {
|
||||
return {
|
||||
|
@ -23,6 +35,25 @@ export function getProductError(
|
|||
};
|
||||
}
|
||||
|
||||
function createProductSuccess( id: number, product: PartialProduct ) {
|
||||
return {
|
||||
type: TYPES.CREATE_PRODUCT_SUCCESS as const,
|
||||
id,
|
||||
product,
|
||||
};
|
||||
}
|
||||
|
||||
export function createProductError(
|
||||
query: Partial< Product >,
|
||||
error: unknown
|
||||
) {
|
||||
return {
|
||||
type: TYPES.CREATE_PRODUCT_ERROR as const,
|
||||
query,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
export function getProductsSuccess(
|
||||
query: Partial< ProductQuery >,
|
||||
products: PartialProduct[],
|
||||
|
@ -69,7 +100,25 @@ export function getProductsTotalCountError(
|
|||
};
|
||||
}
|
||||
|
||||
export function* createProduct( data: Pick< Product, MutableProperties > ) {
|
||||
try {
|
||||
const product: Product = yield apiFetch( {
|
||||
path: WC_PRODUCT_NAMESPACE,
|
||||
method: 'POST',
|
||||
data,
|
||||
} );
|
||||
|
||||
yield createProductSuccess( product.id, product );
|
||||
return product;
|
||||
} catch ( error ) {
|
||||
yield createProductError( data, error );
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export type Actions = ReturnType<
|
||||
| typeof createProductError
|
||||
| typeof createProductSuccess
|
||||
| typeof getProductSuccess
|
||||
| typeof getProductError
|
||||
| typeof getProductsSuccess
|
||||
|
@ -77,3 +126,7 @@ export type Actions = ReturnType<
|
|||
| typeof getProductsTotalCountSuccess
|
||||
| typeof getProductsTotalCountError
|
||||
>;
|
||||
|
||||
export type ActionDispatchers = DispatchFromMap< {
|
||||
createProduct: typeof createProduct;
|
||||
} >;
|
||||
|
|
|
@ -37,6 +37,7 @@ const reducer: Reducer< ProductState, Actions > = (
|
|||
) => {
|
||||
if ( payload && 'type' in payload ) {
|
||||
switch ( payload.type ) {
|
||||
case TYPES.CREATE_PRODUCT_SUCCESS:
|
||||
case TYPES.GET_PRODUCT_SUCCESS:
|
||||
const productData = state.data || {};
|
||||
return {
|
||||
|
@ -88,6 +89,7 @@ const reducer: Reducer< ProductState, Actions > = (
|
|||
case TYPES.GET_PRODUCT_ERROR:
|
||||
case TYPES.GET_PRODUCTS_ERROR:
|
||||
case TYPES.GET_PRODUCTS_TOTAL_COUNT_ERROR:
|
||||
case TYPES.CREATE_PRODUCT_ERROR:
|
||||
return {
|
||||
...state,
|
||||
errors: {
|
||||
|
|
|
@ -77,7 +77,16 @@ export const getProductsError = (
|
|||
return state.errors[ resourceName ];
|
||||
};
|
||||
|
||||
export const getCreateProductError = (
|
||||
state: ProductState,
|
||||
query: ProductQuery
|
||||
) => {
|
||||
const resourceName = getProductResourceName( query );
|
||||
return state.errors[ resourceName ];
|
||||
};
|
||||
|
||||
export type ProductsSelectors = {
|
||||
getCreateProductError: WPDataSelector< typeof getCreateProductError >;
|
||||
getProducts: WPDataSelector< typeof getProducts >;
|
||||
getProductsTotalCount: WPDataSelector< typeof getProductsTotalCount >;
|
||||
getProductsError: WPDataSelector< typeof getProductsError >;
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
getTotalProductCountResourceName,
|
||||
} from '../utils';
|
||||
import { Actions } from '../actions';
|
||||
import { PartialProduct, ProductQuery } from '../types';
|
||||
import { PartialProduct, ProductQuery, Product } from '../types';
|
||||
|
||||
const defaultState: ProductState = {
|
||||
products: {},
|
||||
|
@ -180,4 +180,34 @@ describe( 'products reducer', () => {
|
|||
|
||||
expect( state.errors[ resourceName ] ).toBe( error );
|
||||
} );
|
||||
|
||||
it( 'should handle CREATE_PRODUCT_SUCCESS', () => {
|
||||
const update: PartialProduct = {
|
||||
id: 2,
|
||||
name: 'Off the hook!',
|
||||
status: 'draft',
|
||||
};
|
||||
|
||||
const state = reducer( defaultState, {
|
||||
type: TYPES.CREATE_PRODUCT_SUCCESS,
|
||||
id: update.id,
|
||||
product: update,
|
||||
} );
|
||||
|
||||
expect( state.data[ 2 ].name ).toEqual( update.name );
|
||||
expect( state.data[ 2 ].status ).toEqual( update.status );
|
||||
} );
|
||||
|
||||
it( 'should handle CREATE_PRODUCT_ERROR', () => {
|
||||
const query: Partial< Product > = { name: 'Donkey Sauce' };
|
||||
const resourceName = getProductResourceName( query );
|
||||
const error = 'Baaam!';
|
||||
const state = reducer( defaultState, {
|
||||
type: TYPES.GET_PRODUCTS_ERROR,
|
||||
query,
|
||||
error,
|
||||
} );
|
||||
|
||||
expect( state.errors[ resourceName ] ).toBe( error );
|
||||
} );
|
||||
} );
|
||||
|
|
|
@ -40,6 +40,18 @@ export type Product<
|
|||
sale_price: string;
|
||||
};
|
||||
|
||||
export type MutableProperties =
|
||||
| 'name'
|
||||
| 'slug'
|
||||
| 'type'
|
||||
| 'status'
|
||||
| 'featured'
|
||||
| 'description'
|
||||
| 'short_description'
|
||||
| 'sku'
|
||||
| 'regular_price'
|
||||
| 'sale_price';
|
||||
|
||||
export type PartialProduct = Partial< Product > & Pick< Product, 'id' >;
|
||||
|
||||
export type ProductQuery<
|
||||
|
|
|
@ -48,14 +48,14 @@
|
|||
},
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
|
||||
"build": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
|
||||
"start": "tsc --build --watch",
|
||||
"prepack": "pnpm run clean && pnpm run build",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"test": "pnpm run build && pnpm run test:nobuild",
|
||||
"test:nobuild": "jest --config ./jest.config.json",
|
||||
"test": "jest --config ./jest.config.json",
|
||||
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
|
||||
},
|
||||
"lint-staged": {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/date",
|
||||
"sourceRoot": "packages/js/date/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/date"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"build-watch": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "start"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,9 +36,10 @@
|
|||
"webpack-cli": "^3.3.12"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"postinstall": "composer install"
|
||||
"lint:fix": "eslint src --fix"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.(t|j)s?(x)": [
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/dependency-extraction-webpack-plugin",
|
||||
"sourceRoot": "packages/js/dependency-extraction-webpack-plugin/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/dependency-extraction-webpack-plugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/e2e-core-tests/",
|
||||
"sourceRoot": "packages/js/e2e-core-tests",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/e2e-core-tests"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"clean": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "clean"
|
||||
}
|
||||
},
|
||||
"compile": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "compile"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "lint"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,7 +38,7 @@ Again, if you don't have shell access to your test site, through WP Admin ensure
|
|||
3. You have an admin user set up (if their credentials differ from u/ `admin` and p/ `password` be sure to update `/plugins/woocommerce/tests/e2e/config/default.json`)
|
||||
4. You have a customer user set up named 'Jane Smith'. This user should be a `subscriber` and again make sure their username and password are reflected in `/plugins/woocommerce/tests/e2e/config/default.json`.
|
||||
|
||||
You should then be able to run the e2e tests by running `pnpm nx test-e2e woocommerce`.
|
||||
You should then be able to run the e2e tests by running `pnpm exec turbo run e2e --filter=woocommerce`.
|
||||
|
||||
### Test Sequencer Setup
|
||||
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/e2e-environment/",
|
||||
"sourceRoot": "packages/js/e2e-environment/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/e2e-environment"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "lint"
|
||||
}
|
||||
},
|
||||
"clean": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "clean"
|
||||
}
|
||||
},
|
||||
"compile": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "compile"
|
||||
}
|
||||
},
|
||||
"docker-up": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "docker:up"
|
||||
}
|
||||
},
|
||||
"docker-down": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "docker:down"
|
||||
}
|
||||
},
|
||||
"docker-clear-all": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "docker:clear-all"
|
||||
}
|
||||
},
|
||||
"docker-ssh": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "docker:ssh"
|
||||
}
|
||||
},
|
||||
"test-e2e": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test:e2e"
|
||||
}
|
||||
},
|
||||
"test-e2e-debug": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test:e2e-debug"
|
||||
}
|
||||
},
|
||||
"test-e2e-dev": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test:e2e-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: add
|
||||
|
||||
Add tests to check usage button loading state
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/e2e-utils/",
|
||||
"sourceRoot": "packages/js/e2e-utils/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/e2e-utils"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"clean": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "clean"
|
||||
}
|
||||
},
|
||||
"compile": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "compile"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "lint"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -129,6 +129,12 @@ const completeOnboardingWizard = async () => {
|
|||
expect( continueButtons ).toHaveLength( 1 );
|
||||
|
||||
await continueButtons[ 0 ].click();
|
||||
await expect( page ).toMatchElement(
|
||||
'.woocommerce-usage-modal__actions button.is-secondary.is-busy'
|
||||
);
|
||||
await expect( page ).not.toMatchElement(
|
||||
'.woocommerce-usage-modal__actions button.is-primary:disabled'
|
||||
);
|
||||
}
|
||||
await page.waitForNavigation( { waitUntil: 'networkidle0' } );
|
||||
|
||||
|
|
|
@ -36,9 +36,10 @@
|
|||
"access": "public"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"lint": "eslint ./rules ./configs",
|
||||
"lint:fix": "eslint ./rules ./configs --fix",
|
||||
"postinstall": "composer install"
|
||||
"lint:fix": "eslint ./rules ./configs --fix"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.5",
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/eslint-plugin",
|
||||
"sourceRoot": "packages/js/eslint-plugin/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/eslint-plugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -75,6 +75,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
|
||||
"build": "pnpm run build:js && pnpm run build:css",
|
||||
"build:js": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
|
||||
|
@ -83,8 +84,7 @@
|
|||
"prepack": "pnpm run clean && pnpm run build",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"test": "pnpm run build && pnpm run test:nobuild",
|
||||
"test:nobuild": "jest --config ./jest.config.json",
|
||||
"test": "jest --config ./jest.config.json",
|
||||
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
|
||||
},
|
||||
"lint-staged": {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/experimental",
|
||||
"sourceRoot": "packages/js/experimental/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/experimental"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"build-watch": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "start"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -48,14 +48,14 @@
|
|||
},
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
|
||||
"build": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
|
||||
"start": "tsc --build --watch",
|
||||
"prepack": "pnpm run clean && pnpm run build",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"test": "pnpm run build && pnpm run test:nobuild",
|
||||
"test:nobuild": "jest --config ./jest.config.json",
|
||||
"test": "jest --config ./jest.config.json",
|
||||
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
|
||||
},
|
||||
"lint-staged": {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/explat",
|
||||
"sourceRoot": "packages/js/explat/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/explat"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"build-watch": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "start"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,12 +34,26 @@ module.exports = {
|
|||
],
|
||||
},
|
||||
webpackImporter: true,
|
||||
additionalData:
|
||||
'@use "sass:math";' +
|
||||
'@import "_colors"; ' +
|
||||
'@import "_variables"; ' +
|
||||
'@import "_breakpoints"; ' +
|
||||
'@import "_mixins"; ',
|
||||
additionalData: ( content, loaderContext ) => {
|
||||
const { resourcePath } = loaderContext;
|
||||
if ( resourcePath.includes( '@automattic+' ) ) {
|
||||
/*
|
||||
* Skip adding additional data for @automattic/* packages to
|
||||
* fix "SassError: @use rules must be written before any other rules."
|
||||
* @automattic/* packages have included '@use "sass:math" and other necessary imports.
|
||||
*/
|
||||
return content;
|
||||
}
|
||||
|
||||
return (
|
||||
'@use "sass:math";' +
|
||||
'@import "_colors"; ' +
|
||||
'@import "_variables"; ' +
|
||||
'@import "_breakpoints"; ' +
|
||||
'@import "_mixins"; ' +
|
||||
content
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/internal-style-build",
|
||||
"sourceRoot": "packages/js/internal-style-build/src",
|
||||
"projectType": "library",
|
||||
"targets": {}
|
||||
}
|
|
@ -40,14 +40,14 @@
|
|||
},
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
|
||||
"build": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
|
||||
"start": "tsc --build --watch",
|
||||
"prepack": "pnpm run clean && pnpm run build",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"test": "pnpm run build && pnpm run test:nobuild",
|
||||
"test:nobuild": "jest --config ./jest.config.json",
|
||||
"test": "jest --config ./jest.config.json",
|
||||
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/navigation",
|
||||
"sourceRoot": "packages/js/navigation/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/navigation"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"build-watch": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "start"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,14 +28,14 @@
|
|||
},
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
|
||||
"build": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
|
||||
"start": "tsc --build --watch",
|
||||
"prepack": "pnpm run clean && pnpm run build",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix",
|
||||
"test": "pnpm run build && pnpm run test:nobuild",
|
||||
"test:nobuild": "jest --config ./jest.config.json",
|
||||
"test": "jest --config ./jest.config.json",
|
||||
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/number",
|
||||
"sourceRoot": "packages/js/number/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/number"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"build-watch": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "start"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -56,6 +56,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
|
||||
"build": "pnpm run build:js && pnpm run build:css",
|
||||
"build:js": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/onboarding",
|
||||
"sourceRoot": "packages/js/onboarding/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/onboarding"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"build-watch": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "start"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"postinstall": "composer install",
|
||||
"changelog": "composer exec -- changelogger",
|
||||
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
|
||||
"build": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
|
||||
"start": "tsc --build --watch",
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"root": "packages/js/tracks",
|
||||
"sourceRoot": "packages/js/tracks/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "packages/js/tracks"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"build-watch": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "start"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
const pluginName = 'AsyncChunkSrcVersionParameterPlugin';
|
||||
/**
|
||||
* Inspired by: https://github.com/webpack/webpack/issues/8115#issuecomment-663902035.
|
||||
*
|
||||
* This plugin modifies the webpack bootstrap code generated by the plugin at
|
||||
* webpack/lib/web/JsonpMainTemplatePlugin.js and the CSS chunk loading code generated
|
||||
* by @automattic/mini-css-extract-plugin-with-rtl.
|
||||
*
|
||||
* It will rename the function jsonpScriptSrc generated by that to webpackJsonpScriptSrc
|
||||
* and install a new version that checks a user provided variable containing a script
|
||||
* version parameter to specify in async chunk URLs.
|
||||
*
|
||||
* The jsonpScriptSrc override is only for webpack 4 (tested with 4.43 and 4.44).
|
||||
*
|
||||
* Webpack 5 has official support for this https://github.com/webpack/webpack/pull/8462
|
||||
* so it won't be necessary.
|
||||
*
|
||||
* It will also append the ?ver parameter to CSS chunk hrefs loaded by @automattic/mini-css-extract-plugin-with-rtl.
|
||||
*/
|
||||
class AsyncChunkSrcVersionParameterPlugin {
|
||||
_applyMainTemplate( mainTemplate ) {
|
||||
// Append script version to all async JS chunks loaded with jsonpScriptSrc().
|
||||
mainTemplate.hooks.localVars.tap(
|
||||
// Use stage 1 to ensure this executes after webpack/lib/web/JsonpMainTemplatePlugin.js.
|
||||
{ name: pluginName, stage: 1 },
|
||||
( source ) => {
|
||||
if ( source.includes( 'function jsonpScriptSrc' ) ) {
|
||||
const modSource = source.replace(
|
||||
'function jsonpScriptSrc',
|
||||
'function webpackJsonpScriptSrc'
|
||||
);
|
||||
return `${ modSource }
|
||||
|
||||
function jsonpScriptSrc(chunkId) {
|
||||
var src = webpackJsonpScriptSrc(chunkId);
|
||||
if ( window.wcAdminAssets && window.wcAdminAssets.version ) {
|
||||
src += '?ver=' + window.wcAdminAssets.version;
|
||||
}
|
||||
return src;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
);
|
||||
|
||||
// Append script version to all async CSS chunks loaded by @automattic/mini-css-extract-plugin-with-rtl.
|
||||
mainTemplate.hooks.requireEnsure.tap(
|
||||
// Use stage 1 to ensure this executes after @automattic/mini-css-extract-plugin-with-rtl.
|
||||
{ name: pluginName, stage: 1 },
|
||||
( source ) => {
|
||||
if (
|
||||
source.includes( '// mini-css-extract-plugin CSS loading' )
|
||||
) {
|
||||
return source.replace(
|
||||
'linkTag.href = fullhref;',
|
||||
`linkTag.href = fullhref;
|
||||
if ( window.wcAdminAssets && window.wcAdminAssets.version ) {
|
||||
linkTag.href += '?ver=' + window.wcAdminAssets.version;
|
||||
}`
|
||||
);
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
apply( compiler ) {
|
||||
compiler.hooks.thisCompilation.tap( pluginName, ( compilation ) => {
|
||||
this._applyMainTemplate( compilation.mainTemplate );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AsyncChunkSrcVersionParameterPlugin;
|
|
@ -22,6 +22,25 @@ import { WcAdminPaymentsGatewaysBannerSlot } from './payments/payments-settings-
|
|||
// eslint-disable-next-line no-undef,camelcase
|
||||
__webpack_public_path__ = global.wcAdminAssets.path;
|
||||
|
||||
// Modify webpack to append the ?ver parameter to JS chunk
|
||||
// https://webpack.js.org/api/module-variables/#__webpack_get_script_filename__-webpack-specific
|
||||
// eslint-disable-next-line no-undef,camelcase
|
||||
const oldGetScriptFileNameFn = __webpack_get_script_filename__;
|
||||
// eslint-disable-next-line no-undef,camelcase
|
||||
__webpack_get_script_filename__ = ( chunk ) => {
|
||||
const filename = oldGetScriptFileNameFn( chunk );
|
||||
return `${ filename }?ver=${ window.wcAdminAssets.version }`;
|
||||
};
|
||||
|
||||
// Modify webpack to append the ?ver parameter to CSS chunk hrefs generated by mini-css-extract-plugin
|
||||
// eslint-disable-next-line no-undef,camelcase
|
||||
const oldMinCssFn = __webpack_require__.miniCssF;
|
||||
// eslint-disable-next-line no-undef,camelcase
|
||||
__webpack_require__.miniCssF = ( chunkId ) => {
|
||||
const filename = oldMinCssFn( chunkId );
|
||||
return `${ filename }?ver=${ window.wcAdminAssets.version }`;
|
||||
};
|
||||
|
||||
const appRoot = document.getElementById( 'root' );
|
||||
const embeddedRoot = document.getElementById( 'woocommerce-embedded-root' );
|
||||
const settingsGroup = 'wc_admin';
|
||||
|
|
|
@ -17,6 +17,7 @@ class UsageModal extends Component {
|
|||
this.state = {
|
||||
isLoadingScripts: false,
|
||||
isRequestStarted: false,
|
||||
selectedAction: null,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -131,7 +132,7 @@ class UsageModal extends Component {
|
|||
acceptActionText = __( 'Yes, count me in!', 'woocommerce' ),
|
||||
} = this.props;
|
||||
|
||||
const { isRequestStarted } = this.state;
|
||||
const { isRequestStarted, selectedAction } = this.state;
|
||||
const isBusy = isRequestStarted && isRequesting;
|
||||
|
||||
return (
|
||||
|
@ -148,19 +149,23 @@ class UsageModal extends Component {
|
|||
<div className="woocommerce-usage-modal__actions">
|
||||
<Button
|
||||
isSecondary
|
||||
isBusy={ isBusy }
|
||||
onClick={ () =>
|
||||
this.updateTracking( { allowTracking: false } )
|
||||
}
|
||||
isBusy={ isBusy && selectedAction === 'dismiss' }
|
||||
disabled={ isBusy && selectedAction === 'accept' }
|
||||
onClick={ () => {
|
||||
this.setState( { selectedAction: 'dismiss' } );
|
||||
this.updateTracking( { allowTracking: false } );
|
||||
} }
|
||||
>
|
||||
{ dismissActionText }
|
||||
</Button>
|
||||
<Button
|
||||
isPrimary
|
||||
isBusy={ isBusy }
|
||||
onClick={ () =>
|
||||
this.updateTracking( { allowTracking: true } )
|
||||
}
|
||||
isBusy={ isBusy && selectedAction === 'accept' }
|
||||
disabled={ isBusy && selectedAction === 'dismiss' }
|
||||
onClick={ () => {
|
||||
this.setState( { selectedAction: 'accept' } );
|
||||
this.updateTracking( { allowTracking: true } );
|
||||
} }
|
||||
>
|
||||
{ acceptActionText }
|
||||
</Button>
|
||||
|
|
|
@ -95,9 +95,12 @@ export const Products = () => {
|
|||
) : (
|
||||
isConfirmingLoadSampleProducts && (
|
||||
<LoadSampleProductConfirmModal
|
||||
onCancel={ () =>
|
||||
setIsConfirmingLoadSampleProducts( false )
|
||||
}
|
||||
onCancel={ () => {
|
||||
setIsConfirmingLoadSampleProducts( false );
|
||||
recordEvent(
|
||||
'tasklist_cancel_load_sample_products_click'
|
||||
);
|
||||
} }
|
||||
onImport={ () => {
|
||||
setIsConfirmingLoadSampleProducts( false );
|
||||
loadSampleProduct();
|
||||
|
|
|
@ -165,5 +165,8 @@ describe( 'Products', () => {
|
|||
|
||||
userEvent.click( getByRole( 'button', { name: 'Cancel' } ) );
|
||||
expect( queryByText( confirmModalText ) ).not.toBeInTheDocument();
|
||||
expect( recordEvent ).toHaveBeenCalledWith(
|
||||
'tasklist_cancel_load_sample_products_click'
|
||||
);
|
||||
} );
|
||||
} );
|
||||
|
|
|
@ -189,9 +189,12 @@ export const Products = () => {
|
|||
) : (
|
||||
isConfirmingLoadSampleProducts && (
|
||||
<LoadSampleProductConfirmModal
|
||||
onCancel={ () =>
|
||||
setIsConfirmingLoadSampleProducts( false )
|
||||
}
|
||||
onCancel={ () => {
|
||||
setIsConfirmingLoadSampleProducts( false );
|
||||
recordEvent(
|
||||
'tasklist_cancel_load_sample_products_click'
|
||||
);
|
||||
} }
|
||||
onImport={ () => {
|
||||
setIsConfirmingLoadSampleProducts( false );
|
||||
loadSampleProduct();
|
||||
|
|
|
@ -292,6 +292,9 @@ describe( 'Products', () => {
|
|||
|
||||
userEvent.click( getByRole( 'button', { name: 'Cancel' } ) );
|
||||
expect( queryByText( confirmModalText ) ).not.toBeInTheDocument();
|
||||
expect( recordEvent ).toHaveBeenCalledWith(
|
||||
'tasklist_cancel_load_sample_products_click'
|
||||
);
|
||||
} );
|
||||
|
||||
it( 'should show spinner when layout experiment is loading', async () => {
|
||||
|
|
|
@ -103,8 +103,12 @@ export default function ProductTemplateModal( { onClose } ) {
|
|||
).then(
|
||||
( data ) => {
|
||||
if ( data && data.id ) {
|
||||
const additionalParams =
|
||||
selectedTemplate === 'physical'
|
||||
? '&spotlight=true'
|
||||
: '';
|
||||
const link = getAdminLink(
|
||||
`post.php?post=${ data.id }&action=edit&wc_onboarding_active_task=products&tutorial=true`
|
||||
`post.php?post=${ data.id }&action=edit&wc_onboarding_active_task=products&tutorial=true${ additionalParams }`
|
||||
);
|
||||
window.location = link;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,284 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { render, useEffect, useState } from '@wordpress/element';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { TourKit, TourKitTypes } from '@woocommerce/components';
|
||||
import qs from 'qs';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { useTmceIframeFocusStyle } from './use-tmce-iframe-focus-style';
|
||||
import { useActiveEditorType } from './use-active-editor-type';
|
||||
import {
|
||||
bindEnableGuideModeClickEvent,
|
||||
waitUntilElementTopNotChange,
|
||||
} from './utils';
|
||||
|
||||
const getTourConfig = ( {
|
||||
isExcerptEditorTmceActive,
|
||||
isContentEditorTmceActive,
|
||||
closeHandler,
|
||||
}: {
|
||||
isExcerptEditorTmceActive: boolean;
|
||||
isContentEditorTmceActive: boolean;
|
||||
closeHandler: () => void;
|
||||
} ): TourKitTypes.WooConfig => {
|
||||
return {
|
||||
placement: 'bottom-start',
|
||||
options: {
|
||||
effects: {
|
||||
spotlight: {
|
||||
interactivity: {
|
||||
enabled: true,
|
||||
rootElementSelector: '#wpwrap',
|
||||
},
|
||||
},
|
||||
arrowIndicator: true,
|
||||
autoScroll: {
|
||||
behavior: 'auto',
|
||||
block: 'center',
|
||||
},
|
||||
},
|
||||
popperModifiers: [
|
||||
{
|
||||
name: 'arrow',
|
||||
options: {
|
||||
padding: ( {
|
||||
popper,
|
||||
}: {
|
||||
popper: { width: number };
|
||||
} ) => {
|
||||
return {
|
||||
// Align the arrow to the left of the popper.
|
||||
right: popper.width - 34,
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
steps: [
|
||||
{
|
||||
referenceElements: {
|
||||
desktop: '#title',
|
||||
},
|
||||
focusElement: {
|
||||
desktop: '#title',
|
||||
},
|
||||
meta: {
|
||||
heading: __( 'Product name', 'woocommerce' ),
|
||||
descriptions: {
|
||||
desktop: __(
|
||||
'Start typing your new product name here. This will be what your customers will see in your store.',
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
referenceElements: {
|
||||
desktop: '#wp-content-wrap',
|
||||
},
|
||||
focusElement: {
|
||||
iframe: isContentEditorTmceActive
|
||||
? '#content_ifr'
|
||||
: undefined,
|
||||
desktop: isContentEditorTmceActive
|
||||
? '#tinymce'
|
||||
: '#wp-content-editor-container > .wp-editor-area',
|
||||
},
|
||||
meta: {
|
||||
heading: __(
|
||||
'Add your product description',
|
||||
'woocommerce'
|
||||
),
|
||||
descriptions: {
|
||||
desktop: __(
|
||||
'Start typing your new product name here. Add your full product description here. Describe your product in detail.',
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
referenceElements: {
|
||||
desktop: '#woocommerce-product-data',
|
||||
},
|
||||
focusElement: {
|
||||
desktop: '#_regular_price',
|
||||
},
|
||||
meta: {
|
||||
heading: __( 'Add your product data', 'woocommerce' ),
|
||||
descriptions: {
|
||||
desktop: __(
|
||||
'Use the tabs to switch between sections and insert product details. Start by adding your product price.',
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
referenceElements: {
|
||||
desktop: '#postexcerpt',
|
||||
},
|
||||
focusElement: {
|
||||
iframe: isExcerptEditorTmceActive
|
||||
? '#excerpt_ifr'
|
||||
: undefined,
|
||||
desktop: isExcerptEditorTmceActive
|
||||
? '#tinymce'
|
||||
: '#wp-excerpt-editor-container > .wp-editor-area',
|
||||
},
|
||||
meta: {
|
||||
heading: __(
|
||||
'Add your short product description',
|
||||
'woocommerce'
|
||||
),
|
||||
descriptions: {
|
||||
desktop: __(
|
||||
'Type a quick summary for your product here. This will appear on the product page right under the product name.',
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
referenceElements: {
|
||||
desktop: '#postimagediv',
|
||||
},
|
||||
focusElement: {
|
||||
desktop: '#set-post-thumbnail',
|
||||
},
|
||||
meta: {
|
||||
heading: __( 'Add your product image', 'woocommerce' ),
|
||||
descriptions: {
|
||||
desktop: __(
|
||||
'Upload an image to your product here. Ideally a JPEG or PNG about 600 px wide or bigger. This image will be shown in your store’s catalog.',
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
referenceElements: {
|
||||
desktop: '#tagsdiv-product_tag',
|
||||
},
|
||||
focusElement: {
|
||||
desktop: '#new-tag-product_tag',
|
||||
},
|
||||
meta: {
|
||||
heading: __( 'Add your product tags', 'woocommerce' ),
|
||||
descriptions: {
|
||||
desktop: __(
|
||||
'Add your product tags here. Tags are a method of labeling your products to make them easier for customers to find. For example, if you sell clothing, and you have a lot of cat prints, you could make a tag for “cat.”',
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
referenceElements: {
|
||||
desktop: '#product_catdiv',
|
||||
},
|
||||
meta: {
|
||||
heading: __( 'Add your product categories', 'woocommerce' ),
|
||||
descriptions: {
|
||||
desktop: __(
|
||||
'Add your product categories here. Assign categories to your products to make them easier to browse through and find in your store.',
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
referenceElements: {
|
||||
desktop: '#submitdiv',
|
||||
},
|
||||
focusElement: {
|
||||
desktop: '#submitdiv',
|
||||
},
|
||||
meta: {
|
||||
heading: __( 'Publish your product 🎉', 'woocommerce' ),
|
||||
descriptions: {
|
||||
desktop: __(
|
||||
'Good work! Now you can publish your product to your store by hitting the “Publish” button or keep editing it.',
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
primaryButton: {
|
||||
text: __( 'Keep editing', 'woocommerce' ),
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
closeHandler,
|
||||
};
|
||||
};
|
||||
|
||||
const ProductTour = () => {
|
||||
const [ showTour, setShowTour ] = useState< boolean >( false );
|
||||
|
||||
const { isTmce: isContentEditorTmceActive } = useActiveEditorType( {
|
||||
editorWrapSelector: '#wp-content-wrap',
|
||||
} );
|
||||
const { isTmce: isExcerptEditorTmceActive } = useActiveEditorType( {
|
||||
editorWrapSelector: '#wp-excerpt-wrap',
|
||||
} );
|
||||
|
||||
const { style: contentTmceIframeFocusStyle } = useTmceIframeFocusStyle( {
|
||||
isActive: showTour && isContentEditorTmceActive,
|
||||
iframeSelector: '#content_ifr',
|
||||
} );
|
||||
const { style: excerptTmceIframeFocusStyle } = useTmceIframeFocusStyle( {
|
||||
isActive: showTour && isExcerptEditorTmceActive,
|
||||
iframeSelector: '#excerpt_ifr',
|
||||
} );
|
||||
|
||||
const tourConfig = getTourConfig( {
|
||||
isContentEditorTmceActive,
|
||||
isExcerptEditorTmceActive,
|
||||
closeHandler: () => setShowTour( false ),
|
||||
} );
|
||||
|
||||
useEffect( () => {
|
||||
bindEnableGuideModeClickEvent( ( e ) => {
|
||||
e.preventDefault();
|
||||
setShowTour( true );
|
||||
} );
|
||||
|
||||
const query = qs.parse( window.location.search.slice( 1 ) );
|
||||
if ( query && query.tutorial === 'true' ) {
|
||||
const intervalId = waitUntilElementTopNotChange(
|
||||
tourConfig.steps[ 0 ].referenceElements?.desktop || '',
|
||||
() => setShowTour( true ),
|
||||
500
|
||||
);
|
||||
return () => clearInterval( intervalId );
|
||||
}
|
||||
// only run once
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [] );
|
||||
|
||||
if ( ! showTour ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<style>
|
||||
{ contentTmceIframeFocusStyle }
|
||||
{ excerptTmceIframeFocusStyle }
|
||||
{ `.wp-editor-area:focus {
|
||||
border: 1.5px solid #007CBA;
|
||||
}` }
|
||||
</style>
|
||||
<TourKit config={ tourConfig } />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const root = document.createElement( 'div' );
|
||||
root.setAttribute( 'id', 'product-tour-root' );
|
||||
render( <ProductTour />, document.body.appendChild( root ) );
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useEffect, useRef, useState } from '@wordpress/element';
|
||||
|
||||
/* TinyMCE or HTML (textarea) editor */
|
||||
export type EditorType = 'tmce' | 'html';
|
||||
|
||||
export const useActiveEditorType = ( {
|
||||
editorWrapSelector,
|
||||
}: {
|
||||
editorWrapSelector: string;
|
||||
} ) => {
|
||||
const editor = useRef( document.querySelector( editorWrapSelector ) );
|
||||
if ( ! editor ) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn( `Editor Wrap ${ editorWrapSelector } not found` );
|
||||
}
|
||||
|
||||
const [ activeEditor, setActiveEditor ] = useState< EditorType >(
|
||||
editor.current && editor.current.classList.contains( 'html-active' )
|
||||
? 'html'
|
||||
: 'tmce' // set to "tmce" if it's active or editor is not found
|
||||
);
|
||||
|
||||
useEffect( () => {
|
||||
const onClickEditorTab = ( e: MouseEvent ) => {
|
||||
if ( e.target ) {
|
||||
setActiveEditor(
|
||||
( e.target as HTMLElement ).classList.contains(
|
||||
'switch-html'
|
||||
)
|
||||
? 'html'
|
||||
: 'tmce'
|
||||
);
|
||||
}
|
||||
};
|
||||
const tmceTab = document.querySelector< HTMLButtonElement >(
|
||||
`${ editorWrapSelector } .switch-tmce`
|
||||
);
|
||||
tmceTab?.addEventListener( 'click', onClickEditorTab );
|
||||
|
||||
const htmlTab = document.querySelector< HTMLButtonElement >(
|
||||
`${ editorWrapSelector } .switch-html`
|
||||
);
|
||||
htmlTab?.addEventListener( 'click', onClickEditorTab );
|
||||
|
||||
return () => {
|
||||
tmceTab?.removeEventListener( 'click', onClickEditorTab );
|
||||
htmlTab?.removeEventListener( 'click', onClickEditorTab );
|
||||
};
|
||||
}, [ editorWrapSelector ] );
|
||||
|
||||
return {
|
||||
activeEditor,
|
||||
isTmce: activeEditor === 'tmce',
|
||||
isHtml: activeEditor === 'html',
|
||||
};
|
||||
};
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useEffect } from '@wordpress/element';
|
||||
|
||||
type addClassToIframeWhenChildFocusProps = {
|
||||
iframeSelector: string;
|
||||
childSelector: string;
|
||||
className: string;
|
||||
};
|
||||
|
||||
const addClassToIframeWhenChildFocus = ( {
|
||||
iframeSelector,
|
||||
childSelector,
|
||||
className,
|
||||
}: addClassToIframeWhenChildFocusProps ) => {
|
||||
const iframe = document.querySelector< HTMLIFrameElement >(
|
||||
iframeSelector
|
||||
);
|
||||
const innerDoc =
|
||||
iframe?.contentDocument ||
|
||||
( iframe?.contentWindow && iframe?.contentWindow.document );
|
||||
|
||||
if ( innerDoc ) {
|
||||
const onFocus = () => iframe?.classList.add( className );
|
||||
const onBlur = () => iframe?.classList.remove( className );
|
||||
|
||||
const child = innerDoc.querySelector< HTMLElement >( childSelector );
|
||||
child?.addEventListener( 'focus', onFocus );
|
||||
child?.addEventListener( 'blur', onBlur );
|
||||
|
||||
return () => {
|
||||
child?.removeEventListener( 'focus', onFocus );
|
||||
child?.removeEventListener( 'blur', onBlur );
|
||||
};
|
||||
}
|
||||
return () => ( {} );
|
||||
};
|
||||
|
||||
export const useTmceIframeFocusStyle = ( {
|
||||
iframeSelector,
|
||||
isActive,
|
||||
}: {
|
||||
iframeSelector: string;
|
||||
isActive: boolean;
|
||||
} ) => {
|
||||
// Add a focus class to tmce iframe when editor is focused.
|
||||
useEffect( () => {
|
||||
if ( ! isActive ) {
|
||||
return;
|
||||
}
|
||||
const clearIFrameEvent = addClassToIframeWhenChildFocus( {
|
||||
iframeSelector: `${ iframeSelector }`,
|
||||
childSelector: '#tinymce',
|
||||
className: 'focus-within',
|
||||
} );
|
||||
return () => {
|
||||
clearIFrameEvent();
|
||||
};
|
||||
}, [ isActive, iframeSelector ] );
|
||||
|
||||
return {
|
||||
style: isActive
|
||||
? `
|
||||
${ iframeSelector }.focus-within {
|
||||
border: 1.5px solid #007CBA;
|
||||
}
|
||||
`
|
||||
: null,
|
||||
};
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
// Wait until the initial element position is ready
|
||||
export const waitUntilElementTopNotChange = (
|
||||
elSelector: string,
|
||||
cb: () => void,
|
||||
pollMs: number
|
||||
) => {
|
||||
const initialElement = document.querySelector( elSelector );
|
||||
let lastInitialElementTop = initialElement?.getBoundingClientRect().top;
|
||||
|
||||
const intervalId = setInterval( () => {
|
||||
const top = initialElement?.getBoundingClientRect().top;
|
||||
if ( lastInitialElementTop === top ) {
|
||||
cb();
|
||||
clearInterval( intervalId );
|
||||
}
|
||||
lastInitialElementTop = top;
|
||||
}, pollMs );
|
||||
|
||||
return intervalId;
|
||||
};
|
||||
|
||||
// Overwrite the default behavior of click event for the "Enable guided mode" button
|
||||
export const bindEnableGuideModeClickEvent = (
|
||||
onClick: EventListenerOrEventListenerObject
|
||||
) => {
|
||||
const enableGuideModeBtn = Array.from(
|
||||
window.document.querySelectorAll( '.page-title-action' )
|
||||
).find( ( el ) => el.textContent === 'Enable guided mode' );
|
||||
|
||||
if ( enableGuideModeBtn ) {
|
||||
enableGuideModeBtn.addEventListener( 'click', onClick );
|
||||
}
|
||||
};
|
|
@ -13,7 +13,7 @@ pnpm install
|
|||
Build the example extension by running the pnpm script and passing the example name.
|
||||
|
||||
```bash
|
||||
WC_EXT=<example> pnpm nx example woocommerce-admin
|
||||
WC_EXT=<example> pnpm example --filter=@woocommerce/admin-library
|
||||
```
|
||||
|
||||
Include the output plugin in your `.wp-env.json` and `.wp-env.override.json` and restart the WordPress instance. WooCommerce Analytics reports will now reflect the changes made by the example extension.
|
||||
|
|
|
@ -10,7 +10,7 @@ This feature is hidden behind a feature flag and can be turned on or off by visi
|
|||
|
||||
The fastest way to get started is by creating an example plugin from WooCommerce Admin. Enter the following command:
|
||||
|
||||
`WC_EXT=add-navigation-items pnpm nx example woocommerce-admin`
|
||||
`WC_EXT=add-navigation-items pnpm example --filter=@woocommerce/admin-library`
|
||||
|
||||
This will create a new plugin that covers various features of the navigation and helps to register some intial items and categories within the new navigation menu. After running the command above, you can make edits directly to the files at `docs/examples/extensions/add-navigation-items` and they will be built and copied to your `wp-content/add-navigation-items` folder on save.
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ Gateway suggestions are retreived from a REST API and can be added via a remote
|
|||
|
||||
To quickly get started with an example plugin, run the following:
|
||||
|
||||
`WC_EXT=payment-gateway-suggestions pnpm nx example woocommerce-admin`
|
||||
`WC_EXT=payment-gateway-suggestions pnpm example --filter=@woocommerce/admin-library`
|
||||
|
||||
This will create a new plugin that when activated will add two new gateway suggestions. The first is a simple gateway demonstrating how configuration fields can be pulled from the gateway class to create a configuration form. The second gateway shows a more customized approach via SlotFill.
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
"start": "pnpm run install-if-deps-outdated && cross-env WC_ADMIN_PHASE=development pnpm run build:packages && cross-env WC_ADMIN_PHASE=development pnpm run build:feature-config && concurrently \"cross-env WC_ADMIN_PHASE=development webpack --watch\" \"cross-env WC_ADMIN_PHASE=development pnpm run:packages -- start --parallel\"",
|
||||
"start:package": "pnpm run:packages -- start --parallel",
|
||||
"pretest": "pnpm run -s install-if-no-packages",
|
||||
"test": "pnpm nx build @woocommerce/internal-js-tests && pnpm run test:client",
|
||||
"test": "pnpm run test:client",
|
||||
"test-staged": "pnpm run test:client -- --bail --findRelatedTests",
|
||||
"test:client": "jest --config client/jest.config.js",
|
||||
"test:debug": "node --inspect-brk ./node_modules/.bin/jest --config client/jest.config.js --watch --runInBand --no-cache",
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
{
|
||||
"root": "plugins/woocommerce-admin/",
|
||||
"sourceRoot": "plugins/woocommerce-admin",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "plugins/woocommerce"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"build-watch": {
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"options": {
|
||||
"commands": [
|
||||
"WC_ADMIN_PHASE=development pnpm nx clean woocommerce-admin",
|
||||
"WC_ADMIN_PHASE=development pnpm nx dev woocommerce-admin",
|
||||
"pnpm nx watch woocommerce-admin"
|
||||
],
|
||||
"parallel": false
|
||||
}
|
||||
},
|
||||
"watch": {
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"options": {
|
||||
"command": "pnpm nx client:watch woocommerce-admin"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "lint"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,9 +13,10 @@ const ForkTsCheckerWebpackPlugin = require( 'fork-ts-checker-webpack-plugin' );
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
const AsyncChunkSrcVersionParameterPlugin = require( './chunk-src-version-param' );
|
||||
const UnminifyWebpackPlugin = require( './unminify' );
|
||||
const { webpackConfig: styleConfig } = require( '@woocommerce/internal-style-build' );
|
||||
const {
|
||||
webpackConfig: styleConfig,
|
||||
} = require( '@woocommerce/internal-style-build' );
|
||||
const WooCommerceDependencyExtractionWebpackPlugin = require( '../../packages/js/dependency-extraction-webpack-plugin/src/index' );
|
||||
|
||||
const NODE_ENV = process.env.NODE_ENV || 'development';
|
||||
|
@ -54,6 +55,7 @@ const wpAdminScripts = [
|
|||
'attributes-tracking',
|
||||
'category-tracking',
|
||||
'tags-tracking',
|
||||
'product-tour',
|
||||
];
|
||||
const getEntryPoints = () => {
|
||||
const entryPoints = {
|
||||
|
@ -137,6 +139,9 @@ const webpackConfig = {
|
|||
// Reduce bundle size by omitting Node crypto library.
|
||||
// See https://github.com/woocommerce/woocommerce-admin/pull/5768
|
||||
crypto: 'empty',
|
||||
// Ignore fs, path to skip resolve errors for @automattic/calypso-config
|
||||
fs: false,
|
||||
path: false,
|
||||
},
|
||||
extensions: [ '.json', '.js', '.jsx', '.ts', '.tsx' ],
|
||||
alias: {
|
||||
|
@ -166,6 +171,9 @@ const webpackConfig = {
|
|||
from: `../../packages/js/${ packageName }/build-style/*.css`,
|
||||
to: `./${ packageName }/[name][ext]`,
|
||||
noErrorOnMissing: true,
|
||||
// Overwrites files already in compilation.assets to ensure we use the assets from the build-style.
|
||||
// This is required for @woocommerce/component to use @automattic/* packages because scss styles from @automattic/* packages will be automatically generated by mini-css-extract-plugin with the same output name.
|
||||
force: true,
|
||||
} ) ),
|
||||
} ),
|
||||
|
||||
|
@ -185,10 +193,6 @@ const webpackConfig = {
|
|||
startYear: 2000,
|
||||
} ),
|
||||
process.env.ANALYZE && new BundleAnalyzerPlugin(),
|
||||
// Adds the script version parameter to the chunk URLs for cache busting
|
||||
// TODO: Partially replace with __webpack_get_script_filename__ in app with Webpack 5.x.
|
||||
// The CSS chunk portion will need to remain, as it originates in MiniCssExtractPlugin.
|
||||
new AsyncChunkSrcVersionParameterPlugin(),
|
||||
// We only want to generate unminified files in the development phase.
|
||||
WC_ADMIN_PHASE === 'development' &&
|
||||
// Generate unminified files to load the unminified version when `define( 'SCRIPT_DEBUG', true );` is set in wp-config.
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
{
|
||||
"root": "plugins/woocommerce-beta-tester/",
|
||||
"sourceRoot": "plugins/woocommerce-beta-tester",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "build"
|
||||
}
|
||||
},
|
||||
"changelog": {
|
||||
"executor": "./tools/executors/changelogger:changelog",
|
||||
"options": {
|
||||
"action": "add",
|
||||
"cwd": "plugins/woocommerce-beta-tester"
|
||||
}
|
||||
},
|
||||
"composer-install": {
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"options": {
|
||||
"command": "composer install",
|
||||
"cwd": "plugins/woocommerce-beta-tester"
|
||||
}
|
||||
},
|
||||
"composer-install-no-dev": {
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"options": {
|
||||
"command": "composer install --no-dev",
|
||||
"cwd": "plugins/woocommerce-beta-tester"
|
||||
}
|
||||
},
|
||||
"composer-dump-autoload": {
|
||||
"executor": "@nrwl/workspace:run-commands",
|
||||
"options": {
|
||||
"command": "composer dump-autoload",
|
||||
"cwd": "plugins/woocommerce-beta-tester"
|
||||
}
|
||||
},
|
||||
"lint-js": {
|
||||
"executor": "@nrwl/workspace:run-script",
|
||||
"options": {
|
||||
"script": "lint:js"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue