diff --git a/.github/actions/confirm-build-ok/action.yml b/.github/actions/confirm-build-ok/action.yml new file mode 100644 index 00000000000..6e9de8f6690 --- /dev/null +++ b/.github/actions/confirm-build-ok/action.yml @@ -0,0 +1,35 @@ +name: 'Confirm build is valid' +description: 'Confirm build is valid' +inputs: + github-token: + description: The GitHub token + required: true + conclusion: + description: The conclusion of the check. failure or success + required: true +runs: + using: composite + steps: + - name: Add GitHub check + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7 + with: + github-token: ${{ inputs.github-token }} + script: | + const conclusion = '${{ inputs.conclusion }}'; // Get the conclusion input + const commitSha = + context.eventName === 'pull_request' ? + context.payload.pull_request.head.sha + : context.eventName === 'merge_group' ? + context.payload.merge_group.head_sha + : context.sha; + + const restOptions = { + owner: context.repo.owner, + repo: context.repo.repo, + sha: commitSha, + state: conclusion, // Use the conclusion input + description: `Build is a ${conclusion}`, + context: 'probot/conclusion', + }; + + github.rest.repos.createCommitStatus(restOptions) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 54e4d95fd06..76b656aef2d 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -2,7 +2,7 @@ name: 'Dependency Review' on: pull_request: - branches: ['master'] + branches: ['v2'] permissions: contents: read diff --git a/.github/workflows/masterbot.yml b/.github/workflows/masterbot.yml index 0ac29c00cf9..5ef0c16ccc0 100644 --- a/.github/workflows/masterbot.yml +++ b/.github/workflows/masterbot.yml @@ -2,8 +2,7 @@ name: Master Robot on: push: branches: - - master - - 'prerelease/**' + - v2 jobs: build: name: 'Build' diff --git a/.github/workflows/package-lock-root-fail.yml b/.github/workflows/package-lock-root-fail.yml index ebdc7f87b8f..738adea5fb0 100644 --- a/.github/workflows/package-lock-root-fail.yml +++ b/.github/workflows/package-lock-root-fail.yml @@ -2,13 +2,13 @@ name: 'package-lock.json root validator' on: push: - branches: [master] + branches: [v2] paths: - '**/package-lock.json' - '!utils/atomic-storybook/package-lock.json' - '!package-lock.json' pull_request: - branches: [master] + branches: [v2] paths: - '**/package-lock.json' - '!utils/atomic-storybook/package-lock.json' diff --git a/.github/workflows/package-lock-root-success.yml b/.github/workflows/package-lock-root-success.yml index 054e5195d33..172c4f52c0a 100644 --- a/.github/workflows/package-lock-root-success.yml +++ b/.github/workflows/package-lock-root-success.yml @@ -2,12 +2,12 @@ name: 'package-lock.json root validator' on: push: - branches: [master] + branches: [v2] paths-ignore: - '**/package-lock.json' - '!package-lock.json' pull_request: - branches: [master] + branches: [v2] paths-ignore: - '**/package-lock.json' - '!package-lock.json' diff --git a/.github/workflows/prbot.yml b/.github/workflows/prbot.yml index a5c5197fba8..358d22e21c0 100644 --- a/.github/workflows/prbot.yml +++ b/.github/workflows/prbot.yml @@ -353,15 +353,20 @@ jobs: - 'e2e-headless-ssr-test-pages-prod' runs-on: ubuntu-latest steps: - - run: | + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + - name: Determine conclusion + run: | success="${{ !contains(needs.*.result, 'cancelled') && !contains(needs.*.result, 'failure')}}" if [[ $success == "true" ]]; then - echo "Build is valid" - exit 0 + echo "conclusion=success" >> "$GITHUB_OUTPUT" else - echo "Build is invalid" - exit 1 + echo "conclusion=failure" >> "$GITHUB_OUTPUT" fi + id: determine-conclusion + - uses: ./.github/actions/confirm-build-ok + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + conclusion: ${{ steps.determine-conclusion.outputs.conclusion }} is-valid-merge-queue: name: 'Confirm build is valid (merge group)' if: ${{ always() && github.event_name == 'merge_group'}} @@ -386,29 +391,17 @@ jobs: - 'e2e-headless-ssr-test-pages-prod' runs-on: ubuntu-latest steps: - - run: | + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + - name: Determine conclusion + run: | success="${{ !contains(needs.*.result, 'cancelled') && !contains(needs.*.result, 'failure')}}" if [[ $success == "true" ]]; then - echo "Build is valid" - exit 0 - else - echo "Build is invalid" - exit 1 - fi - is-valid: - name: 'Confirm build is valid' - if: ${{ always() }} - needs: - - 'is-valid-pr' - - 'is-valid-merge-queue' - runs-on: ubuntu-latest - steps: - - run: | - success="${{ contains(needs.*.result, 'success')}}" - if [[ $success == "true" ]]; then - echo "Build is valid" - exit 0 + echo "conclusion=success" >> "$GITHUB_OUTPUT" else - echo "Build is invalid" - exit 1 + echo "conclusion=failure" >> "$GITHUB_OUTPUT" fi + id: determine-conclusion + - uses: ./.github/actions/confirm-build-ok + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + conclusion: ${{ steps.determine-conclusion.outputs.conclusion }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 257d854dca9..24e6e68fdc6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -73,32 +73,33 @@ jobs: run: npm run notify:docs env: GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} - quantic-prod: - needs: release - runs-on: ubuntu-latest - environment: 'Quantic Production' - permissions: - contents: read - packages: write - discussions: write - steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 - with: - ref: 'release/v2' - - uses: ./.github/actions/setup - - uses: ./.github/actions/setup-sfdx - - name: Promote SFDX package to production - run: | - echo "${{ secrets.SFDX_AUTH_JWT_KEY }}" > ${{ vars.SFDX_AUTH_JWT_KEY_FILE }} - npx --no-install nx run quantic:"promote:sfdx:ci" - rm ${{ vars.SFDX_AUTH_JWT_KEY_FILE }} - env: - SFDX_AUTH_CLIENT_ID: ${{ secrets.SFDX_AUTH_CLIENT_ID }} - SFDX_AUTH_JWT_KEY: ${{ secrets.SFDX_AUTH_JWT_KEY }} - SFDX_AUTH_JWT_USERNAME: ${{ vars.SFDX_AUTH_JWT_USERNAME }} - SFDX_AUTH_JWT_KEY_FILE: ${{ vars.SFDX_AUTH_JWT_KEY_FILE }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - working-directory: ./packages/quantic + # TODO SFINT-5697 + # quantic-prod: + # needs: release + # runs-on: ubuntu-latest + # environment: 'Quantic Production' + # permissions: + # contents: read + # packages: write + # discussions: write + # steps: + # - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 + # with: + # ref: 'release/v2' + # - uses: ./.github/actions/setup + # - uses: ./.github/actions/setup-sfdx + # - name: Promote SFDX package to production + # run: | + # echo "${{ secrets.SFDX_AUTH_JWT_KEY }}" > ${{ vars.SFDX_AUTH_JWT_KEY_FILE }} + # npx --no-install nx run quantic:"promote:sfdx:ci" + # rm ${{ vars.SFDX_AUTH_JWT_KEY_FILE }} + # env: + # SFDX_AUTH_CLIENT_ID: ${{ secrets.SFDX_AUTH_CLIENT_ID }} + # SFDX_AUTH_JWT_KEY: ${{ secrets.SFDX_AUTH_JWT_KEY }} + # SFDX_AUTH_JWT_USERNAME: ${{ vars.SFDX_AUTH_JWT_USERNAME }} + # SFDX_AUTH_JWT_KEY_FILE: ${{ vars.SFDX_AUTH_JWT_KEY_FILE }} + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # working-directory: ./packages/quantic # TODO KIT-3074 Fix the publication into the GitHub Packages, and uncomment # github-prod: diff --git a/nx.json b/nx.json index a3ab67db235..10da6340e57 100644 --- a/nx.json +++ b/nx.json @@ -129,7 +129,7 @@ ] } }, - "defaultBase": "master", + "defaultBase": "v2", "$schema": "./node_modules/nx/schemas/nx-schema.json", "useInferencePlugins": false } diff --git a/package-lock.json b/package-lock.json index 639a98e9efa..d03ca2c2e8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2677,11 +2677,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.9.tgz", + "integrity": "sha512-z88xeGxnzehn2sqZ8UdGQEvYErF1odv2CftxInpSYJt6uHuPe9YjahKZITGs3l5LeI9d2ROG+obuDAoSlqbNfQ==", + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.7", + "@babel/highlight": "^7.25.9", "picocolors": "^1.0.0" }, "engines": { @@ -3146,17 +3147,18 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -3199,11 +3201,12 @@ } }, "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz", + "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==", + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", + "@babel/helper-validator-identifier": "^7.25.9", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -3213,9 +3216,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.0.tgz", - "integrity": "sha512-CzdIU9jdP0dg7HdyB+bHvDJGagUv+qtzZt5rYCWwW6tITNqV9odjp6Qu41gkG0ca5UfdDUWrKkiAnHHdGRnOrA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.9.tgz", + "integrity": "sha512-aI3jjAAO1fh7vY/pBGsn1i9LDbRP43+asrRlkPuTXW5yHXtd1NgTEMudbBoDDxrf1daEEfPJqR+JBMakzrR4Dg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -5037,28 +5044,30 @@ } }, "node_modules/@babel/template": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", - "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.0.tgz", - "integrity": "sha512-ubALThHQy4GCf6mbb+5ZRNmLLCI7bJ3f8Q6LHBSRlSKSWj5a7dSUzJBLv3VuIhFrFPgjF4IzPF567YG/HSCdZA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.0", + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -5067,27 +5076,40 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", - "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.9.tgz", + "integrity": "sha512-omlUGkr5EaoIJrhLf9CJ0TvjBRpd9+AXRG//0GEQ9THSo8wPiTlbpy1/Ow8ZTrbXpjd9FHXfbFQx32I04ht0FA==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.25.0", + "@babel/types": "^7.25.9", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/traverse/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@babel/types": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.0.tgz", - "integrity": "sha512-LcnxQSsd9aXOIgmmSpvZ/1yo46ra2ESYyqLcryaBZOghxy5qqOBjvCWP5JfkI8yl9rlxRgdLTTMCQQRcN2hdCg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.9.tgz", + "integrity": "sha512-OwS2CM5KocvQ/k7dFJa8i5bNGJP0hXWfVCfDkqRFP1IreH1JDC7wG6eCYCi0+McbfT8OR/kNqsI0UU0xP9H6PQ==", + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -26525,6 +26547,37 @@ "typescript": ">=4" } }, + "node_modules/coveo.analytics": { + "version": "2.30.38", + "resolved": "https://registry.npmjs.org/coveo.analytics/-/coveo.analytics-2.30.38.tgz", + "integrity": "sha512-CxiBWV7XxDNAyCWS7gwikHjJYz8NigYVHSkGU23JkcQf2oK0XJEsxcU/eRN3VRBfLLmhBTRZbpWJ1SW2imDovQ==", + "dependencies": { + "@types/uuid": "^9.0.0", + "cross-fetch": "^3.1.5", + "react-native-get-random-values": "^1.11.0", + "uuid": "^9.0.0" + } + }, + "node_modules/coveo.analytics/node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/coveo.analytics/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -45375,9 +45428,10 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -50572,9 +50626,10 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -52439,6 +52494,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, "engines": { "node": ">=4" } @@ -55808,10 +55864,10 @@ }, "packages/atomic": { "name": "@coveo/atomic", - "version": "2.78.0", + "version": "2.78.3", "license": "Apache-2.0", "dependencies": { - "@coveo/bueno": "0.46.1", + "@coveo/bueno": "0.46.3", "@popperjs/core": "^2.11.6", "@salesforce-ux/design-system": "^2.16.1", "@stencil/store": "2.0.16", @@ -55830,7 +55886,7 @@ "@axe-core/playwright": "4.9.1", "@babel/core": "7.24.9", "@coveo/atomic": "file:.", - "@coveo/headless": "2.80.0", + "@coveo/headless": "2.80.3", "@coveo/release": "1.0.0", "@custom-elements-manifest/analyzer": "0.10.3", "@fullhuman/postcss-purgecss": "6.0.0", @@ -55907,7 +55963,7 @@ "node": ">=12.9.0" }, "peerDependencies": { - "@coveo/headless": "2.80.0" + "@coveo/headless": "2.80.3" } }, "packages/atomic-angular": { @@ -55922,14 +55978,14 @@ "@angular/platform-browser": "17.3.12", "@angular/platform-browser-dynamic": "17.3.12", "@angular/router": "17.3.12", - "@coveo/atomic": "2.78.0", + "@coveo/atomic": "2.78.3", "rxjs": "7.8.1" }, "devDependencies": { "@angular-devkit/build-angular": "17.3.8", "@angular/cli": "17.3.8", "@angular/compiler-cli": "17.3.12", - "@coveo/headless": "2.80.0", + "@coveo/headless": "2.80.3", "@types/jasmine": "5.1.4", "@types/node": "20.14.12", "jasmine-core": "5.2.0", @@ -55943,7 +55999,7 @@ "typescript": "5.4.5" }, "peerDependencies": { - "@coveo/headless": "2.80.0" + "@coveo/headless": "2.80.3" } }, "packages/atomic-angular/node_modules/jasmine-core": { @@ -55972,25 +56028,25 @@ }, "packages/atomic-angular/projects/atomic-angular": { "name": "@coveo/atomic-angular", - "version": "2.28.0", + "version": "2.28.3", "license": "Apache-2.0", "dependencies": { - "@coveo/atomic": "2.78.0", + "@coveo/atomic": "2.78.3", "tslib": "2.6.3" }, "peerDependencies": { "@angular/common": "14 - 17", "@angular/core": "14 - 17", - "@coveo/headless": "2.80.0" + "@coveo/headless": "2.80.3" } }, "packages/atomic-hosted-page": { "name": "@coveo/atomic-hosted-page", - "version": "0.6.7", + "version": "1.0.9", "license": "Apache-2.0", "dependencies": { - "@coveo/bueno": "0.46.1", - "@coveo/headless": "2.80.0", + "@coveo/bueno": "0.46.3", + "@coveo/headless": "2.80.3", "@stencil/core": "4.20.0" }, "devDependencies": { @@ -56069,12 +56125,12 @@ }, "packages/atomic-react": { "name": "@coveo/atomic-react", - "version": "2.14.0", + "version": "2.14.3", "dependencies": { - "@coveo/atomic": "2.78.0" + "@coveo/atomic": "2.78.3" }, "devDependencies": { - "@coveo/headless": "2.80.0", + "@coveo/headless": "2.80.3", "@coveo/release": "1.0.0", "@rollup/plugin-commonjs": "^25.0.0", "@rollup/plugin-node-resolve": "^15.0.0", @@ -56091,7 +56147,7 @@ "rollup-plugin-polyfill-node": "^0.13.0" }, "peerDependencies": { - "@coveo/headless": "2.80.0", + "@coveo/headless": "2.80.3", "react": ">=18.0.0", "react-dom": ">=18.0.0" } @@ -58567,7 +58623,7 @@ }, "packages/auth": { "name": "@coveo/auth", - "version": "1.11.22", + "version": "1.11.24", "license": "Apache-2.0", "devDependencies": { "@coveo/release": "1.0.0", @@ -59167,7 +59223,7 @@ }, "packages/bueno": { "name": "@coveo/bueno", - "version": "0.46.1", + "version": "0.46.3", "license": "Apache-2.0", "devDependencies": { "@coveo/release": "1.0.0", @@ -59225,17 +59281,17 @@ }, "packages/headless": { "name": "@coveo/headless", - "version": "2.80.0", + "version": "2.80.3", "license": "Apache-2.0", "dependencies": { - "@coveo/bueno": "0.46.1", + "@coveo/bueno": "0.46.3", "@coveo/relay": "0.7.10", "@coveo/relay-event-types": "9.4.0", "@microsoft/fetch-event-source": "2.0.1", "@reduxjs/toolkit": "2.2.7", "abab": "2.0.6", "abortcontroller-polyfill": "1.7.5", - "coveo.analytics": "2.30.26", + "coveo.analytics": "2.30.38", "dayjs": "1.11.12", "exponential-backoff": "3.1.0", "fast-equals": "5.0.1", @@ -59268,10 +59324,10 @@ }, "packages/headless-react": { "name": "@coveo/headless-react", - "version": "1.1.4", + "version": "1.1.7", "license": "Apache-2.0", "dependencies": { - "@coveo/headless": "2.80.0" + "@coveo/headless": "2.80.3" }, "devDependencies": { "@coveo/release": "1.0.0", @@ -59603,25 +59659,6 @@ } } }, - "packages/headless/node_modules/coveo.analytics": { - "version": "2.30.26", - "resolved": "https://registry.npmjs.org/coveo.analytics/-/coveo.analytics-2.30.26.tgz", - "integrity": "sha512-HeKmwt254jHws2w7nCklKa8VCo0vnmZGv79/rXqJcNZraig5XQxBQoLbpphP3/L+SoP4F/m5nAOdE1C0QbaSuQ==", - "dependencies": { - "@types/uuid": "^9.0.0", - "cross-fetch": "^3.1.5", - "react-native-get-random-values": "^1.11.0", - "uuid": "^9.0.0" - } - }, - "packages/headless/node_modules/cross-fetch": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", - "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", - "dependencies": { - "node-fetch": "^2.6.12" - } - }, "packages/headless/node_modules/dayjs": { "version": "1.11.12", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz", @@ -59826,12 +59863,12 @@ }, "packages/quantic": { "name": "@coveo/quantic", - "version": "2.57.1", + "version": "2.57.4", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@coveo/bueno": "0.46.1", - "@coveo/headless": "2.80.0", + "@coveo/bueno": "0.46.3", + "@coveo/headless": "2.80.3", "dompurify": "3.1.6", "marked": "12.0.2" }, @@ -61528,7 +61565,7 @@ "@angular/platform-browser": "17.3.12", "@angular/platform-browser-dynamic": "17.3.12", "@angular/router": "17.3.12", - "@coveo/atomic-angular": "2.28.0", + "@coveo/atomic-angular": "2.28.3", "rxjs": "7.8.1", "tslib": "2.6.3", "zone.js": "0.14.8" @@ -61829,9 +61866,9 @@ "name": "@coveo/atomic-next-samples", "version": "0.0.0", "dependencies": { - "@coveo/atomic": "2.78.0", - "@coveo/atomic-react": "2.14.0", - "@coveo/headless": "2.80.0", + "@coveo/atomic": "2.78.3", + "@coveo/atomic-react": "2.14.3", + "@coveo/headless": "2.80.3", "next": "14.2.5", "react": "18.3.1", "react-dom": "18.3.1" @@ -61894,9 +61931,9 @@ "name": "@coveo/atomic-react-samples", "version": "0.0.0", "dependencies": { - "@coveo/atomic": "2.78.0", - "@coveo/atomic-react": "2.14.0", - "@coveo/headless": "2.80.0", + "@coveo/atomic": "2.78.3", + "@coveo/atomic-react": "2.14.3", + "@coveo/headless": "2.80.3", "react": "18.3.1", "react-dom": "18.3.1" }, @@ -62384,7 +62421,7 @@ "name": "@coveo/headless-commerce-react-samples", "version": "0.1.0", "dependencies": { - "@coveo/headless": "2.80.0", + "@coveo/headless": "2.80.3", "@testing-library/jest-dom": "6.4.8", "@testing-library/react": "16.0.0", "@testing-library/user-event": "14.5.2", @@ -64851,8 +64888,8 @@ "name": "@coveo/headless-react-samples", "version": "0.0.0", "dependencies": { - "@coveo/auth": "1.11.22", - "@coveo/headless": "2.80.0", + "@coveo/auth": "1.11.24", + "@coveo/headless": "2.80.3", "@testing-library/jest-dom": "6.4.8", "@testing-library/react": "14.3.1", "@testing-library/user-event": "14.5.2", @@ -68518,8 +68555,8 @@ "name": "@coveo/headless-ssr-samples-common", "version": "0.0.0", "dependencies": { - "@coveo/headless": "2.80.0", - "@coveo/headless-react": "1.1.4", + "@coveo/headless": "2.80.3", + "@coveo/headless-react": "1.1.7", "next": "14.2.5", "react": "^18.2.0", "react-dom": "^18.2.0" @@ -68543,7 +68580,7 @@ "name": "@coveo/headless-ssr-commerce-samples", "version": "0.0.0", "dependencies": { - "@coveo/headless": "2.80.0", + "@coveo/headless": "2.80.3", "next": "14.2.5", "react": "^18.2.0", "react-dom": "^18.2.0" @@ -68662,10 +68699,10 @@ "version": "0.1.0", "dependencies": { "@babel/standalone": "7.25.0", - "@coveo/atomic": "2.78.0", - "@coveo/atomic-hosted-page": "0.6.7", - "@coveo/atomic-react": "2.14.0", - "@coveo/headless": "2.80.0", + "@coveo/atomic": "2.78.3", + "@coveo/atomic-hosted-page": "1.0.9", + "@coveo/atomic-react": "2.14.3", + "@coveo/headless": "2.80.3", "react": "18.3.1", "react-dom": "18.3.1" }, @@ -68734,8 +68771,8 @@ "name": "@coveo/atomic-stencil-samples", "version": "0.0.0", "dependencies": { - "@coveo/atomic": "2.78.0", - "@coveo/headless": "2.80.0", + "@coveo/atomic": "2.78.3", + "@coveo/headless": "2.80.3", "@stencil/core": "4.20.0", "stencil-router-v2": "0.6.0" }, @@ -69018,7 +69055,7 @@ "name": "@coveo/atomic-vuejs-samples", "version": "0.0.0", "dependencies": { - "@coveo/atomic": "2.78.0", + "@coveo/atomic": "2.78.3", "vue": "^3.4.15" }, "devDependencies": { diff --git a/package.json b/package.json index 7393571ceaf..f17f9fe5f13 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "private": true, "scripts": { "postinstall": "husky install && patch-package && npx playwright install", - "reset:install": "git checkout origin/master package-lock.json && npm i", + "reset:install": "git checkout origin/v2 package-lock.json && npm i", "clean:install": "git clean -xfd && npm run reset:install", "dev:atomic": "concurrently \"npm run -w @coveo/headless dev\" \"npm run -w @coveo/atomic start\"", "build": "nx run-many --target=build", diff --git a/packages/atomic-angular/package.json b/packages/atomic-angular/package.json index bb5a9f5a691..75dd7310bee 100644 --- a/packages/atomic-angular/package.json +++ b/packages/atomic-angular/package.json @@ -20,17 +20,17 @@ "@angular/platform-browser": "17.3.12", "@angular/platform-browser-dynamic": "17.3.12", "@angular/router": "17.3.12", - "@coveo/atomic": "2.78.0", + "@coveo/atomic": "2.78.3", "rxjs": "7.8.1" }, "peerDependencies": { - "@coveo/headless": "2.80.0" + "@coveo/headless": "2.80.3" }, "devDependencies": { "@angular-devkit/build-angular": "17.3.8", "@angular/cli": "17.3.8", "@angular/compiler-cli": "17.3.12", - "@coveo/headless": "2.80.0", + "@coveo/headless": "2.80.3", "@types/jasmine": "5.1.4", "@types/node": "20.14.12", "jasmine-core": "5.2.0", diff --git a/packages/atomic-angular/projects/atomic-angular/CHANGELOG.md b/packages/atomic-angular/projects/atomic-angular/CHANGELOG.md index 061da079dcf..97b35ff434c 100644 --- a/packages/atomic-angular/projects/atomic-angular/CHANGELOG.md +++ b/packages/atomic-angular/projects/atomic-angular/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.28.3 (2024-10-22) + +## 2.28.1 (2024-08-29) + # 2.28.0 (2024-08-27) ### Features diff --git a/packages/atomic-angular/projects/atomic-angular/package.json b/packages/atomic-angular/projects/atomic-angular/package.json index 58f450308bd..3f058a428ed 100644 --- a/packages/atomic-angular/projects/atomic-angular/package.json +++ b/packages/atomic-angular/projects/atomic-angular/package.json @@ -1,6 +1,6 @@ { "name": "@coveo/atomic-angular", - "version": "2.28.0", + "version": "2.28.3", "license": "Apache-2.0", "repository": { "url": "https://github.com/coveo/ui-kit" @@ -8,10 +8,10 @@ "peerDependencies": { "@angular/common": "14 - 17", "@angular/core": "14 - 17", - "@coveo/headless": "2.80.0" + "@coveo/headless": "2.80.3" }, "dependencies": { - "@coveo/atomic": "2.78.0", + "@coveo/atomic": "2.78.3", "tslib": "2.6.3" } } diff --git a/packages/atomic-angular/projects/atomic-angular/project.json b/packages/atomic-angular/projects/atomic-angular/project.json index 3fdd499c3a8..cb7e638b35e 100644 --- a/packages/atomic-angular/projects/atomic-angular/project.json +++ b/packages/atomic-angular/projects/atomic-angular/project.json @@ -9,7 +9,7 @@ "outputs": [], "executor": "nx:run-commands", "options": { - "command": "node ../../../../scripts/deploy/update-npm-tag.mjs latest", + "command": "npm run-script -w=@coveo/release promote-npm-prod", "cwd": "packages/atomic-angular/projects/atomic-angular" } } diff --git a/packages/atomic-hosted-page/CHANGELOG.md b/packages/atomic-hosted-page/CHANGELOG.md index 20bb9f27d24..fd3e3ecc12c 100644 --- a/packages/atomic-hosted-page/CHANGELOG.md +++ b/packages/atomic-hosted-page/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.6.9 (2024-09-16) + +## 0.6.8 (2024-08-29) + ## 0.6.3 (2024-08-07) ## 0.6.2 (2024-07-31) diff --git a/packages/atomic-hosted-page/package.json b/packages/atomic-hosted-page/package.json index 4d90b2f25ae..35a282020fd 100644 --- a/packages/atomic-hosted-page/package.json +++ b/packages/atomic-hosted-page/package.json @@ -1,7 +1,7 @@ { "name": "@coveo/atomic-hosted-page", "description": "Web Component used to inject a Coveo Hosted Search Page in the DOM.", - "version": "0.6.7", + "version": "1.0.9", "repository": { "type": "git", "url": "git+https://github.com/coveo/ui-kit.git", @@ -27,11 +27,11 @@ "validate:definitions": "tsc --noEmit --esModuleInterop --skipLibCheck ./dist/types/components.d.ts", "publish:npm": "npm run-script -w=@coveo/release npm-publish", "publish:bump": "npm run-script -w=@coveo/release bump", - "promote:npm:latest": "node ../../scripts/deploy/update-npm-tag.mjs latest" + "promote:npm:latest": "npm run-script -w=@coveo/release promote-npm-prod" }, "dependencies": { - "@coveo/bueno": "0.46.1", - "@coveo/headless": "2.80.0", + "@coveo/bueno": "0.46.3", + "@coveo/headless": "2.80.3", "@stencil/core": "4.20.0" }, "devDependencies": { diff --git a/packages/atomic-hosted-page/src/components/utils/options-utils.ts b/packages/atomic-hosted-page/src/components/utils/options-utils.ts index a073633e203..9a41781d4e9 100644 --- a/packages/atomic-hosted-page/src/components/utils/options-utils.ts +++ b/packages/atomic-hosted-page/src/components/utils/options-utils.ts @@ -23,7 +23,7 @@ export interface InitializationOptions { * * For example: `https://orgid.admin.org.coveo.com` * - * The [getOrganizationEndpoints](https://github.com/coveo/ui-kit/blob/master/packages/headless/src/api/platform-client.ts) helper function can be useful to create the appropriate object. + * The [getOrganizationEndpoints](https://github.com/coveo/ui-kit/blob/v2/packages/headless/src/api/platform-client.ts) helper function can be useful to create the appropriate object. * * We recommend using this option, since it has resiliency benefits and simplifies the overall configuration for multi-region deployments. */ diff --git a/packages/atomic-react/CHANGELOG.md b/packages/atomic-react/CHANGELOG.md index 2d1cd4c28b1..7b78fe244df 100644 --- a/packages/atomic-react/CHANGELOG.md +++ b/packages/atomic-react/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2.14.2 (2024-09-16) + +## 2.14.1 (2024-08-29) + +### Bug Fixes + +- **atomic-react:** deprecate analytics from atomic search interface ([#4342](https://github.com/coveo/ui-kit/issues/4342)) ([fbb90fb](https://github.com/coveo/ui-kit/commits/fbb90fbdc8ebd410ffbf41711cbfef1b62b705c0)), closes [#4348](https://github.com/coveo/ui-kit/issues/4348) + # 2.14.0 (2024-08-27) ### Features diff --git a/packages/atomic-react/package.json b/packages/atomic-react/package.json index cbfe483b818..93b7eee9fbd 100644 --- a/packages/atomic-react/package.json +++ b/packages/atomic-react/package.json @@ -1,7 +1,7 @@ { "name": "@coveo/atomic-react", "sideEffects": false, - "version": "2.14.0", + "version": "2.14.3", "description": "React specific wrapper for the Atomic component library", "repository": { "type": "git", @@ -17,7 +17,7 @@ "build:bundles": "concurrently \"npm run build:bundles:esm\" \"npm run build:bundles:cjs\" \"npm run build:bundles:iife\"", "publish:npm": "npm run-script -w=@coveo/release npm-publish", "publish:bump": "npm run-script -w=@coveo/release bump", - "promote:npm:latest": "node ../../scripts/deploy/update-npm-tag.mjs latest", + "promote:npm:latest": "npm run-script -w=@coveo/release promote-npm-prod", "build:assets": "ncp ../atomic/dist/atomic/assets dist/assets && ncp ../atomic/dist/atomic/lang dist/lang " }, "main": "./dist/cjs/index.js", @@ -29,11 +29,11 @@ "commerce/" ], "dependencies": { - "@coveo/atomic": "2.78.0" + "@coveo/atomic": "2.78.3" }, "devDependencies": { "@coveo/release": "1.0.0", - "@coveo/headless": "2.80.0", + "@coveo/headless": "2.80.3", "@rollup/plugin-commonjs": "^25.0.0", "@rollup/plugin-node-resolve": "^15.0.0", "@rollup/plugin-replace": "^5.0.0", @@ -49,7 +49,7 @@ "@rollup/plugin-terser": "0.4.4" }, "peerDependencies": { - "@coveo/headless": "2.80.0", + "@coveo/headless": "2.80.3", "react": ">=18.0.0", "react-dom": ">=18.0.0" } diff --git a/packages/atomic-react/src/components/search/SearchInterfaceWrapper.tsx b/packages/atomic-react/src/components/search/SearchInterfaceWrapper.tsx index 9cade2b5225..fbe2a1fb7b7 100644 --- a/packages/atomic-react/src/components/search/SearchInterfaceWrapper.tsx +++ b/packages/atomic-react/src/components/search/SearchInterfaceWrapper.tsx @@ -11,7 +11,10 @@ type ExecuteSearch = HTMLAtomicSearchInterfaceElement['executeFirstSearch']; * The properties of the AtomicSearchInterface component */ interface WrapperProps - extends Omit { + extends Omit< + JSX.AtomicSearchInterface, + 'i18n' | 'pipeline' | 'searchHub' | 'analytics' + > { /** * An optional callback function that can be used to control the execution of the first query. * @@ -33,6 +36,10 @@ interface WrapperProps * @deprecated This option has no effect. Rather, set the search hub through the `engine` `search` configuration. */ searchHub?: string; + /** + * @deprecated This option has no effect. Rather, set the analytics through the `engine` `analytics` `enabled` configuration. + */ + analytics?: boolean; } const DefaultProps: Required> = { diff --git a/packages/atomic/CHANGELOG.md b/packages/atomic/CHANGELOG.md index 402186acb0f..bf23730a52a 100644 --- a/packages/atomic/CHANGELOG.md +++ b/packages/atomic/CHANGELOG.md @@ -1,3 +1,23 @@ +## 2.78.3 (2024-10-22) + +### Bug Fixes + +- **atomic,quantic:** broken HTML because of formatting in CRGA markdown heading ([#4564](https://github.com/coveo/ui-kit/issues/4564)) ([9fd1f95](https://github.com/coveo/ui-kit/commits/9fd1f95ca50fb57a0a3e2b49f7e675313a121994)) +- **genqa:** fix rga feedback position with chrome ([#4501](https://github.com/coveo/ui-kit/issues/4501)) ([3814405](https://github.com/coveo/ui-kit/commits/381440540ab9224595f061cc7eaf37561b7674b6)) + +## 2.78.2 (2024-09-16) + +### Bug Fixes + +- **atomic:** use getter instead of fn ([#4395](https://github.com/coveo/ui-kit/issues/4395)) ([547ca04](https://github.com/coveo/ui-kit/commits/547ca049554a18a93b55a885a0555feb680684a5)) + +## 2.78.1 (2024-08-29) + +### Bug Fixes + +- **atomic:** do not add click outside of grid layout ([#4354](https://github.com/coveo/ui-kit/issues/4354)) ([bc6cb1f](https://github.com/coveo/ui-kit/commits/bc6cb1f4b3c48be221da8bb70ad6b9465fa9c19d)), closes [#4355](https://github.com/coveo/ui-kit/issues/4355) +- **atomic:** field sort should be applied when selected ([#4345](https://github.com/coveo/ui-kit/issues/4345)) ([dbb23f0](https://github.com/coveo/ui-kit/commits/dbb23f0445bc23fe2d24d0d61c3c0bd185a36405)), closes [#4308](https://github.com/coveo/ui-kit/issues/4308) + # 2.78.0 (2024-08-27) ### Bug Fixes diff --git a/packages/atomic/cypress/e2e/facets/color-facet/color-facet.cypress.ts b/packages/atomic/cypress/e2e/facets/color-facet/color-facet.cypress.ts index 098cd9ad021..6aa03d46f8c 100644 --- a/packages/atomic/cypress/e2e/facets/color-facet/color-facet.cypress.ts +++ b/packages/atomic/cypress/e2e/facets/color-facet/color-facet.cypress.ts @@ -647,7 +647,7 @@ describe('Color Facet Test Suites', () => { describe('as a dependent', () => { const parentFacetId = 'def'; const parentField = 'author'; - const expectedValue = 'amoreau'; + const expectedValue = 'Susan Cook'; beforeEach(() => { new TestFixture() .with( diff --git a/packages/atomic/cypress/e2e/pager.cypress.ts b/packages/atomic/cypress/e2e/pager.cypress.ts index c195f7b2b5d..4ea46a48f06 100644 --- a/packages/atomic/cypress/e2e/pager.cypress.ts +++ b/packages/atomic/cypress/e2e/pager.cypress.ts @@ -153,7 +153,7 @@ describe('Pager Test Suites', () => { describe('Should allow customization of', () => { const iconTypes = ['previous', 'next']; const testCustomIcon = - 'https://raw.githubusercontent.com/coveo/ui-kit/master/packages/atomic/src/images/arrow-top-rounded.svg'; + 'https://raw.githubusercontent.com/coveo/ui-kit/v2/packages/atomic/src/images/arrow-top-rounded.svg'; beforeEach(() => { cy.intercept({ diff --git a/packages/atomic/package.json b/packages/atomic/package.json index 1083abc7b8b..14ebb1c5e5c 100644 --- a/packages/atomic/package.json +++ b/packages/atomic/package.json @@ -1,6 +1,6 @@ { "name": "@coveo/atomic", - "version": "2.78.0", + "version": "2.78.3", "description": "A web-component library for building modern UIs interfacing with the Coveo platform", "homepage": "https://docs.coveo.com/en/atomic/latest/", "repository": { @@ -43,11 +43,11 @@ "e2e:insight:watch": "cypress open --config-file cypress-insight-panel.config.ts --browser chrome", "publish:npm": "npm run-script -w=@coveo/release npm-publish", "publish:bump": "npm run-script -w=@coveo/release bump", - "promote:npm:latest": "node ../../scripts/deploy/update-npm-tag.mjs latest", + "promote:npm:latest": "npm run-script -w=@coveo/release promote-npm-prod", "validate:definitions": "tsc --noEmit --esModuleInterop --skipLibCheck ./dist/types/components.d.ts" }, "dependencies": { - "@coveo/bueno": "0.46.1", + "@coveo/bueno": "0.46.3", "@popperjs/core": "^2.11.6", "@salesforce-ux/design-system": "^2.16.1", "@stencil/store": "2.0.16", @@ -66,7 +66,7 @@ "@axe-core/playwright": "4.9.1", "@babel/core": "7.24.9", "@coveo/atomic": "file:.", - "@coveo/headless": "2.80.0", + "@coveo/headless": "2.80.3", "@coveo/release": "1.0.0", "@custom-elements-manifest/analyzer": "0.10.3", "@fullhuman/postcss-purgecss": "6.0.0", @@ -140,7 +140,7 @@ "wait-on": "7.2.0" }, "peerDependencies": { - "@coveo/headless": "2.80.0" + "@coveo/headless": "2.80.3" }, "license": "Apache-2.0", "engines": { diff --git a/packages/atomic/playwright.config.ts b/packages/atomic/playwright.config.ts index f8542191478..a773b2e7a0c 100644 --- a/packages/atomic/playwright.config.ts +++ b/packages/atomic/playwright.config.ts @@ -26,14 +26,14 @@ export default defineConfig({ viewport: DEFAULT_DESKTOP_VIEWPORT, }, }, - { - name: 'firefox', - use: {...devices['Desktop Firefox'], viewport: DEFAULT_DESKTOP_VIEWPORT}, - }, - { - name: 'webkit', - use: {...devices['Desktop Safari'], viewport: DEFAULT_DESKTOP_VIEWPORT}, - }, + // { + // name: 'firefox', + // use: {...devices['Desktop Firefox'], viewport: DEFAULT_DESKTOP_VIEWPORT}, + // }, + // { + // name: 'webkit', + // use: {...devices['Desktop Safari'], viewport: DEFAULT_DESKTOP_VIEWPORT}, + // }, ], expect: { timeout: 7 * 1000, diff --git a/packages/atomic/src/components/commerce/atomic-commerce-pager/atomic-commerce-pager.new.stories.tsx b/packages/atomic/src/components/commerce/atomic-commerce-pager/atomic-commerce-pager.new.stories.tsx index 1dcd6a0f354..087bff27acd 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-pager/atomic-commerce-pager.new.stories.tsx +++ b/packages/atomic/src/components/commerce/atomic-commerce-pager/atomic-commerce-pager.new.stories.tsx @@ -33,9 +33,9 @@ export const CustomIcon: Story = { tags: ['commerce'], args: { 'attributes-previous-button-icon': - 'https://raw.githubusercontent.com/coveo/ui-kit/master/packages/atomic/src/images/arrow-top-rounded.svg', + 'https://raw.githubusercontent.com/coveo/ui-kit/v2/packages/atomic/src/images/arrow-top-rounded.svg', 'attributes-next-button-icon': - 'https://raw.githubusercontent.com/coveo/ui-kit/master/packages/atomic/src/images/arrow-top-rounded.svg', + 'https://raw.githubusercontent.com/coveo/ui-kit/v2/packages/atomic/src/images/arrow-top-rounded.svg', }, play: async (context) => { await play(context); diff --git a/packages/atomic/src/components/commerce/atomic-commerce-pager/e2e/atomic-commerce-pager.e2e.ts b/packages/atomic/src/components/commerce/atomic-commerce-pager/e2e/atomic-commerce-pager.e2e.ts index 3cfb9b991e4..0f958b6f1d7 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-pager/e2e/atomic-commerce-pager.e2e.ts +++ b/packages/atomic/src/components/commerce/atomic-commerce-pager/e2e/atomic-commerce-pager.e2e.ts @@ -190,7 +190,7 @@ test.describe('with numberOfPages=-5', () => { test.describe('should allow custom icons', () => { const customIcon = - 'https://raw.githubusercontent.com/coveo/ui-kit/master/packages/atomic/src/images/arrow-top-rounded.svg'; + 'https://raw.githubusercontent.com/coveo/ui-kit/v2/packages/atomic/src/images/arrow-top-rounded.svg'; test.beforeEach(async ({pager}) => { await pager.load({story: 'custom-icon'}); diff --git a/packages/atomic/src/components/commerce/atomic-commerce-product-list/atomic-commerce-product-list.tsx b/packages/atomic/src/components/commerce/atomic-commerce-product-list/atomic-commerce-product-list.tsx index f54bd762538..84df7b05881 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-product-list/atomic-commerce-product-list.tsx +++ b/packages/atomic/src/components/commerce/atomic-commerce-product-list/atomic-commerce-product-list.tsx @@ -263,7 +263,10 @@ export class AtomicCommerceProductList this.imageSize ), content: this.productTemplateProvider.getTemplateContent(product), - linkContent: this.productTemplateProvider.getLinkTemplateContent(product), + linkContent: + this.display === 'grid' + ? this.productTemplateProvider.getLinkTemplateContent(product) + : this.productTemplateProvider.getEmptyLinkTemplateContent(), store: this.bindings.store, density: this.density, imageSize: this.imageSize, diff --git a/packages/atomic/src/components/commerce/atomic-commerce-recommendation-list/atomic-commerce-recommendation-list.tsx b/packages/atomic/src/components/commerce/atomic-commerce-recommendation-list/atomic-commerce-recommendation-list.tsx index 842c353f18b..c2e455dbad1 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-recommendation-list/atomic-commerce-recommendation-list.tsx +++ b/packages/atomic/src/components/commerce/atomic-commerce-recommendation-list/atomic-commerce-recommendation-list.tsx @@ -323,7 +323,10 @@ export class AtomicCommerceRecommendationList this.imageSize ), content: this.productTemplateProvider.getTemplateContent(product), - linkContent: this.productTemplateProvider.getLinkTemplateContent(product), + linkContent: + this.display === 'grid' + ? this.productTemplateProvider.getLinkTemplateContent(product) + : this.productTemplateProvider.getEmptyLinkTemplateContent(), store: this.bindings.store, density: this.density, display: this.display, diff --git a/packages/atomic/src/components/commerce/atomic-commerce-search-box/atomic-commerce-search-box.tsx b/packages/atomic/src/components/commerce/atomic-commerce-search-box/atomic-commerce-search-box.tsx index 949e299bf94..8a4fae66fa0 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-search-box/atomic-commerce-search-box.tsx +++ b/packages/atomic/src/components/commerce/atomic-commerce-search-box/atomic-commerce-search-box.tsx @@ -34,7 +34,12 @@ import { StorageItems, } from '../../../utils/local-storage-utils'; import {updateBreakpoints} from '../../../utils/replace-breakpoint'; -import {isFocusingOut, once, randomID} from '../../../utils/utils'; +import { + isFocusingOut, + once, + randomID, + spreadProperties, +} from '../../../utils/utils'; import {SearchBoxWrapper} from '../../common/search-box/search-box-wrapper'; import {SearchTextArea} from '../../common/search-box/search-text-area'; import {TextAreaSubmitButton} from '../../common/search-box/text-area-submit-button'; @@ -330,11 +335,11 @@ export class AtomicCommerceSearchBox private get suggestionBindings(): SearchBoxSuggestionsBindings< SearchBox | StandaloneSearchBox > { - return { - ...this.bindings, - ...this.suggestionManager.partialSuggestionBindings, - ...this.partialSuggestionBindings, - }; + return spreadProperties( + this.bindings, + this.suggestionManager.partialSuggestionBindings, + this.partialSuggestionBindings + ); } private get partialSuggestionBindings(): Pick< @@ -345,14 +350,38 @@ export class AtomicCommerceSearchBox | 'numberOfQueries' | 'clearFilters' > { - return { - ...this.bindings, - id: this.id, - isStandalone: () => !!this.redirectionUrl, - searchBoxController: () => this.searchBox, - numberOfQueries: this.numberOfQueries, - clearFilters: this.clearFilters, - }; + return Object.defineProperties( + {...this.bindings}, + { + id: { + get: () => this.id, + enumerable: true, + }, + searchBoxController: { + get: () => this.searchBox, + enumerable: true, + }, + isStandalone: { + get: () => !!this.redirectionUrl, + enumerable: true, + }, + numberOfQueries: { + get: () => this.numberOfQueries, + enumerable: true, + }, + clearFilters: { + get: () => this.clearFilters, + enumerable: true, + }, + } + ) as unknown as Pick< + SearchBoxSuggestionsBindings, + | 'id' + | 'isStandalone' + | 'searchBoxController' + | 'numberOfQueries' + | 'clearFilters' + >; } private get searchBoxOptions(): SearchBoxOptions { diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts index 81ebd47b3f9..a2221181f0e 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts @@ -23,7 +23,7 @@ test.describe('default', async () => { }, }); await expect(facets.expandedFacets).toHaveCount(1); - await expect(facets.collapsedFacets).toHaveCount(7); + await expect(facets.collapsedFacets).toHaveCount(8); }); test('should disable collapse facets when set to -1', async ({facets}) => { @@ -33,7 +33,7 @@ test.describe('default', async () => { }, }); await expect(facets.collapsedFacets).toHaveCount(0); - await expect(facets.expandedFacets).toHaveCount(8); + await expect(facets.expandedFacets).toHaveCount(9); }); }); diff --git a/packages/atomic/src/components/commerce/product-template-components/product-template-decorators.tsx b/packages/atomic/src/components/commerce/product-template-components/product-template-decorators.tsx index c66828b22e8..a4c9ee7fd5c 100644 --- a/packages/atomic/src/components/commerce/product-template-components/product-template-decorators.tsx +++ b/packages/atomic/src/components/commerce/product-template-components/product-template-decorators.tsx @@ -16,7 +16,7 @@ import { * @ProductContext() private product!: Product; * ``` * - * For more information and examples, view the [Utilities section](https://github.com/coveo/ui-kit/tree/master/packages/atomic#utilities) of the Coveo Atomic README. + * For more information and examples, view the [Utilities section](https://github.com/coveo/ui-kit/tree/v2/packages/atomic#utilities) of the Coveo Atomic README. */ export function ProductContext(opts: {folded: boolean} = {folded: false}) { return ItemContext({parentName: 'atomic-product', folded: opts.folded}); diff --git a/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-instant-products/atomic-commerce-search-box-instant-products.tsx b/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-instant-products/atomic-commerce-search-box-instant-products.tsx index 6f3e244bfbb..77f6456e277 100644 --- a/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-instant-products/atomic-commerce-search-box-instant-products.tsx +++ b/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-instant-products/atomic-commerce-search-box-instant-products.tsx @@ -178,10 +178,10 @@ export class AtomicCommerceSearchBoxInstantProducts content: , onSelect: () => { this.bindings.clearSuggestions(); - this.bindings - .searchBoxController() - .updateText(this.instantProducts.state.query); - this.bindings.searchBoxController().submit(); + this.bindings.searchBoxController.updateText( + this.instantProducts.state.query + ); + this.bindings.searchBoxController.submit(); }, }); } @@ -228,7 +228,7 @@ export class AtomicCommerceSearchBoxInstantProducts private onSuggestedQueryChange() { if ( !this.bindings.getSuggestionElements().length && - !this.bindings.searchBoxController().state.value + !this.bindings.searchBoxController.state.value ) { console.warn( "There doesn't seem to be any query suggestions configured. Make sure to include either an atomic-commerce-search-box-query-suggestions or atomic-commerce-search-box-recent-queries in your search box in order to see some instant products." diff --git a/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-query-suggestions/atomic-commerce-search-box-query-suggestions.tsx b/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-query-suggestions/atomic-commerce-search-box-query-suggestions.tsx index ab5f5add258..fe892b4f80d 100644 --- a/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-query-suggestions/atomic-commerce-search-box-query-suggestions.tsx +++ b/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-query-suggestions/atomic-commerce-search-box-query-suggestions.tsx @@ -87,16 +87,15 @@ export class AtomicCommerceSearchBoxQuerySuggestions { } private renderItems(): SearchBoxSuggestionElement[] { - const hasQuery = this.bindings.searchBoxController().state.value !== ''; + const hasQuery = this.bindings.searchBoxController.state.value !== ''; const max = hasQuery ? this.maxWithQuery : this.maxWithoutQuery; - return this.bindings - .searchBoxController() - .state.suggestions.slice(0, max) + return this.bindings.searchBoxController.state.suggestions + .slice(0, max) .map((suggestion) => this.renderItem(suggestion)); } private renderItem(suggestion: Suggestion) { - const hasQuery = this.bindings.searchBoxController().state.value !== ''; + const hasQuery = this.bindings.searchBoxController.state.value !== ''; const partialItem = getPartialSearchBoxSuggestionElement( suggestion, this.bindings.i18n @@ -115,9 +114,7 @@ export class AtomicCommerceSearchBoxQuerySuggestions { ), onSelect: () => { - this.bindings - .searchBoxController() - .selectSuggestion(suggestion.rawValue); + this.bindings.searchBoxController.selectSuggestion(suggestion.rawValue); }, }; } diff --git a/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-recent-queries/atomic-commerce-search-box-recent-queries.tsx b/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-recent-queries/atomic-commerce-search-box-recent-queries.tsx index 9d7f67c8e9e..b10687db4d6 100644 --- a/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-recent-queries/atomic-commerce-search-box-recent-queries.tsx +++ b/packages/atomic/src/components/commerce/search-box-suggestions/atomic-commerce-search-box-recent-queries/atomic-commerce-search-box-recent-queries.tsx @@ -123,7 +123,7 @@ export class AtomicCommerceSearchBoxRecentQueries { return []; } - const query = this.bindings.searchBoxController().state.value; + const query = this.bindings.searchBoxController.state.value; const hasQuery = query !== ''; const max = hasQuery ? this.maxWithQuery : this.maxWithoutQuery; const filteredQueries = this.recentQueriesList.state.queries @@ -157,7 +157,7 @@ export class AtomicCommerceSearchBoxRecentQueries { } private renderItem(value: string): SearchBoxSuggestionElement { - const query = this.bindings.searchBoxController().state.value; + const query = this.bindings.searchBoxController.state.value; const partialItem = getPartialRecentQueryElement(value, this.bindings.i18n); return { ...partialItem, @@ -169,9 +169,9 @@ export class AtomicCommerceSearchBoxRecentQueries { ), onSelect: () => { - if (this.bindings.isStandalone()) { - this.bindings.searchBoxController().updateText(value); - this.bindings.searchBoxController().submit(); + if (this.bindings.isStandalone) { + this.bindings.searchBoxController.updateText(value); + this.bindings.searchBoxController.submit(); return; } diff --git a/packages/atomic/src/components/common/generated-answer/generated-content/markdown-utils.test.ts b/packages/atomic/src/components/common/generated-answer/generated-content/markdown-utils.test.ts index 6a02911344d..77be9e990f0 100644 --- a/packages/atomic/src/components/common/generated-answer/generated-content/markdown-utils.test.ts +++ b/packages/atomic/src/components/common/generated-answer/generated-content/markdown-utils.test.ts @@ -302,6 +302,22 @@ describe('markdownUtils', () => { ); }); }); + + it('should transform formatted heading', () => { + const text = '# **bold** *emphasized* with `code` title'; + const html = transformMarkdownToHtml(text); + expect(removeLineBreaks(html)).toBe( + '
bold emphasized with code title
' + ); + }); + + it('should transform heading with nested formatting', () => { + const text = '# ***bold** emphasized with `code`* title'; + const html = transformMarkdownToHtml(text); + expect(removeLineBreaks(html)).toBe( + '
bold emphasized with code title
' + ); + }); }); describe('with unclosed inline elements in text', () => { diff --git a/packages/atomic/src/components/common/generated-answer/generated-content/markdown-utils.ts b/packages/atomic/src/components/common/generated-answer/generated-content/markdown-utils.ts index 8659f42840a..3ebd5b57391 100644 --- a/packages/atomic/src/components/common/generated-answer/generated-content/markdown-utils.ts +++ b/packages/atomic/src/components/common/generated-answer/generated-content/markdown-utils.ts @@ -1,5 +1,11 @@ import {marked} from 'marked'; +const toInlinePlainText = (textWithHtml: string): string => { + const withoutHtmlTags = textWithHtml.replace(/<[^>]*>/g, ' '); + const withCollapsedWhitespaces = withoutHtmlTags.replace(/\s{2,}/g, ' '); + return withCollapsedWhitespaces.trim(); +}; + const unclosedElement = /(\*{1,3}|`)($|\w[\w\s]*$)/; const completeUnclosedElement = (text: string) => { @@ -48,7 +54,9 @@ const customRenderer = { }, heading(text: string, level: number) { - return `
${text}
`; + const plainText = toInlinePlainText(text); + + return `
${text}
`; }, html(text: string) { diff --git a/packages/atomic/src/components/common/generated-answer/styles/generated-answer.pcss b/packages/atomic/src/components/common/generated-answer/styles/generated-answer.pcss index 0b51927fa4c..a774e9d8a43 100644 --- a/packages/atomic/src/components/common/generated-answer/styles/generated-answer.pcss +++ b/packages/atomic/src/components/common/generated-answer/styles/generated-answer.pcss @@ -61,6 +61,7 @@ [part='container'] { container-type: inline-size; + contain: layout; } .footer { diff --git a/packages/atomic/src/components/common/suggestions/suggestions-common.ts b/packages/atomic/src/components/common/suggestions/suggestions-common.ts index 5a12198f1fa..de127841a3b 100644 --- a/packages/atomic/src/components/common/suggestions/suggestions-common.ts +++ b/packages/atomic/src/components/common/suggestions/suggestions-common.ts @@ -141,11 +141,11 @@ export type SearchBoxSuggestionsBindings< /** * Whether the search box is [standalone](https://docs.coveo.com/en/atomic/latest/usage/ssb/). */ - isStandalone(): boolean; + isStandalone: boolean; /** * The search box headless controller. */ - searchBoxController(): SearchBoxController; + searchBoxController: SearchBoxController; /** * The number of queries to display when the user interacts with the search box. */ diff --git a/packages/atomic/src/components/common/template-provider/template-provider.ts b/packages/atomic/src/components/common/template-provider/template-provider.ts index c091994ec5b..5371c6f3733 100644 --- a/packages/atomic/src/components/common/template-provider/template-provider.ts +++ b/packages/atomic/src/components/common/template-provider/template-provider.ts @@ -73,6 +73,10 @@ export abstract class TemplateProvider { return this.templateManager.selectLinkTemplate(item)!; } + public getEmptyLinkTemplateContent() { + return document.createDocumentFragment(); + } + public get templatesRegistered() { return this.props.getResultTemplateRegistered(); } diff --git a/packages/atomic/src/components/search/atomic-result/e2e/page-object.ts b/packages/atomic/src/components/search/atomic-result/e2e/page-object.ts new file mode 100644 index 00000000000..0b14f29cd33 --- /dev/null +++ b/packages/atomic/src/components/search/atomic-result/e2e/page-object.ts @@ -0,0 +1,8 @@ +import type {Page} from '@playwright/test'; +import {BasePageObject} from '../../../../../playwright-utils/base-page-object'; + +export class AtomicResultPageObject extends BasePageObject<'atomic-result'> { + constructor(page: Page) { + super(page, 'atomic-result'); + } +} diff --git a/packages/atomic/src/components/search/atomic-search-box/atomic-search-box.tsx b/packages/atomic/src/components/search/atomic-search-box/atomic-search-box.tsx index f30cc025266..ed77be7f2da 100644 --- a/packages/atomic/src/components/search/atomic-search-box/atomic-search-box.tsx +++ b/packages/atomic/src/components/search/atomic-search-box/atomic-search-box.tsx @@ -33,7 +33,12 @@ import { StorageItems, } from '../../../utils/local-storage-utils'; import {updateBreakpoints} from '../../../utils/replace-breakpoint'; -import {isFocusingOut, once, randomID} from '../../../utils/utils'; +import { + isFocusingOut, + once, + randomID, + spreadProperties, +} from '../../../utils/utils'; import {SearchBoxWrapper} from '../../common/search-box/search-box-wrapper'; import {SearchInput} from '../../common/search-box/search-input'; import {SearchTextArea} from '../../common/search-box/search-text-area'; @@ -358,11 +363,11 @@ export class AtomicSearchBox implements InitializableComponent { private get suggestionBindings(): SearchBoxSuggestionsBindings< SearchBox | StandaloneSearchBox > { - return { - ...this.bindings, - ...this.suggestionManager.partialSuggestionBindings, - ...this.partialSuggestionBindings, - }; + return spreadProperties( + this.bindings, + this.suggestionManager.partialSuggestionBindings, + this.partialSuggestionBindings + ); } private get partialSuggestionBindings(): Pick< @@ -373,14 +378,38 @@ export class AtomicSearchBox implements InitializableComponent { | 'numberOfQueries' | 'clearFilters' > { - return { - ...this.bindings, - id: this.id, - isStandalone: () => !!this.redirectionUrl, - searchBoxController: () => this.searchBox, - numberOfQueries: this.numberOfQueries, - clearFilters: this.clearFilters, - }; + return Object.defineProperties( + {...this.bindings}, + { + id: { + get: () => this.id, + enumerable: true, + }, + searchBoxController: { + get: () => this.searchBox, + enumerable: true, + }, + isStandalone: { + get: () => !!this.redirectionUrl, + enumerable: true, + }, + numberOfQueries: { + get: () => this.numberOfQueries, + enumerable: true, + }, + clearFilters: { + get: () => this.clearFilters, + enumerable: true, + }, + } + ) as unknown as Pick< + SearchBoxSuggestionsBindings, + | 'id' + | 'isStandalone' + | 'searchBoxController' + | 'numberOfQueries' + | 'clearFilters' + >; } private get searchBoxOptions(): SearchBoxOptions { diff --git a/packages/atomic/src/components/search/atomic-sort-dropdown/atomic-sort-dropdown.new.stories.tsx b/packages/atomic/src/components/search/atomic-sort-dropdown/atomic-sort-dropdown.new.stories.tsx index 6b4e3f4dadc..5d9646349ad 100644 --- a/packages/atomic/src/components/search/atomic-sort-dropdown/atomic-sort-dropdown.new.stories.tsx +++ b/packages/atomic/src/components/search/atomic-sort-dropdown/atomic-sort-dropdown.new.stories.tsx @@ -29,6 +29,14 @@ export const Default: Story = { label="most-recent" expression="date descending" > + + `, }, }; diff --git a/packages/atomic/src/components/search/atomic-sort-dropdown/atomic-sort-dropdown.tsx b/packages/atomic/src/components/search/atomic-sort-dropdown/atomic-sort-dropdown.tsx index 4ddfe22f2e3..e6ca809684d 100644 --- a/packages/atomic/src/components/search/atomic-sort-dropdown/atomic-sort-dropdown.tsx +++ b/packages/atomic/src/components/search/atomic-sort-dropdown/atomic-sort-dropdown.tsx @@ -123,10 +123,13 @@ export class AtomicSortDropdown implements InitializableComponent { ); option && this.sort.sortBy(option.criteria); } + public componentShouldUpdate(): void { if ( this.options.some( - (option) => option.expression === this.sortState.sortCriteria + (option) => + option.expression.trim().replace(/\s*,\s*/g, ',') === + this.sortState.sortCriteria.replace(/@/g, '') ) ) { return; diff --git a/packages/atomic/src/components/search/atomic-sort-dropdown/e2e/atomic-sort-dropdown.e2e.ts b/packages/atomic/src/components/search/atomic-sort-dropdown/e2e/atomic-sort-dropdown.e2e.ts new file mode 100644 index 00000000000..fe13afc2813 --- /dev/null +++ b/packages/atomic/src/components/search/atomic-sort-dropdown/e2e/atomic-sort-dropdown.e2e.ts @@ -0,0 +1,58 @@ +import {expect, test} from './fixture'; + +test.describe('default', () => { + test.beforeEach(async ({sortDropdown}) => { + await sortDropdown.load(); + }); + + test.describe('when selecting a field sort criterion', async () => { + test.beforeEach(async ({sortDropdown}) => { + await sortDropdown.dropdown.selectOption('sncost ascending'); + }); + + test('should properly reflect the selected sort criteria into the URL', async ({ + page, + }) => { + expect(page.url()).toContain('sortCriteria=%40sncost%20ascending'); + }); + }); + + test.describe('when selecting a composite field sort criterion', async () => { + test.beforeEach(async ({sortDropdown}) => { + await sortDropdown.dropdown.selectOption( + 'sncost ascending, date descending' + ); + }); + + test('should properly reflect the selected sort criteria into the URL', async ({ + page, + }) => { + expect(page.url()).toContain( + // eslint-disable-next-line @cspell/spellchecker + 'sortCriteria=%40sncost%20ascending%2Cdate%20descending' + ); + }); + }); + + test.describe('when selecting a relevance sort criterion', async () => { + test.beforeEach(async ({sortDropdown}) => { + await sortDropdown.dropdown.selectOption('relevancy'); + }); + + test('should not reflect any sortCriteria in the URL', async ({page}) => { + expect(page.url()).not.toContain('sortCriteria='); + }); + }); + + test.describe('when selecting a date sort criterion', async () => { + test.beforeEach(async ({sortDropdown}) => { + await sortDropdown.dropdown.selectOption('date descending'); + }); + + test('should properly reflect the selected sort criteria into the URL', async ({ + page, + }) => { + expect(page.url()).toContain('sortCriteria=date%20descending'); + }); + }); +}); diff --git a/packages/atomic/src/components/search/atomic-sort-dropdown/e2e/fixture.ts b/packages/atomic/src/components/search/atomic-sort-dropdown/e2e/fixture.ts new file mode 100644 index 00000000000..e18e812bdfb --- /dev/null +++ b/packages/atomic/src/components/search/atomic-sort-dropdown/e2e/fixture.ts @@ -0,0 +1,19 @@ +import {test as base} from '@playwright/test'; +import { + AxeFixture, + makeAxeBuilder, +} from '../../../../../playwright-utils/base-fixture'; +import {AtomicSortDropdownPageObject} from './page-object'; + +type MyFixture = { + sortDropdown: AtomicSortDropdownPageObject; +}; + +export const test = base.extend({ + makeAxeBuilder, + sortDropdown: async ({page}, use) => { + await use(new AtomicSortDropdownPageObject(page)); + }, +}); + +export {expect} from '@playwright/test'; diff --git a/packages/atomic/src/components/search/atomic-sort-dropdown/e2e/page-object.ts b/packages/atomic/src/components/search/atomic-sort-dropdown/e2e/page-object.ts new file mode 100644 index 00000000000..01ebc5a90ff --- /dev/null +++ b/packages/atomic/src/components/search/atomic-sort-dropdown/e2e/page-object.ts @@ -0,0 +1,12 @@ +import type {Page} from '@playwright/test'; +import {BasePageObject} from '../../../../../playwright-utils/base-page-object'; + +export class AtomicSortDropdownPageObject extends BasePageObject<'atomic-sort-dropdown'> { + constructor(page: Page) { + super(page, 'atomic-sort-dropdown'); + } + + get dropdown() { + return this.page.getByLabel('Sort by'); + } +} diff --git a/packages/atomic/src/components/search/result-lists/atomic-result-list/atomic-result-list.new.stories.tsx b/packages/atomic/src/components/search/result-lists/atomic-result-list/atomic-result-list.new.stories.tsx index 92e21da9f21..691c1111b30 100644 --- a/packages/atomic/src/components/search/result-lists/atomic-result-list/atomic-result-list.new.stories.tsx +++ b/packages/atomic/src/components/search/result-lists/atomic-result-list/atomic-result-list.new.stories.tsx @@ -3,7 +3,16 @@ import {renderComponent} from '@coveo/atomic/storybookUtils/common/render-compon import {wrapInSearchInterface} from '@coveo/atomic/storybookUtils/search/search-interface-wrapper'; import type {Meta, StoryObj as Story} from '@storybook/web-components'; -const {decorator, play} = wrapInSearchInterface(); +const {decorator, play} = wrapInSearchInterface({ + search: { + preprocessSearchResponseMiddleware: (r) => { + const [result] = r.body.results; + result.title = 'Manage the Coveo In-Product Experiences (IPX)'; + result.clickUri = 'https://docs.coveo.com/en/3160'; + return r; + }, + }, +}); const meta: Meta = { component: 'atomic-result-list', title: 'Atomic/ResultList', @@ -18,5 +27,12 @@ const meta: Meta = { export default meta; export const Default: Story = { - name: 'atomic-result-list', + name: 'List Display', +}; + +export const Grid: Story = { + name: 'Grid Display', + args: { + 'attributes-display': 'grid', + }, }; diff --git a/packages/atomic/src/components/search/result-lists/atomic-result-list/atomic-result-list.tsx b/packages/atomic/src/components/search/result-lists/atomic-result-list/atomic-result-list.tsx index d1a74dd1f26..957c8907677 100644 --- a/packages/atomic/src/components/search/result-lists/atomic-result-list/atomic-result-list.tsx +++ b/packages/atomic/src/components/search/result-lists/atomic-result-list/atomic-result-list.tsx @@ -217,7 +217,10 @@ export class AtomicResultList implements InitializableComponent { this.imageSize ), content: this.itemTemplateProvider.getTemplateContent(result), - linkContent: this.itemTemplateProvider.getLinkTemplateContent(result), + linkContent: + this.display === 'grid' + ? this.itemTemplateProvider.getLinkTemplateContent(result) + : this.itemTemplateProvider.getEmptyLinkTemplateContent(), store: this.bindings.store, density: this.density, imageSize: this.imageSize, diff --git a/packages/atomic/src/components/search/result-lists/atomic-result-list/e2e/atomic-result-list.e2e.ts b/packages/atomic/src/components/search/result-lists/atomic-result-list/e2e/atomic-result-list.e2e.ts new file mode 100644 index 00000000000..721c6bc086b --- /dev/null +++ b/packages/atomic/src/components/search/result-lists/atomic-result-list/e2e/atomic-result-list.e2e.ts @@ -0,0 +1,35 @@ +import {test, expect} from './fixture'; + +test.describe('When using a list layout', () => { + test.beforeEach(async ({resultList}) => { + await resultList.load(); + }); + + test.describe('when clicking a result', () => { + test.beforeEach(async ({result}) => { + await result.hydrated.first().click(); + }); + + test('should not navigate', async ({page}) => { + expect(page.url()).toContain('http://localhost:4400/iframe.html'); + }); + }); +}); + +test.describe('When using a grid layout', () => { + test.beforeEach(async ({resultList}) => { + await resultList.load({story: 'grid'}); + }); + + test.describe('when clicking a result', () => { + test.beforeEach(async ({result}) => { + await result.hydrated.first().click(); + }); + + test('should navigate', async ({page}) => { + await expect + .poll(() => page.url()) + .toContain('https://docs.coveo.com/en/3160'); + }); + }); +}); diff --git a/packages/atomic/src/components/search/result-lists/atomic-result-list/e2e/fixture.ts b/packages/atomic/src/components/search/result-lists/atomic-result-list/e2e/fixture.ts new file mode 100644 index 00000000000..6076f85fed5 --- /dev/null +++ b/packages/atomic/src/components/search/result-lists/atomic-result-list/e2e/fixture.ts @@ -0,0 +1,24 @@ +import {test as base} from '@playwright/test'; +import { + AxeFixture, + makeAxeBuilder, +} from '../../../../../../playwright-utils/base-fixture'; +import {AtomicResultPageObject as Result} from '../../../atomic-result/e2e/page-object'; +import {AtomicResultListPageObject as ResultList} from './page-object'; + +type Fixture = { + resultList: ResultList; + result: Result; +}; + +export const test = base.extend({ + makeAxeBuilder, + resultList: async ({page}, use) => { + await use(new ResultList(page)); + }, + result: async ({page}, use) => { + await use(new Result(page)); + }, +}); + +export {expect} from '@playwright/test'; diff --git a/packages/atomic/src/components/search/result-lists/atomic-result-list/e2e/page-object.ts b/packages/atomic/src/components/search/result-lists/atomic-result-list/e2e/page-object.ts new file mode 100644 index 00000000000..fcf5261b305 --- /dev/null +++ b/packages/atomic/src/components/search/result-lists/atomic-result-list/e2e/page-object.ts @@ -0,0 +1,8 @@ +import type {Page} from '@playwright/test'; +import {BasePageObject} from '../../../../../../playwright-utils/base-page-object'; + +export class AtomicResultListPageObject extends BasePageObject<'atomic-result-list'> { + constructor(page: Page) { + super(page, 'atomic-result-list'); + } +} diff --git a/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-instant-results/atomic-search-box-instant-results.tsx b/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-instant-results/atomic-search-box-instant-results.tsx index 62e2e57dc55..4ebf8b16494 100644 --- a/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-instant-results/atomic-search-box-instant-results.tsx +++ b/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-instant-results/atomic-search-box-instant-results.tsx @@ -180,10 +180,10 @@ export class AtomicSearchBoxInstantResults implements InitializableComponent { content: , onSelect: () => { this.bindings.clearSuggestions(); - this.bindings - .searchBoxController() - .updateText(this.instantResults.state.q); - this.bindings.searchBoxController().submit(); + this.bindings.searchBoxController.updateText( + this.instantResults.state.q + ); + this.bindings.searchBoxController.submit(); }, }); } @@ -225,7 +225,7 @@ export class AtomicSearchBoxInstantResults implements InitializableComponent { private onSuggestedQueryChange() { if ( !this.bindings.getSuggestionElements().length && - !this.bindings.searchBoxController().state.value + !this.bindings.searchBoxController.state.value ) { console.warn( "There doesn't seem to be any query suggestions configured. Make sure to include either an atomic-search-box-query-suggestions or atomic-search-box-recent-queries in your search box in order to see some instant results." diff --git a/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-query-suggestions/atomic-search-box-query-suggestions.tsx b/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-query-suggestions/atomic-search-box-query-suggestions.tsx index 3dbad9a8ca6..107793f3ef4 100644 --- a/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-query-suggestions/atomic-search-box-query-suggestions.tsx +++ b/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-query-suggestions/atomic-search-box-query-suggestions.tsx @@ -92,16 +92,15 @@ export class AtomicSearchBoxQuerySuggestions { } private renderItems(): SearchBoxSuggestionElement[] { - const hasQuery = this.bindings.searchBoxController().state.value !== ''; + const hasQuery = this.bindings.searchBoxController.state.value !== ''; const max = hasQuery ? this.maxWithQuery : this.maxWithoutQuery; - return this.bindings - .searchBoxController() - .state.suggestions.slice(0, max) + return this.bindings.searchBoxController.state.suggestions + .slice(0, max) .map((suggestion) => this.renderItem(suggestion)); } private renderItem(suggestion: Suggestion) { - const hasQuery = this.bindings.searchBoxController().state.value !== ''; + const hasQuery = this.bindings.searchBoxController.state.value !== ''; const partialItem = getPartialSearchBoxSuggestionElement( suggestion, this.bindings.i18n @@ -120,9 +119,7 @@ export class AtomicSearchBoxQuerySuggestions { ), onSelect: () => { - this.bindings - .searchBoxController() - .selectSuggestion(suggestion.rawValue); + this.bindings.searchBoxController.selectSuggestion(suggestion.rawValue); }, }; } diff --git a/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-recent-queries/atomic-search-box-recent-queries.tsx b/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-recent-queries/atomic-search-box-recent-queries.tsx index cd79c6b7a16..b497cfcd7a3 100644 --- a/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-recent-queries/atomic-search-box-recent-queries.tsx +++ b/packages/atomic/src/components/search/search-box-suggestions/atomic-search-box-recent-queries/atomic-search-box-recent-queries.tsx @@ -121,7 +121,7 @@ export class AtomicSearchBoxRecentQueries { return []; } - const query = this.bindings.searchBoxController().state.value; + const query = this.bindings.searchBoxController.state.value; const hasQuery = query !== ''; const max = hasQuery ? this.maxWithQuery : this.maxWithoutQuery; const filteredQueries = this.recentQueriesList.state.queries @@ -155,7 +155,7 @@ export class AtomicSearchBoxRecentQueries { } private renderItem(value: string): SearchBoxSuggestionElement { - const query = this.bindings.searchBoxController().state.value; + const query = this.bindings.searchBoxController.state.value; const partialItem = getPartialRecentQueryElement(value, this.bindings.i18n); return { ...partialItem, @@ -167,9 +167,9 @@ export class AtomicSearchBoxRecentQueries { ), onSelect: () => { - if (this.bindings.isStandalone()) { - this.bindings.searchBoxController().updateText(value); - this.bindings.searchBoxController().submit(); + if (this.bindings.isStandalone) { + this.bindings.searchBoxController.updateText(value); + this.bindings.searchBoxController.submit(); return; } diff --git a/packages/atomic/src/utils/utils.ts b/packages/atomic/src/utils/utils.ts index 342c8e0fd75..794eb77cf27 100644 --- a/packages/atomic/src/utils/utils.ts +++ b/packages/atomic/src/utils/utils.ts @@ -250,3 +250,23 @@ export function aggregate( >{} ); } + +/** + * Similar as a classic spread, but preserve all characteristics of properties (e.g. getter/setter). + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#description + * for an explanation why (spread & assign work similarly). + * @param objects the objects to "spread" together + * @returns the spread result + */ +export function spreadProperties( + ...objects: object[] +) { + const returnObject = {}; + for (const obj of objects) { + Object.defineProperties( + returnObject, + Object.getOwnPropertyDescriptors(obj) + ); + } + return returnObject as Output; +} diff --git a/packages/auth/CHANGELOG.md b/packages/auth/CHANGELOG.md index 4fa8d2b7a12..a0ba03a3f22 100644 --- a/packages/auth/CHANGELOG.md +++ b/packages/auth/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.11.24 (2024-09-16) + +## 1.11.23 (2024-08-29) + ## 1.11.22 (2024-07-31) ## 1.11.21 (2024-06-06) diff --git a/packages/auth/package.json b/packages/auth/package.json index 27bab812f9e..27139bfb3a9 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@coveo/auth", - "version": "1.11.22", + "version": "1.11.24", "description": "Functions to help authenticate with the Coveo platform.", "main": "./dist/auth.js", "module": "./dist/auth.esm.js", @@ -21,7 +21,7 @@ "clean": "rimraf -rf dist/*", "publish:npm": "npm run-script -w=@coveo/release npm-publish", "publish:bump": "npm run-script -w=@coveo/release bump", - "promote:npm:latest": "node ../../scripts/deploy/update-npm-tag.mjs latest", + "promote:npm:latest": "node ../../scripts/deploy/update-npm-tag.mjs v2-latest", "e2e": "npm run e2e:saml", "e2e:saml": "vite manual-e2e/saml/" }, diff --git a/packages/bueno/CHANGELOG.md b/packages/bueno/CHANGELOG.md index 6504668f0b3..9f88514e390 100644 --- a/packages/bueno/CHANGELOG.md +++ b/packages/bueno/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.46.3 (2024-09-16) + +## 0.46.2 (2024-08-29) + ## 0.46.1 (2024-07-31) # 0.46.0 (2024-07-24) diff --git a/packages/bueno/package.json b/packages/bueno/package.json index 2d01301b3fd..6714ba6ad7a 100644 --- a/packages/bueno/package.json +++ b/packages/bueno/package.json @@ -13,7 +13,7 @@ }, "types": "./dist/definitions/index.d.ts", "license": "Apache-2.0", - "version": "0.46.1", + "version": "0.46.3", "files": [ "dist/" ], @@ -27,7 +27,7 @@ "test:watch": "jest --watch --colors --no-cache", "publish:npm": "npm run-script -w=@coveo/release npm-publish", "publish:bump": "npm run-script -w=@coveo/release bump", - "promote:npm:latest": "node ../../scripts/deploy/update-npm-tag.mjs latest" + "promote:npm:latest": "npm run-script -w=@coveo/release promote-npm-prod" }, "devDependencies": { "@coveo/release": "1.0.0", diff --git a/packages/headless-react/CHANGELOG.md b/packages/headless-react/CHANGELOG.md index d7d66524929..1ebecb4cc19 100644 --- a/packages/headless-react/CHANGELOG.md +++ b/packages/headless-react/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.6 (2024-09-16) + +## 1.1.5 (2024-08-29) + # 1.1.0 (2024-08-07) ### Features diff --git a/packages/headless-react/README.md b/packages/headless-react/README.md index b75d204cf12..f8f1b4ea72d 100644 --- a/packages/headless-react/README.md +++ b/packages/headless-react/README.md @@ -5,5 +5,5 @@ ## Learn more - Checkout our [Documentation](https://docs.coveo.com/en/headless/latest/usage/headless-server-side-rendering/) -- Refer to [samples/headless-ssr](https://github.com/coveo/ui-kit/tree/master/packages/samples/headless-ssr/) for examples. +- Refer to [samples/headless-ssr](https://github.com/coveo/ui-kit/tree/v2/packages/samples/headless-ssr/) for examples. - All exports from `@coveo/headless/ssr` are also available from under `@coveo/headless-react/ssr` as convenience. diff --git a/packages/headless-react/package.json b/packages/headless-react/package.json index 92f07afafc4..79a17f6b1e8 100644 --- a/packages/headless-react/package.json +++ b/packages/headless-react/package.json @@ -1,6 +1,6 @@ { "name": "@coveo/headless-react", - "version": "1.1.4", + "version": "1.1.7", "description": "React utilities for SSR (Server Side Rendering) with headless", "homepage": "https://docs.coveo.com/en/headless/latest/", "repository": { @@ -30,10 +30,10 @@ "lint": "eslint .; publint", "publish:npm": "npm run-script -w=@coveo/release npm-publish", "publish:bump": "npm run-script -w=@coveo/release bump", - "promote:npm:latest": "node ../../scripts/deploy/update-npm-tag.mjs latest" + "promote:npm:latest": "npm run-script -w=@coveo/release promote-npm-prod" }, "dependencies": { - "@coveo/headless": "2.80.0" + "@coveo/headless": "2.80.3" }, "devDependencies": { "@coveo/release": "1.0.0", diff --git a/packages/headless/CHANGELOG.md b/packages/headless/CHANGELOG.md index 43c3a2852db..bc5edb30079 100644 --- a/packages/headless/CHANGELOG.md +++ b/packages/headless/CHANGELOG.md @@ -1,3 +1,14 @@ +## 2.80.3 (2024-10-22) + +### Bug Fixes + +- **answerApi:** custom event ([#4478](https://github.com/coveo/ui-kit/issues/4478)) ([a4534e0](https://github.com/coveo/ui-kit/commits/a4534e01ace5580edb658dd6a06b0dd872ae963b)) +- **headless:** ensure each result keep a reference of its 'source' searchId V2 ([#4510](https://github.com/coveo/ui-kit/issues/4510)) ([269b205](https://github.com/coveo/ui-kit/commits/269b2051b8e07559ef37782423e05c77461fd663)), closes [#4391](https://github.com/coveo/ui-kit/issues/4391) + +## 2.80.2 (2024-09-16) + +## 2.80.1 (2024-08-29) + # 2.80.0 (2024-08-27) ### Bug Fixes diff --git a/packages/headless/package.json b/packages/headless/package.json index e414dec0725..cabffddab17 100644 --- a/packages/headless/package.json +++ b/packages/headless/package.json @@ -14,7 +14,7 @@ }, "types": "./dist/definitions/index.d.ts", "license": "Apache-2.0", - "version": "2.80.0", + "version": "2.80.3", "files": [ "dist/", "recommendation/", @@ -39,7 +39,7 @@ "test:integration": "jest --testPathPattern=src/integration-tests", "publish:npm": "npm run-script -w=@coveo/release npm-publish", "publish:bump": "npm run-script -w=@coveo/release bump", - "promote:npm:latest": "node ../../scripts/deploy/update-npm-tag.mjs latest", + "promote:npm:latest": "npm run-script -w=@coveo/release promote-npm-prod", "build:doc": "npm run build:doc:extract && npm run build:doc:parse", "build:doc:extract": "node ./scripts/extract-documentation.mjs", "build:doc:parse": "ts-node --project ./doc-parser/tsconfig.build.json ./doc-parser/doc-parser.ts" @@ -49,14 +49,14 @@ "pino-pretty": "^6.0.0 || ^10.0.0 || ^11.0.0" }, "dependencies": { - "@coveo/bueno": "0.46.1", + "@coveo/bueno": "0.46.3", "@coveo/relay": "0.7.10", "@coveo/relay-event-types": "9.4.0", "@microsoft/fetch-event-source": "2.0.1", "@reduxjs/toolkit": "2.2.7", "abab": "2.0.6", "abortcontroller-polyfill": "1.7.5", - "coveo.analytics": "2.30.26", + "coveo.analytics": "2.30.38", "dayjs": "1.11.12", "exponential-backoff": "3.1.0", "fast-equals": "5.0.1", diff --git a/packages/headless/src/api/search/search/result.ts b/packages/headless/src/api/search/search/result.ts index 2158ed85746..cb61b025701 100644 --- a/packages/headless/src/api/search/search/result.ts +++ b/packages/headless/src/api/search/search/result.ts @@ -177,4 +177,9 @@ export interface Result { * Whether the result item has been previously viewed by one of the users specified in the `canSeeUserProfileOf` section of the [search token](https://docs.coveo.com/en/13/api-reference/search-api#tag/Search-V2/operation/token) generated to perform the search request. */ isUserActionView: boolean; + + /** + * The unique identifier of the search that returned this result. + */ + searchUid: string; } diff --git a/packages/headless/src/app/engine-configuration.ts b/packages/headless/src/app/engine-configuration.ts index 6f026d34507..e2e92218a27 100644 --- a/packages/headless/src/app/engine-configuration.ts +++ b/packages/headless/src/app/engine-configuration.ts @@ -18,7 +18,7 @@ import {CoveoFramework} from '../utils/version'; * * For example: `https://orgid.org.coveo.com` * - * The [getOrganizationEndpoints](https://github.com/coveo/ui-kit/blob/master/packages/headless/src/api/platform-client.ts) helper function can be useful to create the appropriate object. + * The [getOrganizationEndpoints](https://github.com/coveo/ui-kit/blob/v2/packages/headless/src/api/platform-client.ts) helper function can be useful to create the appropriate object. */ export interface CoreEngineOrganizationEndpoints { /** @@ -83,7 +83,7 @@ export interface EngineConfiguration< * * For example: `https://orgid.org.coveo.com` * - * The [getOrganizationEndpoints](https://github.com/coveo/ui-kit/blob/master/packages/headless/src/api/platform-client.ts) helper function can be useful to create the appropriate object. + * The [getOrganizationEndpoints](https://github.com/coveo/ui-kit/blob/v2/packages/headless/src/api/platform-client.ts) helper function can be useful to create the appropriate object. * * We recommend using this option, since it has resiliency benefits and simplifies the overall configuration for multi-region deployments. See [Organization endpoints](https://docs.coveo.com/en/mcc80216). */ diff --git a/packages/headless/src/controllers/knowledge/generated-answer/headless-answerapi-generated-answer.ts b/packages/headless/src/controllers/knowledge/generated-answer/headless-answerapi-generated-answer.ts index 79f5c47a039..d0208454c0f 100644 --- a/packages/headless/src/controllers/knowledge/generated-answer/headless-answerapi-generated-answer.ts +++ b/packages/headless/src/controllers/knowledge/generated-answer/headless-answerapi-generated-answer.ts @@ -96,10 +96,10 @@ const subscribeToSearchRequest = ( const strictListener = () => { const state = engine.state; const triggerParams = selectAnswerTriggerParams(state); - if (triggerParams.requestId === undefined) { + if (triggerParams.q.length === 0 || triggerParams.requestId.length === 0) { return; } - if (JSON.stringify(triggerParams) === JSON.stringify(lastTriggerParams)) { + if (triggerParams?.requestId === lastTriggerParams?.requestId) { return; } lastTriggerParams = triggerParams; diff --git a/packages/headless/src/features/generated-answer/generated-answer-analytics-actions.ts b/packages/headless/src/features/generated-answer/generated-answer-analytics-actions.ts index 3fca657482e..91bf5188b00 100644 --- a/packages/headless/src/features/generated-answer/generated-answer-analytics-actions.ts +++ b/packages/headless/src/features/generated-answer/generated-answer-analytics-actions.ts @@ -48,13 +48,15 @@ export const logRephraseGeneratedAnswer = ( responseFormat: GeneratedResponseFormat ): LegacySearchAction => makeAnalyticsAction('analytics/generatedAnswer/rephrase', (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.makeRephraseGeneratedAnswer({ - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), rephraseFormat: responseFormat.answerStyle, }); }); @@ -65,14 +67,17 @@ export const logOpenGeneratedAnswerSource = ( makeAnalyticsAction({ prefix: 'analytics/generatedAnswer/openAnswerSource', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); const citation = citationSourceSelector(state, citationId); - if (!generativeQuestionAnsweringId || !citation) { + if (!rgaID || !citation) { return null; } + return client.makeOpenGeneratedAnswerSource({ - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), permanentId: citation.permanentid, citationId: citation.id, }); @@ -99,15 +104,17 @@ export const logHoverCitation = ( makeAnalyticsAction({ prefix: 'analytics/generatedAnswer/hoverCitation', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); const citation = citationSourceSelector(state, citationId); - if (!generativeQuestionAnsweringId || !citation) { + if (!rgaID || !citation) { return null; } return client.makeGeneratedAnswerSourceHover({ - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), permanentId: citation.permanentid, citationId: citation.id, citationHoverTimeMs: citationHoverTimeInMs, @@ -133,13 +140,15 @@ export const logLikeGeneratedAnswer = (): CustomAction => makeAnalyticsAction({ prefix: 'analytics/generatedAnswer/like', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.makeLikeGeneratedAnswer({ - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), }); }, analyticsType: 'Qna.AnswerAction', @@ -158,13 +167,15 @@ export const logDislikeGeneratedAnswer = (): CustomAction => makeAnalyticsAction({ prefix: 'analytics/generatedAnswer/dislike', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.makeDislikeGeneratedAnswer({ - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), }); }, analyticsType: 'Qna.AnswerAction', @@ -185,18 +196,23 @@ export const logGeneratedAnswerFeedback = ( makeAnalyticsAction({ prefix: 'analytics/generatedAnswer/sendFeedback', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } + + const genAiID = answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}; + return isGeneratedAnswerFeedbackV2(feedback) ? client.makeGeneratedAnswerFeedbackSubmitV2({ - generativeQuestionAnsweringId, + ...genAiID, ...feedback, }) : client.makeGeneratedAnswerFeedbackSubmit({ - generativeQuestionAnsweringId, + ...genAiID, reason: feedback, }); }, @@ -242,13 +258,16 @@ export const logGeneratedAnswerDetailedFeedback = ( makeAnalyticsAction({ prefix: 'analytics/generatedAnswer/sendFeedback', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } + return client.makeGeneratedAnswerFeedbackSubmit({ - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), reason: 'other', details, }); @@ -262,17 +281,19 @@ export const logGeneratedAnswerStreamEnd = ( makeAnalyticsAction( 'analytics/generatedAnswer/streamEnd', (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); const answerTextIsEmpty = answerGenerated ? !state.generatedAnswer?.answer || !state.generatedAnswer?.answer.length : undefined; - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.makeGeneratedAnswerStreamEnd({ - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), answerGenerated, answerTextIsEmpty, }); @@ -283,13 +304,15 @@ export const logGeneratedAnswerShowAnswers = (): CustomAction => makeAnalyticsAction({ prefix: 'analytics/generatedAnswer/show', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.makeGeneratedAnswerShowAnswers({ - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), }); }, analyticsType: 'Qna.AnswerAction', @@ -308,13 +331,15 @@ export const logGeneratedAnswerHideAnswers = (): CustomAction => makeAnalyticsAction({ prefix: 'analytics/generatedAnswer/hide', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.makeGeneratedAnswerHideAnswers({ - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), }); }, analyticsType: 'Qna.AnswerAction', @@ -333,13 +358,15 @@ export const logGeneratedAnswerExpand = (): CustomAction => makeAnalyticsAction({ prefix: 'analytics/generatedAnswer/expand', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.makeGeneratedAnswerExpand({ - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), }); }, analyticsType: 'Qna.AnswerAction', @@ -358,13 +385,15 @@ export const logGeneratedAnswerCollapse = (): CustomAction => makeAnalyticsAction({ prefix: 'analytics/generatedAnswer/collapse', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.makeGeneratedAnswerCollapse({ - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), }); }, analyticsType: 'Qna.AnswerAction', @@ -383,13 +412,15 @@ export const logCopyGeneratedAnswer = (): CustomAction => makeAnalyticsAction({ prefix: 'analytics/generatedAnswer/copy', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.makeGeneratedAnswerCopyToClipboard({ - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), }); }, analyticsType: 'Qna.AnswerAction', diff --git a/packages/headless/src/features/generated-answer/generated-answer-insight-analytics-actions.ts b/packages/headless/src/features/generated-answer/generated-answer-insight-analytics-actions.ts index d9c06056061..1025644b986 100644 --- a/packages/headless/src/features/generated-answer/generated-answer-insight-analytics-actions.ts +++ b/packages/headless/src/features/generated-answer/generated-answer-insight-analytics-actions.ts @@ -35,14 +35,16 @@ export const logRephraseGeneratedAnswer = ( makeInsightAnalyticsActionFactory(SearchPageEvents.rephraseGeneratedAnswer)( 'analytics/generatedAnswer/rephrase', (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.logRephraseGeneratedAnswer( { - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), rephraseFormat: responseFormat.answerStyle, }, getCaseContextAnalyticsMetadata(state.insightCaseContext) @@ -57,16 +59,18 @@ export const logOpenGeneratedAnswerSource = ( { prefix: 'analytics/generatedAnswer/openAnswerSource', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); const citation = citationSourceSelector(state, citationId); - if (!generativeQuestionAnsweringId || !citation) { + if (!rgaID || !citation) { return null; } return client.logOpenGeneratedAnswerSource( { - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), permanentId: citation.permanentid, citationId: citation.id, }, @@ -99,16 +103,18 @@ export const logHoverCitation = ( )({ prefix: 'analytics/generatedAnswer/hoverCitation', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); const citation = citationSourceSelector(state, citationId); - if (!generativeQuestionAnsweringId || !citation) { + if (!rgaID || !citation) { return null; } return client.logGeneratedAnswerSourceHover( { - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), permanentId: citation.permanentid, citationId: citation.id, citationHoverTimeMs: citationHoverTimeInMs, @@ -137,14 +143,16 @@ export const logLikeGeneratedAnswer = (): InsightAction => makeInsightAnalyticsActionFactory(SearchPageEvents.likeGeneratedAnswer)({ prefix: 'analytics/generatedAnswer/like', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.logLikeGeneratedAnswer( { - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), }, getCaseContextAnalyticsMetadata(state.insightCaseContext) ); @@ -165,14 +173,16 @@ export const logDislikeGeneratedAnswer = (): InsightAction => makeInsightAnalyticsActionFactory(SearchPageEvents.dislikeGeneratedAnswer)({ prefix: 'analytics/generatedAnswer/dislike', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.logDislikeGeneratedAnswer( { - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), }, getCaseContextAnalyticsMetadata(state.insightCaseContext) ); @@ -197,22 +207,27 @@ export const logGeneratedAnswerFeedback = ( )({ prefix: 'analytics/generatedAnswer/sendFeedback', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } + + const genAiId = answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}; + return isGeneratedAnswerFeedbackV2(feedback) ? client.logGeneratedAnswerFeedbackSubmitV2( { - generativeQuestionAnsweringId, + ...genAiId, ...feedback, }, getCaseContextAnalyticsMetadata(state.insightCaseContext) ) : client.logGeneratedAnswerFeedbackSubmit( { - generativeQuestionAnsweringId, + ...genAiId, reason: feedback, }, getCaseContextAnalyticsMetadata(state.insightCaseContext) @@ -262,14 +277,16 @@ export const logGeneratedAnswerDetailedFeedback = ( )({ prefix: 'analytics/generatedAnswer/sendFeedback', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.logGeneratedAnswerFeedbackSubmit( { - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), reason: 'other', details, }, @@ -285,14 +302,16 @@ export const logGeneratedAnswerStreamEnd = ( makeInsightAnalyticsActionFactory(SearchPageEvents.generatedAnswerStreamEnd)( 'analytics/generatedAnswer/streamEnd', (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.logGeneratedAnswerStreamEnd( { - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), answerGenerated, }, getCaseContextAnalyticsMetadata(state.insightCaseContext) @@ -306,14 +325,16 @@ export const logGeneratedAnswerShowAnswers = (): InsightAction => )({ prefix: 'analytics/generatedAnswer/show', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.logGeneratedAnswerShowAnswers( { - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), }, getCaseContextAnalyticsMetadata(state.insightCaseContext) ); @@ -336,14 +357,16 @@ export const logGeneratedAnswerHideAnswers = (): InsightAction => )({ prefix: 'analytics/generatedAnswer/hide', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.logGeneratedAnswerHideAnswers( { - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), }, getCaseContextAnalyticsMetadata(state.insightCaseContext) ); @@ -364,14 +387,16 @@ export const logGeneratedAnswerExpand = (): InsightAction => makeInsightAnalyticsActionFactory(SearchPageEvents.generatedAnswerExpand)({ prefix: 'analytics/generatedAnswer/expand', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.logGeneratedAnswerExpand( { - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), }, getCaseContextAnalyticsMetadata(state.insightCaseContext) ); @@ -392,14 +417,16 @@ export const logGeneratedAnswerCollapse = (): InsightAction => makeInsightAnalyticsActionFactory(SearchPageEvents.generatedAnswerCollapse)({ prefix: 'analytics/generatedAnswer/collapse', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.logGeneratedAnswerCollapse( { - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), }, getCaseContextAnalyticsMetadata(state.insightCaseContext) ); @@ -422,14 +449,16 @@ export const logCopyGeneratedAnswer = (): InsightAction => )({ prefix: 'analytics/generatedAnswer/copy', __legacy__getBuilder: (client, state) => { - const generativeQuestionAnsweringId = + const {id: rgaID, answerAPIEnabled} = generativeQuestionAnsweringIdSelector(state); - if (!generativeQuestionAnsweringId) { + if (!rgaID) { return null; } return client.logGeneratedAnswerCopyToClipboard( { - generativeQuestionAnsweringId, + ...(answerAPIEnabled + ? {answerAPIStreamId: rgaID} + : {generativeQuestionAnsweringId: rgaID}), }, getCaseContextAnalyticsMetadata(state.insightCaseContext) ); diff --git a/packages/headless/src/features/generated-answer/generated-answer-selectors.test.ts b/packages/headless/src/features/generated-answer/generated-answer-selectors.test.ts new file mode 100644 index 00000000000..a5930be3633 --- /dev/null +++ b/packages/headless/src/features/generated-answer/generated-answer-selectors.test.ts @@ -0,0 +1,56 @@ +import {streamAnswerAPIStateMock} from '../../api/knowledge/tests/stream-answer-api-state-mock'; +import {SearchAppState} from '../../state/search-app-state'; +import {generativeQuestionAnsweringIdSelector} from './generated-answer-selectors'; + +jest.mock('../../api/knowledge/stream-answer-api', () => ({ + ...jest.requireActual>>( + '../../api/knowledge/stream-answer-api' + ), + selectAnswer: (_state: Partial) => ({ + data: { + answerId: 'answerId1234', + }, + }), +})); + +describe('generated-answer-selectors', () => { + describe('generativeQuestionAnsweringIdSelector', () => { + afterAll(() => { + jest.clearAllMocks(); + }); + it('returns the answerId if an answer configuration id is in state', () => { + const state = { + ...(streamAnswerAPIStateMock as Partial), + generatedAnswer: { + answerConfigurationId: 'answerConfigurationId', + }, + } as Partial; + + const result = generativeQuestionAnsweringIdSelector(state); + expect(result).toEqual({id: 'answerId1234', answerAPIEnabled: true}); + }); + + it('returns the generativeQuestionAnsweringId if an answer configuration id is not in state', () => { + const state = { + ...(streamAnswerAPIStateMock as Partial), + generatedAnswer: { + answerConfigurationId: undefined, + }, + search: { + response: { + extendedResults: { + generativeQuestionAnsweringId: + 'generativeQuestionAnsweringId4321', + }, + }, + }, + } as Partial; + + const result = generativeQuestionAnsweringIdSelector(state); + expect(result).toEqual({ + id: 'generativeQuestionAnsweringId4321', + answerAPIEnabled: false, + }); + }); + }); +}); diff --git a/packages/headless/src/features/generated-answer/generated-answer-selectors.ts b/packages/headless/src/features/generated-answer/generated-answer-selectors.ts index a513d95d744..b92b904464e 100644 --- a/packages/headless/src/features/generated-answer/generated-answer-selectors.ts +++ b/packages/headless/src/features/generated-answer/generated-answer-selectors.ts @@ -1,12 +1,44 @@ +import {isNullOrUndefined} from '@coveo/bueno'; import {createSelector} from '@reduxjs/toolkit'; +import { + selectAnswer, + StateNeededByAnswerAPI, +} from '../../api/knowledge/stream-answer-api'; import {GeneratedAnswerCitation} from '../../controllers/generated-answer/headless-generated-answer'; import {SearchAppState} from '../../state/search-app-state'; -import {GeneratedAnswerSection} from '../../state/state-sections'; +import { + GeneratedAnswerSection, + SearchSection, +} from '../../state/state-sections'; import {selectQuery} from '../query/query-selectors'; export const generativeQuestionAnsweringIdSelector = ( state: Partial -) => state.search?.response?.extendedResults?.generativeQuestionAnsweringId; +): {answerAPIEnabled: boolean; id: string | undefined} => { + if (isGeneratedAnswerSection(state)) { + return {answerAPIEnabled: true, id: selectAnswer(state).data?.answerId}; + } + + if (isSearchSection(state)) { + return { + answerAPIEnabled: false, + id: state.search.response.extendedResults.generativeQuestionAnsweringId, + }; + } + + return {answerAPIEnabled: false, id: undefined}; +}; + +const isSearchSection = ( + state: Partial | StateNeededByAnswerAPI +): state is SearchSection => 'search' in state; + +const isGeneratedAnswerSection = ( + state: Partial +): state is StateNeededByAnswerAPI => + 'answer' in state && + 'generatedAnswer' in state && + !isNullOrUndefined(state.generatedAnswer?.answerConfigurationId); export const selectFieldsToIncludeInCitation = ( state: Partial diff --git a/packages/headless/src/features/result-preview/result-preview-analytics-actions.test.ts b/packages/headless/src/features/result-preview/result-preview-analytics-actions.test.ts index fa94246a891..4baeb18ba8d 100644 --- a/packages/headless/src/features/result-preview/result-preview-analytics-actions.test.ts +++ b/packages/headless/src/features/result-preview/result-preview-analytics-actions.test.ts @@ -13,7 +13,7 @@ jest.mock('@coveo/relay'); jest.mock('coveo.analytics'); describe('#logDocumentQuickview', () => { - const testResult = buildMockNonEmptyResult(); + const testResult = buildMockNonEmptyResult({searchUid: 'someid'}); let engine: SearchEngine; const makeDocumentQuickview = jest.fn(); const emit = jest.fn(); diff --git a/packages/headless/src/features/result-preview/result-preview-analytics-actions.ts b/packages/headless/src/features/result-preview/result-preview-analytics-actions.ts index 270e6f3efcf..6978211f665 100644 --- a/packages/headless/src/features/result-preview/result-preview-analytics-actions.ts +++ b/packages/headless/src/features/result-preview/result-preview-analytics-actions.ts @@ -1,4 +1,5 @@ import {ItemClick} from '@coveo/relay-event-types'; +import {SearchAnalyticsProvider} from '../../api/analytics/search-analytics'; import {Result} from '../../api/search/search/result'; import { ClickAction, @@ -17,6 +18,11 @@ export const logDocumentQuickview = (result: Result): ClickAction => { const id = documentIdentifier(result); return client.makeDocumentQuickview(info, id); }, + __legacy__provider: (getState) => { + const customAnalyticsProvider = new SearchAnalyticsProvider(getState); + customAnalyticsProvider.getSearchUID = () => result.searchUid ?? ''; + return customAnalyticsProvider; + }, analyticsType: 'itemClick', analyticsPayloadBuilder: (state): ItemClick => { const docInfo = partialDocumentInformation(result, state); diff --git a/packages/headless/src/features/result/result-analytics-actions.test.ts b/packages/headless/src/features/result/result-analytics-actions.test.ts index dcad7dd2850..7a63d6cb44b 100644 --- a/packages/headless/src/features/result/result-analytics-actions.test.ts +++ b/packages/headless/src/features/result/result-analytics-actions.test.ts @@ -13,7 +13,9 @@ jest.mock('@coveo/relay'); jest.mock('coveo.analytics'); describe('#logDocumentOpen', () => { - const testResult = buildMockNonEmptyResult(); + const testResult = buildMockNonEmptyResult({ + searchUid: 'example searchUid', + }); let engine: SearchEngine; const makeDocumentOpen = jest.fn(); const emit = jest.fn(); diff --git a/packages/headless/src/features/result/result-analytics-actions.ts b/packages/headless/src/features/result/result-analytics-actions.ts index 5e82de5a55b..dce02e87164 100644 --- a/packages/headless/src/features/result/result-analytics-actions.ts +++ b/packages/headless/src/features/result/result-analytics-actions.ts @@ -1,4 +1,5 @@ import {ItemClick} from '@coveo/relay-event-types'; +import {SearchAnalyticsProvider} from '../../api/analytics/search-analytics'; import {Result} from '../../api/search/search/result'; import { partialDocumentInformation, @@ -18,6 +19,11 @@ export const logDocumentOpen = (result: Result): ClickAction => documentIdentifier(result) ); }, + __legacy__provider: (getState) => { + const customAnalyticsProvider = new SearchAnalyticsProvider(getState); + customAnalyticsProvider.getSearchUID = () => result.searchUid ?? ''; + return customAnalyticsProvider; + }, analyticsType: 'itemClick', analyticsPayloadBuilder: (state): ItemClick => { const docInfo = partialDocumentInformation(result, state); diff --git a/packages/headless/src/features/search/search-slice.test.ts b/packages/headless/src/features/search/search-slice.test.ts index a6835e83983..e4c5109075f 100644 --- a/packages/headless/src/features/search/search-slice.test.ts +++ b/packages/headless/src/features/search/search-slice.test.ts @@ -148,6 +148,22 @@ describe('search-slice', () => { expect(finalState.searchResponseId).toBe('a_new_id'); }); + it('when a executeSearch fulfilled is received, results should contain last #searchUid', () => { + state.searchResponseId = 'an_initial_id'; + const response = buildMockSearchResponse({results: [newResult]}); + response.searchUid = 'a_new_id'; + const search = buildMockSearch({ + response, + }); + + const finalState = searchReducer( + state, + executeSearch.fulfilled(search, '', {legacy: logSearchboxSubmit()}) + ); + + expect(finalState.results[0].searchUid).toBe('a_new_id'); + }); + it('when a executeSearch fulfilled is received, it overwrites the #questionAnswer', () => { state.questionAnswer = buildMockQuestionsAnswers({ question: 'When?', @@ -200,6 +216,26 @@ describe('search-slice', () => { expect(finalState.searchResponseId).toBe('an_initial_id'); }); + it('when a fetchMoreResults fulfilled is received, previous results keep their #searchUiD', () => { + state.results = state.results.map((result) => ({ + ...result, + searchUid: 'an_initial_id', + })); + const response = buildMockSearchResponse({results: [newResult]}); + response.searchUid = 'a_new_id'; + const search = buildMockSearch({ + response, + }); + + const finalState = searchReducer( + state, + fetchMoreResults.fulfilled(search, '') + ); + + expect(finalState.results[0].searchUid).toBe('an_initial_id'); + expect(finalState.results[1].searchUid).toBe('a_new_id'); + }); + it('when a fetchMoreResults fulfilled is received, keeps the previous #questionAnswer', () => { const originalQuestionAnswers = buildMockQuestionsAnswers({ question: 'Why?', diff --git a/packages/headless/src/features/search/search-slice.ts b/packages/headless/src/features/search/search-slice.ts index 7281201000d..a48fce9e50b 100644 --- a/packages/headless/src/features/search/search-slice.ts +++ b/packages/headless/src/features/search/search-slice.ts @@ -44,7 +44,10 @@ function handleFulfilledNewSearch( action: ReturnType ) { handleFulfilledSearch(state, action); - state.results = action.payload.response.results; + state.results = action.payload.response.results.map((result) => ({ + ...result, + searchUid: action.payload.response.searchUid, + })); state.searchResponseId = action.payload.response.searchUid; state.questionAnswer = action.payload.response.questionAnswer; state.extendedResults = action.payload.response.extendedResults; @@ -81,7 +84,13 @@ export const searchReducer = createReducer( }); builder.addCase(fetchMoreResults.fulfilled, (state, action) => { handleFulfilledSearch(state, action); - state.results = [...state.results, ...action.payload.response.results]; + state.results = [ + ...state.results, + ...action.payload.response.results.map((result) => ({ + ...result, + searchUid: action.payload.response.searchUid, + })), + ]; }); builder.addCase(fetchPage.fulfilled, (state, action) => { handleFulfilledSearch(state, action); diff --git a/packages/headless/src/test/mock-result.ts b/packages/headless/src/test/mock-result.ts index f9c6008b892..11e668a6ea5 100644 --- a/packages/headless/src/test/mock-result.ts +++ b/packages/headless/src/test/mock-result.ts @@ -33,6 +33,7 @@ export function buildMockResult(config: Partial = {}): Result { absentTerms: [], raw: buildMockRaw(), isUserActionView: false, + searchUid: '', ...config, }; } diff --git a/packages/quantic/CHANGELOG.md b/packages/quantic/CHANGELOG.md index 81f292e663c..1764ede6eb1 100644 --- a/packages/quantic/CHANGELOG.md +++ b/packages/quantic/CHANGELOG.md @@ -1,3 +1,13 @@ +## 2.57.4 (2024-10-22) + +### Bug Fixes + +- **atomic,quantic:** broken HTML because of formatting in CRGA markdown heading ([#4564](https://github.com/coveo/ui-kit/issues/4564)) ([9fd1f95](https://github.com/coveo/ui-kit/commits/9fd1f95ca50fb57a0a3e2b49f7e675313a121994)) + +## 2.57.3 (2024-09-16) + +## 2.57.2 (2024-08-29) + # 2.57.0 (2024-08-21) ### Features diff --git a/packages/quantic/cypress/e2e/default-1/case-classification/case-classification-selectors.ts b/packages/quantic/cypress/e2e/default-1/case-classification/case-classification-selectors.ts index 2dd026b5e5f..ac31d43d8ac 100644 --- a/packages/quantic/cypress/e2e/default-1/case-classification/case-classification-selectors.ts +++ b/packages/quantic/cypress/e2e/default-1/case-classification/case-classification-selectors.ts @@ -55,7 +55,9 @@ export const CaseClassificationSelectors: CaseClassificationSelector & .find('.case-classification-option input') .eq(idx), error: () => - CaseClassificationSelectors.get().find('.slds-form-element__help'), + CaseClassificationSelectors.get().find( + '[data-cy="case-classification-error-message"]' + ), loadingSpinner: () => CaseClassificationSelectors.get().find('lightning-spinner'), componentError: () => diff --git a/packages/quantic/cypress/e2e/default-1/refine-modal-content/refine-modal-content.cypress.ts b/packages/quantic/cypress/e2e/default-1/refine-modal-content/refine-modal-content.cypress.ts index 8b40fbcfd9a..bd059dce328 100644 --- a/packages/quantic/cypress/e2e/default-1/refine-modal-content/refine-modal-content.cypress.ts +++ b/packages/quantic/cypress/e2e/default-1/refine-modal-content/refine-modal-content.cypress.ts @@ -77,6 +77,7 @@ describe('quantic-refine-content', () => { Expect.displayClearAllFiltersButton(true); Expect.displayDuplicatedTimeframeFacetClearFiltersButton(true); Expect.displayTimeframeFacetClearFiltersButton(true); + Actions.clickClearAllFilters(); Actions.clickDuplicatedFacetExpandButton(); Actions.clickDuplicatedFacetFirstOption(); Expect.displayClearAllFiltersButton(true); diff --git a/packages/quantic/cypress/e2e/facets-2/timeframe-facet/timeframe-facet-selectors.ts b/packages/quantic/cypress/e2e/facets-2/timeframe-facet/timeframe-facet-selectors.ts index 613bd47d36e..45e598b1287 100644 --- a/packages/quantic/cypress/e2e/facets-2/timeframe-facet/timeframe-facet-selectors.ts +++ b/packages/quantic/cypress/e2e/facets-2/timeframe-facet/timeframe-facet-selectors.ts @@ -58,5 +58,8 @@ export const TimeframeFacetSelectors: TimeframeFacetSelector = { applyButton: () => TimeframeFacetSelectors.get().find('.timeframe-facet__apply'), form: () => TimeframeFacetSelectors.get().find('form'), - validationError: () => TimeframeFacetSelectors.form().find('.slds-has-error'), + validationError: () => + TimeframeFacetSelectors.form().find( + '.slds-form-element__help[data-error-message]' + ), }; diff --git a/packages/quantic/cypress/e2e/facets-2/timeframe-facet/timeframe-facet.cypress.ts b/packages/quantic/cypress/e2e/facets-2/timeframe-facet/timeframe-facet.cypress.ts index 8de48992bde..2bdc4073fd2 100644 --- a/packages/quantic/cypress/e2e/facets-2/timeframe-facet/timeframe-facet.cypress.ts +++ b/packages/quantic/cypress/e2e/facets-2/timeframe-facet/timeframe-facet.cypress.ts @@ -314,7 +314,7 @@ describe('quantic-timeframe-facet', () => { Actions.submitForm(); Expect.numberOfValidationErrors(2); - Expect.validationError('Complete this field.'); + Expect.validationError('Complete this field'); }); scope('when entering then erasing dates', () => { @@ -322,7 +322,7 @@ describe('quantic-timeframe-facet', () => { Actions.submitForm(); Expect.numberOfValidationErrors(1); - Expect.validationError('Complete this field.'); + Expect.validationError('Complete this field'); Actions.typeEndDate(validRange.end); Actions.submitForm(); @@ -343,7 +343,7 @@ describe('quantic-timeframe-facet', () => { Expect.numberOfValidationErrors(1); Expect.validationError( - 'Your entry does not match the allowed format yyyy-MM-dd.' + 'Your entry does not match the allowed format' ); }); @@ -352,7 +352,7 @@ describe('quantic-timeframe-facet', () => { Expect.numberOfValidationErrors(1); Expect.validationError( - 'Your entry does not match the allowed format yyyy-MM-dd.' + 'Your entry does not match the allowed format' ); }); diff --git a/packages/quantic/force-app/main/default/lwc/quanticCaseClassification/quanticCaseClassification.html b/packages/quantic/force-app/main/default/lwc/quanticCaseClassification/quanticCaseClassification.html index 61ae02fb8fe..669c985de40 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticCaseClassification/quanticCaseClassification.html +++ b/packages/quantic/force-app/main/default/lwc/quanticCaseClassification/quanticCaseClassification.html @@ -64,7 +64,7 @@ diff --git a/packages/quantic/force-app/main/default/lwc/quanticFeedbackModal/quanticFeedbackModal.js b/packages/quantic/force-app/main/default/lwc/quanticFeedbackModal/quanticFeedbackModal.js index 8ff6d8a4ba0..47256b69c78 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticFeedbackModal/quanticFeedbackModal.js +++ b/packages/quantic/force-app/main/default/lwc/quanticFeedbackModal/quanticFeedbackModal.js @@ -20,7 +20,7 @@ import successTemplate from './success.html'; * The `QuanticFeedbackModal` component overlays a message modal on top of the current app window, the modal contains a form that allows the user to give feedback. * * Under the hood, the component relies on a [`lightningModal`](https://developer.salesforce.com/docs/component-library/bundle/lightning-modal/documentation) component. - * For an example of how to use the `QuanticFeedbackModal` component, see the [`quanticSmartSnippet`](https://github.com/coveo/ui-kit/blob/master/packages/quantic/force-app/main/default/lwc/quanticSmartSnippet/quanticSmartSnippet.js) implementation. + * For an example of how to use the `QuanticFeedbackModal` component, see the [`quanticSmartSnippet`](https://github.com/coveo/ui-kit/blob/v2/packages/quantic/force-app/main/default/lwc/quanticSmartSnippet/quanticSmartSnippet.js) implementation. * * @category Search * @category Insight Panel diff --git a/packages/quantic/force-app/main/default/lwc/quanticFeedbackModalQna/quanticFeedbackModalQna.js b/packages/quantic/force-app/main/default/lwc/quanticFeedbackModalQna/quanticFeedbackModalQna.js index cf72cbfd9bd..b6b5397a08c 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticFeedbackModalQna/quanticFeedbackModalQna.js +++ b/packages/quantic/force-app/main/default/lwc/quanticFeedbackModalQna/quanticFeedbackModalQna.js @@ -32,7 +32,7 @@ import successTemplate from './templates/success.html'; * The `QuanticFeedbackModalQna` component overlays a message modal on top of the current app window, the modal contains a form that allows the user to give feedback on a CRGA response. * * Under the hood, the component relies on a [`lightningModal`](https://developer.salesforce.com/docs/component-library/bundle/lightning-modal/documentation) component. - * For an example of how to use the `QuanticFeedbackModalQna` component, see the [`quanticGeneratedAnswer`](https://github.com/coveo/ui-kit/blob/master/packages/quantic/force-app/main/default/lwc/quanticGeneratedAnswer/quanticGeneratedAnswer.js) implementation. + * For an example of how to use the `QuanticFeedbackModalQna` component, see the [`quanticGeneratedAnswer`](https://github.com/coveo/ui-kit/blob/v2/packages/quantic/force-app/main/default/lwc/quanticGeneratedAnswer/quanticGeneratedAnswer.js) implementation. * * @category Search * @category Insight Panel diff --git a/packages/quantic/force-app/main/default/lwc/quanticUtils/__tests__/markdownUtils.test.js b/packages/quantic/force-app/main/default/lwc/quanticUtils/__tests__/markdownUtils.test.js index 3a161743252..e2cbe00e963 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticUtils/__tests__/markdownUtils.test.js +++ b/packages/quantic/force-app/main/default/lwc/quanticUtils/__tests__/markdownUtils.test.js @@ -28,6 +28,14 @@ describe('c/markdownUtils', () => { ); }); + it('should transform markdown heading with formatting to HTML
', () => { + const text = '# **bold** and *emphasized* title'; + const result = transformMarkdownToHtml(text, marked); + expect(removeLineBreaks(result)).toEqual( + '
bold and emphasized title
' + ); + }); + it('should transform markdown list item to HTML
  • ', () => { const text = '- Hello, world!'; const result = transformMarkdownToHtml(text, marked); diff --git a/packages/quantic/force-app/main/default/lwc/quanticUtils/markdownUtils.js b/packages/quantic/force-app/main/default/lwc/quanticUtils/markdownUtils.js index 88e87d83f03..062b0c7d85d 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticUtils/markdownUtils.js +++ b/packages/quantic/force-app/main/default/lwc/quanticUtils/markdownUtils.js @@ -3,6 +3,17 @@ import MARKED_JS from '@salesforce/resourceUrl/marked'; // @ts-ignore import {loadScript} from 'lightning/platformResourceLoader'; +/** + * Transforms a single line of text that may contain HTML to plain text. + * @param {string} textWithHtml A single line of text that may contain HTML + * @returns {string} The value as plain text + */ +const toInlinePlainText = (textWithHtml) => { + const withoutHtmlTags = textWithHtml.replace(/<[^>]*>/g, ' '); + const withCollapsedWhitespaces = withoutHtmlTags.replace(/\s{2,}/g, ' '); + return withCollapsedWhitespaces.trim(); +}; + // Any number of `*` between 1 and 3, or a single backtick, followed by a word character or whitespace character const unclosedElement = /(\*{1,3}|`)($|\w[\w\s]*$)/; @@ -49,7 +60,9 @@ const customRenderer = { * @param {string} level */ heading(text, level) { - return `
    ${text}
    `; + const plainText = toInlinePlainText(text); + + return `
    ${text}
    `; }, /** diff --git a/packages/quantic/package.json b/packages/quantic/package.json index 80f6e3e51ba..9351064cb33 100644 --- a/packages/quantic/package.json +++ b/packages/quantic/package.json @@ -1,6 +1,6 @@ { "name": "@coveo/quantic", - "version": "2.57.1", + "version": "2.57.4", "description": "A Salesforce Lightning Web Component (LWC) library for building modern UIs interfacing with the Coveo platform", "author": "coveo.com", "homepage": "https://coveo.com", @@ -40,13 +40,13 @@ "promote:sfdx:ci": "npm run publish:sfdx -- --promote --ci", "publish:npm": "npm run-script -w=@coveo/release npm-publish", "publish:bump": "npm run-script -w=@coveo/release bump", - "promote:npm:latest": "node ../../scripts/deploy/update-npm-tag.mjs latest", + "promote:npm:latest": "npm run-script -w=@coveo/release promote-npm-prod", "preinstall": "node scripts/npm/check-sfdx-project.js", "postinstall": "node scripts/npm/setup-quantic.js" }, "dependencies": { - "@coveo/bueno": "0.46.1", - "@coveo/headless": "2.80.0", + "@coveo/bueno": "0.46.3", + "@coveo/headless": "2.80.3", "dompurify": "3.1.6", "marked": "12.0.2" }, diff --git a/packages/samples/angular/package.json b/packages/samples/angular/package.json index 23200009935..36ec8647900 100644 --- a/packages/samples/angular/package.json +++ b/packages/samples/angular/package.json @@ -19,7 +19,7 @@ "@angular/platform-browser": "17.3.12", "@angular/platform-browser-dynamic": "17.3.12", "@angular/router": "17.3.12", - "@coveo/atomic-angular": "2.28.0", + "@coveo/atomic-angular": "2.28.3", "rxjs": "7.8.1", "tslib": "2.6.3", "zone.js": "0.14.8" diff --git a/packages/samples/atomic-next/package.json b/packages/samples/atomic-next/package.json index e8157dc0079..8d3e0369c7e 100644 --- a/packages/samples/atomic-next/package.json +++ b/packages/samples/atomic-next/package.json @@ -3,9 +3,9 @@ "version": "0.0.0", "private": true, "dependencies": { - "@coveo/atomic": "2.78.0", - "@coveo/atomic-react": "2.14.0", - "@coveo/headless": "2.80.0", + "@coveo/atomic": "2.78.3", + "@coveo/atomic-react": "2.14.3", + "@coveo/headless": "2.80.3", "next": "14.2.5", "react": "18.3.1", "react-dom": "18.3.1" diff --git a/packages/samples/atomic-react/package.json b/packages/samples/atomic-react/package.json index 5d696f649e5..be779fca195 100644 --- a/packages/samples/atomic-react/package.json +++ b/packages/samples/atomic-react/package.json @@ -4,9 +4,9 @@ "description": "Samples with atomic-react", "private": true, "dependencies": { - "@coveo/atomic": "2.78.0", - "@coveo/atomic-react": "2.14.0", - "@coveo/headless": "2.80.0", + "@coveo/atomic": "2.78.3", + "@coveo/atomic-react": "2.14.3", + "@coveo/headless": "2.80.3", "react": "18.3.1", "react-dom": "18.3.1" }, diff --git a/packages/samples/headless-commerce-react/package.json b/packages/samples/headless-commerce-react/package.json index ca20499bdec..4c8887355e6 100644 --- a/packages/samples/headless-commerce-react/package.json +++ b/packages/samples/headless-commerce-react/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { - "@coveo/headless": "2.80.0", + "@coveo/headless": "2.80.3", "@testing-library/jest-dom": "6.4.8", "@testing-library/react": "16.0.0", "@testing-library/user-event": "14.5.2", diff --git a/packages/samples/headless-react/package.json b/packages/samples/headless-react/package.json index 8184ea2b470..48d582465d4 100644 --- a/packages/samples/headless-react/package.json +++ b/packages/samples/headless-react/package.json @@ -4,8 +4,8 @@ "version": "0.0.0", "private": true, "dependencies": { - "@coveo/auth": "1.11.22", - "@coveo/headless": "2.80.0", + "@coveo/auth": "1.11.24", + "@coveo/headless": "2.80.3", "@testing-library/jest-dom": "6.4.8", "@testing-library/react": "14.3.1", "@testing-library/user-event": "14.5.2", diff --git a/packages/samples/headless-ssr-commerce/package.json b/packages/samples/headless-ssr-commerce/package.json index 76e46b5bba7..53232832d8e 100644 --- a/packages/samples/headless-ssr-commerce/package.json +++ b/packages/samples/headless-ssr-commerce/package.json @@ -11,7 +11,7 @@ "build:next": "next build" }, "dependencies": { - "@coveo/headless": "2.80.0", + "@coveo/headless": "2.80.3", "next": "14.2.5", "react": "^18.2.0", "react-dom": "^18.2.0" diff --git a/packages/samples/headless-ssr/package.json b/packages/samples/headless-ssr/package.json index 9d00370e329..fd4b6b0a886 100644 --- a/packages/samples/headless-ssr/package.json +++ b/packages/samples/headless-ssr/package.json @@ -8,8 +8,8 @@ "e2e:watch": "cypress open --browser chrome --e2e" }, "dependencies": { - "@coveo/headless-react": "1.1.4", - "@coveo/headless": "2.80.0", + "@coveo/headless-react": "1.1.7", + "@coveo/headless": "2.80.3", "next": "14.2.5", "react": "^18.2.0", "react-dom": "^18.2.0" diff --git a/packages/samples/iife/package.json b/packages/samples/iife/package.json index ce3949d865c..004a0aa44da 100644 --- a/packages/samples/iife/package.json +++ b/packages/samples/iife/package.json @@ -12,10 +12,10 @@ }, "dependencies": { "@babel/standalone": "7.25.0", - "@coveo/atomic": "2.78.0", - "@coveo/atomic-hosted-page": "0.6.7", - "@coveo/atomic-react": "2.14.0", - "@coveo/headless": "2.80.0", + "@coveo/atomic": "2.78.3", + "@coveo/atomic-hosted-page": "1.0.9", + "@coveo/atomic-react": "2.14.3", + "@coveo/headless": "2.80.3", "react": "18.3.1", "react-dom": "18.3.1" }, diff --git a/packages/samples/stencil/package.json b/packages/samples/stencil/package.json index 6d95ec4ac73..7f8d9c37240 100644 --- a/packages/samples/stencil/package.json +++ b/packages/samples/stencil/package.json @@ -8,8 +8,8 @@ "e2e:watch": "cypress open --browser chrome --e2e" }, "dependencies": { - "@coveo/atomic": "2.78.0", - "@coveo/headless": "2.80.0", + "@coveo/atomic": "2.78.3", + "@coveo/headless": "2.80.3", "@stencil/core": "4.20.0", "stencil-router-v2": "0.6.0" }, diff --git a/packages/samples/vuejs/package.json b/packages/samples/vuejs/package.json index 8145756a9f6..6cc84516c85 100644 --- a/packages/samples/vuejs/package.json +++ b/packages/samples/vuejs/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "vue": "^3.4.15", - "@coveo/atomic": "2.78.0" + "@coveo/atomic": "2.78.3" }, "devDependencies": { "@vitejs/plugin-vue": "^5.0.3", diff --git a/patches/@coveo+semantic-monorepo-tools+2.4.43.patch b/patches/@coveo+semantic-monorepo-tools+2.4.43.patch new file mode 100644 index 00000000000..4853ba4ce40 --- /dev/null +++ b/patches/@coveo+semantic-monorepo-tools+2.4.43.patch @@ -0,0 +1,33 @@ +diff --git a/node_modules/@coveo/semantic-monorepo-tools/dist/git/getLastGitTag.d.ts b/node_modules/@coveo/semantic-monorepo-tools/dist/git/getLastGitTag.d.ts +index 9c99911..85e65ec 100644 +--- a/node_modules/@coveo/semantic-monorepo-tools/dist/git/getLastGitTag.d.ts ++++ b/node_modules/@coveo/semantic-monorepo-tools/dist/git/getLastGitTag.d.ts +@@ -3,4 +3,7 @@ + * @param prefix only consider tag that has this prefix. Will return the last tag of the current branch by default. + * @return an array containing the last tag and the process that was spawned + */ +-export default function (prefix?: string): Promise; ++export default function ({ ++ prefix, ++ onBranch, ++ }: { prefix?: string; onBranch?: string } = {}): Promise; +diff --git a/node_modules/@coveo/semantic-monorepo-tools/dist/git/getLastGitTag.js b/node_modules/@coveo/semantic-monorepo-tools/dist/git/getLastGitTag.js +index f0ecdcf..1cfe9b1 100644 +--- a/node_modules/@coveo/semantic-monorepo-tools/dist/git/getLastGitTag.js ++++ b/node_modules/@coveo/semantic-monorepo-tools/dist/git/getLastGitTag.js +@@ -5,11 +5,14 @@ import gitLogger from "./utils/gitLogger.js"; + * @param prefix only consider tag that has this prefix. Will return the last tag of the current branch by default. + * @return an array containing the last tag and the process that was spawned + */ +-export default async function (prefix) { ++export default async function ({prefix, onBranch}) { + const gitParams = ["describe", "--tags", "--abbrev=0"]; + if (prefix) { + gitParams.push(`--match=${prefix}*`); + } ++ if(onBranch){ ++ gitParams.push(onBranch); ++ } + const gitPs = await spawn("git", gitParams, gitLogger); + return gitPs.stdout.trim(); + } diff --git a/patches/coveo.analytics+2.30.38.patch b/patches/coveo.analytics+2.30.38.patch new file mode 100644 index 00000000000..3d1c165cd4d --- /dev/null +++ b/patches/coveo.analytics+2.30.38.patch @@ -0,0 +1,31 @@ +diff --git a/node_modules/coveo.analytics/dist/browser.mjs b/node_modules/coveo.analytics/dist/browser.mjs +index 78efccc..115b8d3 100644 +--- a/node_modules/coveo.analytics/dist/browser.mjs ++++ b/node_modules/coveo.analytics/dist/browser.mjs +@@ -1135,8 +1135,6 @@ class NoopAnalyticsClient { + } + } + +-const fetch$1 = window.fetch; +- + class AnalyticsFetchClient { + constructor(opts) { + this.opts = opts; +@@ -1156,7 +1154,7 @@ class AnalyticsFetchClient { + const _a = Object.assign(Object.assign({}, defaultOptions), (preprocessRequest ? yield preprocessRequest(defaultOptions, 'analyticsFetch') : {})), { url } = _a, fetchData = __rest(_a, ["url"]); + let response; + try { +- response = yield fetch$1(url, fetchData); ++ response = yield fetch(url, fetchData); + } + catch (error) { + console.error('An error has occured when sending the event.', error); +@@ -1184,7 +1182,7 @@ class AnalyticsFetchClient { + return __awaiter(this, void 0, void 0, function* () { + const { baseUrl } = this.opts; + const url = `${baseUrl}/analytics/visit`; +- yield fetch$1(url, { headers: this.getHeaders(), method: 'DELETE' }); ++ yield fetch(url, { headers: this.getHeaders(), method: 'DELETE' }); + }); + } + shouldAppendVisitorId(eventType) { diff --git a/scripts/deploy/trigger-ui-kit-cd.mjs b/scripts/deploy/trigger-ui-kit-cd.mjs index 663308d55c7..b4e691097a2 100644 --- a/scripts/deploy/trigger-ui-kit-cd.mjs +++ b/scripts/deploy/trigger-ui-kit-cd.mjs @@ -6,6 +6,7 @@ await octokit.rest.repos.createDispatchEvent({ event_type: 'deploy', client_payload: { run_Id: context.runId, + version: 'v2', }, owner: 'coveo-platform', repo: 'ui-kit-cd', diff --git a/scripts/deploy/update-npm-tag.mjs b/scripts/deploy/update-npm-tag.mjs deleted file mode 100644 index 50738107cd8..00000000000 --- a/scripts/deploy/update-npm-tag.mjs +++ /dev/null @@ -1,49 +0,0 @@ -import {execute} from '../exec.mjs'; -import {getPackageManifestFromPackagePath} from '../packages.mjs'; - -const pkg = getPackageManifestFromPackagePath(process.cwd()); - -async function updateNpmTag(packageName, version) { - const tag = process.argv[2]; - const latestVersion = await getLatestVersion(packageName); - - if (!isGreaterThanLatestVersion(version, latestVersion)) { - console.log( - `skipping tag update for ${packageName} because version "${version}" is not greater than latest version "${latestVersion}".` - ); - return; - } - - console.log(`updating ${packageName}@${version} to ${tag}.`); - await execute('npm', ['dist-tag', 'add', `${packageName}@${version}`, tag]); -} - -async function getLatestVersion(packageName) { - const res = await execute('npm', ['view', packageName, 'version']); - return res.trim(); -} - -function isGreaterThanLatestVersion(version, latestVersion) { - const candidate = parseVersion(version); - const latest = parseVersion(latestVersion); - - return isCandidateGreaterThanLatestVersion(candidate, latest, 0); -} - -function parseVersion(version) { - return version.split('.').map((num) => parseInt(num, 10)); -} - -function isCandidateGreaterThanLatestVersion(candidate, latest, i) { - if (i >= candidate.length) { - return false; - } - - if (candidate[i] === latest[i]) { - return isCandidateGreaterThanLatestVersion(candidate, latest, i + 1); - } - - return candidate[i] > latest[i]; -} - -updateNpmTag(pkg.name, pkg.version); diff --git a/scripts/reports/bundle-size/time-series.mjs b/scripts/reports/bundle-size/time-series.mjs index 57493eecd22..1ee4c4429aa 100644 --- a/scripts/reports/bundle-size/time-series.mjs +++ b/scripts/reports/bundle-size/time-series.mjs @@ -5,7 +5,7 @@ const branch = process.env.GIT_BRANCH; const fileName = 'bundle-size-time-series.csv'; function isMasterBranch() { - return branch === 'origin/master'; + return branch === 'origin/v2'; } function dataFileExists() { diff --git a/utils/release/bump-package.mjs b/utils/release/bump-package.mjs index 225c4c7918f..86a16459916 100755 --- a/utils/release/bump-package.mjs +++ b/utils/release/bump-package.mjs @@ -17,10 +17,12 @@ import {appendFileSync, readFileSync, writeFileSync} from 'node:fs'; import {resolve, join} from 'node:path'; import {gt, SemVer} from 'semver'; import { + NPM_BETA_TAG, REPO_FS_ROOT, REPO_HOST, REPO_NAME, REPO_OWNER, + REPO_RELEASE_BRANCH, } from './common/constants.mjs'; if (!process.env.INIT_CWD) { @@ -82,7 +84,10 @@ await (async () => { ); const versionPrefix = `${packageJson.name}@`; const convention = await angularChangelogConvention(); - const lastTag = await getLastTag(versionPrefix); + const lastTag = await getLastTag({ + prefix: versionPrefix, + onBranch: `refs/remotes/origin/${REPO_RELEASE_BRANCH}`, + }); const commits = await getCommits(PATH, lastTag); if (commits.length === 0 && !hasPackageJsonChanged(PATH)) { return; @@ -92,7 +97,7 @@ await (async () => { let currentNpmVersion = new SemVer( privatePackage ? '0.0.0' // private package does not have a npm version, so we default to the 'lowest' possible - : await describeNpmTag(packageJson.name, 'beta') + : await describeNpmTag(packageJson.name, NPM_BETA_TAG) ); const isRedo = gt(currentNpmVersion, currentGitVersion); const bumpInfo = isRedo diff --git a/utils/release/common/constants.mjs b/utils/release/common/constants.mjs index a4469049a39..66a334baf66 100644 --- a/utils/release/common/constants.mjs +++ b/utils/release/common/constants.mjs @@ -4,7 +4,9 @@ import {fileURLToPath} from 'node:url'; export const REPO_HOST = 'https://github.com'; export const REPO_OWNER = 'coveo'; export const REPO_NAME = 'ui-kit'; -export const REPO_MAIN_BRANCH = 'master'; +export const REPO_MAIN_BRANCH = 'v2'; +export const REPO_RELEASE_BRANCH = 'release/v2'; + export const REPO_FS_ROOT = resolve( dirname(fileURLToPath(import.meta.url)), '..', @@ -18,3 +20,7 @@ export const RELEASER_AUTH_SECRETS = { clientSecret: process.env.RELEASER_CLIENT_SECRET, installationId: process.env.RELEASER_INSTALLATION_ID, }; + +export const NPM_LATEST_TAG = 'v2-latest'; +export const NPM_BETA_TAG = 'v2-beta'; +export const NPM_ALPHA_TAG = 'v2-alpha'; diff --git a/utils/release/git-publish-all.mjs b/utils/release/git-publish-all.mjs index 959cccccd84..5e1d11f9944 100755 --- a/utils/release/git-publish-all.mjs +++ b/utils/release/git-publish-all.mjs @@ -24,6 +24,7 @@ import { RELEASER_AUTH_SECRETS, REPO_NAME, REPO_OWNER, + REPO_RELEASE_BRANCH, } from './common/constants.mjs'; import {removeWriteAccessRestrictions} from './lock-master.mjs'; @@ -73,12 +74,10 @@ process.chdir(process.env.INIT_CWD); await gitPushTags(); // Current release branch - // TODO v3: Bump to release/v3 - const currentReleaseBranch = 'release/v2'; await octokit.rest.git.updateRef({ owner: REPO_OWNER, repo: REPO_NAME, - ref: `heads/${currentReleaseBranch}`, + ref: `heads/${REPO_RELEASE_BRANCH}`, sha: commit, force: false, }); diff --git a/utils/release/lock-master.mjs b/utils/release/lock-master.mjs index 2244758878c..e72b5caa613 100644 --- a/utils/release/lock-master.mjs +++ b/utils/release/lock-master.mjs @@ -10,7 +10,7 @@ import { REPO_OWNER, } from './common/constants.mjs'; -const RELEASE_FREEZE_ID = 215874; +const RELEASE_FREEZE_ID = 1510095; export const limitWriteAccessToBot = () => changeBranchRestrictions(true); diff --git a/utils/release/npm-publish-package.mjs b/utils/release/npm-publish-package.mjs index 6ff2cc3c660..7fe3a227ff6 100755 --- a/utils/release/npm-publish-package.mjs +++ b/utils/release/npm-publish-package.mjs @@ -2,6 +2,7 @@ import {describeNpmTag, npmPublish} from '@coveo/semantic-monorepo-tools'; import retry from 'async-retry'; import {readFileSync} from 'node:fs'; +import {NPM_ALPHA_TAG, NPM_BETA_TAG} from './common/constants.mjs'; if (!process.env.INIT_CWD) { throw new Error('Should be called using npm run-script'); @@ -38,7 +39,7 @@ if (!name || !version) { throw 'Expected name and version to exist in package.json.'; } if (!(await isPublished(name, version))) { - const tagToPublish = isPrerelease ? 'alpha' : 'beta'; + const tagToPublish = isPrerelease ? NPM_ALPHA_TAG : NPM_BETA_TAG; await npmPublish('.', { tag: tagToPublish, provenance: shouldProvideProvenance, diff --git a/utils/release/package.json b/utils/release/package.json index 6ce5cb75b02..2ff3e68154e 100644 --- a/utils/release/package.json +++ b/utils/release/package.json @@ -22,6 +22,7 @@ "typescript": "5.4.5" }, "scripts": { + "promote-npm-prod": "./promote-npm-tag-to-latest.mjs", "git-lock": "./git-lock.mjs", "bump": "./bump-package.mjs", "npm-publish": "./npm-publish-package.mjs", diff --git a/utils/release/promote-npm-tag-to-latest.mjs b/utils/release/promote-npm-tag-to-latest.mjs new file mode 100755 index 00000000000..3e33bfa26d8 --- /dev/null +++ b/utils/release/promote-npm-tag-to-latest.mjs @@ -0,0 +1,25 @@ +#!/usr/bin/env node +import {describeNpmTag, npmSetTag} from '@coveo/semantic-monorepo-tools'; +import {readFileSync} from 'node:fs'; +import {gt} from 'semver'; +import {NPM_LATEST_TAG} from './common/constants.mjs'; + +if (!process.env.INIT_CWD) { + throw new Error('Should be called using npm run-script'); +} +process.chdir(process.env.INIT_CWD); + +const {name, version} = JSON.parse( + readFileSync('package.json', {encoding: 'utf-8'}) +); + +const publishedVersion = await describeNpmTag(name, NPM_LATEST_TAG); + +if (gt(publishedVersion, version)) { + console.log( + `skipping tag update for ${name} because version "${version}" is not greater than latest version "${publishedVersion}".` + ); + process.exit(1); +} + +await npmSetTag(name, version, NPM_LATEST_TAG);