diff --git a/.github/workflows/PullRequest.yml b/.github/workflows/PullRequest.yml deleted file mode 100644 index 055ba8eed..000000000 --- a/.github/workflows/PullRequest.yml +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# CI workflow for PRs and merges to main -# https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions -name: PullRequest - -on: - push: - branches: [ main ] - pull_request: - branches: - - main - - 'release/stable' - - 'features/PowerPagesAgent' - workflow_dispatch: - -jobs: - build: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ windows-latest, macos-latest, ubuntu-latest ] - fail-fast: false - - steps: - - uses: actions/checkout@v3 - with: - lfs: true - - - name: Setup Node.js environment - uses: actions/setup-node@v3 - with: - node-version: 18 - - # - name: Install dependencies - # run: npm i -g npm - - - name: Build and unit test - run: | - npm ci - npm run dist - env: - AZ_DevOps_Read_PAT: ${{ secrets.AZ_DevOps_Read_PAT }} - - - name: Run integration tests - uses: coactions/setup-xvfb@v1 - with: - run: | - npm run test-integration - npm run test-web-integration diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..e497fe5e0 --- /dev/null +++ b/.npmrc @@ -0,0 +1,3 @@ +@gia:registry=https://msazure.pkgs.visualstudio.com/One/_packaging/BAP_GIA_Survey_Feed/npm/registry/ + +always-auth=true diff --git a/package-lock.json b/package-lock.json index 5a03e1afe..ac040f3bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "SEE LICENSE IN LICENSE", "dependencies": { "@fluidframework/azure-client": "^1.2.0", + "@gia/survey-sdk": "^1.0.12", "@microsoft/1ds-core-js": "4.0.5", "@microsoft/1ds-post-js": "4.0.5", "@microsoft/generator-powerpages": "1.21.19", @@ -19,6 +20,7 @@ "@xmldom/xmldom": "^0.8.10", "cockatiel": "^3.1.1", "command-exists": "^1.2.9", + "copy-webpack-plugin": "^12.0.2", "find-process": "^1.4.7", "fluid-framework": "^1.4.0", "glob": "^7.1.7", @@ -870,6 +872,25 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@fluentui/web-components": { + "version": "2.5.16", + "resolved": "https://registry.npmjs.org/@fluentui/web-components/-/web-components-2.5.16.tgz", + "integrity": "sha512-Ur+DziCm2FtvQoRjx62DH069uTz/HTq0gk9uKmW8K7bmxCS7fYYpV9GFEnK7QdEbdRHyUINE3uFfLEcL6IY3Xg==", + "license": "MIT", + "dependencies": { + "@microsoft/fast-colors": "^5.3.0", + "@microsoft/fast-element": "^1.11.1", + "@microsoft/fast-foundation": "^2.48.1", + "@microsoft/fast-web-utilities": "^5.4.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@fluentui/web-components/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "license": "0BSD" + }, "node_modules/@fluidframework/aqueduct": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@fluidframework/aqueduct/-/aqueduct-1.4.0.tgz", @@ -2307,6 +2328,16 @@ "@fluidframework/core-interfaces": "^1.4.0" } }, + "node_modules/@gia/survey-sdk": { + "version": "1.0.12", + "resolved": "https://msazure.pkgs.visualstudio.com/One/_packaging/BAP_GIA_Survey_Feed/npm/registry/@gia/survey-sdk/-/survey-sdk-1.0.12.tgz", + "integrity": "sha1-nBMBeGBeHCsOijnSxStWWiymT+E=", + "license": "ISC", + "dependencies": { + "@fluentui/web-components": "2.5.16", + "@microsoft/fast-colors": "5.3.1" + } + }, "node_modules/@gulp-sourcemaps/identity-map": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz", @@ -2858,6 +2889,39 @@ "@nevware21/ts-utils": ">= 0.10.4 < 2.x" } }, + "node_modules/@microsoft/fast-colors": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@microsoft/fast-colors/-/fast-colors-5.3.1.tgz", + "integrity": "sha512-72RZXVfCbwQzvo5sXXkuLXLT7rMeYaSf5r/6ewQiv/trBtqpWRm4DEH2EilHw/iWTBKOXs1qZNQndgUMa5n4LA==", + "license": "MIT" + }, + "node_modules/@microsoft/fast-element": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@microsoft/fast-element/-/fast-element-1.13.0.tgz", + "integrity": "sha512-iFhzKbbD0cFRo9cEzLS3Tdo9BYuatdxmCEKCpZs1Cro/93zNMpZ/Y9/Z7SknmW6fhDZbpBvtO8lLh9TFEcNVAQ==", + "license": "MIT" + }, + "node_modules/@microsoft/fast-foundation": { + "version": "2.49.6", + "resolved": "https://registry.npmjs.org/@microsoft/fast-foundation/-/fast-foundation-2.49.6.tgz", + "integrity": "sha512-DZVr+J/NIoskFC1Y6xnAowrMkdbf2d5o7UyWK6gW5AiQ6S386Ql8dw4KcC4kHaeE1yL2CKvweE79cj6ZhJhTvA==", + "license": "MIT", + "dependencies": { + "@microsoft/fast-element": "^1.13.0", + "@microsoft/fast-web-utilities": "^5.4.1", + "tabbable": "^5.2.0", + "tslib": "^1.13.0" + } + }, + "node_modules/@microsoft/fast-web-utilities": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@microsoft/fast-web-utilities/-/fast-web-utilities-5.4.1.tgz", + "integrity": "sha512-ReWYncndjV3c8D8iq9tp7NcFNc1vbVHvcBFPME2nNFKNbS1XCesYZGlIlf3ot5EmuOXPlrzUHOWzQ2vFpIkqDg==", + "license": "MIT", + "dependencies": { + "exenv-es6": "^1.1.1" + } + }, "node_modules/@microsoft/generator-powerpages": { "version": "1.21.19", "resolved": "https://registry.npmjs.org/@microsoft/generator-powerpages/-/generator-powerpages-1.21.19.tgz", @@ -3437,6 +3501,18 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@sinonjs/commons": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", @@ -4763,6 +4839,45 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, "node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -6657,6 +6772,136 @@ "node": ">= 10.13.0" } }, + "node_modules/copy-webpack-plugin": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz", + "integrity": "sha512-SNwdBeHyII+rWvee/bTnAYyO8vfVdcSTud4EIb6jcZ8inLeWucJE0DnxXQBjlQ5zlteuuvooGQy3LIyGxhvlOA==", + "license": "MIT", + "dependencies": { + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.1", + "globby": "^14.0.0", + "normalize-path": "^3.0.0", + "schema-utils": "^4.2.0", + "serialize-javascript": "^6.0.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/copy-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.2.tgz", + "integrity": "sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==", + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/copy-webpack-plugin/node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/copy-webpack-plugin/node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -8090,6 +8335,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/exenv-es6": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exenv-es6/-/exenv-es6-1.1.1.tgz", + "integrity": "sha512-vlVu3N8d6yEMpMsEm+7sUBAI81aqYYuEvfK0jNqmdb/OPXzzH7QWDDnVjMvDSY47JdHEqx/dfC/q8WkfoTmpGQ==", + "license": "MIT" + }, "node_modules/exit-on-epipe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", @@ -8255,9 +8506,10 @@ "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -16664,6 +16916,21 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -17871,6 +18138,12 @@ "semver": "bin/semver.js" } }, + "node_modules/tabbable": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz", + "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA==", + "license": "MIT" + }, "node_modules/table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", @@ -18733,6 +19006,28 @@ } }, "node_modules/undertaker/node_modules/fast-levenshtein": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", + "integrity": "sha512-Ia0sQNrMPXXkqVFt6w6M1n1oKo3NfKs+mvaV811Jwir7vAk9a6PVV9VPYf6X3BU97QiLEmuW3uXH9u87zDFfdw==", + "dev": true + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, "version": "3.0.0", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz", "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==", diff --git a/package.json b/package.json index 751f3d518..2d5438c5d 100644 --- a/package.json +++ b/package.json @@ -1101,6 +1101,7 @@ }, "dependencies": { "@fluidframework/azure-client": "^1.2.0", + "@gia/survey-sdk": "^1.0.12", "@microsoft/1ds-core-js": "4.0.5", "@microsoft/1ds-post-js": "4.0.5", "@microsoft/generator-powerpages": "1.21.19", @@ -1110,6 +1111,7 @@ "@xmldom/xmldom": "^0.8.10", "cockatiel": "^3.1.1", "command-exists": "^1.2.9", + "copy-webpack-plugin": "^12.0.2", "find-process": "^1.4.7", "fluid-framework": "^1.4.0", "glob": "^7.1.7", diff --git a/src/common/OneDSLoggerTelemetry/web/client/webExtensionTelemetryEvents.ts b/src/common/OneDSLoggerTelemetry/web/client/webExtensionTelemetryEvents.ts index 5dd63e32b..9d430d364 100644 --- a/src/common/OneDSLoggerTelemetry/web/client/webExtensionTelemetryEvents.ts +++ b/src/common/OneDSLoggerTelemetry/web/client/webExtensionTelemetryEvents.ts @@ -122,4 +122,10 @@ export enum webExtensionTelemetryEventNames { WEB_EXTENSION_SEARCH_TEXT_RESULTS = "WebExtensionSearchTextResults", WEB_EXTENSION_SEARCH_TEXT = "WebExtensionSearchText", WEB_EXTENSION_SEARCH_FILE = "WebExtensionSearchFile", + WEB_EXTENSION_NPS_WEBVIEW_FAILED_TO_INITIALIZE = "WebExtensionNPSWebViewFailedToInitialize", + WEB_EXTENSION_FETCH_LOCAL_SCRIPT_CONTENT = "webExtensionFetchLocalScriptContent", + WEB_EXTENSION_FETCH_LOCAL_SCRIPT_CONTENT_SUCCESS = "webExtensionFetchLocalScriptContentSuccess", + WEB_EXTENSION_FETCH_LOCAL_SCRIPT_CONTENT_FAILED = "webExtensionFetchLocalScriptContentFailed", + WEB_EXTENSION_NPS_SUBMIT_FEEDBACK_FAILED = "webExtensionNpsSubmitFeedbackFailed", + WEB_EXTENSION_NPS_SUBMIT_FEEDBACK_SUCCESS = "webExtensionNpsSubmitFeedbackSuccess", } diff --git a/src/common/copilot/user-feedback/constants.ts b/src/common/copilot/user-feedback/constants.ts index 8afadb6fc..e78a81a45 100644 --- a/src/common/copilot/user-feedback/constants.ts +++ b/src/common/copilot/user-feedback/constants.ts @@ -4,8 +4,8 @@ */ export enum SurveyConstants { - TEAM_NAME = "PowerPages", - SURVEY_NAME = "PowerPages-NPS", - EVENT_NAME = "VscodeWeb", + TEAM_NAME = "powerpages", + SURVEY_NAME = "powerpages-nps", + EVENT_NAME = "vscodeweb", AUTHORIZATION_ENDPOINT = "https://microsoft.onmicrosoft.com/cessurvey/user", -} \ No newline at end of file +} diff --git a/src/web/client/WebExtensionContext.ts b/src/web/client/WebExtensionContext.ts index 6be2cf609..0065d69d2 100644 --- a/src/web/client/WebExtensionContext.ts +++ b/src/web/client/WebExtensionContext.ts @@ -104,6 +104,7 @@ class WebExtensionContext implements IWebExtensionContext { private _currentSchemaVersion: string; private _websiteLanguageCode: string; private _telemetry: WebExtensionTelemetry; + private _npsAccessToken: string; private _npsEligibility: boolean; private _userId: string; private _formsProEligibilityId: string; @@ -190,6 +191,9 @@ class WebExtensionContext implements IWebExtensionContext { public get telemetry() { return this._telemetry; } + public get npsAccessToken() { + return this._npsAccessToken; + } public get npsEligibility() { return this._npsEligibility; } @@ -255,6 +259,7 @@ class WebExtensionContext implements IWebExtensionContext { this._currentSchemaVersion = ""; this._websiteLanguageCode = ""; this._telemetry = new WebExtensionTelemetry(); + this._npsAccessToken = ""; this._npsEligibility = false; this._userId = ""; this._formsProEligibilityId = ""; @@ -682,6 +687,10 @@ class WebExtensionContext implements IWebExtensionContext { ); } + public setNPSAccessToken(npsAccessToken: string) { + this._npsAccessToken = npsAccessToken; + } + public setNPSEligibility(eligibility: boolean) { this._npsEligibility = eligibility; } @@ -716,33 +725,33 @@ class WebExtensionContext implements IWebExtensionContext { } // eslint-disable-next-line @typescript-eslint/no-explicit-any - public async getWorkerScript(workerUrl: URL): Promise { + public async fetchLocalScriptContent(scriptUrl: URL): Promise { try { this.telemetry.sendInfoTelemetry( webExtensionTelemetryEventNames.WEB_EXTENSION_FETCH_WORKER_SCRIPT ); const response = await this.concurrencyHandler.handleRequest( - workerUrl + scriptUrl ) if (!response.ok) { throw new Error( - `Failed to fetch worker script '${workerUrl.toString()}': ${response.statusText}` + `Failed to fetch script '${scriptUrl.toString()}': ${response.statusText}` ); } this.telemetry.sendInfoTelemetry( webExtensionTelemetryEventNames.WEB_EXTENSION_FETCH_WORKER_SCRIPT_SUCCESS, - { workerUrl: workerUrl.toString() } + { workerUrl: scriptUrl.toString() } ); return await response.text(); } catch (error) { this.telemetry.sendErrorTelemetry( webExtensionTelemetryEventNames.WEB_EXTENSION_FETCH_WORKER_SCRIPT_FAILED, - this.getWorkerScript.name, - Constants.WEB_EXTENSION_FETCH_WORKER_SCRIPT_FAILED, + this.fetchLocalScriptContent.name, + Constants.WEB_EXTENSION_FETCH_LOCAL_SCRIPT_CONTENT_FAILED, error as Error ); } diff --git a/src/web/client/common/constants.ts b/src/web/client/common/constants.ts index bc2d613b6..f0a399b8e 100644 --- a/src/web/client/common/constants.ts +++ b/src/web/client/common/constants.ts @@ -26,11 +26,11 @@ export const BACK_TO_STUDIO_URL_TEMPLATE = "https://make{.region}.powerpages.mic export const STUDIO_PROD_REGION = "prod"; export const ARTEMIS_RESPONSE_FAILED = "Artemis response failed"; export const WEB_EXTENSION_GET_FROM_GRAPH_CLIENT_FAILED = "Web extension get from graph client failed"; -export const WEB_EXTENSION_FETCH_WORKER_SCRIPT_FAILED = "Web extension fetch worker script failed"; export const WEB_EXTENSION_POPULATE_SHARED_WORKSPACE_SYSTEM_ERROR = "Web extension populate shared workspace system error"; export const WEB_EXTENSION_WEB_WORKER_REGISTRATION_FAILED = "Web extension web worker registration failed"; export const WEB_EXTENSION_FETCH_GET_OR_CREATE_SHARED_WORK_SPACE_ERROR = "Web extension fetch get or create shared workspace error"; export const WEB_EXTENSION_QUICK_PICK_DEFAULT_STRING = "No users are currently viewing this page"; +export const WEB_EXTENSION_FETCH_LOCAL_SCRIPT_CONTENT_FAILED = "Web extension fetch local script content failed"; // Web extension constants export const BASE_64 = 'base64'; diff --git a/src/web/client/extension.ts b/src/web/client/extension.ts index a65c2a692..ae3d1d854 100644 --- a/src/web/client/extension.ts +++ b/src/web/client/extension.ts @@ -386,7 +386,7 @@ export function createWebWorkerInstance( const workerUrl = new URL(webworkerMain.toString()); - WebExtensionContext.getWorkerScript(workerUrl) + WebExtensionContext.fetchLocalScriptContent(workerUrl) .then((workerScript) => { const workerBlob = new Blob([workerScript], { type: "application/javascript", diff --git a/src/web/client/services/NPSService.ts b/src/web/client/services/NPSService.ts index 9b0ddd45f..4e732245c 100644 --- a/src/web/client/services/NPSService.ts +++ b/src/web/client/services/NPSService.ts @@ -71,6 +71,7 @@ export class NPSService { if (accessToken) { WebExtensionContext.telemetry.sendInfoTelemetry(webExtensionTelemetryEventNames.WEB_EXTENSION_NPS_AUTHENTICATION_COMPLETED); } + WebExtensionContext.setNPSAccessToken(accessToken); // eslint-disable-next-line @typescript-eslint/no-explicit-any const parsedToken = jwt_decode(accessToken) as any; diff --git a/src/web/client/webViews/NPSWebView.ts b/src/web/client/webViews/NPSWebView.ts index f2a6a408f..7e54000da 100644 --- a/src/web/client/webViews/NPSWebView.ts +++ b/src/web/client/webViews/NPSWebView.ts @@ -6,9 +6,9 @@ import * as vscode from "vscode"; import WebExtensionContext from "../WebExtensionContext"; import { queryParameters } from "../common/constants"; -import { getDeviceType } from "../utilities/deviceType"; import { webExtensionTelemetryEventNames } from "../../../common/OneDSLoggerTelemetry/web/client/webExtensionTelemetryEvents"; -import { getEnvironmentIdFromUrl } from "../utilities/commonUtil"; +import { SurveyConstants } from "../../../common/copilot/user-feedback/constants"; +import { NPSService } from "../services/NPSService"; export class NPSWebView { private readonly _webviewPanel: vscode.WebviewPanel; @@ -18,50 +18,139 @@ export class NPSWebView { webViewPanel: vscode.WebviewPanel ) { this._webviewPanel = webViewPanel; - this._webviewPanel.webview.html = this._getHtml(); + this.initializeWebView().catch((error) => this.handleError(error)); } - private _getHtml() { + private async initializeWebView() { try { - const nonce = getNonce(); - const mainJs = this.extensionResourceUrl("media", "main.js"); - const tid = WebExtensionContext.urlParametersMap?.get( - queryParameters.TENANT_ID + const webviewHtml = await this._getHtml(); + this._webviewPanel.webview.html = webviewHtml; + } catch (error) { + this.handleError(error); + } + } + + private handleError(error: unknown) { + WebExtensionContext.telemetry.sendErrorTelemetry( + webExtensionTelemetryEventNames.WEB_EXTENSION_NPS_WEBVIEW_FAILED_TO_INITIALIZE, + this.initializeWebView.name, + (error as Error)?.message + ); + this._webviewPanel.dispose(); + } + + private async submitFeedback( + teamName: string, + surveyName: string, + userId: string, + feedback: string + ) { + try { + const npsSurveyHeaders: HeadersInit = NPSService.getCesHeader( + WebExtensionContext.npsAccessToken + ); + const npsSurveyEndpoint = NPSService.getNpsSurveyEndpoint(); + const requestUrl = `${npsSurveyEndpoint}/api/v1/${teamName}/Surveys/${surveyName}/Feedbacks?userId=${userId}`; + + const requestSentAtTime = new Date().getTime(); + const response = + await WebExtensionContext.concurrencyHandler.handleRequest( + requestUrl, + { + method: "POST", + headers: npsSurveyHeaders, + body: JSON.stringify(feedback), + } + ); + + if (!response.ok) { + WebExtensionContext.telemetry.sendAPIFailureTelemetry( + requestUrl, + "NPS-Survey", + "POST", + new Date().getTime() - requestSentAtTime, + this.submitFeedback.name, + response.statusText, + ); + + throw new Error(JSON.stringify(response)); + } + + const data = await response.json(); + + WebExtensionContext.telemetry.sendAPISuccessTelemetry( + requestUrl, + "NPS-Survey", + "POST", + new Date().getTime() - requestSentAtTime, + this.submitFeedback.name + ); + + return data.feedbackId; + } catch (error) { + WebExtensionContext.telemetry.sendErrorTelemetry( + webExtensionTelemetryEventNames.WEB_EXTENSION_NPS_SUBMIT_FEEDBACK_FAILED, + this.submitFeedback.name, + (error as Error)?.message ); - const envId = getEnvironmentIdFromUrl(); - const geo = WebExtensionContext.urlParametersMap?.get( - queryParameters.GEO + + throw error; + } + } + + private async _getHtml(): Promise { + try { + const surveyLocation = vscode.Uri.joinPath( + this.extensionUri, + "dist", + "Nps-Survey-SDK", + "survey.lib.umd.v1.0.10.min.js" ); - const culture = vscode.env.language; - const productVersion = process?.env?.BUILD_NAME; - const deviceType = getDeviceType(); - const referrerPath: string[] = [ - "https:/", - vscode.env.appHost, - "powerplatform/portal", - WebExtensionContext.defaultEntityType, - WebExtensionContext.defaultEntityId, - ]; - const urlReferrer = referrerPath.join("/"); - const formsProEligibilityId = - WebExtensionContext.formsProEligibilityId; - WebExtensionContext.telemetry.sendInfoTelemetry( - webExtensionTelemetryEventNames.WEB_EXTENSION_RENDER_NPS + const surveyUrl = new URL(surveyLocation.toString()); + const surveyScript = + await WebExtensionContext.fetchLocalScriptContent(surveyUrl); + + const tid = WebExtensionContext.urlParametersMap?.get( + queryParameters.TENANT_ID ); - return ` - - - - Test CES Survey - - - -
- - - - - `; + const userId = WebExtensionContext.userId; + + return ` + + + + + + Microsoft wants your feedback + + + + + + + + `; } catch (error) { WebExtensionContext.telemetry.sendErrorTelemetry( webExtensionTelemetryEventNames.WEB_EXTENSION_RENDER_NPS_FAILED, @@ -72,34 +161,18 @@ export class NPSWebView { } } - private extensionResourceUrl(...parts: string[]): vscode.Uri { - return this._webviewPanel.webview.asWebviewUri( - vscode.Uri.joinPath(this.extensionUri, ...parts) - ); - } - public static createOrShow(extensionUri: vscode.Uri): NPSWebView { const webview = vscode.window.createWebviewPanel( "testCESSurvey", - vscode.l10n.t("Microsoft wants your feeback"), + vscode.l10n.t("Microsoft wants your feedback"), { viewColumn: vscode.ViewColumn.One, preserveFocus: false }, { enableScripts: true, localResourceRoots: [ - vscode.Uri.joinPath(extensionUri, "media", "main.js"), + vscode.Uri.joinPath(extensionUri, "dist", "Nps-Survey-SDK"), ], } ); return new NPSWebView(extensionUri, webview); } } - -function getNonce() { - let text = ""; - const possible = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - for (let i = 0; i < 64; i++) { - text += possible.charAt(Math.floor(Math.random() * possible.length)); - } - return text; -} diff --git a/webpack.config.js b/webpack.config.js index c27c00a87..ee3fc52a8 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -10,6 +10,7 @@ const path = require('path'); const webpack = require('webpack'); const { dependencies } = require('./package.json'); +const copyWebpackPlugin = require('copy-webpack-plugin'); /**@type {import('webpack').Configuration}*/ @@ -58,6 +59,7 @@ const nodeConfig = { }), ] }; + const webConfig = { mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production') target: 'webworker', // extensions run in a webworker context @@ -108,6 +110,14 @@ const webConfig = { new webpack.DefinePlugin({ IS_DESKTOP: false, }), + new copyWebpackPlugin({ + patterns: [ + { + from: path.resolve(__dirname, 'node_modules/@gia/survey-sdk/dist/survey.lib.umd.v1.0.10.min.js'), + to: path.resolve(__dirname, 'dist/Nps-Survey-SDK') + }, + ] + }) ], externals: { 'vscode': 'commonjs vscode', // ignored because it doesn't exist