diff --git a/.changeset/bright-horses-peel.md b/.changeset/bright-horses-peel.md
deleted file mode 100644
index ac95e6b3a3c..00000000000
--- a/.changeset/bright-horses-peel.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": minor
----
-
-fixes failing test: product visible in shop SALEOR_2506
diff --git a/.changeset/brown-readers-hang.md b/.changeset/brown-readers-hang.md
deleted file mode 100644
index 5c652277efd..00000000000
--- a/.changeset/brown-readers-hang.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Fix sending attibutes on variant create/update in datagrid on product details page
diff --git a/.changeset/brown-years-wash.md b/.changeset/brown-years-wash.md
deleted file mode 100644
index cf586db92ce..00000000000
--- a/.changeset/brown-years-wash.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Fix sending too many request on line item update
diff --git a/.changeset/curly-rules-sin.md b/.changeset/curly-rules-sin.md
deleted file mode 100644
index e12d7f14558..00000000000
--- a/.changeset/curly-rules-sin.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Updates data-test-id for variant name input on variant page
diff --git a/.changeset/curly-zoos-do.md b/.changeset/curly-zoos-do.md
deleted file mode 100644
index c428b5117d4..00000000000
--- a/.changeset/curly-zoos-do.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Add 'feature' as extempt label for stalebot
diff --git a/.changeset/curvy-bulldogs-drum.md b/.changeset/curvy-bulldogs-drum.md
deleted file mode 100644
index 1312450159b..00000000000
--- a/.changeset/curvy-bulldogs-drum.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Use changes files to detect if changeset file is present
diff --git a/.changeset/dirty-dragons-film.md b/.changeset/dirty-dragons-film.md
deleted file mode 100644
index f234946f4af..00000000000
--- a/.changeset/dirty-dragons-film.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Fix pasting data into page create type picker
diff --git a/.changeset/empty-falcons-boil.md b/.changeset/empty-falcons-boil.md
new file mode 100644
index 00000000000..726fea08faa
--- /dev/null
+++ b/.changeset/empty-falcons-boil.md
@@ -0,0 +1,5 @@
+---
+"saleor-dashboard": minor
+---
+
+Introduce intial component for catalog discounts
diff --git a/.changeset/fast-masks-deny.md b/.changeset/fast-masks-deny.md
deleted file mode 100644
index b7285eeec74..00000000000
--- a/.changeset/fast-masks-deny.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Fix input placeholder text in the tax classes section
diff --git a/.changeset/fast-tips-sparkle.md b/.changeset/fast-tips-sparkle.md
new file mode 100644
index 00000000000..b41afe28290
--- /dev/null
+++ b/.changeset/fast-tips-sparkle.md
@@ -0,0 +1,5 @@
+---
+"saleor-dashboard": patch
+---
+
+Add exemption labels to ignore stale issues
diff --git a/.changeset/few-drinks-compete.md b/.changeset/few-drinks-compete.md
deleted file mode 100644
index e67def19a06..00000000000
--- a/.changeset/few-drinks-compete.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Remove flaky product update page test
diff --git a/.changeset/fifty-peas-cheer.md b/.changeset/fifty-peas-cheer.md
deleted file mode 100644
index a1376cb6304..00000000000
--- a/.changeset/fifty-peas-cheer.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Fix form blink in customer edition for orders
diff --git a/.changeset/fifty-weeks-teach.md b/.changeset/fifty-weeks-teach.md
new file mode 100644
index 00000000000..bfdea5dd627
--- /dev/null
+++ b/.changeset/fifty-weeks-teach.md
@@ -0,0 +1,5 @@
+---
+"saleor-dashboard": patch
+---
+
+Fix duplicates when assigning reference attributes & eligible entities for vouchers and products
diff --git a/.changeset/five-eggs-brake.md b/.changeset/five-eggs-brake.md
deleted file mode 100644
index a845151cc84..00000000000
--- a/.changeset/five-eggs-brake.md
+++ /dev/null
@@ -1,2 +0,0 @@
----
----
diff --git a/.changeset/fluffy-buckets-tell.md b/.changeset/fluffy-buckets-tell.md
deleted file mode 100644
index e9806120dab..00000000000
--- a/.changeset/fluffy-buckets-tell.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Fix GHA worflow that runs chromatic on main branch
diff --git a/.changeset/proud-shirts-hammer.md b/.changeset/four-news-glow.md
similarity index 52%
rename from .changeset/proud-shirts-hammer.md
rename to .changeset/four-news-glow.md
index 8db023518e0..215242ecc63 100644
--- a/.changeset/proud-shirts-hammer.md
+++ b/.changeset/four-news-glow.md
@@ -2,4 +2,4 @@
"saleor-dashboard": minor
---
-Removed unused get info request
+add env var LOCALE_CODE
diff --git a/.changeset/fresh-forks-battle.md b/.changeset/fresh-forks-battle.md
deleted file mode 100644
index fe688d303e1..00000000000
--- a/.changeset/fresh-forks-battle.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Fix saving previously removed country exceptions
diff --git a/.changeset/honest-otters-bow.md b/.changeset/honest-otters-bow.md
deleted file mode 100644
index cc923742199..00000000000
--- a/.changeset/honest-otters-bow.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": minor
----
-
-Use macaw-ui alias to 1.0.0 versions
diff --git a/.changeset/itchy-pumas-sip.md b/.changeset/itchy-pumas-sip.md
new file mode 100644
index 00000000000..0e7bd76fe75
--- /dev/null
+++ b/.changeset/itchy-pumas-sip.md
@@ -0,0 +1,5 @@
+---
+"saleor-dashboard": patch
+---
+
+Use stale action instead of stalebot
diff --git a/.changeset/lovely-walls-shake.md b/.changeset/lovely-walls-shake.md
deleted file mode 100644
index 337a36f01b3..00000000000
--- a/.changeset/lovely-walls-shake.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": minor
----
-
-Introduce voucher codes datagrid
diff --git a/.changeset/metal-cows-yawn.md b/.changeset/metal-cows-yawn.md
deleted file mode 100644
index 34595fcd04d..00000000000
--- a/.changeset/metal-cows-yawn.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": minor
----
-
-Migrated "TC: SALEOR_26 Create basic info variant - via edit variant page" to playwright
diff --git a/.changeset/moody-countries-dream.md b/.changeset/moody-countries-dream.md
new file mode 100644
index 00000000000..2489d114302
--- /dev/null
+++ b/.changeset/moody-countries-dream.md
@@ -0,0 +1,5 @@
+---
+"saleor-dashboard": patch
+---
+
+Fix drag and drop in navigation configuration
diff --git a/.changeset/ninety-pillows-sing.md b/.changeset/ninety-pillows-sing.md
deleted file mode 100644
index 4854b907514..00000000000
--- a/.changeset/ninety-pillows-sing.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Fix error related to can not read property of undefined in metadata and reading search page info
diff --git a/.changeset/olive-walls-joke.md b/.changeset/olive-walls-joke.md
deleted file mode 100644
index 24ad1bbeee3..00000000000
--- a/.changeset/olive-walls-joke.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": minor
----
-
-Home page critical test migration to playwright
diff --git a/.changeset/perfect-ligers-hope.md b/.changeset/perfect-ligers-hope.md
deleted file mode 100644
index cfc7b1deeda..00000000000
--- a/.changeset/perfect-ligers-hope.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": minor
----
-
-migrated navigation tests to playwright
diff --git a/.changeset/tricky-needles-brush.md b/.changeset/rude-falcons-peel.md
similarity index 53%
rename from .changeset/tricky-needles-brush.md
rename to .changeset/rude-falcons-peel.md
index 7bdb5ada186..bea7b15d904 100644
--- a/.changeset/tricky-needles-brush.md
+++ b/.changeset/rude-falcons-peel.md
@@ -2,4 +2,4 @@
"saleor-dashboard": patch
---
-Fix language switcher
+Improve channel delete dialogs
diff --git a/.changeset/short-deers-learn.md b/.changeset/short-deers-learn.md
deleted file mode 100644
index 9aee0d9e113..00000000000
--- a/.changeset/short-deers-learn.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": minor
----
-
-Migrated warehouse creat test to playwright
diff --git a/.changeset/six-deers-exist.md b/.changeset/six-deers-exist.md
new file mode 100644
index 00000000000..079707b1bd1
--- /dev/null
+++ b/.changeset/six-deers-exist.md
@@ -0,0 +1,5 @@
+---
+"saleor-dashboard": patch
+---
+
+Add missing units for attributes
diff --git a/.changeset/soft-hornets-relax.md b/.changeset/soft-hornets-relax.md
deleted file mode 100644
index f9d0b5a439a..00000000000
--- a/.changeset/soft-hornets-relax.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Change e2e default browser to electron
diff --git a/.changeset/spotty-files-dance.md b/.changeset/spotty-files-dance.md
deleted file mode 100644
index ab0aaf670c7..00000000000
--- a/.changeset/spotty-files-dance.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Fix assigning products to collection
diff --git a/.changeset/stale-shirts-lie.md b/.changeset/stale-shirts-lie.md
deleted file mode 100644
index 52811fa3dce..00000000000
--- a/.changeset/stale-shirts-lie.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Fix pasting float number into datagrid
diff --git a/.changeset/ten-wasps-raise.md b/.changeset/ten-wasps-raise.md
deleted file mode 100644
index bd631665eee..00000000000
--- a/.changeset/ten-wasps-raise.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": minor
----
-
-Migrated Create basic order test to playwright
diff --git a/.changeset/tidy-planes-wash.md b/.changeset/tidy-planes-wash.md
deleted file mode 100644
index d48b9b48d31..00000000000
--- a/.changeset/tidy-planes-wash.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Update selector for orders tests in cypress
diff --git a/.changeset/tiny-pumas-leave.md b/.changeset/tiny-pumas-leave.md
new file mode 100644
index 00000000000..c14d9bd29ec
--- /dev/null
+++ b/.changeset/tiny-pumas-leave.md
@@ -0,0 +1,5 @@
+---
+"saleor-dashboard": patch
+---
+
+Create instance when it has been not created yet
diff --git a/.changeset/tricky-feet-type.md b/.changeset/tricky-feet-type.md
deleted file mode 100644
index 311cbc371b7..00000000000
--- a/.changeset/tricky-feet-type.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Fix clear datagrid added variants after submit
diff --git a/.changeset/twenty-shrimps-breathe.md b/.changeset/twenty-shrimps-breathe.md
deleted file mode 100644
index b4b062c0911..00000000000
--- a/.changeset/twenty-shrimps-breathe.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": minor
----
-
-Migrated shipping methods tests to playwright
diff --git a/.changeset/twenty-snails-retire.md b/.changeset/twenty-snails-retire.md
deleted file mode 100644
index cd3f2947066..00000000000
--- a/.changeset/twenty-snails-retire.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Fix copy on back button when failure during apo installation
diff --git a/.changeset/two-bears-happen.md b/.changeset/two-bears-happen.md
new file mode 100644
index 00000000000..26badfcd947
--- /dev/null
+++ b/.changeset/two-bears-happen.md
@@ -0,0 +1,5 @@
+---
+"saleor-dashboard": patch
+---
+
+Display warning for long branch names
diff --git a/.changeset/wicked-planes-lick.md b/.changeset/wicked-planes-lick.md
new file mode 100644
index 00000000000..7a35b76449b
--- /dev/null
+++ b/.changeset/wicked-planes-lick.md
@@ -0,0 +1,5 @@
+---
+"saleor-dashboard": patch
+---
+
+Prevent empty subscription query for new webhooks
diff --git a/.changeset/young-spoons-count.md b/.changeset/young-spoons-count.md
deleted file mode 100644
index d5ffc35a392..00000000000
--- a/.changeset/young-spoons-count.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"saleor-dashboard": patch
----
-
-Fix disappearing labels of reference attributes
diff --git a/.env.template b/.env.template
index e9ef865c22d..184b914d84c 100644
--- a/.env.template
+++ b/.env.template
@@ -1,3 +1,4 @@
API_URI=https://demo.saleor.io/graphql/
APP_MOUNT_URI=/
-APPS_MARKETPLACE_API_URI=https://apps.saleor.io/api/v2/saleor-apps
\ No newline at end of file
+APPS_MARKETPLACE_API_URI=https://apps.saleor.io/api/v2/saleor-apps
+LOCALE_CODE="EN"
\ No newline at end of file
diff --git a/.featureFlags/generated.tsx b/.featureFlags/generated.tsx
index 119f2612b77..41125a51af5 100644
--- a/.featureFlags/generated.tsx
+++ b/.featureFlags/generated.tsx
@@ -1,13 +1,11 @@
// @ts-nocheck
-import O81816 from "./images/filters.png"
+import D31948 from "./images/filters.png"
-const product_filters = () => (<>
+const product_filters = () => (<>
Experience the new look and enhanced abilities of new fitering mechanism.
Easily combine any criteria you want, and quickly browse their values.
>)
-const voucher_codes = () => (<>Allow to generat multple codes per single voucher
->)
export const AVAILABLE_FLAGS = [{
name: "product_filters",
@@ -18,13 +16,4 @@ export const AVAILABLE_FLAGS = [{
enabled: true,
payload: "default",
}
-},{
- name: "voucher_codes",
- displayName: "Voucher codes",
- component: voucher_codes,
- visible: false,
- content: {
- enabled: false,
- payload: "default",
- }
}] as const;
diff --git a/.featureFlags/voucher-codes.md b/.featureFlags/voucher-codes.md
deleted file mode 100644
index 69938b52504..00000000000
--- a/.featureFlags/voucher-codes.md
+++ /dev/null
@@ -1,9 +0,0 @@
----
-name: voucher_codes
-displayName: Voucher codes
-enabled: false
-payload: "default"
-visible: false
----
-
-Allow to generat multple codes per single voucher
diff --git a/.github/ISSUE_TEMPLATE/enhancement_request.yml b/.github/ISSUE_TEMPLATE/enhancement_request.yml
new file mode 100644
index 00000000000..395a2f58749
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/enhancement_request.yml
@@ -0,0 +1,25 @@
+name: Enhancement request
+description: "Small scope enhancements that do not alter the behavior of the product: Spelling, text adjustments, translations, documentation, small visual design corrections, icon adjustments, etc."
+title: "[Enhancement]: "
+labels: ["enhancement", "backlog"]
+
+body:
+ - type: textarea
+ id: description
+ attributes:
+ label: Description of the enhancement
+ description: Describe what you want to improve, attach the reasoning.
+ placeholder: |
+ Example: I want to adjust the border colors as well as inner padding to be consistent with the other views
+ validations:
+ required: true
+ - type: textarea
+ id: additional-info
+ attributes:
+ label: Additional information
+ description: Attach some additional references, links, some context
+ placeholder: |
+ Example: Currently we use old color values, we need to update it in the future
+ validations:
+ required: false
+
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
index 2ef3ea1f5f5..ab12beff379 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -1,5 +1,5 @@
name: Feature request
-description: Publish a new feature request
+description: "Broader scope requests, a new implementation that is not yet present in the project."
title: "[Feature]: "
labels: ["feature", "backlog"]
diff --git a/.github/actions/cli-login/action.yml b/.github/actions/cli-login/action.yml
new file mode 100644
index 00000000000..95d8243ad50
--- /dev/null
+++ b/.github/actions/cli-login/action.yml
@@ -0,0 +1,15 @@
+name: Saleor CLI login
+description: Saleor CLI login
+inputs:
+ token:
+ description: "Cloud accces token"
+ required: true
+runs:
+ using: "composite"
+ steps:
+ - name: Write config file
+ shell: bash
+ id: write-config-file
+ env:
+ ACCESS_TOKEN: ${{ inputs.token }}
+ run: jq --null-input --arg token "Token $ACCESS_TOKEN" '{"token":$token,"telemetry":"false","organization_slug":"saleor","organization_name":"Saleor"}' > ~/.config/saleor.json
diff --git a/.github/stale.yml b/.github/stale.yml
deleted file mode 100644
index 0927b9e0099..00000000000
--- a/.github/stale.yml
+++ /dev/null
@@ -1,63 +0,0 @@
-# Configuration for probot-stale - https://github.com/probot/stale
-
-# Number of days of inactivity before an Issue or Pull Request becomes stale
-daysUntilStale: 60
-
-# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
-# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
-daysUntilClose: 7
-
-# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
-onlyLabels: []
-
-# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
-exemptLabels:
- - epic
- - triage
- - bug
- - blocker
- - backlog
- - feature
-
-# Set to true to ignore issues in a project (defaults to false)
-exemptProjects: false
-
-# Set to true to ignore issues in a milestone (defaults to false)
-exemptMilestones: false
-
-# Set to true to ignore issues with an assignee (defaults to false)
-exemptAssignees: false
-
-# Label to use when marking as stale
-staleLabel: stale
-
-# Comment to post when marking as stale. Set to `false` to disable
-markComment: >
- This issue has been automatically marked as stale because it has not had
- recent activity. It will be closed if no further activity occurs. Thank you
- for your contributions.
-
-# Comment to post when removing the stale label.
-# unmarkComment: >
-# Your comment here.
-
-# Comment to post when closing a stale Issue or Pull Request.
-# closeComment: >
-# Your comment here.
-
-# Limit the number of actions per hour, from 1-30. Default is 30
-limitPerRun: 30
-# Limit to only `issues` or `pulls`
-# only: issues
-
-# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
-# pulls:
-# daysUntilStale: 30
-# markComment: >
-# This pull request has been automatically marked as stale because it has not had
-# recent activity. It will be closed if no further activity occurs. Thank you
-# for your contributions.
-
-# issues:
-# exemptLabels:
-# - confirmed
diff --git a/.github/workflows/changesets-status.yml b/.github/workflows/changesets-status.yml
index 2a45a5b870d..1687ab3c9e9 100644
--- a/.github/workflows/changesets-status.yml
+++ b/.github/workflows/changesets-status.yml
@@ -6,16 +6,16 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout Repo
- uses: actions/checkout@v3
- - name: Extract branch name
- id: extract_branch
- run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT
+ uses: actions/checkout@v4
+ with:
+ sparse-checkout: ./.changeset
+
- name: Changeset file lookup
env:
GH_TOKEN: ${{ github.token }}
- PR_BRANCH: ${{ steps.extract_branch.outputs.branch }}
+ PR_ID: ${{ github.event.number }}
run: |
- files=$(gh pr diff "$PR_BRANCH" --name-only)
+ files=$(gh pr diff "$PR_ID" --name-only)
if [[ $files =~ \.changeset\/.*.md ]]; then
echo "Changesets found!"
else
diff --git a/.github/workflows/pr-automation.yml b/.github/workflows/pr-automation.yml
new file mode 100644
index 00000000000..6571a43f54d
--- /dev/null
+++ b/.github/workflows/pr-automation.yml
@@ -0,0 +1,341 @@
+name: PR automation
+
+on: [pull_request]
+
+concurrency:
+ group: ${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ prepare_variables:
+ runs-on: ubuntu-22.04
+ if: github.event.pull_request.head.repo.full_name == 'saleor/saleor-dashboard'
+ outputs:
+ POOL_NAME: ${{ steps.generate.outputs.POOL_NAME }}
+ POOL_INSTANCE: ${{ steps.generate.outputs.POOL_INSTANCE }}
+ BASE_URL: ${{ steps.generate.outputs.BASE_URL }}
+ API_URI: ${{ steps.generate.outputs.API_URI }}
+ BACKUP_ID: ${{ steps.backup.outputs.BACKUP_ID }}
+ BACKUP_VER: ${{ steps.backup.outputs.BACKUP_VER }}
+ BACKUP_NAME: ${{ steps.backup.outputs.BACKUP_NAME }}
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ sparse-checkout: ./.github/actions
+
+ - name: Inject slug/short variables
+ uses: rlespinasse/github-slug-action@102b1a064a9b145e56556e22b18b19c624538d94
+
+ - name: Generate
+ id: generate
+ env:
+ PREFIX: pr-
+ run: |
+ echo "BASE_URL=${PREFIX}${GITHUB_HEAD_REF_SLUG_URL}.dashboard.saleor.rocks" >> $GITHUB_OUTPUT
+ echo "API_URI=https://${PREFIX}${GITHUB_HEAD_REF_SLUG_URL}.staging.saleor.cloud/graphql/" >> $GITHUB_OUTPUT
+ echo "POOL_NAME=${PREFIX}${GITHUB_HEAD_REF_SLUG_URL}" >> $GITHUB_OUTPUT
+ echo "POOL_INSTANCE=https://${PREFIX}${GITHUB_HEAD_REF_SLUG_URL}.staging.saleor.cloud" >> $GITHUB_OUTPUT
+
+ - name: Saleor login
+ uses: ./.github/actions/cli-login
+ with:
+ token: ${{ secrets.STAGING_TOKEN }}
+
+ - name: Obtain backup id
+ id: backup
+ env:
+ SALEOR_CLI_ENV: staging
+ BACKUP_NAME: snapshot-automation-tests
+ run: |
+ BACKUPS=$(npx saleor backup list --name=snapshot-automation-tests --latest --json)
+ BACKUP_ID=$(echo "$BACKUPS" | jq -r '.[0].key')
+ BACKUP_VER=$(echo "$BACKUPS" | jq -r '.[0].saleor_version')
+ BACKUP_NAME=$(echo "$BACKUPS" | jq -r '.[0].name')
+
+ echo "BACKUP_ID=$BACKUP_ID" >> $GITHUB_OUTPUT
+ echo "BACKUP_VER=$BACKUP_VER" >> $GITHUB_OUTPUT
+ echo "BACKUP_NAME=$BACKUP_NAME" >> $GITHUB_OUTPUT
+
+ - name: Print annotations
+ env:
+ BASE_URL: ${{ steps.generate.outputs.BASE_URL }}
+ API_URI: ${{ steps.generate.outputs.API_URI }}
+ POOL_NAME: ${{ steps.generate.outputs.POOL_NAME }}
+ POOL_INSTANCE: ${{ steps.generate.outputs.POOL_INSTANCE }}
+ BACKUP_ID: ${{ steps.backup.outputs.BACKUP_ID }}
+ BACKUP_VER: ${{ steps.backup.outputs.BACKUP_VER }}
+ BACKUP_NAME: ${{ steps.backup.outputs.BACKUP_NAME }}
+ run: |
+ echo "::notice title=BASE_URL::${BASE_URL}"
+ echo "::notice title=API_URI::${API_URI}"
+ echo "::notice title=POOL_NAME::${POOL_NAME}"
+ echo "::notice title=POOL_INSTANCE::${POOL_INSTANCE}"
+ echo "::notice title=SNAPSHOT::backup_id=${BACKUP_ID}, version=${BACKUP_VER}, name=${BACKUP_NAME}"
+
+ prepare_instance:
+ runs-on: ubuntu-22.04
+ needs: prepare_variables
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ sparse-checkout: ./.github/actions
+
+ - name: Inject slug/short variables
+ uses: rlespinasse/github-slug-action@102b1a064a9b145e56556e22b18b19c624538d94
+
+ - name: Saleor login
+ uses: ./.github/actions/cli-login
+ with:
+ token: ${{ secrets.STAGING_TOKEN }}
+
+ - name: Instance check
+ id: instance_check
+ env:
+ SALEOR_CLI_ENV: staging
+ INSTANCE_NAME: ${{ needs.prepare_variables.outputs.POOL_NAME }}
+ run: |
+ INSTANCE_KEY=$(npx saleor env show "$INSTANCE_NAME" --json | jq .key)
+ echo "INSTANCE_KEY=$INSTANCE_KEY" >> $GITHUB_OUTPUT
+
+ - name: Reload snapshot
+ if: ${{ steps.instance_check.outputs.INSTANCE_KEY }}
+ env:
+ SALEOR_CLI_ENV: staging
+ BACKUP_ID: ${{ needs.prepare_variables.outputs.BACKUP_ID }}
+ INSTANCE_NAME: ${{ needs.prepare_variables.outputs.POOL_NAME }}
+ run: |
+ npx saleor backup restore "$BACKUP_ID" \
+ --environment="$INSTANCE_NAME" \
+ --skip-webhooks-update
+
+ - name: Create new instance
+ if: ${{ !steps.instance_check.outputs.INSTANCE_KEY }}
+ env:
+ SALEOR_CLI_ENV: staging
+ BACKUP_ID: ${{ needs.prepare_variables.outputs.BACKUP_ID }}
+ INSTANCE_NAME: ${{ needs.prepare_variables.outputs.POOL_NAME }}
+ run: |
+ npx saleor env create "$INSTANCE_NAME" \
+ --project=project-for-pr-testing \
+ --database=snapshot \
+ --restore-from="$BACKUP_ID" \
+ --saleor=saleor-master-staging \
+ --domain="$INSTANCE_NAME" \
+ --skip-restrict \
+ --skip-webhooks-update
+
+ deploy_dashboard:
+ if: github.event.pull_request.head.repo.full_name == 'saleor/saleor-dashboard'
+ runs-on: ubuntu-22.04
+ needs: prepare_variables
+ permissions:
+ deployments: write
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node
+ uses: actions/setup-node@v3
+ with:
+ node-version-file: ".nvmrc"
+
+ - name: Start deployment
+ uses: bobheadxi/deployments@88ce5600046c82542f8246ac287d0a53c461bca3
+ id: deployment
+ with:
+ step: start
+ token: ${{ secrets.GITHUB_TOKEN }}
+ env: ${{ needs.prepare_variables.outputs.POOL_NAME }}
+ ref: ${{ github.head_ref }}
+
+ - name: Cache node modules
+ uses: actions/cache@v3
+ env:
+ cache-name: cache-node-modules
+ with:
+ path: ~/.npm
+ key: ${{ runner.os }}-qa-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-qa-${{ env.cache-name }}-
+ ${{ runner.os }}-qa-
+ ${{ runner.os }}-
+
+ - name: Install deps
+ run: npm ci
+
+ - name: Build dashboard
+ env:
+ API_URI: ${{ needs.prepare_variables.outputs.API_URI }}
+ APPS_MARKETPLACE_API_URI: "https://apps.staging.saleor.io/api/v2/saleor-apps"
+ APP_MOUNT_URI: /
+ STATIC_URL: /
+ IS_CLOUD_INSTANCE: true
+ run: npm run build
+
+ - name: Configure AWS credentials
+ uses: aws-actions/configure-aws-credentials@v3
+ with:
+ aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
+ aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+ aws-region: ${{ secrets.AWS_DEFAULT_REGION }}
+
+ - name: Deploy to S3
+ env:
+ AWS_TEST_DEPLOYMENT_BUCKET: ${{ secrets.AWS_TEST_DEPLOYMENT_BUCKET }}
+ BASE_URL: ${{ needs.prepare_variables.outputs.BASE_URL }}
+ run: aws s3 sync ./build/dashboard "s3://${AWS_TEST_DEPLOYMENT_BUCKET}/${BASE_URL}"
+
+ - name: Invalidate cache
+ env:
+ AWS_TEST_CF_DIST_ID: ${{ secrets.AWS_TEST_CF_DIST_ID }}
+ BASE_URL: ${{ needs.prepare_variables.outputs.BASE_URL }}
+ run: aws cloudfront create-invalidation --distribution-id "$AWS_TEST_CF_DIST_ID" --paths "/${BASE_URL}/*"
+
+ - name: Update deployment status
+ uses: bobheadxi/deployments@88ce5600046c82542f8246ac287d0a53c461bca3
+ if: always()
+ with:
+ step: finish
+ token: ${{ secrets.GITHUB_TOKEN }}
+ status: ${{ job.status }}
+ env_url: https://${{ needs.prepare_variables.outputs.BASE_URL }}/
+ deployment_id: ${{ steps.deployment.outputs.deployment_id }}
+ env: ${{ needs.prepare_variables.outputs.POOL_NAME }}
+
+
+ deploy_storybook:
+ if: github.event.pull_request.head.repo.full_name == 'saleor/saleor-dashboard'
+ runs-on: ubuntu-22.04
+ needs: prepare_variables
+ permissions:
+ deployments: write
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup Node
+ uses: actions/setup-node@v3
+ with:
+ node-version-file: ".nvmrc"
+
+ - name: Start storybook deployment
+ uses: bobheadxi/deployments@88ce5600046c82542f8246ac287d0a53c461bca3
+ id: storybook-deployment
+ with:
+ step: start
+ token: ${{ secrets.GITHUB_TOKEN }}
+ env: storybook ${{ needs.prepare_variables.outputs.POOL_NAME }}
+ ref: ${{ github.head_ref }}
+
+ - name: Cache node modules
+ uses: actions/cache@v3
+ env:
+ cache-name: cache-node-modules
+ with:
+ path: ~/.npm
+ key: ${{ runner.os }}-qa-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-qa-${{ env.cache-name }}-
+ ${{ runner.os }}-qa-
+ ${{ runner.os }}-
+
+ - name: Install deps
+ run: npm ci
+
+ - name: Build storybook
+ run: npm run build-storybook
+
+ - name: Configure AWS credentials
+ uses: aws-actions/configure-aws-credentials@v3
+ with:
+ aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
+ aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+ aws-region: ${{ secrets.AWS_DEFAULT_REGION }}
+
+ - name: Deploy to S3
+ env:
+ AWS_TEST_DEPLOYMENT_BUCKET: ${{ secrets.AWS_TEST_DEPLOYMENT_BUCKET }}
+ BASE_URL: ${{ needs.prepare_variables.outputs.BASE_URL }}
+ run: aws s3 sync ./build/storybook "s3://${AWS_TEST_DEPLOYMENT_BUCKET}/${BASE_URL}/storybook"
+
+ - name: Invalidate cache
+ env:
+ AWS_TEST_CF_DIST_ID: ${{ secrets.AWS_TEST_CF_DIST_ID }}
+ BASE_URL: ${{ needs.prepare_variables.outputs.BASE_URL }}
+ run: aws cloudfront create-invalidation --distribution-id "$AWS_TEST_CF_DIST_ID" --paths "/${BASE_URL}/*"
+
+ - name: Update storybook deployment status
+ uses: bobheadxi/deployments@88ce5600046c82542f8246ac287d0a53c461bca3
+ if: always()
+ with:
+ step: finish
+ token: ${{ secrets.GITHUB_TOKEN }}
+ status: ${{ job.status }}
+ env_url: https://${{ needs.prepare_variables.outputs.BASE_URL }}/storybook/index.html
+ deployment_id: ${{ steps.storybook-deployment.outputs.deployment_id }}
+ env: storybook ${{ needs.prepare_variables.outputs.POOL_NAME }}
+
+ run-tests:
+ runs-on: ubuntu-latest
+ needs: [prepare_variables, deploy_dashboard, prepare_instance]
+ strategy:
+ fail-fast: false
+ matrix:
+ shard: [1/2, 2/2]
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-node@v3
+ with:
+ node-version-file: ".nvmrc"
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Install Playwright Browsers
+ run: npx playwright install --with-deps
+
+ - name: Run tests
+ env:
+ API_URI: ${{ needs.prepare_variables.outputs.API_URI }}
+ BASE_URL: https://${{ needs.prepare_variables.outputs.BASE_URL }}/
+ E2E_USER_NAME: ${{ secrets.CYPRESS_USER_NAME }}
+ E2E_USER_PASSWORD: ${{ secrets.CYPRESS_USER_PASSWORD }}
+ E2E_PERMISSIONS_USERS_PASSWORD: ${{ secrets.CYPRESS_PERMISSIONS_USERS_PASSWORD }}
+ run: npx playwright test --shard ${{ matrix.shard }}
+
+ - name: Upload blob report to GitHub Actions Artifacts
+ uses: actions/upload-artifact@v3
+ if: always()
+ with:
+ name: all-blob-reports
+ path: blob-report
+ retention-days: 1
+
+ merge-reports:
+ if: '!cancelled()'
+ needs: [run-tests]
+
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v3
+ with:
+ node-version: 18
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Download blob reports from GitHub Actions Artifacts
+ uses: actions/download-artifact@v3
+ with:
+ name: all-blob-reports
+ path: all-blob-reports
+
+ - name: Merge into HTML Report
+ run: npx playwright merge-reports --reporter html ./all-blob-reports
+
+ - name: Upload HTML report
+ uses: actions/upload-artifact@v3
+ with:
+ name: html-report--attempt-${{ github.run_attempt }}
+ path: playwright-report
+ retention-days: 14
diff --git a/.github/workflows/pr-cleanup.yml b/.github/workflows/pr-cleanup.yml
new file mode 100644
index 00000000000..03ae4273ef3
--- /dev/null
+++ b/.github/workflows/pr-cleanup.yml
@@ -0,0 +1,31 @@
+name: PR cleanup
+
+on:
+ pull_request:
+ types: [closed]
+
+jobs:
+ remove_instance:
+ runs-on: ubuntu-22.04
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ sparse-checkout: ./.github/actions
+
+ - name: Setup Node
+ uses: actions/setup-node@v3
+ with:
+ node-version-file: ".nvmrc"
+
+ - name: Inject slug/short variables
+ uses: rlespinasse/github-slug-action@102b1a064a9b145e56556e22b18b19c624538d94
+
+ - name: Saleor login
+ uses: ./.github/actions/cli-login
+ with:
+ token: ${{ secrets.STAGING_TOKEN }}
+
+ - name: Remove instance
+ env:
+ SALEOR_CLI_ENV: staging
+ run: npx saleor env remove "pr-${GITHUB_HEAD_REF_SLUG_URL}" --force
\ No newline at end of file
diff --git a/.github/workflows/stale-bot.yaml b/.github/workflows/stale-bot.yaml
new file mode 100644
index 00000000000..4245518eb95
--- /dev/null
+++ b/.github/workflows/stale-bot.yaml
@@ -0,0 +1,22 @@
+name: Close stale issues and PRs
+on:
+ schedule:
+ - cron: '30 1 * * *' # every day at 1:30am UTC
+
+jobs:
+ stale:
+ runs-on: ubuntu-22.04
+ permissions:
+ issues: write
+ pull-requests: write
+ steps:
+ - uses: actions/stale@v8
+ with:
+ stale-issue-message: This issue is stale because it has been open 14 days with no activity.
+ stale-pr-message: This pull request is stale because it has been open 14 days with no activity.
+ close-issue-message: This issue was closed because it has been stalled for 2 days with no activity. You are still welcome to reopen it and continue from where you finished. Best regards Saleor team
+ close-pr-message: This PR request has been closed because it has been stalled for 2 days with no activity. You are still welcome to reopen it and continue from where you finished. Best regards Saleor team
+ days-before-stale: 14
+ days-before-close: 2
+ exempt-pr-labels: epic,triage,bug,blocker,backlog,feature
+ exempt-issue-labels: epic,triage,bug,blocker,backlog,feature
diff --git a/.github/workflows/test-env-cleanup.yml b/.github/workflows/test-env-cleanup.yml
index 1ea8811e268..bf695308077 100644
--- a/.github/workflows/test-env-cleanup.yml
+++ b/.github/workflows/test-env-cleanup.yml
@@ -1,4 +1,4 @@
-name: TEST-ENV-CLEANUP
+name: Testing
# Remove test instance for closed pull requests
on:
diff --git a/.github/workflows/test-env-deploy.yml b/.github/workflows/test-env-deploy.yml
deleted file mode 100644
index ca0da6e0bb2..00000000000
--- a/.github/workflows/test-env-deploy.yml
+++ /dev/null
@@ -1,267 +0,0 @@
-name: TEST-ENV-DEPLOYMENT
-# Build and deploy test instance for every pull request
-
-on: [pull_request]
-jobs:
- deploy:
- if: github.event.pull_request.head.repo.full_name == 'saleor/saleor-dashboard'
- runs-on: ubuntu-22.04
- outputs:
- base_URL: ${{ steps.set-domain.outputs.domain }}
- steps:
- - uses: actions/checkout@v4
- - name: Setup Node
- uses: actions/setup-node@v3
- with:
- node-version-file: ".nvmrc"
-
- - uses: rlespinasse/github-slug-action@v4
-
- - name: Start deployment
- uses: bobheadxi/deployments@v1
- id: deployment
- with:
- step: start
- token: ${{ secrets.GITHUB_TOKEN }}
- env: ${{ env.GITHUB_HEAD_REF_SLUG_URL }}
- ref: ${{ github.head_ref }}
-
- - name: Start storybook deployment
- uses: bobheadxi/deployments@v1
- id: storybook-deployment
- with:
- step: start
- token: ${{ secrets.GITHUB_TOKEN }}
- env: storybook ${{ env.GITHUB_HEAD_REF_SLUG_URL }}
- ref: ${{ github.head_ref }}
-
- - name: Cache node modules
- uses: actions/cache@v3
- env:
- cache-name: cache-node-modules
- with:
- path: ~/.npm
- key: ${{ runner.os }}-qa-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
- restore-keys: |
- ${{ runner.os }}-qa-${{ env.cache-name }}-
- ${{ runner.os }}-qa-
- ${{ runner.os }}-
- - name: Install deps
- run: |
- npm ci
- - name: Get custom API_URI
- id: api_uri
- # Search for API_URI in PR description
- env:
- pull_request_body: ${{ github.event.pull_request.body }}
- prefix: API_URI=
- pattern: (http|https)://[a-zA-Z0-9.-]+/graphql/?
- run: |
- echo "custom_api_uri=$(echo "$pull_request_body" | grep -Eo "$prefix$pattern" | sed s/$prefix// | head -n 1)" >> $GITHUB_OUTPUT
- - name: Get APPS_MARKETPLACE_API_URI
- id: apps_marketplace_api_uri
- # Search for APPS_MARKETPLACE_API_URI in PR description
- env:
- pull_request_body: ${{ github.event.pull_request.body }}
- prefix: APPS_MARKETPLACE_API_URI=
- pattern: (http|https)://[a-zA-Z0-9.-]+[a-zA-Z0-9/-]+/?
- run: |
- echo "custom_apps_marketplace_api_uri=$(echo "$pull_request_body" | grep -Eo "$prefix$pattern" | sed s/$prefix// | head -n 1)" >> $GITHUB_OUTPUT
- - name: Run build
- env:
- # Use custom API_URI or the default one
- API_URI: ${{ steps.api_uri.outputs.custom_api_uri || 'https://qa.staging.saleor.cloud/graphql/' }}
- APPS_MARKETPLACE_API_URI: ${{ steps.apps_marketplace_api_uri.outputs.custom_apps_marketplace_api_uri }}
- APP_MOUNT_URI: /
- STATIC_URL: /
- IS_CLOUD_INSTANCE: true
- run: |
- npm run build
- - name: Run build storybook
- run: |
- npm run build-storybook
- - name: Set domain
- id: set-domain
- # Set test instance domain based on branch name slug
- run: |
- echo "domain=${{ env.GITHUB_HEAD_REF_SLUG_URL }}.dashboard.saleor.rocks" >> $GITHUB_OUTPUT
- - name: Configure AWS credentials
- uses: aws-actions/configure-aws-credentials@v3
- with:
- aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
- aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- aws-region: ${{ secrets.AWS_DEFAULT_REGION }}
-
- - name: Deploy to S3
- run: |
- aws s3 sync ./build/dashboard s3://${{ secrets.AWS_TEST_DEPLOYMENT_BUCKET }}/${{ steps.set-domain.outputs.domain }}
- aws s3 sync ./build/storybook s3://${{ secrets.AWS_TEST_DEPLOYMENT_BUCKET }}/${{ steps.set-domain.outputs.domain }}/storybook
- - name: Invalidate cache
- run: aws cloudfront create-invalidation --distribution-id ${{ secrets.AWS_TEST_CF_DIST_ID }} --paths "/${{ steps.set-domain.outputs.domain }}/*"
-
- - name: Update deployment status
- uses: bobheadxi/deployments@v1
- if: always()
- with:
- step: finish
- token: ${{ secrets.GITHUB_TOKEN }}
- status: ${{ job.status }}
- env_url: https://${{ steps.set-domain.outputs.domain }}/
- deployment_id: ${{ steps.deployment.outputs.deployment_id }}
- env: ${{ env.GITHUB_HEAD_REF_SLUG_URL }}
-
- - name: Update storybook deployment status
- uses: bobheadxi/deployments@v1
- if: always()
- with:
- step: finish
- token: ${{ secrets.GITHUB_TOKEN }}
- status: ${{ job.status }}
- env_url: https://${{ steps.set-domain.outputs.domain }}/storybook/index.html
- deployment_id: ${{ steps.storybook-deployment.outputs.deployment_id }}
- env: storybook ${{ env.GITHUB_HEAD_REF_SLUG_URL }}
-
- prepare-tests:
- runs-on: ubuntu-22.04
- needs: deploy
- outputs:
- tags: ${{steps.get_tags.outputs.result}}
- containers: ${{ steps.get_containers.outputs.result}}
- steps:
- - name: Get tags
- id: get_tags
- uses: actions/github-script@v6
- env:
- pullRequestBody: ${{ github.event.pull_request.body }}
- with:
- result-encoding: string
- script: |
- const { pullRequestBody } = process.env
- const tags = ["@critical"];
- try{
- const removedPullRequestBodyBeforeTests = pullRequestBody.split(`### Do you want to run more stable tests?`);
- const removedPullRequestBodyAfterTests = removedPullRequestBodyBeforeTests[1].split(`CONTAINERS`);
- let tagsInString = removedPullRequestBodyAfterTests[0];
- tagsInString = tagsInString.split('\n');
- tagsInString.forEach(line => {
- if (line.includes('[x]')) tags.push(line.replace(/[0-9]+\. \[x\] /, "@stable+@"))
- });
- const tagsToReturn = tags.join(",").toString();
- return tagsToReturn.replace(/\r/g, '')
- }catch{
- return '@critical'
- }
-
- - name: get-containers
- id: get_containers
- uses: actions/github-script@v6
- env:
- pullRequestBody: ${{ github.event.pull_request.body }}
- with:
- script: |
- const { pullRequestBody } = process.env
- const containers = [];
- const numberOfContainersRegex = /CONTAINERS=(\d*)/
- const numberOfContainers = pullRequestBody.match(numberOfContainersRegex);
- for(let i=1; i<=numberOfContainers[1]; i++){
- containers.push(i)
- }
- return {"containers": containers}
-
- - name: echo-tags
- run: |
- echo ${{steps.get_tags.outputs.result}}
-
- testmo-report-preparation:
- needs: prepare-tests
- if: github.event.pull_request.head.repo.fork == false
- runs-on: ubuntu-22.04
- outputs:
- testmo-run-id: ${{ steps.init-testmo.outputs.testmo-run-id }}
- steps:
- - uses: actions/checkout@v4
- - uses: ./.github/actions/testmo/testmo-init
- with:
- testmoUrl: ${{ secrets.TESTMO_URL }}
- testmoToken: ${{ secrets.TESTMO_TOKEN }}
- id: init-testmo
-
- cypress-run-selected:
- runs-on: ubuntu-22.04
- needs: [prepare-tests, deploy, testmo-report-preparation]
- container: cypress/browsers:node18.12.0-chrome106-ff106
- strategy:
- fail-fast: false
- max-parallel: 6
- matrix: ${{ fromJson(needs.prepare-tests.outputs.containers) }}
-
- steps:
- - uses: actions/checkout@v4
- - name: Get API_URI
- id: api_uri
- # Search for API_URI in PR description and use default if not defined
- env:
- pull_request_body: ${{ github.event.pull_request.body }}
- prefix: API_URI=
- pattern: (http|https)://[a-zA-Z0-9.-]+/graphql/?
- fallback_uri: ${{ secrets.CYPRESS_API_URI }}
- run: |
- echo "custom_api_uri=$(echo "$pull_request_body" | grep -Eo "$prefix$pattern" | sed s/$prefix// | head -n 1 | { read custom_uri; if [ -z "$custom_uri" ]; then echo "$fallback_uri"; else echo "$custom_uri"; fi })" >> $GITHUB_OUTPUT
- - name: Setup Node
- uses: actions/setup-node@v3
- with:
- node-version-file: ".nvmrc"
-
- - name: Cache node modules
- uses: actions/cache@v3
- env:
- cache-name: cache-node-modules
- with:
- path: ~/.npm
- key: ${{ runner.os }}-qa-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
- restore-keys: |
- ${{ runner.os }}-qa-${{ env.cache-name }}-
- ${{ runner.os }}-qa-
- ${{ runner.os }}-
- - name: Install Dependencies
- if: steps.cache-node-modules.outputs.cache-hit != 'true'
- run: NODE_OPTIONS=--max_old_space_size=4096 npm install
-
- - name: Cypress run critical
- if: ${{ ! cancelled() }}
- uses: ./.github/actions/e2e
- with:
- apiUrl: "${{ steps.api_uri.outputs.custom_api_uri }}"
- appMountUri: ${{ secrets.APP_MOUNT_URI }}
- baseUrl: "https://${{needs.deploy.outputs.base_URL}}/"
- userName: ${{ secrets.CYPRESS_USER_NAME }}
- secondUserName: ${{ secrets.CYPRESS_SECOND_USER_NAME }}
- userPassword: ${{ secrets.CYPRESS_USER_PASSWORD }}
- permissionsUserPassword: ${{ secrets.CYPRESS_PERMISSIONS_USERS_PASSWORD }}
- mailpitUrl: ${{ secrets.CYPRESS_MAILPITURL }}
- cypressGrepTags: ${{ needs.prepare-tests.outputs.tags }}
- split: ${{ strategy.job-total }}
- splitIndex: ${{ strategy.job-index }}
- - name: Testmo threads submit
- if: github.event.pull_request.head.repo.fork == false && !cancelled()
- uses: ./.github/actions/testmo/testmo-threads-submit
- with:
- testmoUrl: ${{ secrets.TESTMO_URL }}
- testmoToken: ${{ secrets.TESTMO_TOKEN }}
- testmoRunId: ${{ needs.testmo-report-preparation.outputs.testmo-run-id }}
-
- test-complete:
- needs: [testmo-report-preparation, cypress-run-selected]
- if: |
- always() && !contains(needs.*.result, 'skipped') && !contains(needs.*.result, 'cancelled') && github.event.pull_request.head.repo.fork == false
- runs-on: ubuntu-22.04
- steps:
- - uses: actions/checkout@v4
- - run: npm ci
- working-directory: .github/workflows
- - name: complete testmo report
- uses: ./.github/actions/testmo/testmo-finish
- with:
- testmoUrl: ${{ secrets.TESTMO_URL }}
- testmoToken: ${{ secrets.TESTMO_TOKEN }}
- testmoRunId: ${{ needs.testmo-report-preparation.outputs.testmo-run-id }}
diff --git a/.github/workflows/tests-nightly.yml b/.github/workflows/tests-nightly.yml
index c9fda1fe255..4ec000db8dc 100644
--- a/.github/workflows/tests-nightly.yml
+++ b/.github/workflows/tests-nightly.yml
@@ -153,9 +153,9 @@ jobs:
case 'workflow_dispatch':
return browser
case 'schedule':
- return 'chrome'
+ return 'electron'
default:
- return 'chrome'
+ return 'electron'
}
- name: Cypress install
@@ -167,7 +167,7 @@ jobs:
- name: Cypress run electron
id: cypress-electron
- if: ${{ github.event.inputs.tests != 'Critical' && github.event_name != 'repository_dispatch' && contains(fromJSON('["chrome", "all"]'), steps.get-browsers.outputs.result) && ! cancelled() }}
+ if: ${{ github.event.inputs.tests != 'Critical' && github.event_name != 'repository_dispatch' && contains(fromJSON('["electron", "all"]'), steps.get-browsers.outputs.result) && ! cancelled() }}
uses: ./.github/actions/e2e
with:
apiUrl: ${{ steps.get-env-uri.outputs.ENV_URI }}graphql/
@@ -211,7 +211,7 @@ jobs:
install: false
browser: firefox
- name: Testmo threads submit
- if: ${{ github.event.inputs.tests != 'Critical' && github.event_name != 'repository_dispatch' && contains(fromJSON('["chrome", "all"]'), steps.get-browsers.outputs.result) && ! cancelled() }}
+ if: ${{ github.event.inputs.tests != 'Critical' && github.event_name != 'repository_dispatch' && contains(fromJSON('["electron", "all"]'), steps.get-browsers.outputs.result) && ! cancelled() }}
uses: ./.github/actions/testmo/testmo-threads-submit
with:
testmoUrl: ${{ secrets.TESTMO_URL }}
diff --git a/.husky/pre-push b/.husky/pre-push
index d0eecb18f1d..d43c508b19f 100755
--- a/.husky/pre-push
+++ b/.husky/pre-push
@@ -1,5 +1,15 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
+# Maximum allowed branch name length (deployment instance name limit)
+MAX_LENGTH=37
+
+# Check if the branch name length exceeds the maximum allowed length
+branch_name=$(git symbolic-ref --short HEAD)
+if [ ${#branch_name} -gt $MAX_LENGTH ]; then
+ echo "⚠️ Warning: Branch name '$branch_name' exceeds the maximum allowed length of $MAX_LENGTH characters."
+ echo "⚠️ The deployment instance will not be created."
+fi
+
npm run check-types
npm run test
diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html
index 8e77ec8b5e1..a2ec30fc7d4 100644
--- a/.storybook/preview-head.html
+++ b/.storybook/preview-head.html
@@ -9,6 +9,7 @@
API_URL: "",
APP_MOUNT_URI: "/",
IS_CLOUD_INSTANCE: false,
+ LOCALE_CODE: "EN",
};
window.process = { cwd: () => "" };
diff --git a/Dockerfile b/Dockerfile
index f8ba24b904c..50b69d18316 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -26,6 +26,7 @@ ARG APPS_MARKETPLACE_API_URI
ARG APPS_TUNNEL_URL_KEYWORDS
ARG STATIC_URL
ARG SKIP_SOURCEMAPS
+ARG LOCALE_CODE
ENV API_URI ${API_URI:-http://localhost:8000/graphql/}
ENV APP_MOUNT_URI ${APP_MOUNT_URI:-/dashboard/}
@@ -33,6 +34,7 @@ ENV APPS_MARKETPLACE_API_URI ${APPS_MARKETPLACE_API_URI:-https://apps.saleor.io/
ENV APPS_TUNNEL_URL_KEYWORDS ${APPS_TUNNEL_URL_KEYWORDS}
ENV STATIC_URL ${STATIC_URL:-/dashboard/}
ENV SKIP_SOURCEMAPS ${SKIP_SOURCEMAPS:-true}
+ENV LOCALE_CODE ${LOCALE_CODE:-EN}
RUN npm run build
FROM nginx:stable-alpine as runner
diff --git a/app.json b/app.json
index 4f47a67746a..21682107b5e 100644
--- a/app.json
+++ b/app.json
@@ -14,6 +14,10 @@
"APP_MOUNT_URI": {
"description": "URI at which the Dashboard app will be mounted",
"value": "/"
+ },
+ "LOCALE_CODE": {
+ "description": "Locale code to select default language",
+ "value": "EN"
}
},
"buildpacks": [
diff --git a/cypress.config.js b/cypress.config.js
index 384450108a5..a7a6a49ebdb 100644
--- a/cypress.config.js
+++ b/cypress.config.js
@@ -14,7 +14,7 @@ module.exports = defineConfig({
screenshotsFolder: "cypress/reports/mochareports",
screenshotOnRunFailure: true,
experimentalMemoryManagement: true,
- numTestsKeptInMemory: 0,
+ numTestsKeptInMemory: 8,
retries: {
runMode: 2,
openMode: 0,
diff --git a/cypress/elements/discounts/vouchers.js b/cypress/elements/discounts/vouchers.js
index 74fc77534d1..e4c0ec36c54 100644
--- a/cypress/elements/discounts/vouchers.js
+++ b/cypress/elements/discounts/vouchers.js
@@ -1,6 +1,9 @@
export const VOUCHERS_SELECTORS = {
createVoucherButton: "[data-test-id='create-voucher']",
- voucherCodeInput: "[name='code']",
+ manualVoucherItem: "[data-test-id='manual']",
+ voucherCodeConfirmButton: "[data-test-id='confirm-button']",
+ voucherCodeAddButton: "[data-test-id='add-code-button']",
+ voucherCodeNameInput: "[data-test-id='enter-code-input']",
discountRadioButtons: "[name='discountType']",
percentageDiscountRadioButton:
"[name='discountType'][value='VALUE_PERCENTAGE']",
@@ -17,12 +20,12 @@ export const VOUCHERS_SELECTORS = {
usageLimitCheckbox: '[data-test-id="has-usage-limit"]',
usageLimitTextField: '[data-test-id="usage-limit"]',
applyOncePerCustomerCheckbox: '[data-test-id="apply-once-per-customer"]',
- onlyForStaffCheckbox: '[data-test-id="only-for-staff"]'
+ onlyForStaffCheckbox: '[data-test-id="only-for-staff"]',
},
requirements: {
minOrderValueCheckbox: '[name="requirementsPicker"][value="ORDER"]',
minAmountOfItemsCheckbox: '[name="requirementsPicker"][value="ITEM"]',
minCheckoutItemsQuantityInput: '[name="minCheckoutItemsQuantity"]',
- minOrderValueInput: '[name="minSpent"]'
- }
+ minOrderValueInput: '[name="minSpent"]',
+ },
};
diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js
index 1c73490b057..ab6693952bb 100644
--- a/cypress/plugins/index.js
+++ b/cypress/plugins/index.js
@@ -38,6 +38,7 @@ module.exports = async (on, config) => {
config.env.MAILPITURL = process.env.CYPRESS_MAILPITURL;
config.env.grepTags = process.env.CYPRESS_grepTags;
config.baseUrl = process.env.BASE_URL;
+ config.env.LOCALE_CODE = process.env.LOCALE_CODE;
on("before:browser:launch", (_browser = {}, launchOptions) => {
launchOptions.args.push("--proxy-bypass-list=<-loopback>");
diff --git a/cypress/support/customCommands/user/index.js b/cypress/support/customCommands/user/index.js
index 0e62fd78cc6..18717a28c6d 100644
--- a/cypress/support/customCommands/user/index.js
+++ b/cypress/support/customCommands/user/index.js
@@ -19,10 +19,10 @@ Cypress.Commands.add("loginInShop", () => {
});
Cypress.Commands.add("visitHomePageLoggedViaApi", user => {
- cy.addAliasToGraphRequest("Home")
+ cy.addAliasToGraphRequest("UserDetails")
.loginUserViaRequest("auth", user)
.visit(urlList.homePage)
- .waitForRequestAndCheckIfNoErrors("@Home");
+ .waitForRequestAndCheckIfNoErrors("@UserDetails");
});
Cypress.Commands.add(
diff --git a/cypress/support/pages/discounts/vouchersPage.js b/cypress/support/pages/discounts/vouchersPage.js
index 8728da31ff0..1bd90b9c0e4 100644
--- a/cypress/support/pages/discounts/vouchersPage.js
+++ b/cypress/support/pages/discounts/vouchersPage.js
@@ -25,10 +25,11 @@ export function createVoucher({
}) {
cy.get(VOUCHERS_SELECTORS.createVoucherButton).click();
selectChannelInDetailsPages(channelName);
- cy.get(VOUCHERS_SELECTORS.voucherCodeInput)
- .type(voucherCode)
- .get(discountOption)
- .click();
+ cy.get(VOUCHERS_SELECTORS.voucherCodeAddButton).click();
+ cy.get(VOUCHERS_SELECTORS.manualVoucherItem).click();
+ cy.get(VOUCHERS_SELECTORS.voucherCodeNameInput).type(voucherCode);
+ cy.get(VOUCHERS_SELECTORS.voucherCodeConfirmButton).click();
+ cy.get(discountOption).click();
if (discountOption !== discountOptions.SHIPPING) {
cy.get(VOUCHERS_SELECTORS.discountValueInputs).type(voucherValue, {
force: true,
diff --git a/cypress/support/pages/homePage.js b/cypress/support/pages/homePage.js
index 09abf4a0cae..f501eafa5e6 100644
--- a/cypress/support/pages/homePage.js
+++ b/cypress/support/pages/homePage.js
@@ -4,11 +4,9 @@ import { HOMEPAGE_SELECTORS } from "../../elements/homePage/homePage-selectors";
export function changeChannel(channelName) {
cy.get(HEADER_SELECTORS.channelSelect)
.click()
- .addAliasToGraphRequest("Home")
.get(HEADER_SELECTORS.channelSelectList)
.contains(channelName)
- .click()
- .wait("@Home");
+ .click();
}
export function expectWelcomeMessageIncludes(name) {
@@ -21,37 +19,37 @@ export function expectWelcomeMessageIncludes(name) {
export function getOrdersReadyToFulfillRegex(
ordersReadyToFulfillBefore,
- quantityOfNewOrders
+ quantityOfNewOrders,
) {
const allOrdersReadyToFulfill =
ordersReadyToFulfillBefore + quantityOfNewOrders;
const notANumberRegex = "\\D*";
return new RegExp(
- `${notANumberRegex}${allOrdersReadyToFulfill}${notANumberRegex}`
+ `${notANumberRegex}${allOrdersReadyToFulfill}${notANumberRegex}`,
);
}
export function getOrdersReadyForCaptureRegex(
ordersReadyForCaptureBefore,
- quantityOfNewOrders
+ quantityOfNewOrders,
) {
const allOrdersReadyForCapture =
ordersReadyForCaptureBefore + quantityOfNewOrders;
const notANumberRegex = "\\D*";
return new RegExp(
- `${notANumberRegex}${allOrdersReadyForCapture}${notANumberRegex}`
+ `${notANumberRegex}${allOrdersReadyForCapture}${notANumberRegex}`,
);
}
export function getProductsOutOfStockRegex(
productsOutOfStockBefore,
- quantityOfNewProducts
+ quantityOfNewProducts,
) {
const allProductsOutOfStock =
productsOutOfStockBefore + quantityOfNewProducts;
const notANumberRegex = "\\D*";
return new RegExp(
- `${notANumberRegex}${allProductsOutOfStock}${notANumberRegex}`
+ `${notANumberRegex}${allProductsOutOfStock}${notANumberRegex}`,
);
}
@@ -67,7 +65,7 @@ export function getSalesAmountRegex(salesAmountBefore, addedAmount) {
const totalAmountWithSeparators = `${totalAmountIntegerWithThousandsSeparator}${decimalSeparator}${totalAmountDecimalValue}`;
const notANumberRegex = "\\D*";
return new RegExp(
- `${notANumberRegex}${totalAmountWithSeparators}${notANumberRegex}`
+ `${notANumberRegex}${totalAmountWithSeparators}${notANumberRegex}`,
);
}
diff --git a/introspection.json b/introspection.json
index 527d79c8d67..832687c9be0 100644
--- a/introspection.json
+++ b/introspection.json
@@ -17703,7 +17703,7 @@
},
{
"name": "displayGrossPrices",
- "description": "Determines whether checkout prices should include taxes when displayed in a storefront.\n\nAdded in Saleor 3.9.",
+ "description": "Determines whether displayed prices should include taxes.\n\nAdded in Saleor 3.9.",
"args": [],
"type": {
"kind": "NON_NULL",
@@ -18314,6 +18314,18 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "voucher",
+ "description": "The voucher assigned to the checkout.\n\nAdded in Saleor 3.18.\n\nRequires one of the following permissions: MANAGE_DISCOUNTS.",
+ "args": [],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Voucher",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "voucherCode",
"description": "The code of voucher assigned to the checkout.",
@@ -29869,6 +29881,26 @@
},
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "voucherCodes",
+ "description": "List of voucher codes which causes the error.\n\nAdded in Saleor 3.18.",
+ "args": [],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"inputFields": null,
@@ -29931,6 +29963,12 @@
"description": null,
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "VOUCHER_ALREADY_USED",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"possibleTypes": null
@@ -30049,7 +30087,7 @@
{
"kind": "OBJECT",
"name": "Domain",
- "description": "Represents shop's domain.",
+ "description": "Represents API domain.",
"fields": [
{
"name": "host",
@@ -30085,7 +30123,7 @@
},
{
"name": "url",
- "description": "Shop's absolute URL.",
+ "description": "The absolute URL of the API.",
"args": [],
"type": {
"kind": "NON_NULL",
@@ -30479,6 +30517,18 @@
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "voucherCode",
+ "description": "A code of the voucher associated with the order.\n\nAdded in Saleor 3.18.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null,
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"interfaces": null,
@@ -30847,6 +30897,18 @@
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "voucherCode",
+ "description": "A code of the voucher associated with the order.\n\nAdded in Saleor 3.18.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null,
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"interfaces": null,
@@ -31908,6 +31970,11 @@
"name": "TranslationUpdated",
"ofType": null
},
+ {
+ "kind": "OBJECT",
+ "name": "VoucherCodeExportCompleted",
+ "ofType": null
+ },
{
"kind": "OBJECT",
"name": "VoucherCreated",
@@ -33743,6 +33810,112 @@
],
"possibleTypes": null
},
+ {
+ "kind": "OBJECT",
+ "name": "ExportVoucherCodes",
+ "description": "Export voucher codes to csv/xlsx file.\n\nAdded in Saleor 3.18.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point. \n\nRequires one of the following permissions: MANAGE_DISCOUNTS.\n\nTriggers the following webhook events:\n- VOUCHER_CODE_EXPORT_COMPLETED (async): A notification for the exported file.",
+ "fields": [
+ {
+ "name": "errors",
+ "description": null,
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "ExportError",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "exportFile",
+ "description": "The newly created export file job which is responsible for export data.",
+ "args": [],
+ "type": {
+ "kind": "OBJECT",
+ "name": "ExportFile",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "ExportVoucherCodesInput",
+ "description": null,
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "fileType",
+ "description": "Type of exported file.",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "FileTypesEnum",
+ "ofType": null
+ }
+ },
+ "defaultValue": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "ids",
+ "description": "List of voucher code IDs to export.",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "voucherId",
+ "description": "The ID of the voucher. If provided, exports all codes belonging to the voucher.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ },
+ "defaultValue": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
{
"kind": "OBJECT",
"name": "ExternalAuthentication",
@@ -34809,6 +34982,18 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "shippingRefundedAmount",
+ "description": "Amount of refunded shipping price.\n\nAdded in Saleor 3.14.",
+ "args": [],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Money",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "status",
"description": null,
@@ -34837,6 +35022,18 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "totalRefundedAmount",
+ "description": "Total refunded amount assigned to this fulfillment.\n\nAdded in Saleor 3.14.",
+ "args": [],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Money",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "trackingNumber",
"description": null,
@@ -54804,6 +55001,35 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "exportVoucherCodes",
+ "description": "Export voucher codes to csv/xlsx file.\n\nAdded in Saleor 3.18.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point. \n\nRequires one of the following permissions: MANAGE_DISCOUNTS.\n\nTriggers the following webhook events:\n- VOUCHER_CODE_EXPORT_COMPLETED (async): A notification for the exported file.",
+ "args": [
+ {
+ "name": "input",
+ "description": "Fields required to export voucher codes.",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "ExportVoucherCodesInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "ExportVoucherCodes",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "externalAuthenticationUrl",
"description": "Prepare external authentication URL for user by custom plugin.",
@@ -62390,7 +62616,7 @@
},
{
"name": "stockBulkUpdate",
- "description": "Updates stocks for a given variant and warehouse.\n\nAdded in Saleor 3.13.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point. \n\nRequires one of the following permissions: MANAGE_PRODUCTS.",
+ "description": "Updates stocks for a given variant and warehouse.\n\nAdded in Saleor 3.13.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point. \n\nRequires one of the following permissions: MANAGE_PRODUCTS.\n\nTriggers the following webhook events:\n- PRODUCT_VARIANT_STOCK_UPDATED (async): A product variant stock details were updated.",
"args": [
{
"name": "errorPolicy",
@@ -63088,7 +63314,7 @@
"args": [
{
"name": "action",
- "description": "The expected action called for the transaction. By default, the `channel.defaultTransactionFlowStrategy` will be used. The field can be used only by app that has `HANDLE_PAYMENTS` permission.",
+ "description": "The expected action called for the transaction. By default, the `channel.paymentSettings.defaultTransactionFlowStrategy` will be used.The field can be used only by app that has `HANDLE_PAYMENTS` permission.",
"type": {
"kind": "ENUM",
"name": "TransactionFlowStrategyEnum",
@@ -63939,6 +64165,43 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "voucherCodeBulkDelete",
+ "description": "Deletes voucher codes.\n\nAdded in Saleor 3.18. \n\nRequires one of the following permissions: MANAGE_DISCOUNTS.\n\nTriggers the following webhook events:\n- VOUCHER_UPDATED (async): A voucher was updated.",
+ "args": [
+ {
+ "name": "ids",
+ "description": "List of voucher codes IDs to delete.",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "defaultValue": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "VoucherCodeBulkDelete",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "voucherCreate",
"description": "Creates a new voucher. \n\nRequires one of the following permissions: MANAGE_DISCOUNTS.\n\nTriggers the following webhook events:\n- VOUCHER_CREATED (async): A voucher was created.",
@@ -65492,7 +65755,7 @@
},
{
"name": "displayGrossPrices",
- "description": "Determines whether checkout prices should include taxes when displayed in a storefront.\n\nAdded in Saleor 3.9.",
+ "description": "Determines whether displayed prices should include taxes.\n\nAdded in Saleor 3.9.",
"args": [],
"type": {
"kind": "NON_NULL",
@@ -66622,6 +66885,18 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "voucherCode",
+ "description": "Voucher code that was used for Order.\n\nAdded in Saleor 3.18.",
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "weight",
"description": null,
@@ -67546,7 +67821,7 @@
},
{
"name": "displayGrossPrices",
- "description": "Determines whether checkout prices should include taxes, when displayed in a storefront.",
+ "description": "Determines whether displayed prices should include taxes.",
"type": {
"kind": "SCALAR",
"name": "Boolean",
@@ -67802,7 +68077,19 @@
},
{
"name": "voucher",
- "description": "Code of a voucher associated with the order.",
+ "description": "Code of a voucher associated with the order.\n\nDEPRECATED: this field will be removed in Saleor 3.19. Use `voucherCode` instead.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "voucherCode",
+ "description": "Code of a voucher associated with the order.\n\nAdded in Saleor 3.18.",
"type": {
"kind": "SCALAR",
"name": "String",
@@ -70088,6 +70375,18 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "INVALID_VOUCHER",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "INVALID_VOUCHER_CODE",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "NOT_AVAILABLE_IN_CHANNEL",
"description": null,
@@ -73479,6 +73778,18 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "saleId",
+ "description": "Denormalized sale ID, set when order line is created for a product variant that is on sale.\n\nAdded in Saleor 3.14.",
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "taxClass",
"description": "Denormalized tax class of the product in this order line.\n\nAdded in Saleor 3.9.\n\nRequires one of the following permissions: AUTHENTICATED_STAFF_USER, AUTHENTICATED_APP.",
@@ -73783,6 +74094,18 @@
},
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "voucherCode",
+ "description": "Voucher code that was used for this order line.\n\nAdded in Saleor 3.14.",
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"inputFields": null,
@@ -75449,22 +75772,6 @@
"isDeprecated": false,
"deprecationReason": null
},
- {
- "name": "defaultTransactionFlowStrategy",
- "description": "Determine the transaction flow strategy to be used. Include the selected option in the payload sent to the payment app, as a requested action for the transaction.\n\nAdded in Saleor 3.13.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.This preview feature field will be removed in Saleor 3.17. Use `PaymentSettings.defaultTransactionFlowStrategy` instead.",
- "args": [],
- "type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "ENUM",
- "name": "TransactionFlowStrategyEnum",
- "ofType": null
- }
- },
- "isDeprecated": false,
- "deprecationReason": null
- },
{
"name": "deleteExpiredOrdersAfter",
"description": "The time in days after expired orders will be deleted.\n\nAdded in Saleor 3.14.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.",
@@ -75493,6 +75800,22 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "includeDraftOrderInVoucherUsage",
+ "description": "Determine if voucher applied on draft order should be count toward voucher usage.\n\nAdded in Saleor 3.18.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "markAsPaidStrategy",
"description": "Determine what strategy will be used to mark the order as paid. Based on the chosen option, the proper object will be created and attached to the order when it's manually marked as paid.\n`PAYMENT_FLOW` - [default option] creates the `Payment` object.\n`TRANSACTION_FLOW` - creates the `TransactionItem` object.\n\nAdded in Saleor 3.13.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.",
@@ -75626,11 +75949,11 @@
"deprecationReason": null
},
{
- "name": "defaultTransactionFlowStrategy",
- "description": "Determine the transaction flow strategy to be used. Include the selected option in the payload sent to the payment app, as a requested action for the transaction.\n\nAdded in Saleor 3.13.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.\n\nDEPRECATED: this preview feature field will be removed in Saleor 3.17. Use `PaymentSettingsInput.defaultTransactionFlowStrategy` instead.",
+ "name": "deleteExpiredOrdersAfter",
+ "description": "The time in days after expired orders will be deleted.Allowed range is from 1 to 120.\n\nAdded in Saleor 3.14.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.",
"type": {
- "kind": "ENUM",
- "name": "TransactionFlowStrategyEnum",
+ "kind": "SCALAR",
+ "name": "Day",
"ofType": null
},
"defaultValue": null,
@@ -75638,11 +75961,11 @@
"deprecationReason": null
},
{
- "name": "deleteExpiredOrdersAfter",
- "description": "The time in days after expired orders will be deleted.Allowed range is from 1 to 120.\n\nAdded in Saleor 3.14.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.",
+ "name": "expireOrdersAfter",
+ "description": "Expiration time in minutes. Default null - means do not expire any orders. Enter 0 or null to disable.\n\nAdded in Saleor 3.13.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.",
"type": {
"kind": "SCALAR",
- "name": "Day",
+ "name": "Minute",
"ofType": null
},
"defaultValue": null,
@@ -75650,11 +75973,11 @@
"deprecationReason": null
},
{
- "name": "expireOrdersAfter",
- "description": "Expiration time in minutes. Default null - means do not expire any orders. Enter 0 or null to disable.\n\nAdded in Saleor 3.13.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.",
+ "name": "includeDraftOrderInVoucherUsage",
+ "description": "Specify whether a coupon applied to draft orders will count toward voucher usage.\n\nWarning: when switching this setting from `false` to `true`, the vouchers will be disconnected from all draft orders.\n\nAdded in Saleor 3.18.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.",
"type": {
"kind": "SCALAR",
- "name": "Minute",
+ "name": "Boolean",
"ofType": null
},
"defaultValue": null,
@@ -75769,7 +76092,7 @@
},
{
"name": "automaticallyFulfillNonShippableGiftCard",
- "description": "When enabled, all non-shippable gift card orders will be fulfilled automatically. By defualt set to True.",
+ "description": "When enabled, all non-shippable gift card orders will be fulfilled automatically. By default set to True.",
"type": {
"kind": "SCALAR",
"name": "Boolean",
@@ -80425,6 +80748,22 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "partial",
+ "description": "Informs whether this is a partial payment.\n\nAdded in Saleor 3.14.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "paymentMethodType",
"description": "Type of method used for payment.",
@@ -80527,6 +80866,18 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "pspReference",
+ "description": "PSP reference of the payment.\n\nAdded in Saleor 3.14.",
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "token",
"description": "Unique token associated with a payment.",
@@ -91714,7 +92065,7 @@
},
{
"name": "displayGrossPrices",
- "description": "Determines whether this product's price displayed in a storefront should include taxes.\n\nAdded in Saleor 3.9.",
+ "description": "Determines whether displayed prices should include taxes.\n\nAdded in Saleor 3.9.",
"args": [],
"type": {
"kind": "NON_NULL",
@@ -118724,7 +119075,7 @@
{
"kind": "OBJECT",
"name": "StockBulkUpdate",
- "description": "Updates stocks for a given variant and warehouse.\n\nAdded in Saleor 3.13.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point. \n\nRequires one of the following permissions: MANAGE_PRODUCTS.",
+ "description": "Updates stocks for a given variant and warehouse.\n\nAdded in Saleor 3.13.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point. \n\nRequires one of the following permissions: MANAGE_PRODUCTS.\n\nTriggers the following webhook events:\n- PRODUCT_VARIANT_STOCK_UPDATED (async): A product variant stock details were updated.",
"fields": [
{
"name": "count",
@@ -121043,7 +121394,7 @@
},
{
"name": "displayGrossPrices",
- "description": "Determines whether prices displayed in a storefront should include taxes.",
+ "description": "Determines whether displayed prices should include taxes.",
"args": [],
"type": {
"kind": "NON_NULL",
@@ -121486,7 +121837,7 @@
},
{
"name": "displayGrossPrices",
- "description": "Determines whether prices displayed in a storefront should include taxes for this country.",
+ "description": "Determines whether displayed prices should include taxes for this country.",
"args": [],
"type": {
"kind": "NON_NULL",
@@ -121558,7 +121909,7 @@
},
{
"name": "displayGrossPrices",
- "description": "Determines whether prices displayed in a storefront should include taxes for this country.",
+ "description": "Determines whether displayed prices should include taxes for this country.",
"type": {
"kind": "NON_NULL",
"name": null,
@@ -121766,7 +122117,7 @@
},
{
"name": "displayGrossPrices",
- "description": "Determines whether prices displayed in a storefront should include taxes.",
+ "description": "Determines whether displayed prices should include taxes.",
"type": {
"kind": "SCALAR",
"name": "Boolean",
@@ -129631,16 +129982,73 @@
},
{
"name": "code",
- "description": "The code of the voucher.",
+ "description": "The code of the voucher.This field will be removed in Saleor 4.0.",
"args": [],
"type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "String",
- "ofType": null
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "codes",
+ "description": "List of codes available for this voucher.\n\nAdded in Saleor 3.18.",
+ "args": [
+ {
+ "name": "after",
+ "description": "Return the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "before",
+ "description": "Return the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "first",
+ "description": "Retrieve the first n elements from the list. Note that the system only allows fetching a maximum of 100 objects in a single query.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "last",
+ "description": "Retrieve the last n elements from the list. Note that the system only allows fetching a maximum of 100 objects in a single query.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null,
+ "isDeprecated": false,
+ "deprecationReason": null
}
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "VoucherCodeCountableConnection",
+ "ofType": null
},
"isDeprecated": false,
"deprecationReason": null
@@ -130079,6 +130487,22 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "singleUse",
+ "description": "Determine if the voucher codes can be used once or multiple times.\n\nAdded in Saleor 3.18.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "startDate",
"description": "The start date and time of voucher.",
@@ -130658,6 +131082,419 @@
"enumValues": null,
"possibleTypes": null
},
+ {
+ "kind": "OBJECT",
+ "name": "VoucherCode",
+ "description": "Represents voucher code.\n\nAdded in Saleor 3.18.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.",
+ "fields": [
+ {
+ "name": "code",
+ "description": "Code to use the voucher.",
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createdAt",
+ "description": "Date time of code creation.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "DateTime",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": "The ID of the voucher code.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "isActive",
+ "description": "Whether a code is active or not.",
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "used",
+ "description": "Number of times a code has been used.",
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "VoucherCodeBulkDelete",
+ "description": "Deletes voucher codes.\n\nAdded in Saleor 3.18. \n\nRequires one of the following permissions: MANAGE_DISCOUNTS.\n\nTriggers the following webhook events:\n- VOUCHER_UPDATED (async): A voucher was updated.",
+ "fields": [
+ {
+ "name": "count",
+ "description": "Returns how many codes were deleted.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": null,
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "VoucherCodeBulkDeleteError",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "VoucherCodeBulkDeleteError",
+ "description": null,
+ "fields": [
+ {
+ "name": "code",
+ "description": "The error code.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "VoucherCodeBulkDeleteErrorCode",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "message",
+ "description": "The error message.",
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "path",
+ "description": "Path to field that caused the error. A value of `null` indicates that the error isn't associated with a particular field.",
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "voucherCodes",
+ "description": "List of voucher codes which causes the error.",
+ "args": [],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "VoucherCodeBulkDeleteErrorCode",
+ "description": "An enumeration.",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "GRAPHQL_ERROR",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "INVALID",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "NOT_FOUND",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "VoucherCodeCountableConnection",
+ "description": null,
+ "fields": [
+ {
+ "name": "edges",
+ "description": null,
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "VoucherCodeCountableEdge",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Pagination data for this connection.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "totalCount",
+ "description": "A total count of items in the collection.",
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "VoucherCodeCountableEdge",
+ "description": null,
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "VoucherCode",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "VoucherCodeExportCompleted",
+ "description": "Event sent when voucher code export is completed.\n\nAdded in Saleor 3.18.",
+ "fields": [
+ {
+ "name": "export",
+ "description": "The export file for voucher codes.",
+ "args": [],
+ "type": {
+ "kind": "OBJECT",
+ "name": "ExportFile",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "issuedAt",
+ "description": "Time of the event.",
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "DateTime",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "issuingPrincipal",
+ "description": "The user or application that triggered the event.",
+ "args": [],
+ "type": {
+ "kind": "UNION",
+ "name": "IssuingPrincipal",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "recipient",
+ "description": "The application receiving the webhook.",
+ "args": [],
+ "type": {
+ "kind": "OBJECT",
+ "name": "App",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "version",
+ "description": "Saleor version that triggered the event.",
+ "args": [],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+ {
+ "kind": "INTERFACE",
+ "name": "Event",
+ "ofType": null
+ }
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
{
"kind": "OBJECT",
"name": "VoucherCountableConnection",
@@ -131248,6 +132085,26 @@
"description": null,
"fields": null,
"inputFields": [
+ {
+ "name": "addCodes",
+ "description": "List of codes to add.\n\nAdded in Saleor 3.18.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "applyOncePerCustomer",
"description": "Voucher should be applied once per customer.",
@@ -131294,7 +132151,7 @@
},
{
"name": "code",
- "description": "Code to use the voucher.",
+ "description": "Code to use the voucher. This field will be removed in Saleor 4.0. Use `addCodes` instead.",
"type": {
"kind": "SCALAR",
"name": "String",
@@ -131424,6 +132281,18 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "singleUse",
+ "description": "When set to 'True', each voucher code can be used only once; otherwise, codes can be used multiple times depending on `usageLimit`.\n\nThe option can only be changed if none of the voucher codes have been used.\n\nAdded in Saleor 3.18.\n\nNote: this API is currently in Feature Preview and can be subject to changes at later point.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "startDate",
"description": "Start date of the voucher in ISO 8601 format.",
@@ -131656,7 +132525,7 @@
"enumValues": [
{
"name": "CODE",
- "description": "Sort vouchers by code.",
+ "description": "Sort vouchers by code.\n\nDEPRECATED: this field will be removed in Saleor 4.0.",
"isDeprecated": false,
"deprecationReason": null
},
@@ -131672,6 +132541,12 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "NAME",
+ "description": "Sort vouchers by name.\n\nAdded in Saleor 3.18.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "START_DATE",
"description": "Sort vouchers by start date.",
@@ -135465,7 +136340,7 @@
},
{
"name": "PRODUCT_VARIANT_DELETED",
- "description": "A product variant is deleted.",
+ "description": "A product variant is deleted. Warning: this event will not be executed when parent product has been deleted. Check PRODUCT_DELETED.",
"isDeprecated": false,
"deprecationReason": null
},
@@ -135661,6 +136536,12 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "VOUCHER_CODE_EXPORT_COMPLETED",
+ "description": "A voucher code export is completed.\n\nAdded in Saleor 3.18.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "VOUCHER_CREATED",
"description": "A new voucher created.",
@@ -136406,7 +137287,7 @@
},
{
"name": "PRODUCT_VARIANT_DELETED",
- "description": "A product variant is deleted.",
+ "description": "A product variant is deleted. Warning: this event will not be executed when parent product has been deleted. Check PRODUCT_DELETED.",
"isDeprecated": false,
"deprecationReason": null
},
@@ -136644,6 +137525,12 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "VOUCHER_CODE_EXPORT_COMPLETED",
+ "description": "A voucher code export is completed.\n\nAdded in Saleor 3.18.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "VOUCHER_CREATED",
"description": "A new voucher created.",
@@ -137632,6 +138519,12 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "VOUCHER_CODE_EXPORT_COMPLETED",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "VOUCHER_CREATED",
"description": null,
diff --git a/locale/defaultMessages.json b/locale/defaultMessages.json
index 9234151da3f..a0468ef3faa 100644
--- a/locale/defaultMessages.json
+++ b/locale/defaultMessages.json
@@ -214,6 +214,9 @@
"context": "section description",
"string": "Strategy defines the preference of warehouses for stock allocations and reservations."
},
+ "/Fa+RP": {
+ "string": "Couldn't load top products"
+ },
"/ILyIf": {
"context": "tax classes menu header",
"string": "Tax class label"
@@ -241,6 +244,9 @@
"context": "page label",
"string": "Hidden"
},
+ "/U8FUp": {
+ "string": "Couldn't load activities"
+ },
"/V7UOC": {
"context": "unassign category from sale and save, button",
"string": "Unassign and save"
@@ -691,6 +697,9 @@
"context": "window title",
"string": "Install App"
},
+ "2dgbGR": {
+ "string": "Those codes already exist"
+ },
"2fgaAQ": {
"context": "search input placeholder",
"string": "Search shipping zones..."
@@ -974,6 +983,9 @@
"context": "Charge in progress transaction amount, data display header",
"string": "Pending charge"
},
+ "4gJAm6": {
+ "string": "Can't delete saved codes"
+ },
"4gT3eD": {
"context": "navigator section header",
"string": "Search in Customers"
@@ -1513,9 +1525,6 @@
"context": "button",
"string": "Go back to dashboard"
},
- "989O5D": {
- "string": "Are you sure you want to delete this voucher code?"
- },
"98Nw4g": {
"context": "card subtitle",
"string": "Rendered prices"
@@ -1528,6 +1537,9 @@
"context": "tile view pagination label",
"string": "No. of products"
},
+ "9BvYb9": {
+ "string": "Voucher"
+ },
"9C7PZE": {
"context": "navigation section name",
"string": "Navigation"
@@ -1855,16 +1867,16 @@
"context": "page type name",
"string": "Content Type Name"
},
+ "BR8au7": {
+ "context": "delete channel",
+ "string": "Select channel that you wish to move existing orders to."
+ },
"BUKMzM": {
"string": "Variant removed"
},
"BWpuKl": {
"string": "Update"
},
- "BXMSl4": {
- "context": "currency channel",
- "string": "There is no available channel to move order information to. Please create a channel with same currency so that information can be moved to it."
- },
"BXkF8Z": {
"context": "header",
"string": "Activity"
@@ -2552,6 +2564,9 @@
"context": "tooltip",
"string": "Checkout reservation time threshold is enabled in settings."
},
+ "GA+Djy": {
+ "string": "Are you sure you want to delete these voucher codes?"
+ },
"GAmGog": {
"context": "value input label",
"string": "Discount value"
@@ -2560,6 +2575,10 @@
"context": "ProductTypeDeleteWarningDialog single assigned items button label",
"string": "View products"
},
+ "GCho9N": {
+ "context": "delete channel",
+ "string": "All channel settings information such as shipping, product listings, warehouse assignments, etc, will be lost."
+ },
"GD/bom": {
"context": "label",
"string": "Min Delivery Time"
@@ -2591,6 +2610,16 @@
"context": "webhooks inactive label",
"string": "Inactive"
},
+ "GOdq5V": {
+ "string": "Catalog"
+ },
+ "GP0zGO": {
+ "context": "dialog header",
+ "string": "Select destination channel:"
+ },
+ "GTCg9O": {
+ "string": "You must add at least one voucher code"
+ },
"GVM/fi": {
"context": "order history message",
"string": "Payment was authorized"
@@ -2619,6 +2648,10 @@
"context": "aria-label, negative money amount",
"string": "minus"
},
+ "Ge+dUe": {
+ "context": "currency channel",
+ "string": "To delete {channelSlug} you have to create a chanel with currency: {currency} to be able to move all existing orders."
+ },
"Gfbp36": {
"context": "dialog header",
"string": "Unassign Products From Shipping"
@@ -3136,10 +3169,6 @@
"JqiqNj": {
"string": "Something went wrong"
},
- "JsPIOX": {
- "context": "voucher code",
- "string": "Code"
- },
"Jsh6+U": {
"context": "product type is digital or physical",
"string": "Type"
@@ -3284,6 +3313,10 @@
"context": "channel select label",
"string": "Channel"
},
+ "LATHyi": {
+ "context": "dialog header",
+ "string": "Delete Channel: {channelSlug}"
+ },
"LEZZkK": {
"context": "WarehouseSettings all warehouses description",
"string": "If selected customer will be able to choose this warehouse as pickup point. Ordered products can be shipped here from a different warehouse"
@@ -3499,10 +3532,6 @@
"context": "add discount button",
"string": "Add Discount"
},
- "Mz0cx+": {
- "context": "delete channel",
- "string": "Deleting channel will delete all product data regarding this channel. Are you sure you want to delete this channel?"
- },
"N2SbNc": {
"string": "{counter,plural,one{Are you sure you want to delete this customer?} other{Are you sure you want to delete {displayQuantity} customers?}}"
},
@@ -3919,6 +3948,9 @@
"context": "page header",
"string": "Create Voucher"
},
+ "PuQb0P": {
+ "string": "Reward"
+ },
"Pyjarj": {
"string": "This shipping rate has no postal codes assigned"
},
@@ -4045,10 +4077,6 @@
"context": "button, unassign attribute from object",
"string": "Unassign and save"
},
- "QZoU0r": {
- "context": "dialog header",
- "string": "Delete Channel"
- },
"Qb2XN5": {
"string": "\"Mark as paid\" feature creates a {link} - used by Payment Apps"
},
@@ -4268,6 +4296,9 @@
"context": "unassign attribute from product type, button",
"string": "Unassign"
},
+ "S8kqP9": {
+ "string": "Conditions"
+ },
"SBb6Ej": {
"context": "select a warehouse to fulfill product from",
"string": "Select warehouse..."
@@ -4331,10 +4362,6 @@
"context": "set variant as default, button",
"string": "Set as default"
},
- "SZJhvK": {
- "context": "dialog header",
- "string": "Select Channel"
- },
"SZt9kC": {
"context": "export filtered items to csv file",
"string": "Current search ({number})"
@@ -4885,6 +4912,9 @@
"context": "used by filter label",
"string": "Used by"
},
+ "WMN0q+": {
+ "string": "Delete voucher codes"
+ },
"WQMTKI": {
"context": "list of warehouses",
"string": "Warehouses A to Z"
@@ -4916,6 +4946,9 @@
"context": "dialog title",
"string": "Delete attribute value"
},
+ "WY3IXU": {
+ "string": "This code already exists"
+ },
"WasHjQ": {
"context": "voucher discount",
"string": "Shipment"
@@ -5132,6 +5165,9 @@
"Xtd0AT": {
"string": "Original String"
},
+ "XtlUj6": {
+ "string": "Add your first rule to set up a promotion"
+ },
"Xu4ech": {
"context": "deactivate app",
"string": "Are you sure you want to disable this app? Your data will be kept until you reactivate the app."
@@ -5489,6 +5525,10 @@
"aKSUWR": {
"string": "Cannot create transaction to non-existing order"
},
+ "aMWJ7/": {
+ "context": "local error",
+ "string": "This field cannot be blank for a new webhook"
+ },
"aMwxYb": {
"string": "Countries"
},
@@ -5926,6 +5966,9 @@
"context": "search box placeholder",
"string": "Search by country name"
},
+ "dHAwu8": {
+ "string": "Code already exists"
+ },
"dJQxHt": {
"context": "delete category",
"string": "Are you sure you want to delete {categoryName}?"
@@ -6371,6 +6414,9 @@
"context": "PluginChannelConfigurationCell channel title",
"string": "Per channel"
},
+ "gzM1em": {
+ "string": "Add rule"
+ },
"h1rPPg": {
"context": "dialog content",
"string": "Are you sure you want to delete {attributeName}?"
@@ -6549,9 +6595,6 @@
"context": "Transaction cancel button - return preauthorized amount to client",
"string": "Cancel"
},
- "iL/zeh": {
- "string": "Delete voucher code"
- },
"iMJka8": {
"string": "No pages found"
},
@@ -6739,9 +6782,6 @@
"context": "dialog header",
"string": "Assign product"
},
- "jvKNMP": {
- "string": "Discount Code"
- },
"jvo0vs": {
"string": "Save"
},
@@ -6794,6 +6834,9 @@
"context": "total order price",
"string": "Total"
},
+ "kAAlGL": {
+ "string": "Rules"
+ },
"kAPaN6": {
"context": "empty metadata text",
"string": "Empty"
@@ -6842,6 +6885,9 @@
"kN6SLs": {
"string": "Min Value"
},
+ "kNK4es": {
+ "string": "Discount value"
+ },
"kPIZ65": {
"context": "page header",
"string": "Order #{orderNumber}"
@@ -7128,10 +7174,6 @@
"context": "Webhook details asynchronous events",
"string": "Asynchronous"
},
- "mSLr9d": {
- "context": "voucher code, button",
- "string": "Generate Code"
- },
"mTEqYL": {
"context": "NoChannels content",
"string": "No channels to assign. Please first assign them for the product."
@@ -7373,6 +7415,9 @@
"context": "Add filter button text",
"string": "+ Add filter"
},
+ "o/4OCR": {
+ "string": "Shipping has already been refunded"
+ },
"o5KXAN": {
"context": "delete webhook",
"string": "Are you sure you want to delete {name}?"
@@ -7973,10 +8018,6 @@
"context": "no products placeholder",
"string": "No products are available in the channel assigned to this order."
},
- "sidKce": {
- "context": "delete channel",
- "string": "All order information from this channel need to be moved to a different channel. Please select channel orders need to be moved to:."
- },
"sjRXXz": {
"string": "Order #{orderId} was placed from draft by {userEmail}"
},
@@ -8227,6 +8268,9 @@
"context": "order history message",
"string": "Order was confirmed"
},
+ "ucLtY8": {
+ "string": "Discount rules for products, collections or categories."
+ },
"uccjUM": {
"context": "Dry run objects",
"string": "Objects"
@@ -8538,6 +8582,10 @@
"wWTUrM": {
"string": "No activities found"
},
+ "wXFttp": {
+ "context": "note on currency",
+ "string": "Note: Only channels with matching currency are available."
+ },
"wbsq7O": {
"string": "Usage"
},
diff --git a/locale/pt_BR.json b/locale/pt-BR.json
similarity index 100%
rename from locale/pt_BR.json
rename to locale/pt-BR.json
diff --git a/package-lock.json b/package-lock.json
index 418930176c7..2a7dc5c446c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,16 +1,18 @@
{
"name": "saleor-dashboard",
- "version": "3.18.0-dev",
+ "version": "3.19.0-dev",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "saleor-dashboard",
- "version": "3.18.0-dev",
- "hasInstallScript": true,
+ "version": "3.19.0-dev",
"license": "BSD-3-Clause",
"dependencies": {
"@apollo/client": "3.4.17",
+ "@dnd-kit/core": "^6.0.8",
+ "@dnd-kit/sortable": "^7.0.2",
+ "@dnd-kit/utilities": "^3.2.1",
"@editorjs/editorjs": "^2.24.3",
"@editorjs/header": "^2.6.2",
"@editorjs/image": "^2.6.2",
@@ -84,7 +86,6 @@
"react-router": "^5.0.1",
"react-router-dom": "^5.0.1",
"react-sortable-hoc": "^1.10.1",
- "react-sortable-tree": "^2.6.2",
"remark-gfm": "^3.0.1",
"slugify": "^1.4.6",
"tslib": "^2.4.1",
@@ -139,7 +140,6 @@
"@types/react-infinite-scroller": "^1.2.3",
"@types/react-router-dom": "^4.3.4",
"@types/react-sortable-hoc": "^0.7.1",
- "@types/react-sortable-tree": "^0.3.15",
"@types/url-join": "^4.0.1",
"@types/uuid": "^9.0.4",
"@types/webappsec-credential-management": "^0.5.1",
@@ -3048,6 +3048,55 @@
"node": ">=10.0.0"
}
},
+ "node_modules/@dnd-kit/accessibility": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.0.1.tgz",
+ "integrity": "sha512-HXRrwS9YUYQO9lFRc/49uO/VICbM+O+ZRpFDe9Pd1rwVv2PCNkRiTZRdxrDgng/UkvdC3Re9r2vwPpXXrWeFzg==",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/@dnd-kit/core": {
+ "version": "6.0.8",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.0.8.tgz",
+ "integrity": "sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==",
+ "dependencies": {
+ "@dnd-kit/accessibility": "^3.0.0",
+ "@dnd-kit/utilities": "^3.2.1",
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@dnd-kit/sortable": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-7.0.2.tgz",
+ "integrity": "sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==",
+ "dependencies": {
+ "@dnd-kit/utilities": "^3.2.0",
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "@dnd-kit/core": "^6.0.7",
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/@dnd-kit/utilities": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.1.tgz",
+ "integrity": "sha512-OOXqISfvBw/1REtkSK2N3Fi2EQiLMlWUlqnOK/UpOISqBZPWpE6TqL+jcPtMOkE8TqYGiURvRdPSI9hltNUjEA==",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
"node_modules/@editorjs/editorjs": {
"version": "2.24.3",
"license": "Apache-2.0",
@@ -8790,18 +8839,6 @@
"react-dom": "^16.8.0 || 17.x"
}
},
- "node_modules/@react-dnd/asap": {
- "version": "4.0.0",
- "license": "MIT"
- },
- "node_modules/@react-dnd/invariant": {
- "version": "2.0.0",
- "license": "MIT"
- },
- "node_modules/@react-dnd/shallowequal": {
- "version": "2.0.0",
- "license": "MIT"
- },
"node_modules/@react-editor-js/client": {
"version": "2.0.6",
"dependencies": {
@@ -20161,16 +20198,6 @@
"react-sortable-hoc": "*"
}
},
- "node_modules/@types/react-sortable-tree": {
- "version": "0.3.15",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/react": "*",
- "@types/react-virtualized": "*",
- "react-dnd": "^11.1.3"
- }
- },
"node_modules/@types/react-transition-group": {
"version": "4.4.1",
"license": "MIT",
@@ -20178,15 +20205,6 @@
"@types/react": "*"
}
},
- "node_modules/@types/react-virtualized": {
- "version": "9.21.21",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/prop-types": "*",
- "@types/react": "^17"
- }
- },
"node_modules/@types/react/node_modules/csstype": {
"version": "3.1.1",
"license": "MIT"
@@ -25075,15 +25093,6 @@
"node": ">=8"
}
},
- "node_modules/dnd-core": {
- "version": "11.1.3",
- "license": "MIT",
- "dependencies": {
- "@react-dnd/asap": "^4.0.0",
- "@react-dnd/invariant": "^2.0.0",
- "redux": "^4.0.4"
- }
- },
"node_modules/doctrine": {
"version": "3.0.0",
"devOptional": true,
@@ -28743,47 +28752,6 @@
"js-yaml": "^3.13.1"
}
},
- "node_modules/frontend-collective-react-dnd-scrollzone": {
- "version": "1.0.2",
- "license": "MIT",
- "dependencies": {
- "hoist-non-react-statics": "^3.1.0",
- "lodash.throttle": "^4.0.1",
- "prop-types": "^15.5.9",
- "raf": "^3.2.0",
- "react": "^16.3.0",
- "react-display-name": "^0.2.0",
- "react-dom": "^16.3.0"
- },
- "peerDependencies": {
- "react-dnd": "^7.3.0"
- }
- },
- "node_modules/frontend-collective-react-dnd-scrollzone/node_modules/react": {
- "version": "16.14.0",
- "license": "MIT",
- "dependencies": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1",
- "prop-types": "^15.6.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/frontend-collective-react-dnd-scrollzone/node_modules/react-dom": {
- "version": "16.14.0",
- "license": "MIT",
- "dependencies": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1",
- "prop-types": "^15.6.2",
- "scheduler": "^0.19.1"
- },
- "peerDependencies": {
- "react": "^16.14.0"
- }
- },
"node_modules/fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@@ -33560,7 +33528,8 @@
},
"node_modules/lodash.isequal": {
"version": "4.5.0",
- "license": "MIT"
+ "license": "MIT",
+ "optional": true
},
"node_modules/lodash.isfunction": {
"version": "3.0.9",
@@ -33633,10 +33602,6 @@
"integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==",
"dev": true
},
- "node_modules/lodash.throttle": {
- "version": "4.1.1",
- "license": "MIT"
- },
"node_modules/lodash.topairs": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.topairs/-/lodash.topairs-4.3.0.tgz",
@@ -36757,7 +36722,8 @@
},
"node_modules/performance-now": {
"version": "2.1.0",
- "license": "MIT"
+ "license": "MIT",
+ "optional": true
},
"node_modules/picocolors": {
"version": "1.0.0",
@@ -37550,13 +37516,6 @@
"integrity": "sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg==",
"dev": true
},
- "node_modules/raf": {
- "version": "3.4.1",
- "license": "MIT",
- "dependencies": {
- "performance-now": "^2.1.0"
- }
- },
"node_modules/ramda": {
"version": "0.29.0",
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.29.0.tgz",
@@ -37633,27 +37592,6 @@
"version": "0.2.5",
"license": "MIT"
},
- "node_modules/react-dnd": {
- "version": "11.1.3",
- "license": "MIT",
- "dependencies": {
- "@react-dnd/shallowequal": "^2.0.0",
- "@types/hoist-non-react-statics": "^3.3.1",
- "dnd-core": "^11.1.3",
- "hoist-non-react-statics": "^3.3.0"
- },
- "peerDependencies": {
- "react": ">= 16.9.0",
- "react-dom": ">= 16.9.0"
- }
- },
- "node_modules/react-dnd-html5-backend": {
- "version": "11.1.3",
- "license": "MIT",
- "dependencies": {
- "dnd-core": "^11.1.3"
- }
- },
"node_modules/react-docgen": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-6.0.4.tgz",
@@ -37988,10 +37926,6 @@
"url": "https://opencollective.com/jss"
}
},
- "node_modules/react-lifecycles-compat": {
- "version": "3.0.4",
- "license": "MIT"
- },
"node_modules/react-moment": {
"version": "1.1.1",
"license": "MIT",
@@ -38179,24 +38113,6 @@
"react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0"
}
},
- "node_modules/react-sortable-tree": {
- "version": "2.8.0",
- "license": "MIT",
- "dependencies": {
- "frontend-collective-react-dnd-scrollzone": "^1.0.2",
- "lodash.isequal": "^4.5.0",
- "prop-types": "^15.6.1",
- "react-dnd": "^11.1.3",
- "react-dnd-html5-backend": "^11.1.3",
- "react-lifecycles-compat": "^3.0.4",
- "react-virtualized": "^9.21.2"
- },
- "peerDependencies": {
- "react": "^16.3.0",
- "react-dnd": "^7.3.0",
- "react-dom": "^16.3.0"
- }
- },
"node_modules/react-style-singleton": {
"version": "2.2.1",
"license": "MIT",
@@ -38232,22 +38148,6 @@
"react-dom": ">=16.6.0"
}
},
- "node_modules/react-virtualized": {
- "version": "9.22.3",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "clsx": "^1.0.4",
- "dom-helpers": "^5.1.3",
- "loose-envify": "^1.4.0",
- "prop-types": "^15.7.2",
- "react-lifecycles-compat": "^3.0.4"
- },
- "peerDependencies": {
- "react": "^15.3.0 || ^16.0.0-alpha",
- "react-dom": "^15.3.0 || ^16.0.0-alpha"
- }
- },
"node_modules/read-pkg": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
@@ -38429,14 +38329,6 @@
"node": ">=8"
}
},
- "node_modules/redux": {
- "version": "4.0.5",
- "license": "MIT",
- "dependencies": {
- "loose-envify": "^1.4.0",
- "symbol-observable": "^1.2.0"
- }
- },
"node_modules/regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -39399,14 +39291,6 @@
"node": ">=10"
}
},
- "node_modules/scheduler": {
- "version": "0.19.1",
- "license": "MIT",
- "dependencies": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1"
- }
- },
"node_modules/scuid": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/scuid/-/scuid-1.1.0.tgz",
@@ -45868,6 +45752,41 @@
"integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
"optional": true
},
+ "@dnd-kit/accessibility": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.0.1.tgz",
+ "integrity": "sha512-HXRrwS9YUYQO9lFRc/49uO/VICbM+O+ZRpFDe9Pd1rwVv2PCNkRiTZRdxrDgng/UkvdC3Re9r2vwPpXXrWeFzg==",
+ "requires": {
+ "tslib": "^2.0.0"
+ }
+ },
+ "@dnd-kit/core": {
+ "version": "6.0.8",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.0.8.tgz",
+ "integrity": "sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==",
+ "requires": {
+ "@dnd-kit/accessibility": "^3.0.0",
+ "@dnd-kit/utilities": "^3.2.1",
+ "tslib": "^2.0.0"
+ }
+ },
+ "@dnd-kit/sortable": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-7.0.2.tgz",
+ "integrity": "sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==",
+ "requires": {
+ "@dnd-kit/utilities": "^3.2.0",
+ "tslib": "^2.0.0"
+ }
+ },
+ "@dnd-kit/utilities": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.1.tgz",
+ "integrity": "sha512-OOXqISfvBw/1REtkSK2N3Fi2EQiLMlWUlqnOK/UpOISqBZPWpE6TqL+jcPtMOkE8TqYGiURvRdPSI9hltNUjEA==",
+ "requires": {
+ "tslib": "^2.0.0"
+ }
+ },
"@editorjs/editorjs": {
"version": "2.24.3",
"requires": {
@@ -49788,15 +49707,6 @@
"tslib": "^2.3.0"
}
},
- "@react-dnd/asap": {
- "version": "4.0.0"
- },
- "@react-dnd/invariant": {
- "version": "2.0.0"
- },
- "@react-dnd/shallowequal": {
- "version": "2.0.0"
- },
"@react-editor-js/client": {
"version": "2.0.6",
"requires": {
@@ -57216,29 +57126,12 @@
"react-sortable-hoc": "*"
}
},
- "@types/react-sortable-tree": {
- "version": "0.3.15",
- "dev": true,
- "requires": {
- "@types/react": "*",
- "@types/react-virtualized": "*",
- "react-dnd": "^11.1.3"
- }
- },
"@types/react-transition-group": {
"version": "4.4.1",
"requires": {
"@types/react": "*"
}
},
- "@types/react-virtualized": {
- "version": "9.21.21",
- "dev": true,
- "requires": {
- "@types/prop-types": "*",
- "@types/react": "^17"
- }
- },
"@types/resolve": {
"version": "1.17.1",
"dev": true,
@@ -60736,14 +60629,6 @@
"path-type": "^4.0.0"
}
},
- "dnd-core": {
- "version": "11.1.3",
- "requires": {
- "@react-dnd/asap": "^4.0.0",
- "@react-dnd/invariant": "^2.0.0",
- "redux": "^4.0.4"
- }
- },
"doctrine": {
"version": "3.0.0",
"devOptional": true,
@@ -63225,37 +63110,6 @@
"js-yaml": "^3.13.1"
}
},
- "frontend-collective-react-dnd-scrollzone": {
- "version": "1.0.2",
- "requires": {
- "hoist-non-react-statics": "^3.1.0",
- "lodash.throttle": "^4.0.1",
- "prop-types": "^15.5.9",
- "raf": "^3.2.0",
- "react": "^16.3.0",
- "react-display-name": "^0.2.0",
- "react-dom": "^16.3.0"
- },
- "dependencies": {
- "react": {
- "version": "16.14.0",
- "requires": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1",
- "prop-types": "^15.6.2"
- }
- },
- "react-dom": {
- "version": "16.14.0",
- "requires": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1",
- "prop-types": "^15.6.2",
- "scheduler": "^0.19.1"
- }
- }
- }
- },
"fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@@ -66532,7 +66386,8 @@
"devOptional": true
},
"lodash.isequal": {
- "version": "4.5.0"
+ "version": "4.5.0",
+ "optional": true
},
"lodash.isfunction": {
"version": "3.0.9",
@@ -66598,9 +66453,6 @@
"integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==",
"dev": true
},
- "lodash.throttle": {
- "version": "4.1.1"
- },
"lodash.topairs": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.topairs/-/lodash.topairs-4.3.0.tgz",
@@ -68723,7 +68575,8 @@
"optional": true
},
"performance-now": {
- "version": "2.1.0"
+ "version": "2.1.0",
+ "optional": true
},
"picocolors": {
"version": "1.0.0",
@@ -69287,12 +69140,6 @@
"integrity": "sha512-twwRO/ilhlG/FIgYeKGFqyHhoEhqgnKVkcmqMKi2r524gz3ZbDTcyFt38E9xjJI2vT+KbRNHVbnJ/e0I25Azwg==",
"dev": true
},
- "raf": {
- "version": "3.4.1",
- "requires": {
- "performance-now": "^2.1.0"
- }
- },
"ramda": {
"version": "0.29.0",
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.29.0.tgz",
@@ -69344,21 +69191,6 @@
"react-display-name": {
"version": "0.2.5"
},
- "react-dnd": {
- "version": "11.1.3",
- "requires": {
- "@react-dnd/shallowequal": "^2.0.0",
- "@types/hoist-non-react-statics": "^3.3.1",
- "dnd-core": "^11.1.3",
- "hoist-non-react-statics": "^3.3.0"
- }
- },
- "react-dnd-html5-backend": {
- "version": "11.1.3",
- "requires": {
- "dnd-core": "^11.1.3"
- }
- },
"react-docgen": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-6.0.4.tgz",
@@ -69592,9 +69424,6 @@
}
}
},
- "react-lifecycles-compat": {
- "version": "3.0.4"
- },
"react-moment": {
"version": "1.1.1"
},
@@ -69727,18 +69556,6 @@
"prop-types": "^15.5.7"
}
},
- "react-sortable-tree": {
- "version": "2.8.0",
- "requires": {
- "frontend-collective-react-dnd-scrollzone": "^1.0.2",
- "lodash.isequal": "^4.5.0",
- "prop-types": "^15.6.1",
- "react-dnd": "^11.1.3",
- "react-dnd-html5-backend": "^11.1.3",
- "react-lifecycles-compat": "^3.0.4",
- "react-virtualized": "^9.21.2"
- }
- },
"react-style-singleton": {
"version": "2.2.1",
"requires": {
@@ -69756,17 +69573,6 @@
"prop-types": "^15.6.2"
}
},
- "react-virtualized": {
- "version": "9.22.3",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "clsx": "^1.0.4",
- "dom-helpers": "^5.1.3",
- "loose-envify": "^1.4.0",
- "prop-types": "^15.7.2",
- "react-lifecycles-compat": "^3.0.4"
- }
- },
"read-pkg": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
@@ -69903,13 +69709,6 @@
"strip-indent": "^3.0.0"
}
},
- "redux": {
- "version": "4.0.5",
- "requires": {
- "loose-envify": "^1.4.0",
- "symbol-observable": "^1.2.0"
- }
- },
"regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -70561,13 +70360,6 @@
"xmlchars": "^2.2.0"
}
},
- "scheduler": {
- "version": "0.19.1",
- "requires": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1"
- }
- },
"scuid": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/scuid/-/scuid-1.1.0.tgz",
diff --git a/package.json b/package.json
index f2ffc211886..944f406b090 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "saleor-dashboard",
- "version": "3.18.0-dev",
+ "version": "3.19.0-dev",
"main": "src/index.tsx",
"repository": {
"type": "git",
@@ -18,6 +18,9 @@
},
"dependencies": {
"@apollo/client": "3.4.17",
+ "@dnd-kit/core": "^6.0.8",
+ "@dnd-kit/sortable": "^7.0.2",
+ "@dnd-kit/utilities": "^3.2.1",
"@editorjs/editorjs": "^2.24.3",
"@editorjs/header": "^2.6.2",
"@editorjs/image": "^2.6.2",
@@ -91,7 +94,6 @@
"react-router": "^5.0.1",
"react-router-dom": "^5.0.1",
"react-sortable-hoc": "^1.10.1",
- "react-sortable-tree": "^2.6.2",
"remark-gfm": "^3.0.1",
"slugify": "^1.4.6",
"tslib": "^2.4.1",
@@ -146,7 +148,6 @@
"@types/react-infinite-scroller": "^1.2.3",
"@types/react-router-dom": "^4.3.4",
"@types/react-sortable-hoc": "^0.7.1",
- "@types/react-sortable-tree": "^0.3.15",
"@types/url-join": "^4.0.1",
"@types/uuid": "^9.0.4",
"@types/webappsec-credential-management": "^0.5.1",
@@ -342,7 +343,6 @@
"lint": "eslint \"src/**/*.@(tsx|ts|jsx|js)\" --fix",
"lint:check-progress": "eslint-nibble \"src/**/*.@(tsx|ts|jsx|js)\"",
"postbuild": "./scripts/sentry.sh",
- "postinstall": "node scripts/patchReactVirtualized.js",
"predev": "npm run build-types",
"release": "echo $npm_package_version | xargs git tag && git push --follow-tags",
"prepare": "is-ci || husky install",
diff --git a/playwright.config.ts b/playwright.config.ts
index f0fbc93108a..d4540f0819f 100644
--- a/playwright.config.ts
+++ b/playwright.config.ts
@@ -9,8 +9,8 @@ export default defineConfig({
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
- workers: process.env.CI ? 1 : undefined,
- reporter: "html",
+ workers: process.env.CI ? 2 : undefined,
+ reporter: process.env.CI ? "blob" : "html",
timeout: 60000,
// webServer: {
// command: "npm run dev",
diff --git a/playwright/data/url.ts b/playwright/data/url.ts
index 8eeeff7f776..364a86a54c7 100644
--- a/playwright/data/url.ts
+++ b/playwright/data/url.ts
@@ -13,21 +13,21 @@ export const URL_LIST = {
draftOrders: "orders/drafts/",
giftCards: "gift-cards/",
homePage: "/",
- newPassword: "new-password/",
- navigation: "navigation/",
- orders: "orders/",
- pages: "pages/",
- pageTypes: "page-types/",
- permissionsGroups: "permission-groups/",
- plugins: "plugins/",
- products: "products/",
+ newPassword: "/new-password/",
+ navigation: "/navigation/",
+ orders: "/orders/",
+ pages: "/pages/",
+ pageTypes: "/page-types/",
+ permissionsGroups: "/permission-groups/",
+ plugins: "/plugins/",
+ products: "/products/",
productsAdd: "add?product-type-id=",
- productTypes: "product-types/",
- productTypesAdd: "product-types/add",
- sales: "discounts/sales/",
- shippingMethods: "shipping/",
- siteSettings: "site-settings/",
- staffMembers: "staff/",
+ productTypes: "/product-types/",
+ productTypesAdd: "/product-types/add",
+ sales: "/discounts/sales/",
+ shippingMethods: "/shipping/",
+ siteSettings: "/site-settings/",
+ staffMembers: "/staff/",
stripeApiPaymentMethods: "https://api.stripe.com/v1/payment_methods",
translations: "translations/",
variants: "variant/",
diff --git a/playwright/pages/loginPage.ts b/playwright/pages/loginPage.ts
index 8392bc8d3a5..41a64a7ac0e 100644
--- a/playwright/pages/loginPage.ts
+++ b/playwright/pages/loginPage.ts
@@ -37,7 +37,7 @@ export class LoginPage {
page: Page,
path: string,
) {
- await this.goto();
+ await page.goto(process.env.BASE_URL!);
await this.typeEmail(userEmail);
await this.typePassword(userPassword);
await this.clickSignInButton();
@@ -46,7 +46,7 @@ export class LoginPage {
await page.context().storageState({ path });
}
async basicUiLogin(userEmail: string, userPassword: string) {
- await this.goto();
+ await this.page.goto(process.env.BASE_URL!);
await this.typeEmail(userEmail);
await this.typePassword(userPassword);
await this.clickSignInButton();
@@ -61,12 +61,4 @@ export class LoginPage {
async clickSignInButton() {
await this.signInButton.click();
}
- async goto() {
- const BASE_URL = process.env.BASE_URL;
- const loginPageUrl =
- BASE_URL === "http://localhost:9000/"
- ? "http://localhost:9000/"
- : "/dashboard";
- await this.page.goto(loginPageUrl);
- }
}
diff --git a/playwright/tests/auth.setup.ts b/playwright/tests/auth.setup.ts
index 141bf12b3a1..a9947b65751 100644
--- a/playwright/tests/auth.setup.ts
+++ b/playwright/tests/auth.setup.ts
@@ -24,15 +24,15 @@ const unauthenticatedUserPermissionsFile =
setup("authenticate as admin", async ({ page }) => {
const loginPage = await new LoginPage(page);
await loginPage.loginAndSetStorageState(
- process.env.CYPRESS_USER_NAME!,
- process.env.CYPRESS_USER_PASSWORD!,
+ process.env.E2E_USER_NAME!,
+ process.env.E2E_USER_PASSWORD!,
page,
adminFile,
);
});
setup("unauthenticated user ", async ({ page }) => {
const loginPage = await new LoginPage(page);
- await loginPage.goto();
+ await page.goto("/");
await loginPage.resetPasswordLink.waitFor({ state: "visible" });
// End of authentication steps.
await page
@@ -43,7 +43,7 @@ setup("authenticate as user with discount permissions", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.loginAndSetStorageState(
USER_PERMISSION.discount,
- process.env.CYPRESS_PERMISSIONS_USERS_PASSWORD!,
+ process.env.E2E_PERMISSIONS_USERS_PASSWORD!,
page,
discountPermissionsFile,
);
@@ -53,7 +53,7 @@ setup("authenticate as user with orders permissions", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.loginAndSetStorageState(
USER_PERMISSION.order,
- process.env.CYPRESS_PERMISSIONS_USERS_PASSWORD!,
+ process.env.E2E_PERMISSIONS_USERS_PASSWORD!,
page,
ordersPermissionsFile,
);
@@ -62,7 +62,7 @@ setup("authenticate as user with apps permissions", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.loginAndSetStorageState(
USER_PERMISSION.app,
- process.env.CYPRESS_PERMISSIONS_USERS_PASSWORD!,
+ process.env.E2E_PERMISSIONS_USERS_PASSWORD!,
page,
appsPermissionsFile,
);
@@ -71,7 +71,7 @@ setup("authenticate as user with channels permissions", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.loginAndSetStorageState(
USER_PERMISSION.channel,
- process.env.CYPRESS_PERMISSIONS_USERS_PASSWORD!,
+ process.env.E2E_PERMISSIONS_USERS_PASSWORD!,
page,
channelsWebhooksPermissionsFile,
);
@@ -80,7 +80,7 @@ setup("authenticate as user with customer permissions", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.loginAndSetStorageState(
USER_PERMISSION.customer,
- process.env.CYPRESS_PERMISSIONS_USERS_PASSWORD!,
+ process.env.E2E_PERMISSIONS_USERS_PASSWORD!,
page,
customerWebhooksPermissionsFile,
);
@@ -89,7 +89,7 @@ setup("authenticate as user with gift cards permissions", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.loginAndSetStorageState(
USER_PERMISSION.giftCard,
- process.env.CYPRESS_PERMISSIONS_USERS_PASSWORD!,
+ process.env.E2E_PERMISSIONS_USERS_PASSWORD!,
page,
giftCardsPermissionsFile,
);
@@ -100,7 +100,7 @@ setup(
const loginPage = new LoginPage(page);
await loginPage.loginAndSetStorageState(
USER_PERMISSION.page,
- process.env.CYPRESS_PERMISSIONS_USERS_PASSWORD!,
+ process.env.E2E_PERMISSIONS_USERS_PASSWORD!,
page,
contentPermissionsFile,
);
@@ -110,7 +110,7 @@ setup("authenticate as user with plugins permissions", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.loginAndSetStorageState(
USER_PERMISSION.plugin,
- process.env.CYPRESS_PERMISSIONS_USERS_PASSWORD!,
+ process.env.E2E_PERMISSIONS_USERS_PASSWORD!,
page,
pluginPermissionsFile,
);
@@ -121,7 +121,7 @@ setup(
const loginPage = new LoginPage(page);
await loginPage.loginAndSetStorageState(
USER_PERMISSION.productTypeAndAttribute,
- process.env.CYPRESS_PERMISSIONS_USERS_PASSWORD!,
+ process.env.E2E_PERMISSIONS_USERS_PASSWORD!,
page,
productTypePermissionsFile,
);
@@ -131,7 +131,7 @@ setup("authenticate as user with settings permissions", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.loginAndSetStorageState(
USER_PERMISSION.settings,
- process.env.CYPRESS_PERMISSIONS_USERS_PASSWORD!,
+ process.env.E2E_PERMISSIONS_USERS_PASSWORD!,
page,
settingsPermissionsFile,
);
@@ -142,7 +142,7 @@ setup(
const loginPage = new LoginPage(page);
await loginPage.loginAndSetStorageState(
USER_PERMISSION.staff,
- process.env.CYPRESS_PERMISSIONS_USERS_PASSWORD!,
+ process.env.E2E_PERMISSIONS_USERS_PASSWORD!,
page,
staffMemberPermissionsFile,
);
@@ -152,7 +152,7 @@ setup("authenticate as user with shipping permissions", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.loginAndSetStorageState(
USER_PERMISSION.shipping,
- process.env.CYPRESS_PERMISSIONS_USERS_PASSWORD!,
+ process.env.E2E_PERMISSIONS_USERS_PASSWORD!,
page,
shippingPermissionsFile,
);
@@ -161,7 +161,7 @@ setup("authenticate as user with translation permissions", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.loginAndSetStorageState(
USER_PERMISSION.translations,
- process.env.CYPRESS_PERMISSIONS_USERS_PASSWORD!,
+ process.env.E2E_PERMISSIONS_USERS_PASSWORD!,
page,
translationPermissionsFile,
);
@@ -170,7 +170,7 @@ setup("authenticate as user with product permissions", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.loginAndSetStorageState(
USER_PERMISSION.product,
- process.env.CYPRESS_PERMISSIONS_USERS_PASSWORD!,
+ process.env.E2E_PERMISSIONS_USERS_PASSWORD!,
page,
productPermissionsFile,
);
diff --git a/schema.graphql b/schema.graphql
index 83f144a7402..1cbdbf620c9 100644
--- a/schema.graphql
+++ b/schema.graphql
@@ -4482,7 +4482,7 @@ type Checkout implements Node & ObjectWithMetadata {
discountName: String
"""
- Determines whether checkout prices should include taxes when displayed in a storefront.
+ Determines whether displayed prices should include taxes.
Added in Saleor 3.9.
"""
@@ -4674,6 +4674,15 @@ type Checkout implements Node & ObjectWithMetadata {
"""
user: User
+ """
+ The voucher assigned to the checkout.
+
+ Added in Saleor 3.18.
+
+ Requires one of the following permissions: MANAGE_DISCOUNTS.
+ """
+ voucher: Voucher
+
"""The code of voucher assigned to the checkout."""
voucherCode: String
}
@@ -7314,6 +7323,13 @@ type DiscountError {
"""List of products IDs which causes the error."""
products: [ID!]
+
+ """
+ List of voucher codes which causes the error.
+
+ Added in Saleor 3.18.
+ """
+ voucherCodes: [String!]
}
"""An enumeration."""
@@ -7326,6 +7342,7 @@ enum DiscountErrorCode {
NOT_FOUND
REQUIRED
UNIQUE
+ VOUCHER_ALREADY_USED
}
enum DiscountStatusEnum {
@@ -7351,7 +7368,7 @@ enum DistanceUnitsEnum {
YD
}
-"""Represents shop's domain."""
+"""Represents API domain."""
type Domain {
"""The host name of the domain."""
host: String!
@@ -7359,7 +7376,7 @@ type Domain {
"""Inform if SSL is enabled."""
sslEnabled: Boolean!
- """Shop's absolute URL."""
+ """The absolute URL of the API."""
url: String!
}
@@ -7441,6 +7458,13 @@ input DraftOrderCreateInput {
"""ID of the voucher associated with the order."""
voucher: ID
+
+ """
+ A code of the voucher associated with the order.
+
+ Added in Saleor 3.18.
+ """
+ voucherCode: String
}
"""
@@ -7537,6 +7561,13 @@ input DraftOrderInput {
"""ID of the voucher associated with the order."""
voucher: ID
+
+ """
+ A code of the voucher associated with the order.
+
+ Added in Saleor 3.18.
+ """
+ voucherCode: String
}
"""
@@ -7987,6 +8018,40 @@ enum ExportScope {
IDS
}
+"""
+Export voucher codes to csv/xlsx file.
+
+Added in Saleor 3.18.
+
+Note: this API is currently in Feature Preview and can be subject to changes at later point.
+
+Requires one of the following permissions: MANAGE_DISCOUNTS.
+
+Triggers the following webhook events:
+- VOUCHER_CODE_EXPORT_COMPLETED (async): A notification for the exported file.
+"""
+type ExportVoucherCodes {
+ errors: [ExportError!]!
+
+ """
+ The newly created export file job which is responsible for export data.
+ """
+ exportFile: ExportFile
+}
+
+input ExportVoucherCodesInput {
+ """Type of exported file."""
+ fileType: FileTypesEnum!
+
+ """List of voucher code IDs to export."""
+ ids: [ID!]
+
+ """
+ The ID of the voucher. If provided, exports all codes belonging to the voucher.
+ """
+ voucherId: ID
+}
+
"""External authentication plugin."""
type ExternalAuthentication {
"""ID of external authentication plugin."""
@@ -8183,10 +8248,24 @@ type Fulfillment implements Node & ObjectWithMetadata {
Added in Saleor 3.3.
"""
privateMetafields(keys: [String!]): Metadata
+
+ """
+ Amount of refunded shipping price.
+
+ Added in Saleor 3.14.
+ """
+ shippingRefundedAmount: Money
status: FulfillmentStatus!
"""User-friendly fulfillment status."""
statusDisplay: String
+
+ """
+ Total refunded amount assigned to this fulfillment.
+
+ Added in Saleor 3.14.
+ """
+ totalRefundedAmount: Money
trackingNumber: String!
"""Warehouse from fulfillment was fulfilled."""
@@ -13328,6 +13407,23 @@ type Mutation {
input: ExportProductsInput!
): ExportProducts
+ """
+ Export voucher codes to csv/xlsx file.
+
+ Added in Saleor 3.18.
+
+ Note: this API is currently in Feature Preview and can be subject to changes at later point.
+
+ Requires one of the following permissions: MANAGE_DISCOUNTS.
+
+ Triggers the following webhook events:
+ - VOUCHER_CODE_EXPORT_COMPLETED (async): A notification for the exported file.
+ """
+ exportVoucherCodes(
+ """Fields required to export voucher codes."""
+ input: ExportVoucherCodesInput!
+ ): ExportVoucherCodes
+
"""Prepare external authentication URL for user by custom plugin."""
externalAuthenticationUrl(
"""The data required by plugin to create external authentication url."""
@@ -15898,6 +15994,9 @@ type Mutation {
Note: this API is currently in Feature Preview and can be subject to changes at later point.
Requires one of the following permissions: MANAGE_PRODUCTS.
+
+ Triggers the following webhook events:
+ - PRODUCT_VARIANT_STOCK_UPDATED (async): A product variant stock details were updated.
"""
stockBulkUpdate(
"""Policies of error handling. DEFAULT: REJECT_EVERYTHING"""
@@ -16135,7 +16234,7 @@ type Mutation {
"""
transactionInitialize(
"""
- The expected action called for the transaction. By default, the `channel.defaultTransactionFlowStrategy` will be used. The field can be used only by app that has `HANDLE_PAYMENTS` permission.
+ The expected action called for the transaction. By default, the `channel.paymentSettings.defaultTransactionFlowStrategy` will be used.The field can be used only by app that has `HANDLE_PAYMENTS` permission.
"""
action: TransactionFlowStrategyEnum
@@ -16411,6 +16510,21 @@ type Mutation {
input: VoucherChannelListingInput!
): VoucherChannelListingUpdate
+ """
+ Deletes voucher codes.
+
+ Added in Saleor 3.18.
+
+ Requires one of the following permissions: MANAGE_DISCOUNTS.
+
+ Triggers the following webhook events:
+ - VOUCHER_UPDATED (async): A voucher was updated.
+ """
+ voucherCodeBulkDelete(
+ """List of voucher codes IDs to delete."""
+ ids: [ID!]!
+ ): VoucherCodeBulkDelete
+
"""
Creates a new voucher.
@@ -16656,7 +16770,7 @@ type Order implements Node & ObjectWithMetadata {
discounts: [OrderDiscount!]!
"""
- Determines whether checkout prices should include taxes when displayed in a storefront.
+ Determines whether displayed prices should include taxes.
Added in Saleor 3.9.
"""
@@ -16965,6 +17079,13 @@ type Order implements Node & ObjectWithMetadata {
"""
userEmail: String
voucher: Voucher
+
+ """
+ Voucher code that was used for Order.
+
+ Added in Saleor 3.18.
+ """
+ voucherCode: String
weight: Weight!
}
@@ -17179,9 +17300,7 @@ input OrderBulkCreateInput {
"""List of discounts."""
discounts: [OrderDiscountCommonInput!]
- """
- Determines whether checkout prices should include taxes, when displayed in a storefront.
- """
+ """Determines whether displayed prices should include taxes."""
displayGrossPrices: Boolean
"""External ID of the order."""
@@ -17228,9 +17347,20 @@ input OrderBulkCreateInput {
"""Customer associated with the order."""
user: OrderBulkCreateUserInput!
- """Code of a voucher associated with the order."""
+ """
+ Code of a voucher associated with the order.
+
+ DEPRECATED: this field will be removed in Saleor 3.19. Use `voucherCode` instead.
+ """
voucher: String
+ """
+ Code of a voucher associated with the order.
+
+ Added in Saleor 3.18.
+ """
+ voucherCode: String
+
"""Weight of the order in kg."""
weight: WeightScalar
}
@@ -17738,6 +17868,8 @@ enum OrderErrorCode {
INSUFFICIENT_STOCK
INVALID
INVALID_QUANTITY
+ INVALID_VOUCHER
+ INVALID_VOUCHER_CODE
NOT_AVAILABLE_IN_CHANNEL
NOT_EDITABLE
NOT_FOUND
@@ -18538,6 +18670,13 @@ type OrderLine implements Node & ObjectWithMetadata {
"""
quantityToFulfill: Int!
+ """
+ Denormalized sale ID, set when order line is created for a product variant that is on sale.
+
+ Added in Saleor 3.14.
+ """
+ saleId: ID
+
"""
Denormalized tax class of the product in this order line.
@@ -18617,6 +18756,13 @@ type OrderLine implements Node & ObjectWithMetadata {
"""
variant: ProductVariant
variantName: String!
+
+ """
+ Voucher code that was used for this order line.
+
+ Added in Saleor 3.14.
+ """
+ voucherCode: String
}
input OrderLineCreateInput {
@@ -19008,15 +19154,6 @@ type OrderSettings {
"""
automaticallyFulfillNonShippableGiftCard: Boolean!
- """
- Determine the transaction flow strategy to be used. Include the selected option in the payload sent to the payment app, as a requested action for the transaction.
-
- Added in Saleor 3.13.
-
- Note: this API is currently in Feature Preview and can be subject to changes at later point.This preview feature field will be removed in Saleor 3.17. Use `PaymentSettings.defaultTransactionFlowStrategy` instead.
- """
- defaultTransactionFlowStrategy: TransactionFlowStrategyEnum!
-
"""
The time in days after expired orders will be deleted.
@@ -19035,6 +19172,15 @@ type OrderSettings {
"""
expireOrdersAfter: Minute
+ """
+ Determine if voucher applied on draft order should be count toward voucher usage.
+
+ Added in Saleor 3.18.
+
+ Note: this API is currently in Feature Preview and can be subject to changes at later point.
+ """
+ includeDraftOrderInVoucherUsage: Boolean!
+
"""
Determine what strategy will be used to mark the order as paid. Based on the chosen option, the proper object will be created and attached to the order when it's manually marked as paid.
`PAYMENT_FLOW` - [default option] creates the `Payment` object.
@@ -19085,17 +19231,6 @@ input OrderSettingsInput {
"""
automaticallyFulfillNonShippableGiftCard: Boolean
- """
- Determine the transaction flow strategy to be used. Include the selected option in the payload sent to the payment app, as a requested action for the transaction.
-
- Added in Saleor 3.13.
-
- Note: this API is currently in Feature Preview and can be subject to changes at later point.
-
- DEPRECATED: this preview feature field will be removed in Saleor 3.17. Use `PaymentSettingsInput.defaultTransactionFlowStrategy` instead.
- """
- defaultTransactionFlowStrategy: TransactionFlowStrategyEnum
-
"""
The time in days after expired orders will be deleted.Allowed range is from 1 to 120.
@@ -19114,6 +19249,17 @@ input OrderSettingsInput {
"""
expireOrdersAfter: Minute
+ """
+ Specify whether a coupon applied to draft orders will count toward voucher usage.
+
+ Warning: when switching this setting from `false` to `true`, the vouchers will be disconnected from all draft orders.
+
+ Added in Saleor 3.18.
+
+ Note: this API is currently in Feature Preview and can be subject to changes at later point.
+ """
+ includeDraftOrderInVoucherUsage: Boolean
+
"""
Determine what strategy will be used to mark the order as paid. Based on the chosen option, the proper object will be created and attached to the order when it's manually marked as paid.
`PAYMENT_FLOW` - [default option] creates the `Payment` object.
@@ -19146,7 +19292,7 @@ input OrderSettingsUpdateInput {
automaticallyConfirmAllNewOrders: Boolean
"""
- When enabled, all non-shippable gift card orders will be fulfilled automatically. By defualt set to True.
+ When enabled, all non-shippable gift card orders will be fulfilled automatically. By default set to True.
"""
automaticallyFulfillNonShippableGiftCard: Boolean
}
@@ -20228,6 +20374,13 @@ type Payment implements Node & ObjectWithMetadata {
"""Order associated with a payment."""
order: Order
+ """
+ Informs whether this is a partial payment.
+
+ Added in Saleor 3.14.
+ """
+ partial: Boolean!
+
"""Type of method used for payment."""
paymentMethodType: String!
@@ -20250,6 +20403,13 @@ type Payment implements Node & ObjectWithMetadata {
"""
privateMetafields(keys: [String!]): Metadata
+ """
+ PSP reference of the payment.
+
+ Added in Saleor 3.14.
+ """
+ pspReference: String
+
"""Unique token associated with a payment."""
token: String!
@@ -23006,7 +23166,7 @@ type ProductPricingInfo {
discountLocalCurrency: TaxedMoney @deprecated(reason: "This field will be removed in Saleor 4.0. Always returns `null`.")
"""
- Determines whether this product's price displayed in a storefront should include taxes.
+ Determines whether displayed prices should include taxes.
Added in Saleor 3.9.
"""
@@ -30045,6 +30205,9 @@ Added in Saleor 3.13.
Note: this API is currently in Feature Preview and can be subject to changes at later point.
Requires one of the following permissions: MANAGE_PRODUCTS.
+
+Triggers the following webhook events:
+- PRODUCT_VARIANT_STOCK_UPDATED (async): A product variant stock details were updated.
"""
type StockBulkUpdate {
"""Returns how many objects were updated."""
@@ -30602,9 +30765,7 @@ type TaxConfiguration implements Node & ObjectWithMetadata {
"""List of country-specific exceptions in tax configuration."""
countries: [TaxConfigurationPerCountry!]!
- """
- Determines whether prices displayed in a storefront should include taxes.
- """
+ """Determines whether displayed prices should include taxes."""
displayGrossPrices: Boolean!
"""The ID of the object."""
@@ -30693,7 +30854,7 @@ type TaxConfigurationPerCountry {
country: CountryDisplay!
"""
- Determines whether prices displayed in a storefront should include taxes for this country.
+ Determines whether displayed prices should include taxes for this country.
"""
displayGrossPrices: Boolean!
@@ -30711,7 +30872,7 @@ input TaxConfigurationPerCountryInput {
countryCode: CountryCode!
"""
- Determines whether prices displayed in a storefront should include taxes for this country.
+ Determines whether displayed prices should include taxes for this country.
"""
displayGrossPrices: Boolean!
@@ -30761,9 +30922,7 @@ input TaxConfigurationUpdateInput {
"""Determines whether taxes are charged in the given channel."""
chargeTaxes: Boolean
- """
- Determines whether prices displayed in a storefront should include taxes.
- """
+ """Determines whether displayed prices should include taxes."""
displayGrossPrices: Boolean
"""Determines whether prices are entered with the tax included."""
@@ -32771,8 +32930,31 @@ type Voucher implements Node & ObjectWithMetadata {
"""
channelListings: [VoucherChannelListing!]
- """The code of the voucher."""
- code: String!
+ """The code of the voucher.This field will be removed in Saleor 4.0."""
+ code: String
+
+ """
+ List of codes available for this voucher.
+
+ Added in Saleor 3.18.
+ """
+ codes(
+ """Return the elements in the list that come after the specified cursor."""
+ after: String
+
+ """Return the elements in the list that come before the specified cursor."""
+ before: String
+
+ """
+ Retrieve the first n elements from the list. Note that the system only allows fetching a maximum of 100 objects in a single query.
+ """
+ first: Int
+
+ """
+ Retrieve the last n elements from the list. Note that the system only allows fetching a maximum of 100 objects in a single query.
+ """
+ last: Int
+ ): VoucherCodeCountableConnection
"""
List of collections this voucher applies to.
@@ -32888,6 +33070,15 @@ type Voucher implements Node & ObjectWithMetadata {
last: Int
): ProductCountableConnection
+ """
+ Determine if the voucher codes can be used once or multiple times.
+
+ Added in Saleor 3.18.
+
+ Note: this API is currently in Feature Preview and can be subject to changes at later point.
+ """
+ singleUse: Boolean!
+
"""The start date and time of voucher."""
startDate: DateTime!
@@ -33016,6 +33207,109 @@ type VoucherChannelListingUpdate {
voucher: Voucher
}
+"""
+Represents voucher code.
+
+Added in Saleor 3.18.
+
+Note: this API is currently in Feature Preview and can be subject to changes at later point.
+"""
+type VoucherCode {
+ """Code to use the voucher."""
+ code: String
+
+ """Date time of code creation."""
+ createdAt: DateTime!
+
+ """The ID of the voucher code."""
+ id: ID!
+
+ """Whether a code is active or not."""
+ isActive: Boolean
+
+ """Number of times a code has been used."""
+ used: Int
+}
+
+"""
+Deletes voucher codes.
+
+Added in Saleor 3.18.
+
+Requires one of the following permissions: MANAGE_DISCOUNTS.
+
+Triggers the following webhook events:
+- VOUCHER_UPDATED (async): A voucher was updated.
+"""
+type VoucherCodeBulkDelete {
+ """Returns how many codes were deleted."""
+ count: Int!
+ errors: [VoucherCodeBulkDeleteError!]!
+}
+
+type VoucherCodeBulkDeleteError {
+ """The error code."""
+ code: VoucherCodeBulkDeleteErrorCode!
+
+ """The error message."""
+ message: String
+
+ """
+ Path to field that caused the error. A value of `null` indicates that the error isn't associated with a particular field.
+ """
+ path: String
+
+ """List of voucher codes which causes the error."""
+ voucherCodes: [ID!]
+}
+
+"""An enumeration."""
+enum VoucherCodeBulkDeleteErrorCode {
+ GRAPHQL_ERROR
+ INVALID
+ NOT_FOUND
+}
+
+type VoucherCodeCountableConnection {
+ edges: [VoucherCodeCountableEdge!]!
+
+ """Pagination data for this connection."""
+ pageInfo: PageInfo!
+
+ """A total count of items in the collection."""
+ totalCount: Int
+}
+
+type VoucherCodeCountableEdge {
+ """A cursor for use in pagination."""
+ cursor: String!
+
+ """The item at the end of the edge."""
+ node: VoucherCode!
+}
+
+"""
+Event sent when voucher code export is completed.
+
+Added in Saleor 3.18.
+"""
+type VoucherCodeExportCompleted implements Event {
+ """The export file for voucher codes."""
+ export: ExportFile
+
+ """Time of the event."""
+ issuedAt: DateTime
+
+ """The user or application that triggered the event."""
+ issuingPrincipal: IssuingPrincipal
+
+ """The application receiving the webhook."""
+ recipient: App
+
+ """Saleor version that triggered the event."""
+ version: String
+}
+
type VoucherCountableConnection {
edges: [VoucherCountableEdge!]!
@@ -33129,6 +33423,15 @@ input VoucherFilterInput {
}
input VoucherInput {
+ """
+ List of codes to add.
+
+ Added in Saleor 3.18.
+
+ Note: this API is currently in Feature Preview and can be subject to changes at later point.
+ """
+ addCodes: [String!]
+
"""Voucher should be applied once per customer."""
applyOncePerCustomer: Boolean
@@ -33138,7 +33441,9 @@ input VoucherInput {
"""Categories discounted by the voucher."""
categories: [ID!]
- """Code to use the voucher."""
+ """
+ Code to use the voucher. This field will be removed in Saleor 4.0. Use `addCodes` instead.
+ """
code: String
"""Collections discounted by the voucher."""
@@ -33165,6 +33470,17 @@ input VoucherInput {
"""Products discounted by the voucher."""
products: [ID!]
+ """
+ When set to 'True', each voucher code can be used only once; otherwise, codes can be used multiple times depending on `usageLimit`.
+
+ The option can only be changed if none of the voucher codes have been used.
+
+ Added in Saleor 3.18.
+
+ Note: this API is currently in Feature Preview and can be subject to changes at later point.
+ """
+ singleUse: Boolean
+
"""Start date of the voucher in ISO 8601 format."""
startDate: DateTime
@@ -33224,7 +33540,11 @@ type VoucherRemoveCatalogues {
}
enum VoucherSortField {
- """Sort vouchers by code."""
+ """
+ Sort vouchers by code.
+
+ DEPRECATED: this field will be removed in Saleor 4.0.
+ """
CODE
"""Sort vouchers by end date."""
@@ -33237,6 +33557,13 @@ enum VoucherSortField {
"""
MINIMUM_SPENT_AMOUNT
+ """
+ Sort vouchers by name.
+
+ Added in Saleor 3.18.
+ """
+ NAME
+
"""Sort vouchers by start date."""
START_DATE
@@ -34357,7 +34684,9 @@ enum WebhookEventTypeAsyncEnum {
"""A new product variant is created."""
PRODUCT_VARIANT_CREATED
- """A product variant is deleted."""
+ """
+ A product variant is deleted. Warning: this event will not be executed when parent product has been deleted. Check PRODUCT_DELETED.
+ """
PRODUCT_VARIANT_DELETED
"""
@@ -34476,6 +34805,13 @@ enum WebhookEventTypeAsyncEnum {
"""A translation is updated."""
TRANSLATION_UPDATED
+ """
+ A voucher code export is completed.
+
+ Added in Saleor 3.18.
+ """
+ VOUCHER_CODE_EXPORT_COMPLETED
+
"""A new voucher created."""
VOUCHER_CREATED
@@ -34939,7 +35275,9 @@ enum WebhookEventTypeEnum {
"""A new product variant is created."""
PRODUCT_VARIANT_CREATED
- """A product variant is deleted."""
+ """
+ A product variant is deleted. Warning: this event will not be executed when parent product has been deleted. Check PRODUCT_DELETED.
+ """
PRODUCT_VARIANT_DELETED
"""
@@ -35091,6 +35429,13 @@ enum WebhookEventTypeEnum {
"""A translation is updated."""
TRANSLATION_UPDATED
+ """
+ A voucher code export is completed.
+
+ Added in Saleor 3.18.
+ """
+ VOUCHER_CODE_EXPORT_COMPLETED
+
"""A new voucher created."""
VOUCHER_CREATED
@@ -35338,6 +35683,7 @@ enum WebhookSampleEventTypeEnum {
TRANSACTION_ITEM_METADATA_UPDATED
TRANSLATION_CREATED
TRANSLATION_UPDATED
+ VOUCHER_CODE_EXPORT_COMPLETED
VOUCHER_CREATED
VOUCHER_DELETED
VOUCHER_METADATA_UPDATED
diff --git a/scripts/patchReactVirtualized.js b/scripts/patchReactVirtualized.js
deleted file mode 100644
index afbd9371340..00000000000
--- a/scripts/patchReactVirtualized.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/* eslint-disable @typescript-eslint/no-var-requires */
-const fs = require("fs");
-
-/*
- react-virtualized has broken ESM file, we need to patch this manually:
- Ref: https://github.com/vitejs/vite/issues/1652#issuecomment-765875146
-*/
-
-const dep =
- "node_modules/react-virtualized/dist/es/WindowScroller/utils/onScroll.js";
-const code = fs
- .readFileSync(dep, "utf-8")
- .replace(
- 'import { bpfrpt_proptype_WindowScroller } from "../WindowScroller.js";',
- "",
- );
-
-fs.writeFileSync(dep, code);
diff --git a/src/attributes/components/AttributeDetails/messages.tsx b/src/attributes/components/AttributeDetails/messages.tsx
index 603c167e0b6..9db9debca88 100644
--- a/src/attributes/components/AttributeDetails/messages.tsx
+++ b/src/attributes/components/AttributeDetails/messages.tsx
@@ -165,17 +165,22 @@ export const unitMessages = defineMessages({
});
export const units = {
+ cubicMillimeter: <>mm³>,
cubicCentimeter: <>cm³>,
cubicDecimeter: <>dm³>,
cubicMeter: <>m³>,
liter: "l",
centimeter: "cm",
+ decimeter: "dm",
meter: "m",
+ millimeter: "mm",
kilometer: "km",
gram: "g",
kilogram: "kg",
tonne: "t",
+ squareMillimeter: <>mm²>,
squareCentimeter: <>cm²>,
+ squareDecimeter: <>dm²>,
squareMeter: <>m²>,
squareKilometer: <>km²>,
cubicFoot: <>ft³>,
diff --git a/src/attributes/components/AttributeDetails/utils.ts b/src/attributes/components/AttributeDetails/utils.ts
index 65d840968f6..4e8ef2fc20f 100644
--- a/src/attributes/components/AttributeDetails/utils.ts
+++ b/src/attributes/components/AttributeDetails/utils.ts
@@ -26,17 +26,22 @@ const UNIT_MESSAGES_MAPPING = {
[MeasurementUnitsEnum.SQ_FT]: M.units.squareFt,
[MeasurementUnitsEnum.SQ_YD]: M.units.squareYd,
[MeasurementUnitsEnum.SQ_INCH]: M.units.squareInch,
+ [MeasurementUnitsEnum.CUBIC_MILLIMETER]: M.units.cubicMillimeter,
[MeasurementUnitsEnum.CUBIC_CENTIMETER]: M.units.cubicCentimeter,
[MeasurementUnitsEnum.CUBIC_DECIMETER]: M.units.cubicDecimeter,
[MeasurementUnitsEnum.CUBIC_METER]: M.units.cubicMeter,
[MeasurementUnitsEnum.LITER]: M.units.liter,
[MeasurementUnitsEnum.CM]: M.units.centimeter,
+ [MeasurementUnitsEnum.DM]: M.units.decimeter,
+ [MeasurementUnitsEnum.MM]: M.units.millimeter,
[MeasurementUnitsEnum.M]: M.units.meter,
[MeasurementUnitsEnum.KM]: M.units.kilometer,
[MeasurementUnitsEnum.G]: M.units.gram,
[MeasurementUnitsEnum.KG]: M.units.kilogram,
[MeasurementUnitsEnum.TONNE]: M.units.tonne,
+ [MeasurementUnitsEnum.SQ_MM]: M.units.squareMillimeter,
[MeasurementUnitsEnum.SQ_CM]: M.units.squareCentimeter,
+ [MeasurementUnitsEnum.SQ_DM]: M.units.squareDecimeter,
[MeasurementUnitsEnum.SQ_M]: M.units.squareMeter,
[MeasurementUnitsEnum.SQ_KM]: M.units.squareKilometer,
};
@@ -48,7 +53,7 @@ export const getMeasurementUnitMessage = (
const message = UNIT_MESSAGES_MAPPING[unit];
return typeof message === "string" || React.isValidElement(message)
? message
- : formatMessage(message);
+ : formatMessage(message as MessageDescriptor);
};
export const unitSystemChoices: Array> = [
@@ -107,13 +112,16 @@ export const unitMapping = {
},
metric: {
volume: [
+ MeasurementUnitsEnum.CUBIC_MILLIMETER,
MeasurementUnitsEnum.CUBIC_CENTIMETER,
MeasurementUnitsEnum.CUBIC_DECIMETER,
MeasurementUnitsEnum.CUBIC_METER,
MeasurementUnitsEnum.LITER,
],
distance: [
+ MeasurementUnitsEnum.MM,
MeasurementUnitsEnum.CM,
+ MeasurementUnitsEnum.DM,
MeasurementUnitsEnum.M,
MeasurementUnitsEnum.KM,
],
@@ -123,7 +131,9 @@ export const unitMapping = {
MeasurementUnitsEnum.TONNE,
],
area: [
+ MeasurementUnitsEnum.SQ_MM,
MeasurementUnitsEnum.SQ_CM,
+ MeasurementUnitsEnum.SQ_DM,
MeasurementUnitsEnum.SQ_M,
MeasurementUnitsEnum.SQ_KM,
],
diff --git a/src/auth/utils.ts b/src/auth/utils.ts
index 4c1e14ef9a7..e9c0fb9425a 100644
--- a/src/auth/utils.ts
+++ b/src/auth/utils.ts
@@ -81,6 +81,7 @@ export const handleNestedMutationErrors = ({
intl,
code: error.code,
field: error.field,
+ voucherCodes: error.voucherCodes,
}),
});
});
diff --git a/src/channels/components/ChannelDeleteDialog/ChannelDeleteDialog.tsx b/src/channels/components/ChannelDeleteDialog/ChannelDeleteDialog.tsx
index b33aa8db579..b5baf3baa15 100644
--- a/src/channels/components/ChannelDeleteDialog/ChannelDeleteDialog.tsx
+++ b/src/channels/components/ChannelDeleteDialog/ChannelDeleteDialog.tsx
@@ -14,37 +14,43 @@ import { useStyles } from "../styles";
const messages = defineMessages({
deleteChannel: {
- id: "QZoU0r",
- defaultMessage: "Delete Channel",
+ id: "LATHyi",
+ defaultMessage: "Delete Channel: {channelSlug} ",
description: "dialog header",
},
deletingAllProductData: {
- id: "Mz0cx+",
+ id: "GCho9N",
defaultMessage:
- "Deleting channel will delete all product data regarding this channel. Are you sure you want to delete this channel?",
+ "All channel settings information such as shipping, product listings, warehouse assignments, etc, will be lost.",
description: "delete channel",
},
needToBeMoved: {
- id: "sidKce",
- defaultMessage:
- "All order information from this channel need to be moved to a different channel. Please select channel orders need to be moved to:.",
+ id: "BR8au7",
+ defaultMessage: "Select channel that you wish to move existing orders to.",
description: "delete channel",
},
+ note: {
+ id: "wXFttp",
+ defaultMessage: "Note: Only channels with matching currency are available.",
+ description: "note on currency",
+ },
noAvailableChannel: {
- id: "BXMSl4",
+ id: "Ge+dUe",
defaultMessage:
- "There is no available channel to move order information to. Please create a channel with same currency so that information can be moved to it.",
+ "To delete {channelSlug} you have to create a chanel with currency: {currency} to be able to move all existing orders.",
description: "currency channel",
},
selectChannel: {
- id: "SZJhvK",
- defaultMessage: "Select Channel",
+ id: "GP0zGO",
+ defaultMessage: "Select destination channel:",
description: "dialog header",
},
});
export interface ChannelDeleteDialogProps {
channelsChoices: Choices;
+ channelSlug: string;
+ currency: string;
hasOrders: boolean;
confirmButtonState: ConfirmButtonTransitionState;
open: boolean;
@@ -55,10 +61,12 @@ export interface ChannelDeleteDialogProps {
const ChannelDeleteDialog: React.FC = ({
channelsChoices = [],
+ channelSlug,
hasOrders,
confirmButtonState,
open,
onBack,
+ currency,
onClose,
onConfirm,
}) => {
@@ -75,21 +83,32 @@ const ChannelDeleteDialog: React.FC = ({
return (
(canBeDeleted ? onConfirm(choice) : onBack())}
- title={intl.formatMessage(messages.deleteChannel)}
+ title={intl.formatMessage(messages.deleteChannel, { channelSlug })}
confirmButtonLabel={intl.formatMessage(
- canBeDeleted ? buttonMessages.delete : buttonMessages.ok,
+ canBeDeleted ? buttonMessages.delete : buttonMessages.cancel,
)}
- variant={canBeDeleted ? "delete" : "default"}
+ variant={canBeDeleted ? "delete" : "info"}
>
{hasOrders ? (
hasChannels ? (
<>
+
+ {intl.formatMessage(messages.deletingAllProductData)}
+
+
{intl.formatMessage(messages.needToBeMoved)}
+
+ {intl.formatMessage(messages.note)}
= ({
onChange={e => setChoice(e.target.value)}
/>
-
- {intl.formatMessage(messages.deletingAllProductData)}
-
>
) : (
- {intl.formatMessage(messages.noAvailableChannel)}
+ {intl.formatMessage(messages.noAvailableChannel, {
+ channelSlug: {channelSlug},
+ currency: {currency},
+ })}
)
) : (
diff --git a/src/channels/views/ChannelDetails/ChannelDetails.tsx b/src/channels/views/ChannelDetails/ChannelDetails.tsx
index 3eff4b8a405..f31775e4132 100644
--- a/src/channels/views/ChannelDetails/ChannelDetails.tsx
+++ b/src/channels/views/ChannelDetails/ChannelDetails.tsx
@@ -278,6 +278,8 @@ export const ChannelDetails: React.FC
= ({
countries={shop?.countries || []}
/>
= ({ params }) => {
{!!selectedChannel && (
;
};
@@ -42,15 +47,24 @@ const AssignAttributeValueDialog: React.FC = ({
entityType,
pages,
products,
+ attribute,
...rest
}) => {
const intl = useIntl();
+ const filteredProducts = filterProductsByAttributeValues(products, attribute);
+ const filteredPages = filterPagesByAttributeValues(pages, attribute);
+
switch (entityType) {
case AttributeEntityTypeEnum.PAGE:
return (
({ id: page.id, name: page.title }))}
+ containers={
+ filteredPages?.map(page => ({
+ id: page.id,
+ name: page.title,
+ })) ?? []
+ }
labels={{
confirmBtn: intl.formatMessage(pagesMessages.confirmBtn),
label: intl.formatMessage(pagesMessages.searchLabel),
@@ -61,9 +75,9 @@ const AssignAttributeValueDialog: React.FC = ({
/>
);
case AttributeEntityTypeEnum.PRODUCT:
- return ;
+ return ;
case AttributeEntityTypeEnum.PRODUCT_VARIANT:
- return ;
+ return ;
}
};
AssignAttributeValueDialog.displayName = "AssignAttributeValueDialog";
diff --git a/src/components/AssignAttributeValueDialog/utils.ts b/src/components/AssignAttributeValueDialog/utils.ts
new file mode 100644
index 00000000000..9fa6428fb05
--- /dev/null
+++ b/src/components/AssignAttributeValueDialog/utils.ts
@@ -0,0 +1,38 @@
+import { SearchPagesQuery, SearchProductsQuery } from "@dashboard/graphql";
+import { RelayToFlat } from "@dashboard/types";
+
+import { AttributeInput } from "../Attributes";
+
+type ProductsToFilter = RelayToFlat;
+type PagesToFilter = RelayToFlat;
+
+export const filterProductsByAttributeValues = (
+ products: ProductsToFilter,
+ attribute: AttributeInput,
+): ProductsToFilter => {
+ switch (attribute.data.entityType) {
+ case "PRODUCT":
+ return (
+ products?.filter(product => !attribute.value.includes(product.id)) ?? []
+ );
+ case "PRODUCT_VARIANT":
+ return (
+ products?.map(product => ({
+ ...product,
+ variants:
+ product.variants?.filter(
+ variant => !attribute.value.includes(variant.id),
+ ) ?? [],
+ })) ?? []
+ );
+ default:
+ return products;
+ }
+};
+
+export const filterPagesByAttributeValues = (
+ pages: PagesToFilter,
+ attribute: AttributeInput,
+): PagesToFilter => {
+ return pages?.filter(page => !attribute.value.includes(page.id)) ?? [];
+};
diff --git a/src/components/AssignContainerDialog/AssignContainerDialog.tsx b/src/components/AssignContainerDialog/AssignContainerDialog.tsx
index e1065f222af..df6245acfed 100644
--- a/src/components/AssignContainerDialog/AssignContainerDialog.tsx
+++ b/src/components/AssignContainerDialog/AssignContainerDialog.tsx
@@ -77,16 +77,21 @@ const AssignContainerDialog: React.FC = props => {
const classes = useStyles(props);
const scrollableDialogClasses = useScrollableDialogStyle({});
- const [query, onQueryChange] = useSearchQuery(onFetch);
+ const [query, onQueryChange, queryReset] = useSearchQuery(onFetch);
const [selectedContainers, setSelectedContainers] = React.useState<
Container[]
>([]);
const handleSubmit = () => onSubmit(selectedContainers);
+ const handleClose = () => {
+ queryReset();
+ onClose();
+ };
+
return (