Merge branch 'trunk' into fix/tax_lookup_and_order_stat_deletion
This commit is contained in:
commit
ad7d209e56
|
@ -27,26 +27,26 @@ runs:
|
|||
echo "BUILD_FILTERS=$(node ./.github/actions/setup-woocommerce-monorepo/scripts/parse-input-filter.js '${{ inputs.build-filters }}')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup PNPM
|
||||
uses: pnpm/action-setup@10693b3829bf86eb2572aef5f3571dcf5ca9287d
|
||||
uses: pnpm/action-setup@c3b53f6a16e57305370b4ae5a540c2077a1d50dd
|
||||
with:
|
||||
version: '^7.13.3'
|
||||
version: '^7.22.0'
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93
|
||||
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
cache: pnpm
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@e04e1d97f0c0481c6e1ba40f8a538454fe5d7709
|
||||
uses: shivammathur/setup-php@8e2ac35f639d3e794c1da1f28999385ab6fdf0fc
|
||||
with:
|
||||
php-version: ${{ inputs.php-version }}
|
||||
coverage: none
|
||||
tools: phpcs, sirbrillig/phpcs-changed
|
||||
|
||||
- name: Cache Composer Dependencies
|
||||
uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77
|
||||
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12
|
||||
with:
|
||||
path: ~/.cache/composer/files
|
||||
key: ${{ runner.os }}-php-${{ inputs.php-version }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
|
@ -59,7 +59,7 @@ runs:
|
|||
pnpm install ${{ steps.parse-input.outputs.INSTALL_FILTERS }}
|
||||
|
||||
- name: Cache Build Output
|
||||
uses: actions/cache@fd5de65bc895cf536527842281bea11763fefd77
|
||||
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12
|
||||
with:
|
||||
path: node_modules/.cache/turbo
|
||||
key: ${{ runner.os }}-build-output-${{ hashFiles('node_modules/.cache/turbo/*-meta.json') }}
|
||||
|
|
|
@ -17,14 +17,14 @@ jobs:
|
|||
name: Verify
|
||||
runs-on: ubuntu-20.04
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93
|
||||
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c
|
||||
|
||||
- name: Install Octokit
|
||||
run: npm --prefix .github/workflows/scripts install @octokit/action
|
||||
|
|
|
@ -1,43 +1,43 @@
|
|||
name: "Pull request post-merge processing"
|
||||
name: 'Pull request post-merge processing'
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [closed]
|
||||
pull_request_target:
|
||||
types: [closed]
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
process-pull-request-after-merge:
|
||||
name: "Process a pull request after it's merged"
|
||||
if: github.event.pull_request.merged == true
|
||||
runs-on: ubuntu-20.04
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: "Get the action scripts"
|
||||
run: |
|
||||
scripts="assign-milestone-to-merged-pr.php add-post-merge-comment.php post-request-shared.php"
|
||||
for script in $scripts
|
||||
do
|
||||
curl \
|
||||
--silent \
|
||||
--fail \
|
||||
--header 'Authorization: bearer ${{ secrets.GITHUB_TOKEN }}' \
|
||||
--header 'User-Agent: GitHub action to set the milestone for a pull request' \
|
||||
--header 'Accept: application/vnd.github.v3.raw' \
|
||||
--output $script \
|
||||
--location "$GITHUB_API_URL/repos/${{ github.repository }}/contents/.github/workflows/scripts/$script?ref=${{ github.event.pull_request.base.ref }}"
|
||||
done
|
||||
env:
|
||||
GITHUB_API_URL: ${{ env.GITHUB_API_URL }}
|
||||
- name: "Install PHP"
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '7.4'
|
||||
- name: "Run the script to assign a milestone"
|
||||
if: |
|
||||
!github.event.pull_request.milestone &&
|
||||
github.event.pull_request.base.ref == 'trunk'
|
||||
run: php assign-milestone-to-merged-pr.php
|
||||
env:
|
||||
PULL_REQUEST_ID: ${{ github.event.pull_request.node_id }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
process-pull-request-after-merge:
|
||||
name: "Process a pull request after it's merged"
|
||||
if: github.event.pull_request.merged == true
|
||||
runs-on: ubuntu-20.04
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: 'Get the action scripts'
|
||||
run: |
|
||||
scripts="assign-milestone-to-merged-pr.php add-post-merge-comment.php post-request-shared.php"
|
||||
for script in $scripts
|
||||
do
|
||||
curl \
|
||||
--silent \
|
||||
--fail \
|
||||
--header 'Authorization: bearer ${{ secrets.GITHUB_TOKEN }}' \
|
||||
--header 'User-Agent: GitHub action to set the milestone for a pull request' \
|
||||
--header 'Accept: application/vnd.github.v3.raw' \
|
||||
--output $script \
|
||||
--location "$GITHUB_API_URL/repos/${{ github.repository }}/contents/.github/workflows/scripts/$script?ref=${{ github.event.pull_request.base.ref }}"
|
||||
done
|
||||
env:
|
||||
GITHUB_API_URL: ${{ env.GITHUB_API_URL }}
|
||||
- name: 'Install PHP'
|
||||
uses: shivammathur/setup-php@8e2ac35f639d3e794c1da1f28999385ab6fdf0fc
|
||||
with:
|
||||
php-version: '7.4'
|
||||
- name: 'Run the script to assign a milestone'
|
||||
if: |
|
||||
!github.event.pull_request.milestone &&
|
||||
github.event.pull_request.base.ref == 'trunk'
|
||||
run: php assign-milestone-to-merged-pr.php
|
||||
env:
|
||||
PULL_REQUEST_ID: ${{ github.event.pull_request.node_id }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
@ -30,7 +30,7 @@ jobs:
|
|||
freeze: ${{ steps.check-freeze.outputs.freeze }}
|
||||
steps:
|
||||
- name: 'Install PHP'
|
||||
uses: shivammathur/setup-php@v2
|
||||
uses: shivammathur/setup-php@8e2ac35f639d3e794c1da1f28999385ab6fdf0fc
|
||||
with:
|
||||
php-version: '7.4'
|
||||
|
||||
|
|
|
@ -17,11 +17,56 @@ concurrency:
|
|||
permissions: {}
|
||||
|
||||
jobs:
|
||||
api-tests:
|
||||
name: API tests on nightly build
|
||||
runs-on: ubuntu-20.04
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
ALLURE_RESULTS_DIR: ${{ github.workspace }}/plugins/woocommerce/tests/api-core-tests/test-results/allure-results
|
||||
ALLURE_REPORT_DIR: ${{ github.workspace }}/plugins/woocommerce/tests/api-core-tests/test-results/allure-report
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.BRANCH_NAME }}
|
||||
|
||||
- name: Setup WooCommerce Monorepo
|
||||
uses: ./.github/actions/setup-woocommerce-monorepo
|
||||
with:
|
||||
install-filters: woocommerce
|
||||
build: false
|
||||
|
||||
- name: Run API tests.
|
||||
working-directory: plugins/woocommerce
|
||||
env:
|
||||
BASE_URL: ${{ secrets.SMOKE_TEST_URL }}
|
||||
USER_KEY: ${{ secrets.SMOKE_TEST_ADMIN_USER }}
|
||||
USER_SECRET: ${{ secrets.SMOKE_TEST_ADMIN_PASSWORD }}
|
||||
DEFAULT_TIMEOUT_OVERRIDE: 120000
|
||||
run: pnpm exec playwright test --config=tests/api-core-tests/playwright.config.js hello.test.js
|
||||
|
||||
- name: Generate API Test report.
|
||||
if: success() || failure()
|
||||
working-directory: plugins/woocommerce
|
||||
run: pnpm exec allure generate --clean ${{ env.ALLURE_RESULTS_DIR }} --output ${{ env.ALLURE_REPORT_DIR }}
|
||||
|
||||
- name: Archive API test report
|
||||
if: success() || failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ env.API_ARTIFACT }}
|
||||
path: |
|
||||
${{ env.ALLURE_RESULTS_DIR }}
|
||||
${{ env.ALLURE_REPORT_DIR }}
|
||||
if-no-files-found: ignore
|
||||
retention-days: 5
|
||||
|
||||
e2e-tests:
|
||||
name: E2E tests on nightly build
|
||||
runs-on: ubuntu-20.04
|
||||
permissions:
|
||||
contents: read
|
||||
needs: [api-tests]
|
||||
env:
|
||||
ADMIN_PASSWORD: ${{ secrets.SMOKE_TEST_ADMIN_PASSWORD }}
|
||||
ADMIN_USER: ${{ secrets.SMOKE_TEST_ADMIN_USER }}
|
||||
|
@ -78,52 +123,6 @@ jobs:
|
|||
if-no-files-found: ignore
|
||||
retention-days: 5
|
||||
|
||||
api-tests:
|
||||
name: API tests on nightly build
|
||||
runs-on: ubuntu-20.04
|
||||
permissions:
|
||||
contents: read
|
||||
needs: [e2e-tests]
|
||||
if: success() || failure()
|
||||
env:
|
||||
ALLURE_RESULTS_DIR: ${{ github.workspace }}/plugins/woocommerce/tests/api-core-tests/test-results/allure-results
|
||||
ALLURE_REPORT_DIR: ${{ github.workspace }}/plugins/woocommerce/tests/api-core-tests/test-results/allure-report
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.BRANCH_NAME }}
|
||||
|
||||
- name: Setup WooCommerce Monorepo
|
||||
uses: ./.github/actions/setup-woocommerce-monorepo
|
||||
with:
|
||||
install-filters: woocommerce
|
||||
build: false
|
||||
|
||||
- name: Run API tests.
|
||||
working-directory: plugins/woocommerce
|
||||
env:
|
||||
BASE_URL: ${{ secrets.SMOKE_TEST_URL }}
|
||||
USER_KEY: ${{ secrets.SMOKE_TEST_ADMIN_USER }}
|
||||
USER_SECRET: ${{ secrets.SMOKE_TEST_ADMIN_PASSWORD }}
|
||||
DEFAULT_TIMEOUT_OVERRIDE: 120000
|
||||
run: pnpm exec playwright test --config=tests/api-core-tests/playwright.config.js hello.test.js
|
||||
|
||||
- name: Generate API Test report.
|
||||
if: success() || failure()
|
||||
working-directory: plugins/woocommerce
|
||||
run: pnpm exec allure generate --clean ${{ env.ALLURE_RESULTS_DIR }} --output ${{ env.ALLURE_REPORT_DIR }}
|
||||
|
||||
- name: Archive API test report
|
||||
if: success() || failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ env.API_ARTIFACT }}
|
||||
path: |
|
||||
${{ env.ALLURE_RESULTS_DIR }}
|
||||
${{ env.ALLURE_REPORT_DIR }}
|
||||
if-no-files-found: ignore
|
||||
retention-days: 5
|
||||
|
||||
k6-tests:
|
||||
name: k6 tests on nightly build
|
||||
runs-on: ubuntu-20.04
|
||||
|
@ -181,6 +180,7 @@ jobs:
|
|||
runs-on: ubuntu-20.04
|
||||
permissions:
|
||||
contents: read
|
||||
needs: [api-tests]
|
||||
env:
|
||||
USE_WP_ENV: 1
|
||||
ALLURE_RESULTS_DIR: ${{ github.workspace }}/plugins/woocommerce/tests/e2e-pw/allure-results
|
||||
|
@ -256,7 +256,7 @@ jobs:
|
|||
runs-on: ubuntu-20.04
|
||||
permissions:
|
||||
contents: read
|
||||
needs: [test-plugins, k6-tests]
|
||||
needs: [e2e-tests, test-plugins, k6-tests]
|
||||
steps:
|
||||
- name: Create dirs
|
||||
run: |
|
||||
|
@ -312,7 +312,7 @@ jobs:
|
|||
( success() || failure() ) &&
|
||||
! github.event.pull_request.head.repo.fork
|
||||
runs-on: ubuntu-20.04
|
||||
needs: [test-plugins, k6-tests]
|
||||
needs: [e2e-tests, test-plugins, k6-tests]
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.REPORTS_TOKEN }}
|
||||
RUN_ID: ${{ github.run_id }}
|
||||
|
|
|
@ -1,37 +1,37 @@
|
|||
name: Synchronize Dependencies with syncpack
|
||||
on:
|
||||
# Run whenever a pull request is updated
|
||||
pull_request:
|
||||
branches:
|
||||
- trunk
|
||||
paths:
|
||||
- '**/package.json'
|
||||
# Run whenever a pull request is updated
|
||||
pull_request:
|
||||
branches:
|
||||
- trunk
|
||||
paths:
|
||||
- '**/package.json'
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
syncpack:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
name: syncpack
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v3
|
||||
syncpack:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
name: syncpack
|
||||
steps:
|
||||
- name: 'Checkout'
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: 'Setup node'
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- name: 'Setup node'
|
||||
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: 'Install Syncpack'
|
||||
run: npm install -g syncpack@^8.2.4
|
||||
- name: 'Install Syncpack'
|
||||
run: npm install -g syncpack@^8.2.4
|
||||
|
||||
- name: 'List Mismatches'
|
||||
run: syncpack list-mismatches
|
||||
- name: 'List Mismatches'
|
||||
run: syncpack list-mismatches
|
||||
|
||||
- name: 'Explain Remedy'
|
||||
if: failure()
|
||||
run: |
|
||||
echo "Dependency version mismatch detected. This can usually be fixed automatically by updating the pinned version in \`.syncpackrc\` and then running: \`pnpm run sync-dependencies\`"
|
||||
exit 1
|
||||
- name: 'Explain Remedy'
|
||||
if: failure()
|
||||
run: |
|
||||
echo "Dependency version mismatch detected. This can usually be fixed automatically by updating the pinned version in \`.syncpackrc\` and then running: \`pnpm run sync-dependencies\`"
|
||||
exit 1
|
||||
|
|
14
.syncpackrc
14
.syncpackrc
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"dev": true,
|
||||
"filter": "^(?:react|react-dom|typescript|@typescript-eslint|@types/react).*$",
|
||||
"filter": "^(?:react|react-dom|eslint|typescript|@typescript-eslint|@types/react).*$",
|
||||
"indent": "\t",
|
||||
"overrides": true,
|
||||
"peer": true,
|
||||
|
@ -51,6 +51,18 @@
|
|||
"**"
|
||||
],
|
||||
"pinVersion": "^4.8.3"
|
||||
},
|
||||
{
|
||||
"dependencies": [
|
||||
"eslint"
|
||||
],
|
||||
"dependencyTypes": [
|
||||
"devDependencies"
|
||||
],
|
||||
"packages": [
|
||||
"**"
|
||||
],
|
||||
"pinVersion": "^8.32.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
"sass": "^1.49.9",
|
||||
"sass-loader": "^10.2.1",
|
||||
"syncpack": "^8.3.9",
|
||||
"turbo": "^1.4.5",
|
||||
"turbo": "^1.7.0",
|
||||
"typescript": "^4.8.3",
|
||||
"url-loader": "^1.1.2",
|
||||
"webpack": "^5.70.0"
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -44,7 +44,7 @@
|
|||
"@typescript-eslint/eslint-plugin": "^5.43.0",
|
||||
"@woocommerce/api": "^0.2.0",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"jest-mock-extended": "^1.0.18",
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"eslint": "^8.12.0"
|
||||
"eslint": "^8.32.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -55,7 +55,7 @@
|
|||
"@typescript-eslint/parser": "^5.43.0",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"axios-mock-adapter": "^1.20.0",
|
||||
"eslint": "^8.2.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27",
|
||||
"ts-jest": "^27",
|
||||
"typescript": "^4.8.3"
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: dev
|
||||
|
||||
Add TreeControl expand/collapse functionality.
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: update
|
||||
|
||||
Move experimental product section components to @woocommerce/product-editor package.
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: fix
|
||||
|
||||
Altering styles to correctly target fields within slot fills on product editor.
|
|
@ -1,4 +0,0 @@
|
|||
Significance: minor
|
||||
Type: tweak
|
||||
|
||||
Update spelling of Cancelled to Canceled for US English.
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: fix
|
||||
|
||||
Include CSS for experimental tree control so it renders properly in Storybook.
|
|
@ -0,0 +1,5 @@
|
|||
Significance: patch
|
||||
Type: fix
|
||||
Comment: Move registerFill call to inside an useEffect since it was updating a component while rendering another component
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Add new WooProductTabItem component for slot filling tab items.
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: update
|
||||
|
||||
Updating the product editor fill components to support multiple targets.
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: update
|
||||
|
||||
Updating WooProductFieldItem to uniquely generate IDs with different sections.
|
|
@ -44,6 +44,7 @@
|
|||
"@woocommerce/navigation": "workspace:*",
|
||||
"@wordpress/a11y": "3.5.0",
|
||||
"@wordpress/api-fetch": "^6.0.1",
|
||||
"@wordpress/base-styles": "^4.3.0",
|
||||
"@wordpress/block-editor": "^9.8.0",
|
||||
"@wordpress/block-library": "^7.16.0",
|
||||
"@wordpress/blocks": "^11.18.0",
|
||||
|
@ -129,7 +130,7 @@
|
|||
"@wordpress/scripts": "^12.6.1",
|
||||
"concurrently": "^7.0.0",
|
||||
"css-loader": "^3.6.0",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"postcss-loader": "^3.0.0",
|
||||
|
@ -164,5 +165,11 @@
|
|||
"pnpm lint:fix",
|
||||
"pnpm test-staged"
|
||||
]
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { TreeItemProps } from '../types';
|
||||
|
||||
export function useExpander( {
|
||||
shouldItemBeExpanded,
|
||||
item,
|
||||
}: Pick< TreeItemProps, 'shouldItemBeExpanded' | 'item' > ) {
|
||||
const [ isExpanded, setExpanded ] = useState( false );
|
||||
|
||||
useEffect( () => {
|
||||
if (
|
||||
item.children?.length &&
|
||||
typeof shouldItemBeExpanded === 'function'
|
||||
) {
|
||||
setExpanded( shouldItemBeExpanded( item ) );
|
||||
}
|
||||
}, [ item, shouldItemBeExpanded ] );
|
||||
|
||||
function onToggleExpand() {
|
||||
setExpanded( ( prev ) => ! prev );
|
||||
}
|
||||
|
||||
return { isExpanded, onToggleExpand };
|
||||
}
|
|
@ -1,30 +1,43 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import React from 'react';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { TreeItemProps } from '../types';
|
||||
import { useExpander } from './use-expander';
|
||||
|
||||
export function useTreeItem( { item, level, ...props }: TreeItemProps ) {
|
||||
export function useTreeItem( {
|
||||
item,
|
||||
level,
|
||||
shouldItemBeExpanded,
|
||||
...props
|
||||
}: TreeItemProps ) {
|
||||
const nextLevel = level + 1;
|
||||
const nextHeadingPaddingLeft = ( level - 1 ) * 28 + 12;
|
||||
|
||||
const expander = useExpander( {
|
||||
item,
|
||||
shouldItemBeExpanded,
|
||||
} );
|
||||
|
||||
return {
|
||||
item,
|
||||
level: nextLevel,
|
||||
expander,
|
||||
treeItemProps: {
|
||||
...props,
|
||||
},
|
||||
headingProps: {
|
||||
style: {
|
||||
paddingLeft: nextHeadingPaddingLeft,
|
||||
},
|
||||
'--level': level,
|
||||
} as React.CSSProperties,
|
||||
},
|
||||
treeProps: {
|
||||
items: item.children,
|
||||
level: nextLevel,
|
||||
shouldItemBeExpanded,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,7 +7,13 @@
|
|||
*/
|
||||
import { TreeProps } from '../types';
|
||||
|
||||
export function useTree( { ref, items, level = 1, ...props }: TreeProps ) {
|
||||
export function useTree( {
|
||||
ref,
|
||||
items,
|
||||
level = 1,
|
||||
shouldItemBeExpanded,
|
||||
...props
|
||||
}: TreeProps ) {
|
||||
return {
|
||||
level,
|
||||
items,
|
||||
|
@ -16,6 +22,7 @@ export function useTree( { ref, items, level = 1, ...props }: TreeProps ) {
|
|||
},
|
||||
treeItemProps: {
|
||||
level,
|
||||
shouldItemBeExpanded,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { BaseControl } from '@wordpress/components';
|
||||
import React, { createElement } from 'react';
|
||||
import { BaseControl, TextControl } from '@wordpress/components';
|
||||
import React, { createElement, useCallback, useState } from 'react';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { TreeControl } from '../tree-control';
|
||||
import { Item } from '../types';
|
||||
import { Item, LinkedTree } from '../types';
|
||||
|
||||
const listItems: Item[] = [
|
||||
{ value: '1', label: 'Technology' },
|
||||
|
@ -36,6 +36,35 @@ export const SimpleTree: React.FC = () => {
|
|||
);
|
||||
};
|
||||
|
||||
function shouldItemBeExpanded( item: LinkedTree, filter: string ) {
|
||||
if ( ! filter || ! item.children?.length ) return false;
|
||||
return item.children.some( ( child ) => {
|
||||
if ( new RegExp( filter, 'ig' ).test( child.data.label ) ) {
|
||||
return true;
|
||||
}
|
||||
return shouldItemBeExpanded( child, filter );
|
||||
} );
|
||||
}
|
||||
|
||||
export const ExpandOnFilter: React.FC = () => {
|
||||
const [ filter, setFilter ] = useState( '' );
|
||||
|
||||
return (
|
||||
<>
|
||||
<TextControl value={ filter } onChange={ setFilter } />
|
||||
<BaseControl label="Expand on filter" id="expand-on-filter">
|
||||
<TreeControl
|
||||
id="expand-on-filter"
|
||||
items={ listItems }
|
||||
shouldItemBeExpanded={ ( item ) =>
|
||||
shouldItemBeExpanded( item, filter )
|
||||
}
|
||||
/>
|
||||
</BaseControl>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default {
|
||||
title: 'WooCommerce Admin/experimental/TreeControl',
|
||||
component: TreeControl,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
flex-grow: 1;
|
||||
gap: $gap-smaller;
|
||||
min-height: $gap-largest;
|
||||
padding: 0 $gap-small;
|
||||
padding: 0 $gap-small 0 calc( ( var( --level ) - 1 ) * ( $gap + $gap-small ) + $gap-small );
|
||||
border-radius: 2px;
|
||||
|
||||
&:hover,
|
||||
|
@ -31,4 +31,12 @@
|
|||
display: block;
|
||||
}
|
||||
}
|
||||
&__expander {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.components-button {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Button } from '@wordpress/components';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { chevronDown, chevronUp } from '@wordpress/icons';
|
||||
import classNames from 'classnames';
|
||||
import { createElement, forwardRef } from 'react';
|
||||
|
||||
|
@ -16,7 +18,13 @@ export const TreeItem = forwardRef( function ForwardedTreeItem(
|
|||
props: TreeItemProps,
|
||||
ref: React.ForwardedRef< HTMLLIElement >
|
||||
) {
|
||||
const { item, treeItemProps, headingProps, treeProps } = useTreeItem( {
|
||||
const {
|
||||
item,
|
||||
treeItemProps,
|
||||
headingProps,
|
||||
treeProps,
|
||||
expander: { isExpanded, onToggleExpand },
|
||||
} = useTreeItem( {
|
||||
...props,
|
||||
ref,
|
||||
} );
|
||||
|
@ -36,9 +44,26 @@ export const TreeItem = forwardRef( function ForwardedTreeItem(
|
|||
<div className="experimental-woocommerce-tree-item__label">
|
||||
<span>{ item.data.label }</span>
|
||||
</div>
|
||||
|
||||
{ Boolean( item.children?.length ) && (
|
||||
<div className="experimental-woocommerce-tree-item__expander">
|
||||
<Button
|
||||
icon={ isExpanded ? chevronUp : chevronDown }
|
||||
onClick={ onToggleExpand }
|
||||
className="experimental-woocommerce-tree-item__expander"
|
||||
aria-label={
|
||||
isExpanded
|
||||
? __( 'Collapse', 'woocommerce' )
|
||||
: __( 'Expand', 'woocommerce' )
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
) }
|
||||
</div>
|
||||
|
||||
{ Boolean( item.children.length ) && <Tree { ...treeProps } /> }
|
||||
{ Boolean( item.children.length ) && isExpanded && (
|
||||
<Tree { ...treeProps } />
|
||||
) }
|
||||
</li>
|
||||
);
|
||||
} );
|
||||
|
|
|
@ -16,6 +16,21 @@ export type TreeProps = React.DetailedHTMLProps<
|
|||
> & {
|
||||
level?: number;
|
||||
items: LinkedTree[];
|
||||
/**
|
||||
* Return if the tree item passed in should be expanded.
|
||||
*
|
||||
* @example
|
||||
* <Tree
|
||||
* shouldItemBeExpanded={
|
||||
* ( item ) => checkExpanded( item, filter )
|
||||
* }
|
||||
* />
|
||||
*
|
||||
* @param item The tree item to determine if should be expanded.
|
||||
*
|
||||
* @see {@link LinkedTree}
|
||||
*/
|
||||
shouldItemBeExpanded?( item: LinkedTree ): boolean;
|
||||
};
|
||||
|
||||
export type TreeItemProps = React.DetailedHTMLProps<
|
||||
|
@ -24,6 +39,7 @@ export type TreeItemProps = React.DetailedHTMLProps<
|
|||
> & {
|
||||
level: number;
|
||||
item: LinkedTree;
|
||||
shouldItemBeExpanded?( item: LinkedTree ): boolean;
|
||||
};
|
||||
|
||||
export type TreeControlProps = Omit< TreeProps, 'items' | 'level' > & {
|
||||
|
|
|
@ -87,10 +87,7 @@ export { CollapsibleContent } from './collapsible-content';
|
|||
export { createOrderedChildren, sortFillsByOrder } from './utils';
|
||||
export { WooProductFieldItem as __experimentalWooProductFieldItem } from './woo-product-field-item';
|
||||
export { WooProductSectionItem as __experimentalWooProductSectionItem } from './woo-product-section-item';
|
||||
export {
|
||||
ProductSectionLayout as __experimentalProductSectionLayout,
|
||||
ProductFieldSection as __experimentalProductFieldSection,
|
||||
} from './product-section-layout';
|
||||
export { WooProductTabItem as __experimentalWooProductTabItem } from './woo-product-tab-item';
|
||||
export * from './product-fields';
|
||||
export {
|
||||
SlotContextProvider,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/**
|
||||
* External Dependencies
|
||||
*/
|
||||
@import 'node_modules/@wordpress/base-styles/colors.native';
|
||||
@import '@automattic/tour-kit/dist/esm/styles.scss';
|
||||
|
||||
/**
|
||||
|
@ -55,4 +56,4 @@
|
|||
@import 'tour-kit/style.scss';
|
||||
@import 'collapsible-content/style.scss';
|
||||
@import 'form/style.scss';
|
||||
@import 'product-section-layout/style.scss';
|
||||
@import 'experimental-tree-control/tree.scss';
|
||||
|
|
|
@ -20,7 +20,10 @@ function createOrderedChildren< T = Fill.Props, S = Record< string, unknown > >(
|
|||
injectProps?: S
|
||||
) {
|
||||
if ( typeof children === 'function' ) {
|
||||
return cloneElement( children( props ), { order, ...injectProps } );
|
||||
return cloneElement( children( { ...props, order, ...injectProps } ), {
|
||||
order,
|
||||
...injectProps,
|
||||
} );
|
||||
} else if ( isValidElement( children ) ) {
|
||||
return cloneElement( children, { ...props, order, ...injectProps } );
|
||||
}
|
||||
|
|
|
@ -1,54 +1,94 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { Slot, Fill } from '@wordpress/components';
|
||||
import { createElement, Children } from '@wordpress/element';
|
||||
import { createElement, Children, Fragment } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { createOrderedChildren, sortFillsByOrder } from '../utils';
|
||||
import { useSlotContext, SlotContextHelpersType } from '../slot-context';
|
||||
import { ProductFillLocationType } from '../woo-product-tab-item';
|
||||
|
||||
type WooProductFieldItemProps = {
|
||||
id: string;
|
||||
section: string;
|
||||
sections: ProductFillLocationType[];
|
||||
pluginId: string;
|
||||
order?: number;
|
||||
};
|
||||
|
||||
type WooProductFieldSlotProps = {
|
||||
section: string;
|
||||
};
|
||||
|
||||
export const WooProductFieldItem: React.FC< WooProductFieldItemProps > & {
|
||||
Slot: React.FC< Slot.Props & WooProductFieldSlotProps >;
|
||||
} = ( { children, order = 20, section, id } ) => {
|
||||
type WooProductFieldFillProps = {
|
||||
fieldName: string;
|
||||
sectionName: string;
|
||||
order: number;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
const WooProductFieldFill: React.FC< WooProductFieldFillProps > = ( {
|
||||
fieldName,
|
||||
sectionName,
|
||||
order,
|
||||
children,
|
||||
} ) => {
|
||||
const { registerFill, getFillHelpers } = useSlotContext();
|
||||
|
||||
registerFill( id );
|
||||
const fieldId = `product_field/${ sectionName }/${ fieldName }`;
|
||||
|
||||
useEffect( () => {
|
||||
registerFill( fieldId );
|
||||
}, [] );
|
||||
|
||||
return (
|
||||
<Fill name={ `woocommerce_product_field_${ section }` }>
|
||||
{ ( fillProps: Fill.Props ) => {
|
||||
return createOrderedChildren<
|
||||
Fill.Props & SlotContextHelpersType,
|
||||
<Fill
|
||||
name={ `woocommerce_product_field_${ sectionName }` }
|
||||
key={ fieldId }
|
||||
>
|
||||
{ ( fillProps: Fill.Props ) =>
|
||||
createOrderedChildren<
|
||||
Fill.Props &
|
||||
SlotContextHelpersType & {
|
||||
sectionName: string;
|
||||
},
|
||||
{ _id: string }
|
||||
>(
|
||||
children,
|
||||
order,
|
||||
{
|
||||
sectionName,
|
||||
...fillProps,
|
||||
...getFillHelpers(),
|
||||
},
|
||||
{ _id: id }
|
||||
);
|
||||
} }
|
||||
{ _id: fieldId }
|
||||
)
|
||||
}
|
||||
</Fill>
|
||||
);
|
||||
};
|
||||
|
||||
export const WooProductFieldItem: React.FC< WooProductFieldItemProps > & {
|
||||
Slot: React.FC< Slot.Props & WooProductFieldSlotProps >;
|
||||
} = ( { children, sections, id } ) => {
|
||||
return (
|
||||
<>
|
||||
{ sections.map( ( { name: sectionName, order = 20 } ) => (
|
||||
<WooProductFieldFill
|
||||
fieldName={ id }
|
||||
sectionName={ sectionName }
|
||||
order={ order }
|
||||
key={ sectionName }
|
||||
>
|
||||
{ children }
|
||||
</WooProductFieldFill>
|
||||
) ) }
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
WooProductFieldItem.Slot = ( { fillProps, section } ) => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const { filterRegisteredFills } = useSlotContext();
|
||||
|
|
|
@ -3,41 +3,51 @@
|
|||
*/
|
||||
import React from 'react';
|
||||
import { Slot, Fill } from '@wordpress/components';
|
||||
import { createElement } from '@wordpress/element';
|
||||
import { createElement, Fragment } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { createOrderedChildren, sortFillsByOrder } from '../utils';
|
||||
import { ProductFillLocationType } from '../woo-product-tab-item';
|
||||
|
||||
type WooProductSectionItemProps = {
|
||||
id: string;
|
||||
location: string;
|
||||
tabs: ProductFillLocationType[];
|
||||
pluginId: string;
|
||||
order?: number;
|
||||
};
|
||||
|
||||
type WooProductFieldSlotProps = {
|
||||
location: string;
|
||||
type WooProductSectionSlotProps = {
|
||||
tab: string;
|
||||
};
|
||||
|
||||
export const WooProductSectionItem: React.FC< WooProductSectionItemProps > & {
|
||||
Slot: React.FC< Slot.Props & WooProductFieldSlotProps >;
|
||||
} = ( { children, order = 20, location } ) => (
|
||||
<Fill name={ `woocommerce_product_section_${ location }` }>
|
||||
{ ( fillProps: Fill.Props ) => {
|
||||
return createOrderedChildren< Fill.Props >(
|
||||
children,
|
||||
order,
|
||||
fillProps
|
||||
);
|
||||
} }
|
||||
</Fill>
|
||||
);
|
||||
Slot: React.FC< Slot.Props & WooProductSectionSlotProps >;
|
||||
} = ( { children, tabs } ) => {
|
||||
return (
|
||||
<>
|
||||
{ tabs.map( ( { name: tabName, order: tabOrder } ) => (
|
||||
<Fill
|
||||
name={ `woocommerce_product_section_${ tabName }` }
|
||||
key={ tabName }
|
||||
>
|
||||
{ ( fillProps: Fill.Props ) => {
|
||||
return createOrderedChildren<
|
||||
Fill.Props & { tabName: string }
|
||||
>( children, tabOrder || 20, {
|
||||
tabName,
|
||||
...fillProps,
|
||||
} );
|
||||
} }
|
||||
</Fill>
|
||||
) ) }
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
WooProductSectionItem.Slot = ( { fillProps, location } ) => (
|
||||
WooProductSectionItem.Slot = ( { fillProps, tab } ) => (
|
||||
<Slot
|
||||
name={ `woocommerce_product_section_${ location }` }
|
||||
name={ `woocommerce_product_section_${ tab }` }
|
||||
fillProps={ fillProps }
|
||||
>
|
||||
{ ( fills ) => {
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
# WooProductTabItem Slot & Fill
|
||||
|
||||
A Slotfill component that will allow you to add a new tab to the product editor.
|
||||
|
||||
## Usage
|
||||
|
||||
```jsx
|
||||
<WooProductTabItem id={ key } location="tab/general" order={ 2 } pluginId="test-plugin" tabProps={ { title: 'New tab', name: 'new-tab' } } >
|
||||
<Card>
|
||||
<CardBody>{ /* Tab content */ }</CardBody>
|
||||
</Card>
|
||||
</WooProductTabItem>
|
||||
|
||||
<WooProductTabItem.Slot location="tab/general" />
|
||||
```
|
||||
|
||||
### WooProductTabItem (fill)
|
||||
|
||||
This is the fill component. You must provide the `id` prop to identify your section fill with a unique string. This component will accept a series of props:
|
||||
|
||||
| Prop | Type | Description |
|
||||
| ---------- | ------ | -------------------------------------------------------------------------------------------------------------- |
|
||||
| `id` | String | A unique string to identify your fill. Used for configuiration management. |
|
||||
| `location` | String | The string used to identify the particular location that you want to render your section. |
|
||||
| `pluginId` | String | A unique plugin ID to identify the plugin/extension that this fill is associated with. |
|
||||
| `tabProps` | Object | An object containing tab props: name, title, className, disabled (see TabPanel.Tab from @wordpress/components) |
|
||||
| `order` | Number | (optional) This number will dictate the order that the sections rendered by a Slot will be appear. |
|
||||
|
||||
### WooProductTabItem.Slot (slot)
|
||||
|
||||
This is the slot component, and will not be used as frequently. It must also receive the required `location` prop that will be identical to the fill `location`.
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---------- | ------ | ---------------------------------------------------------------------------------------------------- |
|
||||
| `location` | String | Unique to the location that the Slot appears, and must be the same as the one provided to any fills. |
|
|
@ -0,0 +1 @@
|
|||
export * from './woo-product-tab-item';
|
|
@ -0,0 +1,107 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import React, { ReactElement, ReactNode } from 'react';
|
||||
import { Slot, Fill, TabPanel } from '@wordpress/components';
|
||||
import { createElement, Fragment } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { createOrderedChildren } from '../utils';
|
||||
|
||||
export type ProductFillLocationType = { name: string; order?: number };
|
||||
|
||||
type WooProductTabItemProps = {
|
||||
id: string;
|
||||
pluginId: string;
|
||||
tabProps:
|
||||
| TabPanel.Tab
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
| ( ( fillProps: Record< string, any > | undefined ) => TabPanel.Tab );
|
||||
templates?: Array< ProductFillLocationType >;
|
||||
};
|
||||
|
||||
type WooProductFieldSlotProps = {
|
||||
template: string;
|
||||
children: (
|
||||
tabs: TabPanel.Tab[],
|
||||
tabChildren: Record< string, ReactNode >
|
||||
) => ReactElement | null;
|
||||
};
|
||||
|
||||
export const WooProductTabItem: React.FC< WooProductTabItemProps > & {
|
||||
Slot: React.VFC<
|
||||
Omit< Slot.Props, 'children' > & WooProductFieldSlotProps
|
||||
>;
|
||||
} = ( { children, tabProps, templates } ) => {
|
||||
if ( ! templates ) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn( 'WooProductTabItem fill is missing templates property.' );
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{ templates.map( ( templateData ) => (
|
||||
<Fill
|
||||
name={ `woocommerce_product_tab_${ templateData.name }` }
|
||||
key={ templateData.name }
|
||||
>
|
||||
{ ( fillProps: Fill.Props ) => {
|
||||
return createOrderedChildren< Fill.Props >(
|
||||
children,
|
||||
templateData.order || 20,
|
||||
{},
|
||||
{
|
||||
tabProps,
|
||||
templateName: templateData.name,
|
||||
order: templateData.order || 20,
|
||||
...fillProps,
|
||||
}
|
||||
);
|
||||
} }
|
||||
</Fill>
|
||||
) ) }
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
WooProductTabItem.Slot = ( { fillProps, template, children } ) => (
|
||||
<Slot
|
||||
name={ `woocommerce_product_tab_${ template }` }
|
||||
fillProps={ fillProps }
|
||||
>
|
||||
{ ( fills ) => {
|
||||
const tabData = fills.reduce(
|
||||
( { childrenMap, tabs }, fill ) => {
|
||||
const props: WooProductTabItemProps & { order: number } =
|
||||
fill[ 0 ].props;
|
||||
if ( props && props.tabProps ) {
|
||||
childrenMap[ props.tabProps.name ] = fill[ 0 ];
|
||||
const tabProps =
|
||||
typeof props.tabProps === 'function'
|
||||
? props.tabProps( fillProps )
|
||||
: props.tabProps;
|
||||
tabs.push( {
|
||||
...tabProps,
|
||||
order: props.order ?? 20,
|
||||
} );
|
||||
}
|
||||
return {
|
||||
childrenMap,
|
||||
tabs,
|
||||
};
|
||||
},
|
||||
{ childrenMap: {}, tabs: [] } as {
|
||||
childrenMap: Record< string, ReactElement >;
|
||||
tabs: Array< TabPanel.Tab & { order: number } >;
|
||||
}
|
||||
);
|
||||
const orderedTabs = tabData.tabs.sort( ( a, b ) => {
|
||||
return a.order - b.order;
|
||||
} );
|
||||
|
||||
return children( orderedTabs, tabData.childrenMap );
|
||||
} }
|
||||
</Slot>
|
||||
);
|
|
@ -2,7 +2,7 @@
|
|||
"phpVersion": null,
|
||||
"core": null,
|
||||
"plugins": [
|
||||
"https://downloads.wordpress.org/plugin/woocommerce.7.1.0.zip",
|
||||
"https://downloads.wordpress.org/plugin/woocommerce.7.3.0.zip",
|
||||
"."
|
||||
],
|
||||
"config": {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Significance: patch
|
||||
Type: update
|
||||
|
||||
Disable TikTok in the OBW
|
||||
bump WooCommerce version
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -50,7 +50,7 @@
|
|||
"@babel/core": "^7.17.5",
|
||||
"@types/jest": "^27.4.1",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"rimraf": "^3.0.2",
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -53,7 +53,7 @@
|
|||
"@babel/core": "^7.17.5",
|
||||
"@types/jest": "^27.4.1",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"rimraf": "^3.0.2",
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Add FeedbackModal and ProductMVPFeedbackModal components
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Add a function to help decide if comments section should be shown
|
|
@ -52,7 +52,7 @@
|
|||
"@wordpress/browserslist-config": "^4.1.1",
|
||||
"concurrently": "^7.0.0",
|
||||
"css-loader": "^3.6.0",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"postcss-loader": "^3.0.0",
|
||||
|
|
|
@ -29,6 +29,10 @@ type CustomerEffortScoreProps = {
|
|||
onModalShownCallback?: () => void;
|
||||
onModalDismissedCallback?: () => void;
|
||||
icon?: React.ReactElement | null;
|
||||
shouldShowComments?: (
|
||||
firstQuestionScore: number,
|
||||
secondQuestionScore: number
|
||||
) => boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -48,6 +52,7 @@ type CustomerEffortScoreProps = {
|
|||
* @param {Function} props.onNoticeDismissedCallback Function to call when the notice is dismissed.
|
||||
* @param {Function} props.onModalShownCallback Function to call when the modal is shown.
|
||||
* @param {Function} props.onModalDismissedCallback Function to call when modal is dismissed.
|
||||
* @param {Function} props.shouldShowComments Callback to determine if comments section should be shown.
|
||||
* @param {Object} props.icon Icon (React component) to be shown on the notice.
|
||||
*/
|
||||
const CustomerEffortScore: React.VFC< CustomerEffortScoreProps > = ( {
|
||||
|
@ -62,6 +67,10 @@ const CustomerEffortScore: React.VFC< CustomerEffortScoreProps > = ( {
|
|||
onModalShownCallback = noop,
|
||||
onModalDismissedCallback = noop,
|
||||
icon,
|
||||
shouldShowComments = ( firstQuestionScore, secondQuestionScore ) =>
|
||||
[ firstQuestionScore, secondQuestionScore ].some(
|
||||
( score ) => score === 1 || score === 2
|
||||
),
|
||||
} ) => {
|
||||
const [ shouldCreateNotice, setShouldCreateNotice ] = useState( true );
|
||||
const [ visible, setVisible ] = useState( false );
|
||||
|
@ -108,6 +117,7 @@ const CustomerEffortScore: React.VFC< CustomerEffortScoreProps > = ( {
|
|||
secondQuestion={ secondQuestion }
|
||||
recordScoreCallback={ recordScoreCallback }
|
||||
onCloseModal={ onModalDismissedCallback }
|
||||
shouldShowComments={ shouldShowComments }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -145,6 +155,10 @@ CustomerEffortScore.propTypes = {
|
|||
* The second survey question.
|
||||
*/
|
||||
secondQuestion: PropTypes.string,
|
||||
/**
|
||||
* A function to determine whether or not the comments field shown be shown.
|
||||
*/
|
||||
shouldShowComments: PropTypes.func,
|
||||
};
|
||||
|
||||
export { CustomerEffortScore };
|
||||
|
|
|
@ -32,6 +32,7 @@ import { __ } from '@wordpress/i18n';
|
|||
* @param {string} props.defaultScore Default score.
|
||||
* @param {Function} props.onCloseModal Callback for when user closes modal by clicking cancel.
|
||||
* @param {Function} props.customOptions List of custom score options, contains label and value.
|
||||
* @param {Function} props.shouldShowComments A function to determine whether or not the comments field shown be shown.
|
||||
*/
|
||||
function CustomerFeedbackModal( {
|
||||
recordScoreCallback,
|
||||
|
@ -42,6 +43,10 @@ function CustomerFeedbackModal( {
|
|||
defaultScore = NaN,
|
||||
onCloseModal,
|
||||
customOptions,
|
||||
shouldShowComments = ( firstQuestionScore, secondQuestionScore ) =>
|
||||
[ firstQuestionScore, secondQuestionScore ].some(
|
||||
( score ) => score === 1 || score === 2
|
||||
),
|
||||
}: {
|
||||
recordScoreCallback: (
|
||||
score: number,
|
||||
|
@ -55,6 +60,10 @@ function CustomerFeedbackModal( {
|
|||
defaultScore?: number;
|
||||
onCloseModal?: () => void;
|
||||
customOptions?: { label: string; value: string }[];
|
||||
shouldShowComments?: (
|
||||
firstQuestionScore: number,
|
||||
secondQuestionScore: number
|
||||
) => boolean;
|
||||
} ): JSX.Element | null {
|
||||
const options =
|
||||
customOptions && customOptions.length > 0
|
||||
|
@ -200,29 +209,33 @@ function CustomerFeedbackModal( {
|
|||
</div>
|
||||
) }
|
||||
|
||||
{ [ firstQuestionScore, secondQuestionScore ].some(
|
||||
( score ) => score === 1 || score === 2
|
||||
) && (
|
||||
<div className="woocommerce-customer-effort-score__comments">
|
||||
<TextareaControl
|
||||
label={ __(
|
||||
'How is that screen useful to you? What features would you add or change?',
|
||||
'woocommerce'
|
||||
) }
|
||||
help={ __(
|
||||
'Your feedback will go to the WooCommerce development team',
|
||||
'woocommerce'
|
||||
) }
|
||||
value={ comments }
|
||||
placeholder={ __(
|
||||
'Optional, but much apprecated. We love reading your feedback!',
|
||||
'woocommerce'
|
||||
) }
|
||||
onChange={ ( value: string ) => setComments( value ) }
|
||||
rows={ 5 }
|
||||
/>
|
||||
</div>
|
||||
) }
|
||||
{ typeof shouldShowComments === 'function' &&
|
||||
shouldShowComments(
|
||||
firstQuestionScore,
|
||||
secondQuestionScore
|
||||
) && (
|
||||
<div className="woocommerce-customer-effort-score__comments">
|
||||
<TextareaControl
|
||||
label={ __(
|
||||
'How is that screen useful to you? What features would you add or change?',
|
||||
'woocommerce'
|
||||
) }
|
||||
help={ __(
|
||||
'Your feedback will go to the WooCommerce development team',
|
||||
'woocommerce'
|
||||
) }
|
||||
value={ comments }
|
||||
placeholder={ __(
|
||||
'Optional, but much apprecated. We love reading your feedback!',
|
||||
'woocommerce'
|
||||
) }
|
||||
onChange={ ( value: string ) =>
|
||||
setComments( value )
|
||||
}
|
||||
rows={ 5 }
|
||||
/>
|
||||
</div>
|
||||
) }
|
||||
|
||||
{ showNoScoreMessage && (
|
||||
<div
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
.woocommerce-feedback-modal__buttons {
|
||||
text-align: right;
|
||||
|
||||
.components-button {
|
||||
margin-left: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-feedback-modal .woocommerce-feedback-modal__description {
|
||||
max-width: 550px;
|
||||
margin: 0 0 1.5em 0;
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { createElement, useState } from '@wordpress/element';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Modal } from '@wordpress/components';
|
||||
import { Text } from '@woocommerce/experimental';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
/**
|
||||
* Provides a modal requesting customer feedback.
|
||||
*
|
||||
* Answers and comments are sent to a callback function.
|
||||
*
|
||||
* @param {Object} props Component props.
|
||||
* @param {Function} props.onSubmit Function to call when the results are sent.
|
||||
* @param {string} props.title Title displayed in the modal.
|
||||
* @param {string} props.description Description displayed in the modal.
|
||||
* @param {string} props.isSubmitButtonDisabled Boolean to enable/disable the send button.
|
||||
* @param {string} props.submitButtonLabel Label for the send button.
|
||||
* @param {string} props.cancelButtonLabel Label for the cancel button.
|
||||
* @param {Function} props.onModalClose Callback for when user closes modal by clicking cancel.
|
||||
* @param {Function} props.children Children to be rendered.
|
||||
*/
|
||||
function FeedbackModal( {
|
||||
onSubmit,
|
||||
title,
|
||||
description,
|
||||
onModalClose,
|
||||
children,
|
||||
isSubmitButtonDisabled,
|
||||
submitButtonLabel,
|
||||
cancelButtonLabel,
|
||||
}: {
|
||||
onSubmit: () => void;
|
||||
title: string;
|
||||
description?: string;
|
||||
onModalClose?: () => void;
|
||||
children?: JSX.Element;
|
||||
isSubmitButtonDisabled?: boolean;
|
||||
submitButtonLabel?: string;
|
||||
cancelButtonLabel?: string;
|
||||
} ): JSX.Element | null {
|
||||
const [ isOpen, setOpen ] = useState( true );
|
||||
|
||||
const closeModal = () => {
|
||||
setOpen( false );
|
||||
if ( onModalClose ) {
|
||||
onModalClose();
|
||||
}
|
||||
};
|
||||
|
||||
if ( ! isOpen ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className="woocommerce-feedback-modal"
|
||||
title={ title }
|
||||
onRequestClose={ closeModal }
|
||||
shouldCloseOnClickOutside={ false }
|
||||
>
|
||||
<Text
|
||||
variant="body"
|
||||
as="p"
|
||||
className="woocommerce-feedback-modal__description"
|
||||
size={ 14 }
|
||||
lineHeight="20px"
|
||||
marginBottom="1.5em"
|
||||
>
|
||||
{ description }
|
||||
</Text>
|
||||
{ children }
|
||||
<div className="woocommerce-feedback-modal__buttons">
|
||||
<Button isTertiary onClick={ closeModal } name="cancel">
|
||||
{ cancelButtonLabel }
|
||||
</Button>
|
||||
<Button
|
||||
isPrimary={ ! isSubmitButtonDisabled }
|
||||
isSecondary={ isSubmitButtonDisabled }
|
||||
onClick={ () => {
|
||||
onSubmit();
|
||||
setOpen( false );
|
||||
} }
|
||||
name="send"
|
||||
disabled={ isSubmitButtonDisabled }
|
||||
>
|
||||
{ submitButtonLabel }
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
FeedbackModal.propTypes = {
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
title: PropTypes.string,
|
||||
description: PropTypes.string,
|
||||
onModalClose: PropTypes.func,
|
||||
isSubmitButtonDisabled: PropTypes.bool,
|
||||
submitButtonLabel: PropTypes.string,
|
||||
cancelButtonLabel: PropTypes.string,
|
||||
};
|
||||
|
||||
export { FeedbackModal };
|
|
@ -0,0 +1 @@
|
|||
export * from './feedback-modal';
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
|
||||
import { createElement } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { FeedbackModal } from '../index';
|
||||
|
||||
const mockRecordScoreCallback = jest.fn();
|
||||
|
||||
describe( 'FeedbackModal', () => {
|
||||
it( 'should render a modal', async () => {
|
||||
render(
|
||||
<FeedbackModal
|
||||
onSubmit={ mockRecordScoreCallback }
|
||||
title="Testing"
|
||||
submitButtonLabel="Send"
|
||||
cancelButtonLabel="Cancel"
|
||||
/>
|
||||
);
|
||||
|
||||
// Wait for the modal to render.
|
||||
await screen.findByRole( 'dialog' );
|
||||
|
||||
expect(
|
||||
screen.getByRole( 'button', { name: /Send/i } )
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole( 'button', { name: /Cancel/i } )
|
||||
).toBeInTheDocument();
|
||||
} );
|
||||
|
||||
it( 'should close modal when cancel button pressed', async () => {
|
||||
render(
|
||||
<FeedbackModal
|
||||
onSubmit={ mockRecordScoreCallback }
|
||||
title="Testing"
|
||||
submitButtonLabel="Send"
|
||||
cancelButtonLabel="Cancel"
|
||||
/>
|
||||
);
|
||||
|
||||
// Wait for the modal to render.
|
||||
await screen.findByRole( 'dialog' );
|
||||
|
||||
// Press cancel button.
|
||||
fireEvent.click( screen.getByRole( 'button', { name: /Cancel/i } ) );
|
||||
|
||||
expect( screen.queryByRole( 'dialog' ) ).not.toBeInTheDocument();
|
||||
} );
|
||||
} );
|
|
@ -1,3 +1,5 @@
|
|||
export * from './customer-effort-score';
|
||||
export * from './customer-feedback-simple';
|
||||
export * from './customer-feedback-modal';
|
||||
export * from './product-mvp-feedback-modal';
|
||||
export * from './feedback-modal';
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './product-mvp-feedback-modal';
|
|
@ -0,0 +1,23 @@
|
|||
.woocommerce-product-mvp-feedback-modal {
|
||||
&__subtitle {
|
||||
margin-top: $gap-smaller !important;
|
||||
}
|
||||
&__checkboxes {
|
||||
margin: $gap-small 0;
|
||||
}
|
||||
&__comments {
|
||||
margin-top: 2em;
|
||||
margin-bottom: 1.5em;
|
||||
|
||||
label {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
text-transform: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { createElement, Fragment, useState } from '@wordpress/element';
|
||||
import PropTypes from 'prop-types';
|
||||
import { CheckboxControl, TextareaControl } from '@wordpress/components';
|
||||
import { Text } from '@woocommerce/experimental';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { FeedbackModal } from '../feedback-modal';
|
||||
|
||||
/**
|
||||
* Provides a modal requesting customer feedback.
|
||||
*
|
||||
*
|
||||
* @param {Object} props Component props.
|
||||
* @param {Function} props.recordScoreCallback Function to call when the results are sent.
|
||||
* @param {Function} props.onCloseModal Callback for when user closes modal by clicking cancel.
|
||||
*/
|
||||
function ProductMVPFeedbackModal( {
|
||||
recordScoreCallback,
|
||||
onCloseModal,
|
||||
}: {
|
||||
recordScoreCallback: ( checked: string[], comments: string ) => void;
|
||||
onCloseModal?: () => void;
|
||||
} ): JSX.Element | null {
|
||||
const [ missingFeatures, setMissingFeatures ] = useState( false );
|
||||
const [ missingPlugins, setMissingPlugins ] = useState( false );
|
||||
const [ difficultToUse, setDifficultToUse ] = useState( false );
|
||||
const [ slowBuggyOrBroken, setSlowBuggyOrBroken ] = useState( false );
|
||||
const [ other, setOther ] = useState( false );
|
||||
const checkboxes = [
|
||||
{
|
||||
key: 'missing-features',
|
||||
label: __( 'Missing features', 'woocommerce' ),
|
||||
checked: missingFeatures,
|
||||
onChange: setMissingFeatures,
|
||||
},
|
||||
{
|
||||
key: 'missing-plugins',
|
||||
label: __( 'Missing plugins', 'woocommerce' ),
|
||||
checked: missingPlugins,
|
||||
onChange: setMissingPlugins,
|
||||
},
|
||||
{
|
||||
key: 'difficult-to-use',
|
||||
label: __( 'It is difficult to use', 'woocommerce' ),
|
||||
checked: difficultToUse,
|
||||
onChange: setDifficultToUse,
|
||||
},
|
||||
{
|
||||
key: 'slow-buggy-or-broken',
|
||||
label: __( 'It is slow, buggy, or broken', 'woocommerce' ),
|
||||
checked: slowBuggyOrBroken,
|
||||
onChange: setSlowBuggyOrBroken,
|
||||
},
|
||||
{
|
||||
key: 'other',
|
||||
label: __( 'Other (describe below)', 'woocommerce' ),
|
||||
checked: other,
|
||||
onChange: setOther,
|
||||
},
|
||||
];
|
||||
const [ comments, setComments ] = useState( '' );
|
||||
|
||||
const onSendFeedback = () => {
|
||||
const checked = checkboxes
|
||||
.filter( ( checkbox ) => checkbox.checked )
|
||||
.map( ( checkbox ) => checkbox.key );
|
||||
recordScoreCallback( checked, comments );
|
||||
};
|
||||
|
||||
const isSendButtonDisabled =
|
||||
! comments &&
|
||||
! missingFeatures &&
|
||||
! missingPlugins &&
|
||||
! difficultToUse &&
|
||||
! slowBuggyOrBroken &&
|
||||
! other;
|
||||
|
||||
return (
|
||||
<FeedbackModal
|
||||
title={ __(
|
||||
'Thanks for trying out the new product editor!',
|
||||
'woocommerce'
|
||||
) }
|
||||
description={ __(
|
||||
'We’re working on making it better, and your feedback will help improve the experience for thousands of merchants like you.',
|
||||
'woocommerce'
|
||||
) }
|
||||
onSubmit={ onSendFeedback }
|
||||
onModalClose={ onCloseModal }
|
||||
isSubmitButtonDisabled={ isSendButtonDisabled }
|
||||
submitButtonLabel={ __( 'Send feedback', 'woocommerce' ) }
|
||||
cancelButtonLabel={ __( 'Skip', 'woocommerce' ) }
|
||||
>
|
||||
<>
|
||||
<Text
|
||||
variant="subtitle.small"
|
||||
as="p"
|
||||
weight="600"
|
||||
size="14"
|
||||
lineHeight="20px"
|
||||
>
|
||||
{ __(
|
||||
'What made you switch back to the classic product editor?',
|
||||
'woocommerce'
|
||||
) }
|
||||
</Text>
|
||||
<Text
|
||||
weight="400"
|
||||
size="12"
|
||||
as="p"
|
||||
lineHeight="16px"
|
||||
color="#757575"
|
||||
className="woocommerce-product-mvp-feedback-modal__subtitle"
|
||||
>
|
||||
{ __( '(Check all that apply)', 'woocommerce' ) }
|
||||
</Text>
|
||||
<div className="woocommerce-product-mvp-feedback-modal__checkboxes">
|
||||
{ checkboxes.map( ( checkbox, index ) => (
|
||||
<CheckboxControl
|
||||
key={ index }
|
||||
label={ checkbox.label }
|
||||
name={ checkbox.key }
|
||||
checked={ checkbox.checked }
|
||||
onChange={ checkbox.onChange }
|
||||
/>
|
||||
) ) }
|
||||
</div>
|
||||
<div className="woocommerce-product-mvp-feedback-modal__comments">
|
||||
<TextareaControl
|
||||
label={ __( 'Additional comments', 'woocommerce' ) }
|
||||
value={ comments }
|
||||
placeholder={ __(
|
||||
'Optional, but much apprecated. We love reading your feedback!',
|
||||
'woocommerce'
|
||||
) }
|
||||
onChange={ ( value: string ) => setComments( value ) }
|
||||
rows={ 5 }
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
</FeedbackModal>
|
||||
);
|
||||
}
|
||||
|
||||
ProductMVPFeedbackModal.propTypes = {
|
||||
recordScoreCallback: PropTypes.func.isRequired,
|
||||
onCloseModal: PropTypes.func,
|
||||
};
|
||||
|
||||
export { ProductMVPFeedbackModal };
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
|
||||
import { createElement } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ProductMVPFeedbackModal } from '../index';
|
||||
|
||||
const mockRecordScoreCallback = jest.fn();
|
||||
|
||||
describe( 'ProductMVPFeedbackModal', () => {
|
||||
it( 'should close the ProductMVPFeedback modal when skip button pressed', async () => {
|
||||
render(
|
||||
<ProductMVPFeedbackModal
|
||||
recordScoreCallback={ mockRecordScoreCallback }
|
||||
/>
|
||||
);
|
||||
// Wait for the modal to render.
|
||||
await screen.findByRole( 'dialog' );
|
||||
// Press cancel button.
|
||||
fireEvent.click( screen.getByRole( 'button', { name: /Skip/i } ) );
|
||||
expect( screen.queryByRole( 'dialog' ) ).not.toBeInTheDocument();
|
||||
} );
|
||||
it( 'should enable Send button when an option is checked', async () => {
|
||||
render(
|
||||
<ProductMVPFeedbackModal
|
||||
recordScoreCallback={ mockRecordScoreCallback }
|
||||
/>
|
||||
);
|
||||
// Wait for the modal to render.
|
||||
await screen.findByRole( 'dialog' );
|
||||
fireEvent.click( screen.getByRole( 'checkbox', { name: /other/i } ) );
|
||||
fireEvent.click(
|
||||
screen.getByRole( 'button', { name: /Send feedback/i } )
|
||||
);
|
||||
} );
|
||||
it( 'should call the function sent as recordScoreCallback with the checked options', async () => {
|
||||
render(
|
||||
<ProductMVPFeedbackModal
|
||||
recordScoreCallback={ mockRecordScoreCallback }
|
||||
/>
|
||||
);
|
||||
// Wait for the modal to render.
|
||||
await screen.findByRole( 'dialog' );
|
||||
fireEvent.click( screen.getByRole( 'checkbox', { name: /other/i } ) );
|
||||
expect( mockRecordScoreCallback ).toHaveBeenCalledWith(
|
||||
[ 'other' ],
|
||||
''
|
||||
);
|
||||
} );
|
||||
} );
|
|
@ -1,4 +1,6 @@
|
|||
@import 'customer-feedback-simple/customer-feedback-simple.scss';
|
||||
@import 'product-mvp-feedback-modal/product-mvp-feedback-modal.scss';
|
||||
@import 'feedback-modal/feedback-modal.scss';
|
||||
|
||||
.woocommerce-customer-effort-score__selection {
|
||||
margin: 1em 0 1.5em 0;
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Update type definition for ProductForm
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: fix
|
||||
|
||||
Removing unused code from ProductForm data store.
|
|
@ -63,7 +63,7 @@
|
|||
"@types/wordpress__data": "^6.0.0",
|
||||
"@types/wordpress__data-controls": "^2.2.0",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"redux": "^4.1.0",
|
||||
|
|
|
@ -24,6 +24,7 @@ export function getProductFormSuccess( productForm: ProductForm ) {
|
|||
fields: productForm.fields,
|
||||
sections: productForm.sections,
|
||||
subsections: productForm.subsections,
|
||||
tabs: productForm.tabs,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ const reducer: Reducer< ProductFormState, Action > = (
|
|||
fields: [],
|
||||
sections: [],
|
||||
subsections: [],
|
||||
tabs: [],
|
||||
},
|
||||
action
|
||||
) => {
|
||||
|
@ -42,6 +43,7 @@ const reducer: Reducer< ProductFormState, Action > = (
|
|||
fields: action.fields,
|
||||
sections: action.sections,
|
||||
subsections: action.subsections,
|
||||
tabs: action.tabs,
|
||||
};
|
||||
break;
|
||||
case TYPES.GET_PRODUCT_FORM_ERROR:
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { apiFetch, select } from '@wordpress/data-controls';
|
||||
import { controls } from '@wordpress/data';
|
||||
import { apiFetch } from '@wordpress/data-controls';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
@ -15,10 +14,6 @@ import {
|
|||
} from './actions';
|
||||
import { WC_ADMIN_NAMESPACE } from '../constants';
|
||||
import { ProductFormField, ProductForm } from './types';
|
||||
import { STORE_NAME } from './constants';
|
||||
|
||||
const resolveSelect =
|
||||
controls && controls.resolveSelect ? controls.resolveSelect : select;
|
||||
|
||||
export function* getFields() {
|
||||
try {
|
||||
|
@ -34,10 +29,6 @@ export function* getFields() {
|
|||
}
|
||||
}
|
||||
|
||||
export function* getCountry() {
|
||||
yield resolveSelect( STORE_NAME, 'getProductForm' );
|
||||
}
|
||||
|
||||
export function* getProductForm() {
|
||||
try {
|
||||
const url = WC_ADMIN_NAMESPACE + '/product-form';
|
||||
|
|
|
@ -23,10 +23,16 @@ export type ProductFormSection = BaseComponent & {
|
|||
|
||||
export type Subsection = BaseComponent;
|
||||
|
||||
export type Tabs = BaseComponent & {
|
||||
name: string;
|
||||
title: string;
|
||||
};
|
||||
|
||||
export type ProductForm = {
|
||||
fields: ProductFormField[];
|
||||
sections: ProductFormSection[];
|
||||
subsections: Subsection[];
|
||||
tabs: Tabs[];
|
||||
};
|
||||
|
||||
export type ProductFormState = ProductForm & {
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -40,7 +40,7 @@
|
|||
"@types/qs": "^6.9.7",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"d3-time-format": "^2.3.0",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"rimraf": "^3.0.2",
|
||||
|
|
|
@ -14,6 +14,7 @@ module.exports = [
|
|||
'@woocommerce/navigation',
|
||||
'@woocommerce/notices',
|
||||
'@woocommerce/number',
|
||||
'@woocommerce/product-editor',
|
||||
'@woocommerce/tracks',
|
||||
// wc-blocks packages
|
||||
'@woocommerce/blocks-checkout',
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Add @woocommerce/product-editor package to the packages list.
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -30,7 +30,7 @@
|
|||
"devDependencies": {
|
||||
"@babel/core": "^7.17.5",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"rimraf": "^3.0.2",
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
"@wordpress/babel-plugin-import-jsx-pragma": "1.1.3",
|
||||
"@wordpress/babel-preset-default": "3.0.2",
|
||||
"@wordpress/browserslist-config": "^4.1.0",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"eslint-plugin-jest": "23.20.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
|
|
@ -16,7 +16,7 @@ const orderStatus = [
|
|||
[ 'Processing', 'wc-processing' ],
|
||||
[ 'On hold', 'wc-on-hold' ],
|
||||
[ 'Completed', 'wc-completed' ],
|
||||
[ 'Canceled', 'wc-cancelled' ],
|
||||
[ 'Cancelled', 'wc-cancelled' ],
|
||||
[ 'Refunded', 'wc-refunded' ],
|
||||
[ 'Failed', 'wc-failed' ],
|
||||
];
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
"@wordpress/babel-plugin-import-jsx-pragma": "1.1.3",
|
||||
"@wordpress/babel-preset-default": "3.0.2",
|
||||
"@wordpress/browserslist-config": "^4.1.0",
|
||||
"eslint": "^8.1.0",
|
||||
"eslint": "^8.32.0",
|
||||
"eslint-plugin-jest": "23.20.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -47,7 +47,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.5",
|
||||
"eslint": "^8.25.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"rimraf": "^3.0.2",
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -65,7 +65,7 @@
|
|||
"@wordpress/browserslist-config": "^4.1.1",
|
||||
"concurrently": "^7.0.0",
|
||||
"css-loader": "^3.6.0",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"postcss-loader": "^3.0.0",
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -45,7 +45,7 @@
|
|||
"@types/qs": "^6.9.7",
|
||||
"@types/react": "^17.0.2",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"rimraf": "^3.0.2",
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
"@babel/core": "7.12.9",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"chalk": "^4.1.2",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"glob": "^7.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"mkdirp": "^1.0.4"
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
"devDependencies": {
|
||||
"@babel/core": "^7.17.5",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"rimraf": "^3.0.2",
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
"devDependencies": {
|
||||
"@babel/core": "^7.17.5",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"rimraf": "^3.0.2",
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -63,7 +63,7 @@
|
|||
"@types/jest": "^27.4.1",
|
||||
"@types/qs": "^6.9.7",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"rimraf": "^3.0.2",
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
"@types/wordpress__data": "^6.0.0",
|
||||
"@types/wordpress__notices": "^3.5.0",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"redux": "^4.2.0",
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -50,7 +50,7 @@
|
|||
"@types/jest": "^27.4.1",
|
||||
"@types/lodash": "^4.14.184",
|
||||
"@woocommerce/eslint-plugin": "workspace:*",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"rimraf": "^3.0.2",
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -48,7 +48,7 @@
|
|||
"@wordpress/browserslist-config": "^4.1.1",
|
||||
"@types/wordpress__components": "^19.10.1",
|
||||
"css-loader": "^3.6.0",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint": "^8.32.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-cli": "^27.5.1",
|
||||
"postcss-loader": "^3.0.0",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
package-lock=false
|
|
@ -0,0 +1,11 @@
|
|||
# Product Editor
|
||||
|
||||
A collection of WooCommerce Admin product editor components and utilities.
|
||||
|
||||
## Installation
|
||||
|
||||
Install the module
|
||||
|
||||
```bash
|
||||
pnpm install @woocommerce/product-editor --save
|
||||
```
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Adding initial build/package files for brand new package: @woocommere/product-editor.
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update eslint to 8.32.0 across the monorepo.
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"name": "woocommerce/product-editor",
|
||||
"description": "WooCommerce Admin product editor component library",
|
||||
"type": "library",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"minimum-stability": "dev",
|
||||
"require-dev": {
|
||||
"automattic/jetpack-changelogger": "3.3.0"
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "7.2"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"changelogger": {
|
||||
"formatter": {
|
||||
"filename": "../../../tools/changelogger/class-package-formatter.php"
|
||||
},
|
||||
"types": {
|
||||
"fix": "Fixes an existing bug",
|
||||
"add": "Adds functionality",
|
||||
"update": "Update existing functionality",
|
||||
"dev": "Development related task",
|
||||
"tweak": "A minor adjustment to the codebase",
|
||||
"performance": "Address performance issues",
|
||||
"enhancement": "Improve existing functionality"
|
||||
},
|
||||
"changelog": "CHANGELOG.md"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,483 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "36c31d66fa022c27e5bb2bf5db177a6b",
|
||||
"packages": [],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "automattic/jetpack-changelogger",
|
||||
"version": "v3.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Automattic/jetpack-changelogger.git",
|
||||
"reference": "8f63c829b8d1b0d7b1d5de93510d78523ed18959"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Automattic/jetpack-changelogger/zipball/8f63c829b8d1b0d7b1d5de93510d78523ed18959",
|
||||
"reference": "8f63c829b8d1b0d7b1d5de93510d78523ed18959",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.6",
|
||||
"symfony/console": "^3.4 || ^5.2 || ^6.0",
|
||||
"symfony/process": "^3.4 || ^5.2 || ^6.0",
|
||||
"wikimedia/at-ease": "^1.2 || ^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"wikimedia/testing-access-wrapper": "^1.0 || ^2.0",
|
||||
"yoast/phpunit-polyfills": "1.0.4"
|
||||
},
|
||||
"bin": [
|
||||
"bin/changelogger"
|
||||
],
|
||||
"type": "project",
|
||||
"extra": {
|
||||
"autotagger": true,
|
||||
"branch-alias": {
|
||||
"dev-trunk": "3.3.x-dev"
|
||||
},
|
||||
"mirror-repo": "Automattic/jetpack-changelogger",
|
||||
"version-constants": {
|
||||
"::VERSION": "src/Application.php"
|
||||
},
|
||||
"changelogger": {
|
||||
"link-template": "https://github.com/Automattic/jetpack-changelogger/compare/${old}...${new}"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Automattic\\Jetpack\\Changelog\\": "lib",
|
||||
"Automattic\\Jetpack\\Changelogger\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"GPL-2.0-or-later"
|
||||
],
|
||||
"description": "Jetpack Changelogger tool. Allows for managing changelogs by dropping change files into a changelog directory with each PR.",
|
||||
"support": {
|
||||
"source": "https://github.com/Automattic/jetpack-changelogger/tree/v3.3.0"
|
||||
},
|
||||
"time": "2022-12-26T13:49:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "1.1.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/log.git",
|
||||
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
|
||||
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Log\\": "Psr/Log/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for logging libraries",
|
||||
"homepage": "https://github.com/php-fig/log",
|
||||
"keywords": [
|
||||
"log",
|
||||
"psr",
|
||||
"psr-3"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/log/tree/1.1.4"
|
||||
},
|
||||
"time": "2021-05-03T11:20:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "3.4.x-dev",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "a10b1da6fc93080c180bba7219b5ff5b7518fe81"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/a10b1da6fc93080c180bba7219b5ff5b7518fe81",
|
||||
"reference": "a10b1da6fc93080c180bba7219b5ff5b7518fe81",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.5.9|>=7.0.8",
|
||||
"symfony/debug": "~2.8|~3.0|~4.0",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/dependency-injection": "<3.4",
|
||||
"symfony/process": "<3.3"
|
||||
},
|
||||
"provide": {
|
||||
"psr/log-implementation": "1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/config": "~3.3|~4.0",
|
||||
"symfony/dependency-injection": "~3.4|~4.0",
|
||||
"symfony/event-dispatcher": "~2.8|~3.0|~4.0",
|
||||
"symfony/lock": "~3.4|~4.0",
|
||||
"symfony/process": "~3.3|~4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "For using the console logger",
|
||||
"symfony/event-dispatcher": "",
|
||||
"symfony/lock": "",
|
||||
"symfony/process": ""
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Console\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/3.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-10-24T10:57:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/debug",
|
||||
"version": "4.4.x-dev",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/debug.git",
|
||||
"reference": "1a692492190773c5310bc7877cb590c04c2f05be"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/debug/zipball/1a692492190773c5310bc7877cb590c04c2f05be",
|
||||
"reference": "1a692492190773c5310bc7877cb590c04c2f05be",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1.3",
|
||||
"psr/log": "^1|^2|^3"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/http-kernel": "<3.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/http-kernel": "^3.4|^4.0|^5.0"
|
||||
},
|
||||
"default-branch": true,
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Debug\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Provides tools to ease debugging PHP code",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/debug/tree/v4.4.44"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"abandoned": "symfony/error-handler",
|
||||
"time": "2022-07-28T16:29:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "dev-main",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"provide": {
|
||||
"ext-mbstring": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "For best performance"
|
||||
},
|
||||
"default-branch": true,
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.27-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for the Mbstring extension",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"mbstring",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "3.4.x-dev",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "b8648cf1d5af12a44a51d07ef9bf980921f15fca"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/b8648cf1d5af12a44a51d07ef9bf980921f15fca",
|
||||
"reference": "b8648cf1d5af12a44a51d07ef9bf980921f15fca",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.5.9|>=7.0.8"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Process\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Process Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/process/tree/3.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-10-24T10:57:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "wikimedia/at-ease",
|
||||
"version": "v2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/wikimedia/at-ease.git",
|
||||
"reference": "013ac61929797839c80a111a3f1a4710d8248e7a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/wikimedia/at-ease/zipball/013ac61929797839c80a111a3f1a4710d8248e7a",
|
||||
"reference": "013ac61929797839c80a111a3f1a4710d8248e7a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.6.99"
|
||||
},
|
||||
"require-dev": {
|
||||
"jakub-onderka/php-console-highlighter": "0.3.2",
|
||||
"jakub-onderka/php-parallel-lint": "1.0.0",
|
||||
"mediawiki/mediawiki-codesniffer": "22.0.0",
|
||||
"mediawiki/minus-x": "0.3.1",
|
||||
"ockcyp/covers-validator": "0.5.1 || 0.6.1",
|
||||
"phpunit/phpunit": "4.8.36 || ^6.5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/Wikimedia/Functions.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Wikimedia\\AtEase\\": "src/Wikimedia/AtEase/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"GPL-2.0-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Tim Starling",
|
||||
"email": "tstarling@wikimedia.org"
|
||||
},
|
||||
{
|
||||
"name": "MediaWiki developers",
|
||||
"email": "wikitech-l@lists.wikimedia.org"
|
||||
}
|
||||
],
|
||||
"description": "Safe replacement to @ for suppressing warnings.",
|
||||
"homepage": "https://www.mediawiki.org/wiki/at-ease",
|
||||
"support": {
|
||||
"source": "https://github.com/wikimedia/at-ease/tree/master"
|
||||
},
|
||||
"time": "2018-10-10T15:39:06+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": [],
|
||||
"platform-overrides": {
|
||||
"php": "7.2"
|
||||
},
|
||||
"plugin-api-version": "2.3.0"
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue