From b83cda9503fff19cdf7d6c9668a7210d8bece213 Mon Sep 17 00:00:00 2001 From: Chidozie Ononiwu Date: Mon, 11 Sep 2023 14:46:36 -0700 Subject: [PATCH 1/5] Implement Cross Language View in Context Show menu for loading cross language view Show menu for loading cross language view Experiments in CrossLanguage APIView Cross Language View POC Show Cross Language Panel Fix Misc Issues More work on Cross Language View Remove Stale Code Add Custom Model Binder Add Language Customizations Implement Cross Language View in Context Updates to Comment for Cross Language --- .../APIView/APIView/CodeFileRenderer.cs | 13 +- src/dotnet/APIView/APIView/CodeLine.cs | 7 +- .../APIView/APIView/Model/CodeFileToken.cs | 4 +- .../APIView/APIViewWeb/Client/css/main.scss | 2 +- .../css/shared/bootstraps-overrides.scss | 19 +- .../Client/css/shared/codeline.scss | 46 + ...cons.scss => language-customizations.scss} | 5 + .../APIViewWeb/Client/package-lock.json | 4035 +++++++++++++++++ .../Client/src/pages/review.module.ts | 289 +- .../APIViewWeb/Client/src/pages/review.ts | 114 +- .../Client/src/shared/comments.module.ts | 13 + .../APIViewWeb/Client/src/shared/comments.ts | 25 +- .../APIViewWeb/Client/src/shared/helpers.ts | 60 +- .../Controllers/CommentsController.cs | 3 +- ...dationAttribute.cs => HelperAttributes.cs} | 5 - .../APIViewWeb/Helpers/HelperModelBinders.cs | 24 + .../Helpers/LanguageServiceHelpers.cs | 55 +- .../APIViewWeb/Helpers/PageModelHelpers.cs | 83 +- .../APIViewWeb/LeanModels/CommentItemModel.cs | 1 + .../LeanModels/ReviewRevisionPageModels.cs | 1 + .../APIViewWeb/Models/CodeLineModel.cs | 10 +- .../APIViewWeb/Models/CommentThreadModel.cs | 2 + .../APIViewWeb/Pages/Assemblies/Review.cshtml | 1157 ++--- .../Pages/Assemblies/Review.cshtml.cs | 22 + .../Pages/Assemblies/Samples.cshtml.cs | 2 +- .../Pages/Assemblies/_CodeLine.cshtml | 12 +- .../Pages/Shared/_CommentThreadPartial.cshtml | 2 +- .../Shared/_CrossLanguageViewPartial.cshtml | 34 + .../APIViewWeb/Pages/Shared/_Layout.cshtml | 2 +- .../Pages/Shared/_ReviewNavBar.cshtml | 37 + .../wwwroot/icons/java-original.svg | 6 +- .../wwwroot/icons/javascript-original.svg | 7 +- .../wwwroot/icons/python-original.svg | 6 +- .../wwwroot/icons/typespec-original.svg | 36 + 34 files changed, 5273 insertions(+), 866 deletions(-) rename src/dotnet/APIView/APIViewWeb/Client/css/shared/{icons.scss => language-customizations.scss} (98%) create mode 100644 src/dotnet/APIView/APIViewWeb/Client/package-lock.json rename src/dotnet/APIView/APIViewWeb/Helpers/{UploadModelValidationAttribute.cs => HelperAttributes.cs} (90%) create mode 100644 src/dotnet/APIView/APIViewWeb/Helpers/HelperModelBinders.cs create mode 100644 src/dotnet/APIView/APIViewWeb/Pages/Shared/_CrossLanguageViewPartial.cshtml create mode 100644 src/dotnet/APIView/APIViewWeb/Pages/Shared/_ReviewNavBar.cshtml create mode 100644 src/dotnet/APIView/APIViewWeb/wwwroot/icons/typespec-original.svg diff --git a/src/dotnet/APIView/APIView/CodeFileRenderer.cs b/src/dotnet/APIView/APIView/CodeFileRenderer.cs index 3f06c791676..fa77997054e 100644 --- a/src/dotnet/APIView/APIView/CodeFileRenderer.cs +++ b/src/dotnet/APIView/APIView/CodeFileRenderer.cs @@ -33,6 +33,7 @@ private void Render(List list, IEnumerable node, bool s { var stringBuilder = new StringBuilder(); string currentId = null; + string currentCrossLangId = null; string currentTableId = null; bool isDocumentationRange = false; bool isHiddenApiToken = false; @@ -57,7 +58,7 @@ private void Render(List list, IEnumerable node, bool s switch (token.Kind) { case CodeFileTokenKind.Newline: - CaptureCodeLine(list, sections, nodesInProcess, ref section, stringBuilder, ref lineNumber, ref leafSectionPlaceHolderNumber, ref currentId, isDocumentationRange, isHiddenApiToken); + CaptureCodeLine(list, sections, nodesInProcess, ref section, stringBuilder, ref lineNumber, ref leafSectionPlaceHolderNumber, ref currentId, ref currentCrossLangId, isDocumentationRange, isHiddenApiToken); break; case CodeFileTokenKind.DocumentRangeStart: @@ -97,6 +98,7 @@ private void Render(List list, IEnumerable node, bool s case CodeFileTokenKind.FoldableSectionHeading: nodesInProcess.Push(SectionType.Heading); currentId = (token.DefinitionId != null) ? token.DefinitionId : currentId; + currentCrossLangId = (token.CrossLanguageDefinitionId != null) ? token.CrossLanguageDefinitionId : currentCrossLangId; RenderToken(token, stringBuilder, isDeprecatedToken, isHiddenApiToken); break; @@ -149,7 +151,7 @@ private void Render(List list, IEnumerable node, bool s stringBuilder.Append(""); stringBuilder.Append(""); tableColumnCount.Curr = 0; - CaptureCodeLine(list, sections, nodesInProcess, ref section, stringBuilder, ref lineNumber, ref leafSectionPlaceHolderNumber, ref currentId, isDocumentationRange, isHiddenApiToken); + CaptureCodeLine(list, sections, nodesInProcess, ref section, stringBuilder, ref lineNumber, ref leafSectionPlaceHolderNumber, ref currentId, ref currentCrossLangId, isDocumentationRange, isHiddenApiToken); } else { @@ -186,7 +188,7 @@ private void Render(List list, IEnumerable node, bool s if (tableColumnCount.Curr == 0) { stringBuilder.Append(""); - CaptureCodeLine(list, sections, nodesInProcess, ref section, stringBuilder, ref lineNumber, ref leafSectionPlaceHolderNumber, ref currentId, isDocumentationRange, isHiddenApiToken); + CaptureCodeLine(list, sections, nodesInProcess, ref section, stringBuilder, ref lineNumber, ref leafSectionPlaceHolderNumber, ref currentId, ref currentCrossLangId, isDocumentationRange, isHiddenApiToken); } break; @@ -208,6 +210,7 @@ private void Render(List list, IEnumerable node, bool s default: currentId = (token.DefinitionId != null) ? token.DefinitionId : currentId; + currentCrossLangId = (token.CrossLanguageDefinitionId != null) ? token.CrossLanguageDefinitionId : currentCrossLangId; RenderToken(token, stringBuilder, isDeprecatedToken, isHiddenApiToken); break; } @@ -228,11 +231,11 @@ protected virtual void StartDocumentationRange(StringBuilder stringBuilder) { } protected virtual void CloseDocumentationRange(StringBuilder stringBuilder) { } private void CaptureCodeLine(List list, Dictionary> sections, Stack nodesInProcess, - ref TreeNode section, StringBuilder stringBuilder, ref int lineNumber, ref int leafSectionPlaceHolderNumber, ref string currentId, + ref TreeNode section, StringBuilder stringBuilder, ref int lineNumber, ref int leafSectionPlaceHolderNumber, ref string currentId, ref string currentCrossLangId, bool isDocumentationRange = false, bool isHiddenApiToken = false) { int? sectionKey = (nodesInProcess.Count > 0 && section == null) ? sections.Count : null; - CodeLine codeLine = new CodeLine(stringBuilder.ToString(), currentId, String.Empty, ++lineNumber, sectionKey, isDocumentation: isDocumentationRange, isHiddenApi: isHiddenApiToken); + CodeLine codeLine = new CodeLine(stringBuilder.ToString(), currentId, currentCrossLangId, String.Empty, ++lineNumber, sectionKey, isDocumentation: isDocumentationRange, isHiddenApi: isHiddenApiToken); if (leafSectionPlaceHolderNumber != 0) { lineNumber += leafSectionPlaceHolderNumber - 1; diff --git a/src/dotnet/APIView/APIView/CodeLine.cs b/src/dotnet/APIView/APIView/CodeLine.cs index b70739a26a6..e98d105808f 100644 --- a/src/dotnet/APIView/APIView/CodeLine.cs +++ b/src/dotnet/APIView/APIView/CodeLine.cs @@ -7,6 +7,7 @@ namespace ApiView { public string DisplayString { get; } public string ElementId { get; } + public string CrossLanguageDefinitionId { get; } public string LineClass { get; } public int? LineNumber { get; } public int? SectionKey { get; } @@ -15,10 +16,11 @@ namespace ApiView public TreeNode NodeRef { get; } public bool IsHiddenApi { get; } - public CodeLine(string html, string id, string lineClass, int? lineNumber = null, int? sectionKey = null, int indent = 0, bool isDocumentation = false, TreeNode nodeRef = null, bool isHiddenApi = false) + public CodeLine(string html, string id, string crossLangId, string lineClass, int? lineNumber = null, int? sectionKey = null, int indent = 0, bool isDocumentation = false, TreeNode nodeRef = null, bool isHiddenApi = false) { this.DisplayString = html; this.ElementId = id; + this.CrossLanguageDefinitionId = crossLangId; this.LineClass = lineClass; this.LineNumber = lineNumber; this.SectionKey = sectionKey; @@ -28,10 +30,11 @@ public CodeLine(string html, string id, string lineClass, int? lineNumber = null this.IsHiddenApi = isHiddenApi; } - public CodeLine(CodeLine codeLine, string html = null, string id = null, string lineClass = null, int? lineNumber = null, int? sectionKey = null, int indent = 0, bool isDocumentation = false, TreeNode nodeRef = null, bool isHiddenApi = false) + public CodeLine(CodeLine codeLine, string html = null, string id = null, string crossLangId = null, string lineClass = null, int? lineNumber = null, int? sectionKey = null, int indent = 0, bool isDocumentation = false, TreeNode nodeRef = null, bool isHiddenApi = false) { this.DisplayString = html ?? codeLine.DisplayString; this.ElementId = id ?? codeLine.ElementId; + this.CrossLanguageDefinitionId = crossLangId ?? codeLine.CrossLanguageDefinitionId; this.LineClass = lineClass ?? codeLine.LineClass; this.LineNumber = lineNumber ?? codeLine.LineNumber; this.SectionKey = sectionKey ?? codeLine.SectionKey; diff --git a/src/dotnet/APIView/APIView/Model/CodeFileToken.cs b/src/dotnet/APIView/APIView/Model/CodeFileToken.cs index 310f8a2e2b0..6d444153f4f 100644 --- a/src/dotnet/APIView/APIView/Model/CodeFileToken.cs +++ b/src/dotnet/APIView/APIView/Model/CodeFileToken.cs @@ -8,7 +8,7 @@ public CodeFileToken(string value, CodeFileTokenKind kind, int? numberOfLinesinL NavigateToId = null; Kind = kind; DefinitionId = null; - CrossLanguageDefId = null; + CrossLanguageDefinitionId = null; NumberOfLinesinLeafSection = numberOfLinesinLeafSection; } @@ -20,7 +20,7 @@ public CodeFileToken(string value, CodeFileTokenKind kind, int? numberOfLinesinL public CodeFileTokenKind Kind { get; set; } - public string CrossLanguageDefId { get; set; } + public string CrossLanguageDefinitionId { get; set; } public int? NumberOfLinesinLeafSection { get; set; } diff --git a/src/dotnet/APIView/APIViewWeb/Client/css/main.scss b/src/dotnet/APIView/APIViewWeb/Client/css/main.scss index 0ec77affb81..ab8faef22e7 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/css/main.scss +++ b/src/dotnet/APIView/APIViewWeb/Client/css/main.scss @@ -4,7 +4,7 @@ @import "./shared/sumo-select.scss"; @import "./shared/bootstraps-overrides.scss"; @import "./shared/off-canvas.scss"; -@import "./shared/icons.scss"; +@import "./shared/language-customizations.scss"; @import "./shared/codeline-navigation.scss"; @import "./shared/codeline.scss"; @import "./shared/comments.scss"; diff --git a/src/dotnet/APIView/APIViewWeb/Client/css/shared/bootstraps-overrides.scss b/src/dotnet/APIView/APIViewWeb/Client/css/shared/bootstraps-overrides.scss index eb4607eb5f4..180a891a634 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/css/shared/bootstraps-overrides.scss +++ b/src/dotnet/APIView/APIViewWeb/Client/css/shared/bootstraps-overrides.scss @@ -67,6 +67,10 @@ box-shadow: var(--box-shadow-link); } +.breadcrumb-item + .breadcrumb-item::before { + margin-top: 0.25rem; +} + .page-link { background-color: var(--base-fg-color); border: 1px solid var(--border-color); @@ -110,19 +114,12 @@ border-bottom: 1px solid var(--border-color) !important; } -.breadcrumb { - margin-bottom: 0rem; -} -.breadcrumb-item + .breadcrumb-item::before { - margin-top: 0rem; -} - -.breadcrumb-item + .breadcrumb-item::before { - padding-right: 0.25rem; +.border-start { + border-left: 1px solid var(--border-color) !important; } -.breadcrumb-item + .breadcrumb-item { - padding-left: 0.25rem; +.border-end { + border-right: 1px solid var(--border-color) !important; } .list-group-item { diff --git a/src/dotnet/APIView/APIViewWeb/Client/css/shared/codeline.scss b/src/dotnet/APIView/APIViewWeb/Client/css/shared/codeline.scss index 77a2751f268..0c118e85edf 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/css/shared/codeline.scss +++ b/src/dotnet/APIView/APIViewWeb/Client/css/shared/codeline.scss @@ -41,6 +41,10 @@ animation: glow normal 1.5s ease-in-out; } +.code-line.cl-active, .code-line tr.cl-active { + background: rgba(239,155,15, 0.22); +} + .code { padding: 0px; position: relative; @@ -133,6 +137,48 @@ width: auto; } +.cl-line-no { + color: goldenrod; +} + +.cross-language-panel { + .nav-link { + color: var(--link-color); + } + + .nav-pills .nav-link.active, .nav-pills .show > .nav-link { + background-color: transparent; + box-shadow: var(--box-shadow-left); + } + + .nav-pills .nav-link { + border-radius: 0; + } + + .badge { + background-color: var(--link-color); + border-color: var(--link-color); + color: var(--primary-btn-color); + } +} + + +.cross-language-pills-tab-content { + width: 55dvw; + margin-right: 5px; + max-height: 35dvh; + overflow: auto; +} + +.cl-custom-popover { + --bs-popover-max-width: 200px; + --bs-popover-border-color: var(--bd-violet-bg); + --bs-popover-header-bg: var(--bd-violet-bg); + --bs-popover-header-color: var(--bs-white); + --bs-popover-body-padding-x: 1rem; + --bs-popover-body-padding-y: .5rem; +} + .line-comment-button:hover { transform: scale(1); text-decoration: none; diff --git a/src/dotnet/APIView/APIViewWeb/Client/css/shared/icons.scss b/src/dotnet/APIView/APIViewWeb/Client/css/shared/language-customizations.scss similarity index 98% rename from src/dotnet/APIView/APIViewWeb/Client/css/shared/icons.scss rename to src/dotnet/APIView/APIViewWeb/Client/css/shared/language-customizations.scss index c596473fdab..063478b032e 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/css/shared/icons.scss +++ b/src/dotnet/APIView/APIViewWeb/Client/css/shared/language-customizations.scss @@ -228,6 +228,11 @@ background: url(/icons/swagger-original.svg) center/contain no-repeat; } +.icon-typespec { + @extend .icon-language; + background: url(/icons/typespec-original.svg) center center no-repeat; +} + .icon-comments { cursor: pointer; position: absolute; diff --git a/src/dotnet/APIView/APIViewWeb/Client/package-lock.json b/src/dotnet/APIView/APIViewWeb/Client/package-lock.json new file mode 100644 index 00000000000..fd1916ac65b --- /dev/null +++ b/src/dotnet/APIView/APIViewWeb/Client/package-lock.json @@ -0,0 +1,4035 @@ +{ + "name": "apiview", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "apiview", + "version": "0.1.0", + "dependencies": { + "@microsoft/signalr": "^7.0.5", + "acorn": "^8.0.0", + "core-js": "^3.3.2", + "form-data": "^4.0.0", + "jquery": "3.6.0", + "underscore": "^1.13.4" + }, + "devDependencies": { + "@playwright/test": "^1.33.0", + "@types/jquery": "3.3.31", + "@types/node": "^20.1.3", + "@types/split.js": "^1.4.0", + "@types/webpack-env": "^1.14.1", + "@typescript-eslint/parser": "5.16.0", + "bootstrap": "5.0.2", + "css-loader": "^3.6.0", + "eslint": "^8.11.0", + "eslint-plugin-vue": "^8.5.0", + "fetch-blob": "^2.1.2", + "form-data-encoder": "^1.9.0", + "formdata-node": "^4.4.1", + "inspectpack": "^4.7.1", + "mini-css-extract-plugin": "^2.7.2", + "node-fetch": "^2.6.11", + "sass": "^1.19.0", + "sass-loader": "^8.0.2", + "style-loader": "^3.3.1", + "ts-loader": "^6.2.0", + "typescript": "^5.0.4", + "webpack": "^5.70.0", + "webpack-cli": "^4.9.2" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.2.tgz", + "integrity": "sha512-0MGxAVt1m/ZK+LTJp/j0qF7Hz97D9O/FH9Ms3ltnyIdDD57cbb1ACIQTkbHvNXtWDv5TPq7w5Kq56+cNukbo7g==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.50.0.tgz", + "integrity": "sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@microsoft/signalr": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-7.0.11.tgz", + "integrity": "sha512-//6ipnYKhHf2MJgM+MQSlgB5L/pcYeZ+v4w6YAr4epRM1iSDQ6WjUkCVX2ZMxcY06XGlLzggs3Z9ZIcL9ws9KQ==", + "dependencies": { + "abort-controller": "^3.0.0", + "eventsource": "^2.0.2", + "fetch-cookie": "^2.0.3", + "node-fetch": "^2.6.7", + "ws": "^7.4.5" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@playwright/test": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.38.1.tgz", + "integrity": "sha512-NqRp8XMwj3AK+zKLbZShl0r/9wKgzqI/527bkptKXomtuo+dOjU9NdMASQ8DNC9z9zLOMbG53T4eihYr3XR+BQ==", + "dev": true, + "dependencies": { + "playwright": "1.38.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "dev": true, + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@types/eslint": { + "version": "8.44.3", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.3.tgz", + "integrity": "sha512-iM/WfkwAhwmPff3wZuPLYiHX18HI24jU8k1ZSH7P8FHwxTjZ2P6CoX2wnF43oprR+YXJM6UUxATkNvyv/JHd+g==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.5.tgz", + "integrity": "sha512-JNvhIEyxVW6EoMIFIvj93ZOywYFatlpu9deeH6eSx6PE3WHYvHaQtmHmQeNw7aA81bYGBPPQqdtBm6b1SsQMmA==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.2.tgz", + "integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==", + "dev": true + }, + "node_modules/@types/jquery": { + "version": "3.3.31", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.3.31.tgz", + "integrity": "sha512-Lz4BAJihoFw5nRzKvg4nawXPzutkv7wmfQ5121avptaSIXlDNJCUuxZxX/G+9EVidZGuO0UBlk+YjKbwRKJigg==", + "dev": true, + "dependencies": { + "@types/sizzle": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", + "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.7.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.7.0.tgz", + "integrity": "sha512-zI22/pJW2wUZOVyguFaUL1HABdmSVxpXrzIqkjsHmyUjNhPoWM1CKfvVuXfetHhIok4RY573cqS0mZ1SJEnoTg==", + "dev": true + }, + "node_modules/@types/sizzle": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.4.tgz", + "integrity": "sha512-jA2llq2zNkg8HrALI7DtWzhALcVH0l7i89yhY3iBdOz6cBPeACoFq+fkQrjHA39t1hnSFOboZ7A/AY5MMZSlag==", + "dev": true + }, + "node_modules/@types/split.js": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@types/split.js/-/split.js-1.6.0.tgz", + "integrity": "sha512-tR/wWtnfZ+ZiEFrusKHn1qKUnZlpROff7a6wvRwS9ImI3pD6ytrRmgt4mbPM2FpRUUTIKsfZXGXBmuvalMUVzw==", + "deprecated": "This is a stub types definition. split.js provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "split.js": "*" + } + }, + "node_modules/@types/webpack-env": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.2.tgz", + "integrity": "sha512-BFqcTHHTrrI8EBmIzNAmLPP3IqtEG9J1IPFWbPeS/F0/TGNmo0pI5svOa7JbMF9vSCXQCvJWT2gxLJNVuf9blw==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.16.0.tgz", + "integrity": "sha512-fkDq86F0zl8FicnJtdXakFs4lnuebH6ZADDw6CYQv0UZeIjHvmEw87m9/29nk2Dv5Lmdp0zQ3zDQhiMWQf/GbA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.16.0", + "@typescript-eslint/types": "5.16.0", + "@typescript-eslint/typescript-estree": "5.16.0", + "debug": "^4.3.2" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.16.0.tgz", + "integrity": "sha512-P+Yab2Hovg8NekLIR/mOElCDPyGgFZKhGoZA901Yax6WR6HVeGLbsqJkZ+Cvk5nts/dAlFKm8PfL43UZnWdpIQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.16.0", + "@typescript-eslint/visitor-keys": "5.16.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.16.0.tgz", + "integrity": "sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.16.0.tgz", + "integrity": "sha512-SE4VfbLWUZl9MR+ngLSARptUv2E8brY0luCdgmUevU6arZRY/KxYoLI/3V/yxaURR8tLRN7bmZtJdgmzLHI6pQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.16.0", + "@typescript-eslint/visitor-keys": "5.16.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.16.0.tgz", + "integrity": "sha512-jqxO8msp5vZDhikTwq9ubyMHqZ67UIvawohr4qF3KhlpL7gzSjOd+8471H3nh5LyABkaI85laEKKU8SnGUK5/g==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.16.0", + "eslint-visitor-keys": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "dev": true, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x", + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "dev": true, + "dependencies": { + "envinfo": "^7.7.3" + }, + "peerDependencies": { + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "dev": true, + "peerDependencies": { + "webpack-cli": "4.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "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==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "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==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/bootstrap": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.0.2.tgz", + "integrity": "sha512-1Ge963tyEQWJJ+8qtXFU6wgmAVj9gweEjibUdbmcCEYsn38tVwRk8107rk2vzt6cfQcRr3SlZ8aQBqaD8aqf+Q==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + }, + "peerDependencies": { + "@popperjs/core": "^2.9.2" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.11", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.11.tgz", + "integrity": "sha512-xn1UXOKUz7DjdGlg9RrUr0GGiWzI97UQJnugHtH0OLDfJB7jMgoIkYvRIEO1l9EeEERVqeqLYOcFBW9ldjypbQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001538", + "electron-to-chromium": "^1.4.526", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001539", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001539.tgz", + "integrity": "sha512-hfS5tE8bnNiNvEOEkm8HElUHroYwlqMMENEzELymy77+tJ6m+gA2krtHl5hxJaj71OlpC2cHZbdSMX1/YEqEkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/core-js": { + "version": "3.32.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.32.2.tgz", + "integrity": "sha512-pxXSw1mYZPDGvTQqEc5vgIb83jGQKFGYWY76z4a7weZXUolw3G+OvpZqSRcfYOoOVUQJYEPsWeQK8pKEnUtWxQ==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-loader": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", + "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.32", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^2.7.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.528", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.528.tgz", + "integrity": "sha512-UdREXMXzLkREF4jA8t89FQjA8WHI6ssP38PMY4/4KhXFQbtImnghh4GkCgrtiZwLKUKVD2iTVXvDVQjfomEQuA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/envinfo": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.10.0.tgz", + "integrity": "sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/es-module-lexer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz", + "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.50.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", + "integrity": "sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.50.0", + "@humanwhocodes/config-array": "^0.11.11", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-vue": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.7.1.tgz", + "integrity": "sha512-28sbtm4l4cOzoO1LtzQPxfxhQABararUb1JtqusQqObJpWX2e/gmVyeYVfepizPFne0Q5cILkYGiBoV36L12Wg==", + "dev": true, + "dependencies": { + "eslint-utils": "^3.0.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", + "semver": "^7.3.5", + "vue-eslint-parser": "^8.0.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fetch-blob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-2.1.2.tgz", + "integrity": "sha512-YKqtUDwqLyfyMnmbw8XD6Q8j9i/HggKtPEI+pZ1+8bvheBu78biSmNaXWusx1TauGqtUUGx/cBb1mKdq2rLYow==", + "dev": true, + "engines": { + "node": "^10.17.0 || >=12.3.0" + }, + "peerDependenciesMeta": { + "domexception": { + "optional": true + } + } + }, + "node_modules/fetch-cookie": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-2.1.0.tgz", + "integrity": "sha512-39+cZRbWfbibmj22R2Jy6dmTbAWC+oqun1f1FzQaNurkPDUP4C38jpeZbiXCR88RKRVDp8UcDrbFXkNhN+NjYg==", + "dependencies": { + "set-cookie-parser": "^2.4.8", + "tough-cookie": "^4.0.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", + "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", + "dev": true, + "dependencies": { + "flatted": "^3.2.7", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.9.0.tgz", + "integrity": "sha512-rahaRMkN8P8d/tgK/BLPX+WBVM27NbvdXBxqQujBtkDAIFspaRqN7Od7lfdGQA6KAD+f82fYCLBq1ipvcu8qLw==", + "dev": true + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dev": true, + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/fp-ts": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.1.tgz", + "integrity": "sha512-by7U5W8dkIzcvDofUcO42yl9JbnHTEDBrzu3pt5fKT+Z4Oy85I21K80EYJYdjQGC2qum4Vo55Ag57iiIK4FYuA==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "13.22.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.22.0.tgz", + "integrity": "sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.14" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/inspectpack": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/inspectpack/-/inspectpack-4.7.1.tgz", + "integrity": "sha512-XoDJbKSM9I2KA+8+OLFJHm8m4NM2pMEgsDD2hze6swVfynEed9ngCx36mRR+otzOsskwnxIZWXjI23FTW1uHqA==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "fp-ts": "^2.6.1", + "io-ts": "^2.2.13", + "io-ts-reporters": "^1.2.2", + "pify": "^5.0.0", + "semver-compare": "^1.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "inspectpack": "bin/inspectpack.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/io-ts": { + "version": "2.2.20", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-2.2.20.tgz", + "integrity": "sha512-Rq2BsYmtwS5vVttie4rqrOCIfHCS9TgpRLFpKQCM1wZBBRY9nWVGmEvm2FnDbSE2un1UE39DvFpTR5UL47YDcA==", + "dev": true, + "peerDependencies": { + "fp-ts": "^2.5.0" + } + }, + "node_modules/io-ts-reporters": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/io-ts-reporters/-/io-ts-reporters-1.2.2.tgz", + "integrity": "sha512-igASwWWkDY757OutNcM6zTtdJf/eTZYkoe2ymsX2qpm5bKZLo74FJYjsCtMQOEdY7dRHLLEulCyFQwdN69GBCg==", + "dev": true, + "peerDependencies": { + "fp-ts": "^2.0.2", + "io-ts": "^2.0.0" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jquery": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", + "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.7.6", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", + "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-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==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-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==", + "dev": true + }, + "node_modules/mini-css-extract-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==", + "dev": true, + "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/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/playwright": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.38.1.tgz", + "integrity": "sha512-oRMSJmZrOu1FP5iu3UrCx8JEFRIMxLDM0c/3o4bpzU5Tz97BypefWf7TuTNPWeCe279TPal5RtPPZ+9lW/Qkow==", + "dev": true, + "dependencies": { + "playwright-core": "1.38.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.38.1.tgz", + "integrity": "sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dev": true, + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", + "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", + "dev": true, + "dependencies": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-modules-values": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", + "dev": true, + "dependencies": { + "icss-utils": "^4.0.0", + "postcss": "^7.0.6" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve": { + "version": "1.22.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", + "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/sass": { + "version": "1.68.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.68.0.tgz", + "integrity": "sha512-Lmj9lM/fef0nQswm1J2HJcEsBUba4wgNx2fea6yJHODREoMFnwRpZydBnX/RjyXw2REIwdkbqE4hrTo4qfDBUA==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-loader": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.2.tgz", + "integrity": "sha512-7o4dbSK8/Ol2KflEmSco4jTjQoV988bM82P9CZdmo9hR3RLnvNc0ufMNdMrB0caq38JQ/FgF4/7RcbcfKzxoFQ==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "loader-utils": "^1.2.3", + "neo-async": "^2.6.1", + "schema-utils": "^2.6.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0", + "sass": "^1.3.0", + "webpack": "^4.36.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/sass-loader/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/split.js": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/split.js/-/split.js-1.6.5.tgz", + "integrity": "sha512-mPTnGCiS/RiuTNsVhCm9De9cCAUsrNFFviRbADdKiiV+Kk8HKp/0fWu7Kr8pi3/yBmsqLFHuXGT9UUZ+CNLwFw==", + "dev": true + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-loader": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz", + "integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.20.0.tgz", + "integrity": "sha512-e56ETryaQDyebBwJIWYB2TT6f2EZ0fL0sW/JRXNMN26zZdKi2u/E/5my5lG6jNxym6qsrVXfFRmOdV42zlAgLQ==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-loader": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-6.2.2.tgz", + "integrity": "sha512-HDo5kXZCBml3EUPcc7RlZOV/JGlLHwppTLEHb3SHnr5V7NXD4klMEkrhJe5wgRbaWsSXi+Y1SIBN/K9B6zWGWQ==", + "dev": true, + "dependencies": { + "chalk": "^2.3.0", + "enhanced-resolve": "^4.0.0", + "loader-utils": "^1.0.2", + "micromatch": "^4.0.0", + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8.6" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/ts-loader/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ts-loader/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ts-loader/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/ts-loader/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/ts-loader/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ts-loader/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ts-loader/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/ts-loader/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-browserslist-db/node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/vue-eslint-parser": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", + "integrity": "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/webpack": { + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "cross-spawn": "^7.0.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "@webpack-cli/migrate": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-merge": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz", + "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack/node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.module.ts b/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.module.ts index 12fab763137..aaf2f472e69 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.module.ts +++ b/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.module.ts @@ -16,22 +16,22 @@ export function splitReviewPageContent() { const rl = $('#review-left'); const rr = $('#review-right'); - if (rl.length && rr.length) { - Split(['#review-left', '#review-right'], { - direction: 'horizontal', - sizes: [17, 83], - elementStyle: (dimension, size, gutterSize) => { - return { - 'flex-basis': `calc(${size}% - ${gutterSize}px` - } - }, - gutterStyle: (dimension, gutterSize) => { - return { - 'flex-basis': `${gutterSize}px` - } + if (rl.length && rr.length) { + Split(['#review-left', '#review-right'], { + direction: 'horizontal', + sizes: [17, 83], + elementStyle: (dimension, size, gutterSize) => { + return { + 'flex-basis': `calc(${size}% - ${gutterSize}px` } - }); - } + }, + gutterStyle: (dimension, gutterSize) => { + return { + 'flex-basis': `${gutterSize}px` + } + } + }); + } } //------------------------------------------------------------------------------------------------- @@ -587,151 +587,160 @@ export function addApprover(lowerTextSpan: HTMLElement, approvedByText: string, addApprovedBorder(); } addApproverHrefToApprovers(lowerTextSpan, approverHref, approver); - } - - /** - * Removes the @approver from @lowerTextSpan of review page - * @param lowerTextSpan HTMLElement of the span that contains who approved the review or pending approval - * @param approver GitHub username of the review approver - * @param approvalPendingText string of approval pending text to use when removing the last approver - */ - export function removeApprover(lowerTextSpan: HTMLElement, approver: string, approvalPendingText: string) { - let children = lowerTextSpan.children; - let numApprovers = children.length; +} - if (numApprovers > 1) { - removeApproverFromApproversList(children, approver); - } else { - lowerTextSpan.textContent = approvalPendingText; - removeApprovalBorder(); - } - } +/** + * Removes the @approver from @lowerTextSpan of review page + * @param lowerTextSpan HTMLElement of the span that contains who approved the review or pending approval + * @param approver GitHub username of the review approver + * @param approvalPendingText string of approval pending text to use when removing the last approver + */ +export function removeApprover(lowerTextSpan: HTMLElement, approver: string, approvalPendingText: string) { + let children = lowerTextSpan.children; + let numApprovers = children.length; - /** - * adds the @approver with a hyperlink to their apiview profile to @lowerTextSpan - */ - export function addApproverHrefToApprovers(lowerTextSpan: HTMLElement, approverHref: string, approver: any) { - $(lowerTextSpan).append('' + approver + ''); + if (numApprovers > 1) { + removeApproverFromApproversList(children, approver); + } else { + lowerTextSpan.textContent = approvalPendingText; + removeApprovalBorder(); } +} - /** - * adds the text above the approve button to indicate whether the current user approved the review - */ - export function addUpperTextSpan(approvesCurrentRevisionText: string) { - let $upperTextSpan = $("").text(approvesCurrentRevisionText).addClass("small text-muted"); - let $upperTextForm = $("ul#approveCollapse form.form-inline"); - $upperTextForm.prepend($upperTextSpan); - } +/** + * adds the @approver with a hyperlink to their apiview profile to @lowerTextSpan + */ +export function addApproverHrefToApprovers(lowerTextSpan: HTMLElement, approverHref: string, approver: any) { + $(lowerTextSpan).append('' + approver + ''); +} - /** - * change the button state from a green "not approved" to grey "approved" - */ - export function addButtonApproval() { - let $approveBtn = $("form.form-inline button.btn.btn-success"); - $approveBtn.removeClass("btn-success"); - $approveBtn.addClass("btn-outline-secondary"); - $approveBtn.text("Revert API Approval"); - } +/** + * adds the text above the approve button to indicate whether the current user approved the review + */ +export function addUpperTextSpan(approvesCurrentRevisionText: string) { + let $upperTextSpan = $("").text(approvesCurrentRevisionText).addClass("small text-muted"); + let $upperTextForm = $("ul#approveCollapse form.form-inline"); + $upperTextForm.prepend($upperTextSpan); +} - /** - * change the button state from a grey "approved" to green "not approved" - */ - export function removeButtonApproval() { - let $approveBtn = $("form.form-inline button.btn.btn-outline-secondary"); - $approveBtn.removeClass("btn-outline-secondary"); - $approveBtn.addClass("btn-success"); - $approveBtn.text("Approve"); - } +/** + * change the button state from a green "not approved" to grey "approved" + */ +export function addButtonApproval() { + let $approveBtn = $("form.form-inline button.btn.btn-success"); + $approveBtn.removeClass("btn-success"); + $approveBtn.addClass("btn-outline-secondary"); + $approveBtn.text("Revert API Approval"); +} - /** - * change the review panel border state from grey "not approved" to green "approved" - */ - export function addApprovedBorder() { - let reviewLeft = $("#review-left"); - reviewLeft.addClass("review-approved"); - reviewLeft.removeClass("border"); - reviewLeft.removeClass("rounded-1"); +/** + * change the button state from a grey "approved" to green "not approved" + */ +export function removeButtonApproval() { + let $approveBtn = $("form.form-inline button.btn.btn-outline-secondary"); + $approveBtn.removeClass("btn-outline-secondary"); + $approveBtn.addClass("btn-success"); + $approveBtn.text("Approve"); +} - let reviewRight = $("#review-right"); - reviewRight.addClass("review-approved"); - reviewRight.removeClass("border"); - reviewRight.removeClass("rounded-1"); - } +/** + * change the review panel border state from grey "not approved" to green "approved" + */ +export function addApprovedBorder() { + let reviewLeft = $("#review-left"); + reviewLeft.addClass("review-approved"); + reviewLeft.removeClass("border"); + reviewLeft.removeClass("rounded-1"); - /** - * change the review panel border state from green "approved" to grey "not approved" - */ - export function removeApprovalBorder() { - let $reviewLeft = $("#review-left"); - $reviewLeft.removeClass("review-approved"); - $reviewLeft.addClass("border"); - $reviewLeft.addClass("rounded-1"); + let reviewRight = $("#review-right"); + reviewRight.addClass("review-approved"); + reviewRight.removeClass("border"); + reviewRight.removeClass("rounded-1"); +} - let $reviewRight = $("#review-right"); - $reviewRight.removeClass("review-approved"); - $reviewRight.addClass("border"); - $reviewRight.addClass("rounded-1"); - } +/** + * change the review panel border state from green "approved" to grey "not approved" + */ +export function removeApprovalBorder() { + let $reviewLeft = $("#review-left"); + $reviewLeft.removeClass("review-approved"); + $reviewLeft.addClass("border"); + $reviewLeft.addClass("rounded-1"); - /** - * parse the approval spans for its existence and order - * @param $approvalSpans may contain , , and/or - * @param approvedByText string for that indicates preexisting approvers - * @param approvalPendingText string for that indicates no current approvers - * @param approvesCurrentRevisionText string for that indicates the current user did not approve - * @returns a dictionary with the index of the upper and lower text elements. Value is -1 if an element does not exist. - */ - export function parseApprovalSpanIndex($approvalSpans: JQuery, approvedByText: string, approvalPendingText: string, approvesCurrentRevisionText: string) { - let indexResult = { - "approvers": -1, - "upperText": -1, - }; + let $reviewRight = $("#review-right"); + $reviewRight.removeClass("review-approved"); + $reviewRight.addClass("border"); + $reviewRight.addClass("rounded-1"); +} - for (var i = 0; i < $approvalSpans.length; i++) { - let content = $approvalSpans[i].textContent; +/** + * parse the approval spans for its existence and order + * @param $approvalSpans may contain , , and/or + * @param approvedByText string for that indicates preexisting approvers + * @param approvalPendingText string for that indicates no current approvers + * @param approvesCurrentRevisionText string for that indicates the current user did not approve + * @returns a dictionary with the index of the upper and lower text elements. Value is -1 if an element does not exist. + */ +export function parseApprovalSpanIndex($approvalSpans: JQuery, approvedByText: string, approvalPendingText: string, approvesCurrentRevisionText: string) { + let indexResult = { + "approvers": -1, + "upperText": -1, + }; - if (!content) { - return indexResult; - } + for (var i = 0; i < $approvalSpans.length; i++) { + let content = $approvalSpans[i].textContent; - if (content.includes(approvedByText) || content.includes(approvalPendingText)) { - indexResult["approvers"] = i; - } - if (content.includes(approvesCurrentRevisionText)) { - indexResult["upperText"] = i; - } + if (!content) { + return indexResult; } - return indexResult; + if (content.includes(approvedByText) || content.includes(approvalPendingText)) { + indexResult["approvers"] = i; + } + if (content.includes(approvesCurrentRevisionText)) { + indexResult["upperText"] = i; + } } - /** - * call when the current user approves the current review. removes the upper text - * @param upperTextIndex index of the upper text in @$approvalSpans - * @param $approvalSpans span that includes revision approval block - */ - export function removeUpperTextSpan(upperTextIndex: number, $approvalSpans: JQuery) { - if (upperTextIndex !== -1) { - let upperTextSpan: HTMLElement = $approvalSpans[upperTextIndex]; - upperTextSpan.remove(); - } + return indexResult; +} + +/** + * call when the current user approves the current review. removes the upper text + * @param upperTextIndex index of the upper text in @$approvalSpans + * @param $approvalSpans span that includes revision approval block + */ +export function removeUpperTextSpan(upperTextIndex: number, $approvalSpans: JQuery) { + if (upperTextIndex !== -1) { + let upperTextSpan: HTMLElement = $approvalSpans[upperTextIndex]; + upperTextSpan.remove(); } +} - /** - * remove the @approver from list of @approvers - * @param approvers list of preexisting approvers - * @param approver GitHub username of user to remove from the list - */ - export function removeApproverFromApproversList(approvers, approver) { - for (var i = 0; i < approvers.length; i++) { - if (approvers[i].innerHTML === approver) { - if (i === 0) { - approvers[i].nextSibling?.remove(); - } else { - approvers[i].previousSibling?.remove(); - } - approvers[i].remove(); - break; +/** + * remove the @approver from list of @approvers + * @param approvers list of preexisting approvers + * @param approver GitHub username of user to remove from the list + */ +export function removeApproverFromApproversList(approvers, approver) { + for (var i = 0; i < approvers.length; i++) { + if (approvers[i].innerHTML === approver) { + if (i === 0) { + approvers[i].nextSibling?.remove(); + } else { + approvers[i].previousSibling?.remove(); } + approvers[i].remove(); + break; } } +} + +/** + * Add event handler for cross language panel button + */ +export function addCrossLaguageCloseBtnHandler() { + $(".cross-language-panel .btn-close").on("click", function (e: JQuery.ClickEvent) { + $(this).closest(".cross-language-panel").addClass("d-none"); + }); +} diff --git a/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.ts b/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.ts index ab97ea9881c..95fcf2d560c 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.ts +++ b/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.ts @@ -2,6 +2,7 @@ import { rightOffCanvasNavToggle } from "../shared/off-canvas"; import * as rvM from "./review.module" import * as hp from "../shared/helpers"; +import * as cm from "../shared/comments.module"; $(() => { const SHOW_DOC_CHECKBOX = ".show-documentation-checkbox"; @@ -36,6 +37,9 @@ $(() => { rvM.findTargetAnchorWithinSections(targetAnchorId); } } + + // Enable cross Language Comments Indicator + cm.crossLanguageViewCommentIndicator(); }); /* ADD FUNCTIONS TO LEFT NAVIGATION @@ -117,19 +121,20 @@ $(() => { var leftContainer = $("#review-left"); var rightContainer = $("#review-right"); var gutter = $(".gutter-horizontal"); - - if (leftContainer.hasClass("d-none")) { - leftContainer.removeClass("d-none"); - rightContainer.removeClass("col-12"); - rightContainer.addClass("col-10"); - rvM.splitReviewPageContent(); - } - else { - leftContainer.addClass("d-none"); - rightContainer.css("flex-basis", "100%"); - gutter.remove(); - rightContainer.removeClass("col-10"); - rightContainer.addClass("col-12"); + if (leftContainer.length && rightContainer.length) { + if (leftContainer.hasClass("d-none")) { + leftContainer.removeClass("d-none"); + rightContainer.removeClass("col-12"); + rightContainer.addClass("col-10"); + rvM.splitReviewPageContent(); + } + else { + leftContainer.addClass("d-none"); + rightContainer.css("flex-basis", "100%"); + gutter.remove(); + rightContainer.removeClass("col-10"); + rightContainer.addClass("col-12"); + } } }); }); @@ -215,7 +220,7 @@ $(() => { // Manage Expand / Collapse State of options [$("#approveCollapse"), $("#requestReviewersCollapse"), $("#reviewOptionsCollapse"), $("#pageSettingsCollapse"), - $("#associatedPRCollapse"), $("#associatedReviewsCollapse"), $("#generateAIReviewCollapse")].forEach(function (value, index) { + $("#associatedPRCollapse"), $("#associatedReviewsCollapse"), $("#generateAIReviewCollapse"), $("#crossLangReviewCollapse")].forEach(function (value, index) { const id = value.attr("id"); value.on('hidden.bs.collapse', function () { document.cookie = `${id}=hidden; max-age=${7 * 24 * 60 * 60}`; @@ -246,4 +251,85 @@ $(() => { url: uri }); }); + + + /* CROSS LANGUAGE VIEW + --------------------------------------------------------------------------------------------------------------------------------------------------------*/ + $("#load-cross-language-view").on("click", function (e: JQuery.ClickEvent) { + const crossLangusges = $(".cross-lang-view-switch"); + const uri = new URL(window.location.href); + const urlParams = new URLSearchParams(uri.search); + urlParams.delete("crossLanguage"); + crossLangusges.each(function (index, value) { + const language = value.querySelector("label")?.textContent; + const isChecked = value.querySelector("input")?.checked; + if (isChecked) { + urlParams.append("crossLanguage", encodeURIComponent(language!)); + } + }); + uri.search = urlParams.toString(); + window.location.href = uri.toString() + }) + + // Load Cross Language Panel + $(".cl-line-no").on("click", function (e: JQuery.ClickEvent) { + e.preventDefault(); + const codeLine = $(this).closest(".code-line"); + const crossLangId = codeLine.data("cross-lang-id"); + const crossLangTables = $("#cross-language-code-lines > table"); + const crossLangCodeLines = new Map() + const crossLangPanel = $("#cross-language-view-template > tbody").children().clone(); + const rowSibling = codeLine.next(); + let showPanel = false; + + crossLangTables.each(function (index, value) { + const langId = $(value).attr("data-language"); + const dataReviewId = $(value).attr("data-review-id"); + const dataRevisionId = $(value).attr("data-revision-id"); + const codeLines = $(value).find(`[data-cross-lang-id='${crossLangId}']`).clone(); + crossLangPanel.find(".cross-language-pills-tab-content").attr("data-review-id", dataReviewId!); + crossLangPanel.find(".cross-language-pills-tab-content").attr("data-revision-id", dataRevisionId!); + crossLangCodeLines.set(langId, codeLines); + }); + + if (rowSibling.hasClass("cross-language-panel")) { + rowSibling.toggleClass("d-none"); + } else { + const clTabs = crossLangPanel.find('[id^="cross-lang-pills-tab"]'); + const clPills = crossLangPanel.find('[id^="cross-lang-pills-content-"]'); + const randomizer = Date.now().toString(36); + + clTabs.each(function (index, value) { + const tbId = $(value).attr("id") + randomizer; + const tbTarget = $(value).attr("data-bs-target") + randomizer; + const tbAria = $(value).attr("aria-controls") + randomizer; + $(value).attr("id", tbId); + $(value).attr("data-bs-target", tbTarget); + $(value).attr("aria-controls", tbAria); + }); + + clPills.each(function (index, value) { + const pillId = $(value).attr("id"); + const pillIdParts = pillId?.split('-'); + const pillLang = pillIdParts![pillIdParts!.length - 1]; + const pillLabel = $(value).attr("aria-labelledby") + randomizer; + const crossLangContent = crossLangCodeLines.get(pillLang); + $(value).attr("id", (pillId + randomizer)); + $(value).attr("aria-labelledby", pillLabel); + if (crossLangContent && crossLangContent.length > 0) { + showPanel = true; + $(value).html(crossLangContent); + const comments = crossLangContent.find(".review-comment"); + if (comments.length > 0) { + crossLangPanel.find(`#cross-lang-pills-tab-${pillLang}${randomizer}`)[0].innerHTML += `${comments.length}`; + } + } + }); + + if (showPanel) { + codeLine.after(crossLangPanel); + rvM.addCrossLaguageCloseBtnHandler(); + } + } + }); }); diff --git a/src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.module.ts b/src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.module.ts index aac62ea0bc8..a17a80d4b29 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.module.ts +++ b/src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.module.ts @@ -75,3 +75,16 @@ export function updateCommentThreadInReviewPageDOM(reviewId: any, elementId: any } } +/** + * Show Cross Language Comment Indicator + */ +export function crossLanguageViewCommentIndicator() { + $(".cl-line-no").each(function (index, value) { + const crossLangId = $(value).closest(".code-line").data("cross-lang-id"); + const crossLangComments = $(`[data-cross-lang-id='${crossLangId}']`).filter(".comment-row"); + if (crossLangComments.length > 0) { + $(value).closest(".code-line").find(".icon.icon-comments").removeClass("invisible"); + } + }) +} + diff --git a/src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.ts b/src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.ts index d0addfa40c8..61147528825 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.ts +++ b/src/dotnet/APIView/APIViewWeb/Client/src/shared/comments.ts @@ -24,12 +24,11 @@ $(() => { $(document).on("click", ".line-comment-button", e => { let id = hp.getElementId(e.target); - let inlineId = hp.getElementId(e.target, "data-inline-id"); + let crossLangId = hp.getElementId(e.target, "data-cross-lang-id"); if (id) { var rowSectionClasses = hp.getCodeRowSectionClasses(id); - if (inlineId) { - let groupNo = inlineId.replace(`${id}-tr-`, ''); - hp.showCommentBox(id, rowSectionClasses, groupNo); + if (crossLangId) { + hp.showCommentBox(id, rowSectionClasses, crossLangId); } else { hp.showCommentBox(id, rowSectionClasses); @@ -107,11 +106,7 @@ $(() => { $(e.target).find('button').prop("disabled", true); const form = $(e.target); let lineId = hp.getElementId(e.target); - let inlineRowNo = $(e.target).find(".new-comment-content small"); - - if (inlineRowNo.length == 0) { - inlineRowNo = hp.getReplyGroupNo($(e.target)); - } + let crossLangId = hp.getElementId(e.target, "data-cross-lang-id"); if (lineId) { let commentRow = hp.getCommentsRow(lineId); @@ -125,9 +120,8 @@ $(() => { serializedForm.push({ name: "sectionClass", value: rowSectionClasses }); serializedForm.push({ name: "taggedUsers", value: getTaggedUsers(e.target) }); - if (inlineRowNo.length > 0) { - let groupNo = inlineRowNo.text().replace("ROW-", ''); - serializedForm.push({ name: "groupNo", value: groupNo }); + if (crossLangId) { + serializedForm.push({ name: "crossLangId", value: crossLangId }); } $.ajax({ @@ -146,15 +140,8 @@ $(() => { $(document).on("click", ".review-thread-reply-button", e => { let lineId = hp.getElementId(e.target); - let inlineRowNo = hp.getReplyGroupNo($(e.target).parent().parent()); if (lineId) { - if (inlineRowNo.length > 0) { - let groupNo = inlineRowNo.text().replace("ROW-", ''); - hp.showCommentBox(lineId,'', groupNo); - } - else { hp.showCommentBox(lineId); - } } e.preventDefault(); }); diff --git a/src/dotnet/APIView/APIViewWeb/Client/src/shared/helpers.ts b/src/dotnet/APIView/APIViewWeb/Client/src/shared/helpers.ts index 4a646154600..38a19b66684 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/src/shared/helpers.ts +++ b/src/dotnet/APIView/APIViewWeb/Client/src/shared/helpers.ts @@ -265,7 +265,7 @@ export function getCommentsRow(id: string) { } // side effect: creates a comment row if it doesn't already exist -export function showCommentBox(id: string, classes: string = '', groupNo: string = '', moveFocus: boolean = true) { +export function showCommentBox(id: string, classes: string = '', crossLangId: string = '', moveFocus: boolean = true) { let commentForm; let commentsRow = getCommentsRow(id); let commentRowClasses = "comment-row"; @@ -274,9 +274,9 @@ export function showCommentBox(id: string, classes: string = '', groupNo: string } if (commentsRow.length === 0) { - commentForm = createCommentForm(groupNo); + commentForm = createCommentForm(); commentsRow = - $(``) + $(``) .append($("") .append(commentForm)); @@ -285,48 +285,10 @@ export function showCommentBox(id: string, classes: string = '', groupNo: string else { // there is one or more comment rows - insert form let replyArea = $(commentsRow).find(".review-thread-reply"); - let targetReplyArea = replyArea.first(); - let firstReplyId = targetReplyArea.attr("data-reply-id"); - let insertAtBegining = false; - - if (groupNo) { - replyArea.siblings(".comment-form").remove(); - if (Number(groupNo) < Number(firstReplyId)) { - insertAtBegining = true; - } - else { - replyArea.each(function (index, value) { - let replyId = $(value).attr("data-reply-id"); - - if (replyId == groupNo) { - targetReplyArea = $(value); - return false; - } - - if (Number(replyId) > Number(groupNo)) { - return false; - } - targetReplyArea = $(value); - }); - } - } - else { - let rowGroupNo = getReplyGroupNo($(targetReplyArea)); - if (rowGroupNo.length > 0) { - insertAtBegining = true; - } - } - - commentForm = $(targetReplyArea).next(); + commentForm = $(replyArea).next(); if (!commentForm.hasClass("comment-form")) { - if (insertAtBegining) { - let commentThreadContent = $(targetReplyArea).closest(".comment-thread-contents"); - $(createCommentForm(groupNo)).prependTo(commentThreadContent); - } - else { - commentForm = $(createCommentForm(groupNo)).insertAfter(targetReplyArea); - } + commentForm = $(createCommentForm()).insertAfter(replyArea); } replyArea.hide(); commentForm.show(); @@ -345,22 +307,14 @@ export function showCommentBox(id: string, classes: string = '', groupNo: string } } -export function createCommentForm(groupNo: string = '') { - var commentForm = $("#js-comment-form-template").children().clone(); - if (groupNo) { - commentForm.find("form .new-comment-content").prepend(`ROW-${groupNo}`); - } - return commentForm; +export function createCommentForm() { + return $("#js-comment-form-template").children().clone(); } export function getDiagnosticsRow(id: string) { return $(`.code-diagnostics[data-line-id='${id}']`); } -export function getReplyGroupNo(sibling: JQuery) { - return $(sibling).prevAll("a").first().find("small"); -} - export function getElementId(element: HTMLElement, idName: string = "data-line-id") { return getParentData(element, idName); } diff --git a/src/dotnet/APIView/APIViewWeb/Controllers/CommentsController.cs b/src/dotnet/APIView/APIViewWeb/Controllers/CommentsController.cs index d97c09c7bdd..b92bf9faab0 100644 --- a/src/dotnet/APIView/APIViewWeb/Controllers/CommentsController.cs +++ b/src/dotnet/APIView/APIViewWeb/Controllers/CommentsController.cs @@ -27,7 +27,7 @@ public CommentsController(ICommentsManager commentsManager, IReviewManager revie } [HttpPost] - public async Task Add(string reviewId, string revisionId, string elementId, string commentText, string sectionClass, string groupNo, string[] taggedUsers, string resolutionLock = "off", bool usageSampleComment = false) + public async Task Add(string reviewId, string revisionId, string elementId, string commentText, string sectionClass, string[] taggedUsers, string resolutionLock = "off", bool usageSampleComment = false, string crossLangId = null) { if (string.IsNullOrEmpty(commentText)) { @@ -46,6 +46,7 @@ public async Task Add(string reviewId, string revisionId, string e comment.CommentType = (usageSampleComment) ? CommentType.SampleRevision : CommentType.APIRevision; comment.ResolutionLocked = !resolutionLock.Equals("on"); comment.CreatedBy = User.GetGitHubLogin(); + comment.CrossLanguageId = crossLangId; foreach(string user in taggedUsers) { diff --git a/src/dotnet/APIView/APIViewWeb/Helpers/UploadModelValidationAttribute.cs b/src/dotnet/APIView/APIViewWeb/Helpers/HelperAttributes.cs similarity index 90% rename from src/dotnet/APIView/APIViewWeb/Helpers/UploadModelValidationAttribute.cs rename to src/dotnet/APIView/APIViewWeb/Helpers/HelperAttributes.cs index f302fadf051..e2db617f474 100644 --- a/src/dotnet/APIView/APIViewWeb/Helpers/UploadModelValidationAttribute.cs +++ b/src/dotnet/APIView/APIViewWeb/Helpers/HelperAttributes.cs @@ -1,13 +1,8 @@ using System; -using System.Globalization; using System.ComponentModel.DataAnnotations; -using System.Reflection; using System.Linq; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; -using System.Text; using APIViewWeb.Pages.Assemblies; namespace APIViewWeb.Helpers diff --git a/src/dotnet/APIView/APIViewWeb/Helpers/HelperModelBinders.cs b/src/dotnet/APIView/APIViewWeb/Helpers/HelperModelBinders.cs new file mode 100644 index 00000000000..1a1be285cd1 --- /dev/null +++ b/src/dotnet/APIView/APIViewWeb/Helpers/HelperModelBinders.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.ModelBinding; + +namespace APIViewWeb.Helpers +{ + public class DecodeModelBinder : IModelBinder + { + public Task BindModelAsync(ModelBindingContext bindingContext) + { + var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); + var decodedValues = new List(); + + foreach (var item in valueProviderResult.Values) + { + decodedValues.Add(Uri.UnescapeDataString(item)); + } + + bindingContext.Result = ModelBindingResult.Success(decodedValues); + return Task.CompletedTask; + } + } +} diff --git a/src/dotnet/APIView/APIViewWeb/Helpers/LanguageServiceHelpers.cs b/src/dotnet/APIView/APIViewWeb/Helpers/LanguageServiceHelpers.cs index 4b89bfe52fc..a8949545316 100644 --- a/src/dotnet/APIView/APIViewWeb/Helpers/LanguageServiceHelpers.cs +++ b/src/dotnet/APIView/APIViewWeb/Helpers/LanguageServiceHelpers.cs @@ -1,5 +1,10 @@ using System.Collections.Generic; using System.Linq; +using APIViewWeb.LeanModels; +using Microsoft.AspNetCore.Http; +using Microsoft.Azure.Cosmos.Serialization.HybridRow; +using Microsoft.Identity.Client; +using Microsoft.VisualStudio.Services.Common; namespace APIViewWeb.Helpers { @@ -7,6 +12,52 @@ public class LanguageServiceHelpers { public static string[] SupportedLanguages = new string[] { "C", "C#", "C++", "Go", "Java", "JavaScript", "Json", "Kotlin", "Python", "Swagger", "Swift", "TypeSpec", "Xml" }; + public static string GetCorrespondingPackageName(string sourceLanguage, string targetlanguage, string packageName) + { + if (packageName.Equals("widgetmanagerclient") || packageName.Equals("Contoso.WidgetManager") || packageName.Equals("com.azure:contoso-widgetmanager")) + { + var result = string.Empty; + switch (targetlanguage) + { + case "TypeSpec": + result = "Contoso.WidgetManager"; + break; + case "Java": + result = "com.azure:contoso-widgetmanager"; + break; + case "Python": + result = "widgetmanagerclient"; + break; + } + return result; + } + else { + var result = string.Empty; + switch (targetlanguage) + { + case "C#": + result = "Azure.Identity"; + break; + case "C++": + result = "azure-identity-cpp"; + break; + case "Go": + result = "azidentity"; + break; + case "Java": + result = "com.azure:azure-identity"; + break; + case "JavaScript": + result = "@azure/identity"; + break; + case "Python": + result = "azure-identity"; + break; + } + return result; + } + } + public static IEnumerable MapLanguageAliases(IEnumerable languages) { HashSet result = new HashSet(); @@ -42,8 +93,8 @@ public static string MapLanguageAlias(string language) } public static LanguageService GetLanguageService(string language, IEnumerable languageServices) - { + { return languageServices.FirstOrDefault(service => service.Name == language); - } + } } } diff --git a/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs b/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs index 420aa0868c4..cafc6c5d2a6 100644 --- a/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs +++ b/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs @@ -17,7 +17,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; - namespace APIViewWeb.Helpers { public static class PageModelHelpers @@ -73,10 +72,11 @@ public static bool IsUserSubscribed(ClaimsPrincipal user, HashSet subscr /// /// /// + /// /// public static CodeLineModel[] CreateLines(CodeDiagnostic[] diagnostics, InlineDiffLine[] lines, ReviewCommentsModel comments, bool showDiffOnly, int reviewDiffContextSize, string diffContextSeparator, - HashSet headingsOfSectionsWithDiff, bool hideCommentRows = false) + HashSet headingsOfSectionsWithDiff, bool hideCommentRows = false, string language = null) { if (showDiffOnly) { @@ -112,7 +112,8 @@ public static CodeLineModel[] CreateLines(CodeDiagnostic[] diagnostics, InlineDi diffSectionId: diffLine.Line.SectionKey != null ? ++diffSectionId : null, otherLineSectionKey: diffLine.Kind == DiffLineKind.Unchanged ? diffLine.OtherLine.SectionKey : null, headingsOfSectionsWithDiff: headingsOfSectionsWithDiff, - isSubHeadingWithDiffInSection: diffLine.IsHeadingWithDiffInSection + isSubHeadingWithDiffInSection: diffLine.IsHeadingWithDiffInSection, + language: language ); } else @@ -133,7 +134,8 @@ public static CodeLineModel[] CreateLines(CodeDiagnostic[] diagnostics, InlineDi diffSectionId: diffLine.Line.SectionKey != null ? ++diffSectionId : null, otherLineSectionKey: diffLine.Kind == DiffLineKind.Unchanged ? diffLine.OtherLine.SectionKey : null, headingsOfSectionsWithDiff: headingsOfSectionsWithDiff, - isSubHeadingWithDiffInSection: diffLine.IsHeadingWithDiffInSection + isSubHeadingWithDiffInSection: diffLine.IsHeadingWithDiffInSection, + language: language ); documentedByLines.Clear(); return c; @@ -148,8 +150,9 @@ public static CodeLineModel[] CreateLines(CodeDiagnostic[] diagnostics, InlineDi /// /// /// + /// /// - public static CodeLineModel[] CreateLines(CodeDiagnostic[] diagnostics, CodeLine[] lines, ReviewCommentsModel comments, bool hideCommentRows = false) + public static CodeLineModel[] CreateLines(CodeDiagnostic[] diagnostics, CodeLine[] lines, ReviewCommentsModel comments, bool hideCommentRows = false, string language = null) { List documentedByLines = new List(); int lineNumberExcludingDocumentation = 0; @@ -161,23 +164,26 @@ public static CodeLineModel[] CreateLines(CodeDiagnostic[] diagnostics, CodeLine // documentedByLines must include the index of a line, assuming that documentation lines are counted documentedByLines.Add(++index); return new CodeLineModel( - DiffLineKind.Unchanged, - line, - comments.TryGetThreadForLine(line.ElementId, out var thread, hideCommentRows) ? thread : null, - diagnostics.Where(d => d.TargetId == line.ElementId).ToArray(), - lineNumberExcludingDocumentation, - new int[] { } + kind: DiffLineKind.Unchanged, + codeLine: line, + commentThread: comments.TryGetThreadForLine(line.ElementId, out var thread, hideCommentRows) ? thread : null, + diagnostics: diagnostics.Where(d => d.TargetId == line.ElementId).ToArray(), + lineNumber: lineNumberExcludingDocumentation, + documentedByLines: new int[] { }, + language: language + ); } else { CodeLineModel c = new CodeLineModel( - DiffLineKind.Unchanged, - line, - comments.TryGetThreadForLine(line.ElementId, out var thread, hideCommentRows) ? thread : null, - diagnostics.Where(d => d.TargetId == line.ElementId).ToArray(), - line.LineNumber ?? ++lineNumberExcludingDocumentation, - documentedByLines.ToArray() + kind: DiffLineKind.Unchanged, + codeLine: line, + commentThread: comments.TryGetThreadForLine(line.ElementId, out var thread, hideCommentRows) ? thread : null, + diagnostics: diagnostics.Where(d => d.TargetId == line.ElementId).ToArray(), + lineNumber: line.LineNumber ?? ++lineNumberExcludingDocumentation, + documentedByLines: documentedByLines.ToArray(), + language: language ); documentedByLines.Clear(); return c; @@ -224,6 +230,7 @@ public static int ComputeActiveConversationsInActiveRevision(CodeLine[] lines, R /// /// /// + /// /// /// /// @@ -235,7 +242,7 @@ public static int ComputeActiveConversationsInActiveRevision(CodeLine[] lines, R public static async Task GetReviewContentAsync( IConfiguration configuration, IReviewManager reviewManager, UserPreferenceCache preferenceCache, ICosmosUserProfileRepository userProfileRepository, IAPIRevisionsManager reviewRevisionsManager, ICommentsManager commentManager, - IBlobCodeFileRepository codeFileRepository, IHubContext signalRHubContext, ClaimsPrincipal user, string reviewId, + IBlobCodeFileRepository codeFileRepository, IHubContext signalRHubContext, ClaimsPrincipal user, ReviewListItemModel review = null, string reviewId = null, string revisionId = null, string diffRevisionId = null, bool showDocumentation = false, bool showDiffOnly = false, int diffContextSize = 3, string diffContextSeperator = "
.....
") { @@ -245,22 +252,25 @@ public static async Task GetReviewContentAsync( }; var userId = user.GetGitHubLogin(); - var review = await reviewManager.GetReviewAsync(user, reviewId); - + if (review == null) + { + review = await reviewManager.GetReviewAsync(user, reviewId); + } + if (review == null) { reviewPageContent.Directive = ReviewContentModelDirective.TryGetlegacyReview; return reviewPageContent; } - var apiRevisions = await reviewRevisionsManager.GetAPIRevisionsAsync(reviewId); + var apiRevisions = await reviewRevisionsManager.GetAPIRevisionsAsync(review.Id); // Try getting latest Automatic Revision, otherwise get latest of any type or default - var activeRevision = await reviewRevisionsManager.GetLatestAPIRevisionsAsync(reviewId, apiRevisions, APIRevisionType.Automatic); + var activeRevision = await reviewRevisionsManager.GetLatestAPIRevisionsAsync(review.Id, apiRevisions, APIRevisionType.Automatic); if (activeRevision == null) { reviewPageContent.Directive = ReviewContentModelDirective.ErrorDueToInvalidAPIRevisonRedirectToIndexPage; - reviewPageContent.NotificationMessage = $"Review with ID {reviewId} has no valid APIRevisons"; + reviewPageContent.NotificationMessage = $"Review with ID {review.Id} has no valid APIRevisons"; return reviewPageContent; } @@ -272,12 +282,12 @@ public static async Task GetReviewContentAsync( } else { - reviewPageContent.NotificationMessage = $"A revision with ID {revisionId} does not exist for review with id {reviewId}"; + reviewPageContent.NotificationMessage = $"A revision with ID {revisionId} does not exist for review with id {review.Id}"; reviewPageContent.Directive = ReviewContentModelDirective.ErrorDueToInvalidAPIRevisonRedirectToIndexPage; return reviewPageContent; } } - var comments = await commentManager.GetReviewCommentsAsync(reviewId); + var comments = await commentManager.GetReviewCommentsAsync(review.Id); var activeRevisionRenderableCodeFile = await codeFileRepository.GetCodeFileAsync(activeRevision.Id, activeRevision.Files[0].FileId); var activeRevisionReviewCodeFile = activeRevisionRenderableCodeFile.CodeFile; @@ -304,7 +314,8 @@ public static async Task GetReviewContentAsync( var headingsOfSectionsWithDiff = activeRevision.HeadingsOfSectionsWithDiff.ContainsKey(diffRevision.Id) ? activeRevision.HeadingsOfSectionsWithDiff[diffRevision.Id] : new HashSet(); codeLines = CreateLines(diagnostics: fileDiagnostics, lines: diffLines, comments: comments, showDiffOnly: showDiffOnly, - reviewDiffContextSize: diffContextSize, diffContextSeparator: diffContextSeperator, headingsOfSectionsWithDiff: headingsOfSectionsWithDiff); + reviewDiffContextSize: diffContextSize, diffContextSeparator: diffContextSeperator, headingsOfSectionsWithDiff: headingsOfSectionsWithDiff, + language: activeRevision.Language); if (!codeLines.Any()) { @@ -323,7 +334,7 @@ public static async Task GetReviewContentAsync( if (string.IsNullOrEmpty(diffRevisionId) || getCodeLines) { - codeLines = CreateLines(diagnostics: fileDiagnostics, lines: activeRevisionHtmlLines, comments: comments); + codeLines = CreateLines(diagnostics: fileDiagnostics, lines: activeRevisionHtmlLines, comments: comments, language: activeRevision.Language); } if (codeLines == null || codeLines.Length == 0) @@ -459,12 +470,12 @@ public static async Task GetCodeLineSectionAsync(ClaimsPrincipa codeLines = PageModelHelpers.CreateLines(diagnostics: fileDiagnostics, lines: diffLines, comments: comments, showDiffOnly: false, reviewDiffContextSize: diffContextSize, diffContextSeparator: diffContextSeperator, - headingsOfSectionsWithDiff: headingsOfSectionsWithDiff); + headingsOfSectionsWithDiff: headingsOfSectionsWithDiff, language: activeRevision.Language); } else { activeRevisionHTMLLines = activeRevisionRenderableCodeFile.GetCodeLineSection(sectionKey); - codeLines = PageModelHelpers.CreateLines(diagnostics: fileDiagnostics, lines: activeRevisionHTMLLines, comments: comments, hideCommentRows: true); + codeLines = PageModelHelpers.CreateLines(diagnostics: fileDiagnostics, lines: activeRevisionHTMLLines, comments: comments, hideCommentRows: true, language: activeRevision.Language); } return codeLines; } @@ -524,6 +535,18 @@ public static async Task UploadAPIRevisionAsync(IAPIRe } } + /// Deside if the content of the API is the header or content + /// + /// + /// + public static bool IsAPIStubHeader(string content) + { + if (content.Contains(">model<") || content.Contains(">enum<") || content.Contains(">alias<")) + { + return true; + } + return false; + } /// /// Create DiffOnly Lines /// @@ -546,7 +569,7 @@ private static InlineDiffLine[] CreateDiffOnlyLines(InlineDiffLine 0) { - filteredLines.Add(new InlineDiffLine(new CodeLine(diffContextSeparator, null, null), DiffLineKind.Unchanged)); + filteredLines.Add(new InlineDiffLine(new CodeLine(html: diffContextSeparator, id: null, crossLangId: null, lineClass: null), DiffLineKind.Unchanged)); } while (preContextIndx < i) diff --git a/src/dotnet/APIView/APIViewWeb/LeanModels/CommentItemModel.cs b/src/dotnet/APIView/APIViewWeb/LeanModels/CommentItemModel.cs index 2b1ddf59a1b..a949766b3b1 100644 --- a/src/dotnet/APIView/APIViewWeb/LeanModels/CommentItemModel.cs +++ b/src/dotnet/APIView/APIViewWeb/LeanModels/CommentItemModel.cs @@ -24,6 +24,7 @@ public class CommentItemModel public string ElementId { get; set; } public string SectionClass { get; set; } public string CommentText { get; set; } + public string CrossLanguageId { get; set; } public List ChangeHistory { get; set; } = new List(); public bool IsResolved { get; set; } public List Upvotes { get; set; } = new List(); diff --git a/src/dotnet/APIView/APIViewWeb/LeanModels/ReviewRevisionPageModels.cs b/src/dotnet/APIView/APIViewWeb/LeanModels/ReviewRevisionPageModels.cs index a8809a3ae4f..b0b5e28376c 100644 --- a/src/dotnet/APIView/APIViewWeb/LeanModels/ReviewRevisionPageModels.cs +++ b/src/dotnet/APIView/APIViewWeb/LeanModels/ReviewRevisionPageModels.cs @@ -30,5 +30,6 @@ public class ReviewContentModel public bool PageHasLoadableSections { get; set; } public string NotificationMessage { get; set; } public ReviewContentModelDirective Directive { get; set; } + public Dictionary CrossLanguageViewContent { get; set; } = new Dictionary(); } } diff --git a/src/dotnet/APIView/APIViewWeb/Models/CodeLineModel.cs b/src/dotnet/APIView/APIViewWeb/Models/CodeLineModel.cs index e66de2f04e7..113a10fde82 100644 --- a/src/dotnet/APIView/APIViewWeb/Models/CodeLineModel.cs +++ b/src/dotnet/APIView/APIViewWeb/Models/CodeLineModel.cs @@ -5,7 +5,6 @@ using ApiView; using APIView; using APIView.DIff; -using Newtonsoft.Json.Serialization; namespace APIViewWeb.Models { @@ -13,7 +12,9 @@ public readonly struct CodeLineModel { public CodeLineModel(DiffLineKind kind, CodeLine codeLine, CommentThreadModel commentThread, CodeDiagnostic[] diagnostics, int lineNumber, int[] documentedByLines = null, - bool isDiffView = false, int? diffSectionId = null, int? otherLineSectionKey = null, HashSet headingsOfSectionsWithDiff = null, bool isSubHeadingWithDiffInSection = false) + bool isDiffView = false, int? diffSectionId = null, int? otherLineSectionKey = null, + HashSet headingsOfSectionsWithDiff = null, bool isSubHeadingWithDiffInSection = false, + string language = null) { CodeLine = codeLine; CommentThread = commentThread; @@ -26,12 +27,13 @@ public CodeLineModel(DiffLineKind kind, CodeLine codeLine, CommentThreadModel co OtherLineSectionKey = otherLineSectionKey; HeadingsOfSectionsWithDiff = headingsOfSectionsWithDiff ?? new HashSet(); IsSubHeadingWithDiffInSection = isSubHeadingWithDiffInSection; + Language = language; } public CodeLineModel(CodeLineModel codeLineModel, DiffLineKind kind = DiffLineKind.Unchanged, CodeLine codeLine = default(CodeLine), CommentThreadModel commentThread = default(CommentThreadModel), CodeDiagnostic[] diagnostics = null, int lineNumber = default(int), int[] documentedByLines = null, bool isDiffView = false, int? diffSectionId = null, - int? otherLineSectionKey = null, HashSet headingsOfSectionsWithDiff = null, bool isSubHeadingWithDiffInSection = false) + int? otherLineSectionKey = null, HashSet headingsOfSectionsWithDiff = null, bool isSubHeadingWithDiffInSection = false, string language = null) { CodeLine = (codeLine.Equals(default(CodeLine))) ? codeLineModel.CodeLine : codeLine; CommentThread = commentThread ?? codeLineModel.CommentThread; @@ -44,6 +46,7 @@ public CodeLineModel(DiffLineKind kind, CodeLine codeLine, CommentThreadModel co OtherLineSectionKey = otherLineSectionKey ?? codeLineModel.OtherLineSectionKey; HeadingsOfSectionsWithDiff = headingsOfSectionsWithDiff ?? codeLineModel.HeadingsOfSectionsWithDiff; IsSubHeadingWithDiffInSection = (!isSubHeadingWithDiffInSection) ? codeLineModel.IsSubHeadingWithDiffInSection : isSubHeadingWithDiffInSection; + Language = language ?? codeLineModel.Language; } public CodeLine CodeLine { get; } @@ -57,5 +60,6 @@ public CodeLineModel(DiffLineKind kind, CodeLine codeLine, CommentThreadModel co public int? OtherLineSectionKey { get; } public HashSet HeadingsOfSectionsWithDiff { get; } public bool IsSubHeadingWithDiffInSection { get; } + public string Language { get; } } } diff --git a/src/dotnet/APIView/APIViewWeb/Models/CommentThreadModel.cs b/src/dotnet/APIView/APIViewWeb/Models/CommentThreadModel.cs index ab1f64126a4..e16f09a2f9d 100644 --- a/src/dotnet/APIView/APIViewWeb/Models/CommentThreadModel.cs +++ b/src/dotnet/APIView/APIViewWeb/Models/CommentThreadModel.cs @@ -12,6 +12,7 @@ public CommentThreadModel(string reviewId, string lineId, IEnumerable c.IsResolved); @@ -22,6 +23,7 @@ public CommentThreadModel(string reviewId, string lineId, IEnumerable Comments { get; set; } public string LineId { get; set; } + public string CrossLanguageId { get; set; } public string LineClass { get; set; } public bool IsResolved { get; set; } public string ResolvedBy { get; set; } diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml index 90e20efb9da..550b7256f0d 100644 --- a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml +++ b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml @@ -1,569 +1,588 @@ -@page "{id}/{revisionId?}" -@model APIViewWeb.Pages.Assemblies.ReviewPageModel -@using APIViewWeb.Helpers -@using APIViewWeb.LeanModels; -@using APIViewWeb.Models -@{ - Layout = "Shared/_Layout"; - ViewData["Title"] = Model.ReviewContent.Review.PackageName; - var userPreference = PageModelHelpers.GetUserPreference(Model._preferenceCache, User); - TempData["UserPreference"] = userPreference; - TempData["LanguageCssSafeName"] = PageModelHelpers.GetLanguageCssSafeName(Model.ReviewContent.Review.Language); - TempData["Comments"] = Model.Comments; - ViewBag.HasSections = Model.ReviewContent.PageHasLoadableSections; -} -@{ - var rightOffCanvasClass = " show-right-offcanvas"; - var leftOffCanvasClass = " show-left-offcanvas"; - var mainContainerLeftClass = " move-main-content-container-left"; - var mainContainerRightClass = " move-main-content-container-right"; - if (userPreference.HideReviewPageOptions.HasValue && userPreference.HideReviewPageOptions == true) - { - rightOffCanvasClass = String.Empty; - mainContainerRightClass = String.Empty; - } - var mainContainerClass = mainContainerLeftClass + mainContainerRightClass; -} - - -
-
-

- Approval   -

- @{ - var approvalCollapseState = " show"; - if (Request.Cookies.ContainsKey("approveCollapse")) - { - if (!Request.Cookies["approveCollapse"].Equals("shown")) - approvalCollapseState = String.Empty; - } - } -
    -
  • -
    - - @if (Model.ReviewContent.DiffAPIRevision == null || Model.ReviewContent.DiffAPIRevision.Approvers.Any()) - { - @if (Model.ReviewContent.ActiveAPIRevision.Approvers.Contains(User.GetGitHubLogin())) - { -
    - -
    - } - else - { - var isActiveRevisionAhead = (Model.ReviewContent.DiffAPIRevision == null)? true: Model.ReviewContent.ActiveAPIRevision.CreatedOn > Model.ReviewContent.DiffAPIRevision.CreatedOn; - @if ((Model.ReviewContent.ActiveConversationsInActiveAPIRevision > 0 - || Model.ReviewContent.ActiveConversationsInSampleRevisions > 0) - && Model.ReviewContent.PreferredApprovers.Contains(User.GetGitHubLogin()) - && isActiveRevisionAhead) - { - Approves the current revision of the API -
    - -
    - } - else - { - @if (Model.ReviewContent.PreferredApprovers.Contains(User.GetGitHubLogin()) - && isActiveRevisionAhead) - { - Approves the current revision of the API -
    - -
    - } - else - { -
    - -
    - } - } - } - } - else - { - @if (Model.ReviewContent.ActiveAPIRevision.Approvers.Contains(User.GetGitHubLogin())) - { -
    - -
    - } - else - { -
    - -
    - } - } -
    - @{ - var approvers = Model.ReviewContent.ActiveAPIRevision.Approvers; - @if (approvers.Count() > 0) - { - - Approved by: - @{ - int i = 0; - } - @foreach (var approver in approvers) - { - @approver - @if (i < (approvers.Count() - 1)) - { - @Html.Raw(", ") - ; - } - i++; - } - - } - else - { - Current Revision Approval Pending - } - } -
  • - @if (Model.ReviewContent.ActiveAPIRevision.PackageName != null && - !(LanguageServiceHelpers.MapLanguageAliases(new List { "Swagger", "TypeSpec" })).Contains(Model.ReviewContent.Review.Language)) - { - var reviewIsApproved = Model.ReviewContent.Review.IsApproved; - string approver = null; - if (reviewIsApproved) - { - var changeAction = Model.ReviewContent.Review.ChangeHistory.First(_ => _.ChangeAction == ReviewChangeAction.Approved); - if (changeAction != null) - { - approver = changeAction.ChangedBy; - } - else - { - approver = "azure-sdk"; - } - } - - @if (!reviewIsApproved) - { -
  • -
    - - Approves First Release of the package -
    - -
    -
    - First Revision Approval Pending -
  • - } - else - { -
  • - @if (approver != null) - { - Package has been approved for first release by @approver - } - else - { - Package has been approved for first release - } -
  • - } - } -
- @* Enables Button for generating AI Review - -

- Generate AI Review   -

- var generateAIReviewCollapseState = String.Empty; - if (Request.Cookies.ContainsKey("generateAIReviewCollapse")) - { - if (Request.Cookies["generateAIReviewCollapse"].Equals("shown")) - generateAIReviewCollapseState = " show"; - } -
    -
    - -
    -
- *@ -

- Request Reviewers   -

- @{ - var requestReviewersCollapseState = String.Empty; - if (Request.Cookies.ContainsKey("requestReviewersCollapse")) - { - if (Request.Cookies["requestReviewersCollapse"].Equals("shown")) - requestReviewersCollapseState = " show"; - } - } -
    - @{ - var anyChecked = false; - } -
    - -
  • -
      - @foreach (var approver in Model.ReviewContent.PreferredApprovers) - { -
    • -
      - @if (Model.ReviewContent.ActiveAPIRevision.AssignedReviewers != null && Model.ReviewContent.ActiveAPIRevision.AssignedReviewers.Where(a => a.AssingedTo == approver).Any()) - { - - - anyChecked = true; - } - else - { - - - } -
      -
    • - } -
    -
  • - - @if (anyChecked) - { - - } - else - { - - } - - -
  • -
    -
- @if (Model.ReviewContent.ActiveAPIRevision.APIRevisionType == APIRevisionType.PullRequest) - { - var associatedPRs = await Model.GetAssociatedPullRequest(); - @if (associatedPRs != null && associatedPRs.Count() > 0) - { - var associatedPRState = String.Empty; - if (Request.Cookies.ContainsKey("associatedPRCollapse")) - { - if (Request.Cookies["associatedPRCollapse"].Equals("shown")) - associatedPRState = " show"; - } -

- Associated Pull Requests   -

-
    - @foreach (var prModel in associatedPRs) - { - var url = $"https://github.com/{prModel.RepoName}/pull/{prModel.PullRequestNumber}"; - var txt = $"{prModel.RepoName}/{prModel.PullRequestNumber}"; -
  • - @txt -
  • - } -
- } - } - @if (Model.ReviewContent.ActiveAPIRevision.APIRevisionType == APIRevisionType.PullRequest) - { - var prsOfAssociatedAPIRevisions = await Model.GetPRsOfAssoicatedReviews(); - @if (prsOfAssociatedAPIRevisions != null && prsOfAssociatedAPIRevisions.Count() > 1) - { - var associatedReviewsState = String.Empty; - if (Request.Cookies.ContainsKey("associatedReviewsCollapse")) - { - if (Request.Cookies["associatedReviewsCollapse"].Equals("shown")) - associatedReviewsState = " show"; - } -

- Associated APIRevisions   -

-
    - @foreach (var pr in prsOfAssociatedAPIRevisions) - { - if (pr.ReviewId != Model.ReviewContent.Review.Id) - { - var url = @Url.ActionLink("Review", "Assemblies", new - { - id = pr.ReviewId, - revisionId = pr.APIRevisionId - }); -
  • - @pr.Language/@pr.PackageName -
  • - } - } -
- } - } -

- Review Options   -

- @{ - var reviewOptionsCollapseState = " show"; - if (Request.Cookies.ContainsKey("reviewOptionsCollapse")) - { - if (!Request.Cookies["reviewOptionsCollapse"].Equals("shown")) - reviewOptionsCollapseState = String.Empty; - } - } -
    -
  • -
    -
    - @if (PageModelHelpers.GetUserEmail(User) != null) - { - if (PageModelHelpers.IsUserSubscribed(User, Model.ReviewContent.Review.Subscribers)) - { - - } - else - { - - } - } - else - { - - } - -
    -
    -
  • -
-

- Page Settings   -

- @{ - var pageSettingsCollapseState = String.Empty; - if (Request.Cookies.ContainsKey("pageSettingsCollapse")) - { - if (Request.Cookies["pageSettingsCollapse"].Equals("shown")) - pageSettingsCollapseState = " show"; - } - } -
    -
  • -
    - @if (userPreference.ShowComments == true) - { - - } - else - { - - } - -
    -
  • -
  • -
    - @if (userPreference.ShowSystemComments == true) - { - - } - else - { - - } - -
    -
  • -
  • -
    - @if (Model.ShowDocumentation) - { - - } - else - { - - } - - - -
    -
  • -
  • -
    - @if (userPreference.ShowHiddenApis == true) - { - - } - else - { - - } - -
    -
  • -
  • -
    - @if (userPreference.HideLineNumbers == true) - { - - } - else - { - - } - -
    -
  • -
  • -
    - @if (userPreference.HideLeftNavigation == true) - { - - } - else - { - - } - -
    -
  • - @if (!String.IsNullOrEmpty(Model.DiffRevisionId) && Model.ReviewContent.Review.Language != "Swagger") - { -
  • -
    - @if (Model.ShowDiffOnly) - { - - } - else - { - - } - - - -
    -
  • - } -
-
-
- -
-
- -
-
- -
-
- @{ - var reviewLeftDisplay = String.Empty; - var reviewRightSize = "10"; - if (userPreference.HideLeftNavigation == true) - { - reviewLeftDisplay = "d-none"; - reviewRightSize = "12"; - } - - var reviewApprovedClass = (Model.ReviewContent.ActiveAPIRevision.Approvers.Count() > 0) ? "review-approved" : "border rounded-1"; - } -
-
-
- @if (Model.ReviewContent.Navigation != null) - { - - } -
-
-
- -
- @if (!string.IsNullOrEmpty(Model.NotificationMessage)) - { - - } - - - @foreach (var line in Model.ReviewContent.codeLines) - { - - } - -
-
-
- -
- - -
- -
- - - -
-
-
Revisions
- -
-
- -
-
\ No newline at end of file +@page "{id}/{revisionId?}" +@model APIViewWeb.Pages.Assemblies.ReviewPageModel +@using APIViewWeb.Helpers +@using APIViewWeb.LeanModels; +@using APIViewWeb.Models +@{ + Layout = "Shared/_Layout"; + ViewData["Title"] = Model.ReviewContent.Review.PackageName; + var userPreference = PageModelHelpers.GetUserPreference(Model._preferenceCache, User); + TempData["UserPreference"] = userPreference; + TempData["LanguageCssSafeName"] = PageModelHelpers.GetLanguageCssSafeName(Model.ReviewContent.Review.Language); + TempData["Comments"] = Model.Comments; + ViewBag.HasSections = Model.ReviewContent.PageHasLoadableSections; +} +@{ + var rightOffCanvasClass = " show-right-offcanvas"; + var leftOffCanvasClass = " show-left-offcanvas"; + var mainContainerLeftClass = " move-main-content-container-left"; + var mainContainerRightClass = " move-main-content-container-right"; + if (userPreference.HideReviewPageOptions.HasValue && userPreference.HideReviewPageOptions == true) + { + rightOffCanvasClass = String.Empty; + mainContainerRightClass = String.Empty; + } + var mainContainerClass = mainContainerLeftClass + mainContainerRightClass; +} + + +
+
+

+ Approval   +

+ @{ + var approvalCollapseState = " show"; + if (Request.Cookies.ContainsKey("approveCollapse")) + { + if (!Request.Cookies["approveCollapse"].Equals("shown")) + approvalCollapseState = String.Empty; + } + } +
    +
  • +
    + + @if (Model.ReviewContent.DiffAPIRevision == null || Model.ReviewContent.DiffAPIRevision.Approvers.Any()) + { + @if (Model.ReviewContent.ActiveAPIRevision.Approvers.Contains(User.GetGitHubLogin())) + { +
    + +
    + } + else + { + var isActiveRevisionAhead = (Model.ReviewContent.DiffAPIRevision == null)? true: Model.ReviewContent.ActiveAPIRevision.CreatedOn > Model.ReviewContent.DiffAPIRevision.CreatedOn; + @if ((Model.ReviewContent.ActiveConversationsInActiveAPIRevision > 0 + || Model.ReviewContent.ActiveConversationsInSampleRevisions > 0) + && Model.ReviewContent.PreferredApprovers.Contains(User.GetGitHubLogin()) + && isActiveRevisionAhead) + { + Approves the current revision of the API +
    + +
    + } + else + { + @if (Model.ReviewContent.PreferredApprovers.Contains(User.GetGitHubLogin()) + && isActiveRevisionAhead) + { + Approves the current revision of the API +
    + +
    + } + else + { +
    + +
    + } + } + } + } + else + { + @if (Model.ReviewContent.ActiveAPIRevision.Approvers.Contains(User.GetGitHubLogin())) + { +
    + +
    + } + else + { +
    + +
    + } + } +
    + @{ + var approvers = Model.ReviewContent.ActiveAPIRevision.Approvers; + @if (approvers.Count() > 0) + { + + Approved by: + @{ + int i = 0; + } + @foreach (var approver in approvers) + { + @approver + @if (i < (approvers.Count() - 1)) + { + @Html.Raw(", ") + ; + } + i++; + } + + } + else + { + Current Revision Approval Pending + } + } +
  • + @if (Model.ReviewContent.ActiveAPIRevision.PackageName != null && + !(LanguageServiceHelpers.MapLanguageAliases(new List { "Swagger", "TypeSpec" })).Contains(Model.ReviewContent.Review.Language)) + { + var reviewIsApproved = Model.ReviewContent.Review.IsApproved; + string approver = null; + if (reviewIsApproved) + { + var changeAction = Model.ReviewContent.Review.ChangeHistory.First(_ => _.ChangeAction == ReviewChangeAction.Approved); + if (changeAction != null) + { + approver = changeAction.ChangedBy; + } + else + { + approver = "azure-sdk"; + } + } + + @if (!reviewIsApproved) + { +
  • +
    + + Approves First Release of the package +
    + +
    +
    + First Revision Approval Pending +
  • + } + else + { +
  • + @if (approver != null) + { + Package has been approved for first release by @approver + } + else + { + Package has been approved for first release + } +
  • + } + } +
+ @* Enables Button for generating AI Review + +

+ Generate AI Review   +

+ var generateAIReviewCollapseState = String.Empty; + if (Request.Cookies.ContainsKey("generateAIReviewCollapse")) + { + if (Request.Cookies["generateAIReviewCollapse"].Equals("shown")) + generateAIReviewCollapseState = " show"; + } +
    +
    + +
    +
+ *@ +

+ Request Reviewers   +

+ @{ + var requestReviewersCollapseState = String.Empty; + if (Request.Cookies.ContainsKey("requestReviewersCollapse")) + { + if (Request.Cookies["requestReviewersCollapse"].Equals("shown")) + requestReviewersCollapseState = " show"; + } + } +
    + @{ + var anyChecked = false; + } +
    + +
  • +
      + @foreach (var approver in Model.ReviewContent.PreferredApprovers) + { +
    • +
      + @if (Model.ReviewContent.ActiveAPIRevision.AssignedReviewers != null && Model.ReviewContent.ActiveAPIRevision.AssignedReviewers.Where(a => a.AssingedTo == approver).Any()) + { + + + anyChecked = true; + } + else + { + + + } +
      +
    • + } +
    +
  • + + @if (anyChecked) + { + + } + else + { + + } + + +
  • +
    +
+ @if (Model.ReviewContent.ActiveAPIRevision.APIRevisionType == APIRevisionType.PullRequest) + { + var associatedPRs = await Model.GetAssociatedPullRequest(); + @if (associatedPRs != null && associatedPRs.Count() > 0) + { + var associatedPRState = String.Empty; + if (Request.Cookies.ContainsKey("associatedPRCollapse")) + { + if (Request.Cookies["associatedPRCollapse"].Equals("shown")) + associatedPRState = " show"; + } +

+ Associated Pull Requests   +

+
    + @foreach (var prModel in associatedPRs) + { + var url = $"https://github.com/{prModel.RepoName}/pull/{prModel.PullRequestNumber}"; + var txt = $"{prModel.RepoName}/{prModel.PullRequestNumber}"; +
  • + @txt +
  • + } +
+ } + } + @if (Model.ReviewContent.ActiveAPIRevision.APIRevisionType == APIRevisionType.PullRequest) + { + var prsOfAssociatedAPIRevisions = await Model.GetPRsOfAssoicatedReviews(); + @if (prsOfAssociatedAPIRevisions != null && prsOfAssociatedAPIRevisions.Count() > 1) + { + var associatedReviewsState = String.Empty; + if (Request.Cookies.ContainsKey("associatedReviewsCollapse")) + { + if (Request.Cookies["associatedReviewsCollapse"].Equals("shown")) + associatedReviewsState = " show"; + } +

+ Associated APIRevisions   +

+
    + @foreach (var pr in prsOfAssociatedAPIRevisions) + { + if (pr.ReviewId != Model.ReviewContent.Review.Id) + { + var url = @Url.ActionLink("Review", "Assemblies", new + { + id = pr.ReviewId, + revisionId = pr.APIRevisionId + }); +
  • + @pr.Language/@pr.PackageName +
  • + } + } +
+ } + } +

+ Review Options   +

+ @{ + var reviewOptionsCollapseState = " show"; + if (Request.Cookies.ContainsKey("reviewOptionsCollapse")) + { + if (!Request.Cookies["reviewOptionsCollapse"].Equals("shown")) + reviewOptionsCollapseState = String.Empty; + } + } +
    +
  • +
    +
    + @if (PageModelHelpers.GetUserEmail(User) != null) + { + if (PageModelHelpers.IsUserSubscribed(User, Model.ReviewContent.Review.Subscribers)) + { + + } + else + { + + } + } + else + { + + } + +
    +
    +
  • +
+

+ Page Settings   +

+ @{ + var pageSettingsCollapseState = String.Empty; + if (Request.Cookies.ContainsKey("pageSettingsCollapse")) + { + if (Request.Cookies["pageSettingsCollapse"].Equals("shown")) + pageSettingsCollapseState = " show"; + } + } +
    +
  • +
    + @if (userPreference.ShowComments == true) + { + + } + else + { + + } + +
    +
  • +
  • +
    + @if (userPreference.ShowSystemComments == true) + { + + } + else + { + + } + +
    +
  • +
  • +
    + @if (Model.ShowDocumentation) + { + + } + else + { + + } + + + +
    +
  • +
  • +
    + @if (userPreference.ShowHiddenApis == true) + { + + } + else + { + + } + +
    +
  • +
  • +
    + @if (userPreference.HideLineNumbers == true) + { + + } + else + { + + } + +
    +
  • +
  • +
    + @if (userPreference.HideLeftNavigation == true) + { + + } + else + { + + } + +
    +
  • + @if (!String.IsNullOrEmpty(Model.DiffRevisionId) && Model.ReviewContent.Review.Language != "Swagger") + { +
  • +
    + @if (Model.ShowDiffOnly) + { + + } + else + { + + } + + + +
    +
  • + } +
+
+
+ +
+
+ +
+
+ +
+
+ @{ + var reviewLeftDisplay = String.Empty; + var reviewRightSize = "10"; + if (userPreference.HideLeftNavigation == true) + { + reviewLeftDisplay = "d-none"; + reviewRightSize = "12"; + } + + var reviewApprovedClass = (Model.ReviewContent.ActiveAPIRevision.Approvers.Count() > 0) ? "review-approved" : "border rounded-1"; + } +
+
+
+ @if (Model.ReviewContent.Navigation != null) + { + + } +
+
+
+ +
+ @if (!string.IsNullOrEmpty(Model.NotificationMessage)) + { + + } + + + @foreach (var line in Model.ReviewContent.codeLines) + { + + } + +
+ +
+
+ @if (Model.CrossLanguage.Any()) + { +
+ @foreach(var language in Model.CrossLanguage) + { + var reviewcontent = Model.ReviewContent.CrossLanguageViewContent[language]; + var langId = PageModelHelpers.GetLanguageCssSafeName(language); + + + @foreach (var line in reviewcontent.codeLines) + { + + } + +
+ } +
+ } +
+ + +
+ +
+ + + +
+
+
Revisions
+ +
+
+ +
+
diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml.cs b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml.cs index ce0fc58ae16..03f5dcad430 100644 --- a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml.cs +++ b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml.cs @@ -70,6 +70,10 @@ public ReviewPageModel( public bool ShowDiffOnly { get; set; } [BindProperty(Name = "notificationMessage", SupportsGet = true)] public string NotificationMessage { get; set; } + [BindProperty(Name = "crossLanguage", SupportsGet = true)] + [ModelBinder(BinderType = typeof(DecodeModelBinder))] + public IEnumerableCrossLanguage { get; set; } + /// /// Handler for loading page @@ -90,6 +94,24 @@ public async Task OnGetAsync(string id, string revisionId = null) showDocumentation: ShowDocumentation, showDiffOnly: ShowDiffOnly, diffContextSize: REVIEW_DIFF_CONTEXT_SIZE, diffContextSeperator: DIFF_CONTEXT_SEPERATOR); + // Get Cross Language View Details + foreach (var language in CrossLanguage) + { + var packageName = LanguageServiceHelpers.GetCorrespondingPackageName(ReviewContent.Review.Language, language, ReviewContent.Review.PackageName); + var review = await _reviewManager.GetReviewAsync(language, packageName); + if (review != null) + { + var reviewContent = await PageModelHelpers.GetReviewContentAsync(configuration: _configuration, + reviewManager: _reviewManager, preferenceCache: _preferenceCache, userProfileRepository: _userProfileRepository, + reviewRevisionsManager: _apiRevisionsManager, commentManager: _commentsManager, codeFileRepository: _codeFileRepository, + signalRHubContext: _signalRHubContext, user: User, review: review, revisionId: null, diffRevisionId: null, + showDocumentation: ShowDocumentation, showDiffOnly: ShowDiffOnly, diffContextSize: REVIEW_DIFF_CONTEXT_SIZE, + diffContextSeperator: DIFF_CONTEXT_SEPERATOR); + + ReviewContent.CrossLanguageViewContent.Add(review.Language, reviewContent); + } + } + if (ReviewContent.Directive == ReviewContentModelDirective.TryGetlegacyReview) { // Check if you can get review from legacy data diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Samples.cshtml.cs b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Samples.cshtml.cs index 72eea812c72..f566e41cb5a 100644 --- a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Samples.cshtml.cs +++ b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Samples.cshtml.cs @@ -198,7 +198,7 @@ private async Task ParseLines(string fileId, ReviewCommentsMode // Allows the indent to work correctly for spacing purposes lineContent = "
   " + lineContent + "
"; - var line = new CodeLine(lineContent, ActiveSampleRevision.FileId + "-line-" + (i+1-skipped).ToString() , ""); + var line = new CodeLine(html: lineContent, id : ActiveSampleRevision.FileId + "-line-" + (i+1-skipped).ToString() , crossLangId : "", lineClass : ""); comments.TryGetThreadForLine(ActiveSampleRevision.FileId + "-line-" + (i+1-skipped).ToString(), out var thread); lines[i] = new CodeLineModel(APIView.DIff.DiffLineKind.Unchanged, line, thread, cd, i+1-skipped, new int[0]); } diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/_CodeLine.cshtml b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/_CodeLine.cshtml index e88c1609059..c11ab291241 100644 --- a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/_CodeLine.cshtml +++ b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/_CodeLine.cshtml @@ -62,6 +62,7 @@ } var userPreference = TempData["UserPreference"] as UserPreferenceModel ?? new UserPreferenceModel(); + var crossLanguageView = TempData["CrossLanguageEntries"] as IEnumerable; // Always show hidden APIs if we are in Diff mode and there are changes. if (Model.CodeLine.IsHiddenApi && Model.Kind == DiffLineKind.Unchanged) @@ -79,7 +80,8 @@ { lineClass += " code-delta"; isHeadingWithDelta = true; - } + } + var rowClass = RemoveMultipleSpaces($"code-line {headingClass} {codeLineClass} {lineClass} {codeLineDisplay} {documentationRow} {hiddenApiRow}"); var cellContent = String.Empty; for (int i = 0; i < Model.CodeLine.Indent; i++) @@ -100,7 +102,7 @@ cellContent += Model.CodeLine.DisplayString; } - + @@ -111,7 +113,11 @@ } else { - var lineNumberClass = RemoveMultipleSpaces($"line-number"); + var lineNumberClass = $"line-number"; + @if (crossLanguageView.Any() && !String.IsNullOrEmpty(Model.CodeLine.CrossLanguageDefinitionId) && PageModelHelpers.IsAPIStubHeader(Model.CodeLine.DisplayString)) + { + lineNumberClass = $"{lineNumberClass} cl-line-no"; } + if (Model.CodeLine.IsDocumentation) { diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Shared/_CommentThreadPartial.cshtml b/src/dotnet/APIView/APIViewWeb/Pages/Shared/_CommentThreadPartial.cshtml index bc9c8df5539..82931d26dae 100644 --- a/src/dotnet/APIView/APIViewWeb/Pages/Shared/_CommentThreadPartial.cshtml +++ b/src/dotnet/APIView/APIViewWeb/Pages/Shared/_CommentThreadPartial.cshtml @@ -11,7 +11,7 @@ @if (Model != null && Model.Comments.Any()) { var commentsDisplayState = (userPreference!.ShowComments == true || TempData["page"].Equals("conversation")) ? String.Empty : " d-none"; - +
@if (Model.IsResolved && Model.Comments.First().CreatedBy == User.GetGitHubLogin()) diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Shared/_CrossLanguageViewPartial.cshtml b/src/dotnet/APIView/APIViewWeb/Pages/Shared/_CrossLanguageViewPartial.cshtml new file mode 100644 index 00000000000..e7733f3436d --- /dev/null +++ b/src/dotnet/APIView/APIViewWeb/Pages/Shared/_CrossLanguageViewPartial.cshtml @@ -0,0 +1,34 @@ +@using APIViewWeb.Helpers +@model IEnumerable + + + + + + +
+
+ +
+ @foreach (var language in Model) + { + var activeClass = (Model.ElementAt(0) == language) ? "active" : ""; + var lang = PageModelHelpers.GetLanguageCssSafeName(language); +
+ @language Content +
+ } +
+ +
+
\ No newline at end of file diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Shared/_Layout.cshtml b/src/dotnet/APIView/APIViewWeb/Pages/Shared/_Layout.cshtml index 1fa58f1eab2..0d4918ffec9 100644 --- a/src/dotnet/APIView/APIViewWeb/Pages/Shared/_Layout.cshtml +++ b/src/dotnet/APIView/APIViewWeb/Pages/Shared/_Layout.cshtml @@ -19,7 +19,7 @@ - + diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Shared/_ReviewNavBar.cshtml b/src/dotnet/APIView/APIViewWeb/Pages/Shared/_ReviewNavBar.cshtml new file mode 100644 index 00000000000..e28b5ed2648 --- /dev/null +++ b/src/dotnet/APIView/APIViewWeb/Pages/Shared/_ReviewNavBar.cshtml @@ -0,0 +1,37 @@ +@using APIViewWeb.Helpers +@using APIViewWeb.Models +@{ + var id = ViewContext.RouteData.Values["id"]; + var userPreference = TempData["UserPreference"] as UserPreferenceModel; +} + +
+ +
\ No newline at end of file diff --git a/src/dotnet/APIView/APIViewWeb/wwwroot/icons/java-original.svg b/src/dotnet/APIView/APIViewWeb/wwwroot/icons/java-original.svg index 6d72499057c..fabe5bc6af3 100644 --- a/src/dotnet/APIView/APIViewWeb/wwwroot/icons/java-original.svg +++ b/src/dotnet/APIView/APIViewWeb/wwwroot/icons/java-original.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + \ No newline at end of file diff --git a/src/dotnet/APIView/APIViewWeb/wwwroot/icons/javascript-original.svg b/src/dotnet/APIView/APIViewWeb/wwwroot/icons/javascript-original.svg index e6cfcfc73b1..f28b07c27ab 100644 --- a/src/dotnet/APIView/APIViewWeb/wwwroot/icons/javascript-original.svg +++ b/src/dotnet/APIView/APIViewWeb/wwwroot/icons/javascript-original.svg @@ -1 +1,6 @@ - \ No newline at end of file + + + + + + \ No newline at end of file diff --git a/src/dotnet/APIView/APIViewWeb/wwwroot/icons/python-original.svg b/src/dotnet/APIView/APIViewWeb/wwwroot/icons/python-original.svg index 60e99f01c92..fe9c33379e7 100644 --- a/src/dotnet/APIView/APIViewWeb/wwwroot/icons/python-original.svg +++ b/src/dotnet/APIView/APIViewWeb/wwwroot/icons/python-original.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + \ No newline at end of file diff --git a/src/dotnet/APIView/APIViewWeb/wwwroot/icons/typespec-original.svg b/src/dotnet/APIView/APIViewWeb/wwwroot/icons/typespec-original.svg new file mode 100644 index 00000000000..2cc9164a5e1 --- /dev/null +++ b/src/dotnet/APIView/APIViewWeb/wwwroot/icons/typespec-original.svg @@ -0,0 +1,36 @@ + + + + + + + + + + From cbb24ebe725418d5c8159cfe1d65f8cfba7bd88f Mon Sep 17 00:00:00 2001 From: Chidozie Ononiwu Date: Fri, 8 Mar 2024 17:42:53 -0800 Subject: [PATCH 2/5] Locate CrossLanguage Packages automatically --- .../css/shared/bootstraps-overrides.scss | 15 +++-- .../APIViewWeb/Client/src/pages/review.ts | 16 ------ .../APIViewWeb/Helpers/HelperModelBinders.cs | 24 -------- .../Helpers/LanguageServiceHelpers.cs | 46 ---------------- .../Managers/APIRevisionsManager.cs | 55 +++++++++++-------- .../Interfaces/IAPIRevisionsManager.cs | 1 + .../Managers/Interfaces/IReviewManager.cs | 1 + .../APIViewWeb/Managers/ReviewManager.cs | 11 ++++ .../APIViewWeb/Pages/Assemblies/Review.cshtml | 6 +- .../Pages/Assemblies/Review.cshtml.cs | 15 ++--- .../Pages/Assemblies/_CodeLine.cshtml | 3 +- .../CosmosAPIRevisionsRepository.cs | 25 +++++++++ .../Repositories/CosmosReviewRepository.cs | 2 +- .../ICosmosAPIRevisionsRepository.cs | 11 ++++ .../Interfaces/ICosmosReviewRepository.cs | 2 +- 15 files changed, 103 insertions(+), 130 deletions(-) delete mode 100644 src/dotnet/APIView/APIViewWeb/Helpers/HelperModelBinders.cs diff --git a/src/dotnet/APIView/APIViewWeb/Client/css/shared/bootstraps-overrides.scss b/src/dotnet/APIView/APIViewWeb/Client/css/shared/bootstraps-overrides.scss index 180a891a634..299be8a4037 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/css/shared/bootstraps-overrides.scss +++ b/src/dotnet/APIView/APIViewWeb/Client/css/shared/bootstraps-overrides.scss @@ -114,12 +114,19 @@ border-bottom: 1px solid var(--border-color) !important; } -.border-start { - border-left: 1px solid var(--border-color) !important; +.breadcrumb { + margin-bottom: 0rem; +} +.breadcrumb-item + .breadcrumb-item::before { + margin-top: 0rem; } -.border-end { - border-right: 1px solid var(--border-color) !important; +.breadcrumb-item + .breadcrumb-item::before { + padding-right: 0.25rem; +} + +.breadcrumb-item + .breadcrumb-item { + padding-left: 0.25rem; } .list-group-item { diff --git a/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.ts b/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.ts index 95fcf2d560c..b64572a3651 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.ts +++ b/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.ts @@ -255,22 +255,6 @@ $(() => { /* CROSS LANGUAGE VIEW --------------------------------------------------------------------------------------------------------------------------------------------------------*/ - $("#load-cross-language-view").on("click", function (e: JQuery.ClickEvent) { - const crossLangusges = $(".cross-lang-view-switch"); - const uri = new URL(window.location.href); - const urlParams = new URLSearchParams(uri.search); - urlParams.delete("crossLanguage"); - crossLangusges.each(function (index, value) { - const language = value.querySelector("label")?.textContent; - const isChecked = value.querySelector("input")?.checked; - if (isChecked) { - urlParams.append("crossLanguage", encodeURIComponent(language!)); - } - }); - uri.search = urlParams.toString(); - window.location.href = uri.toString() - }) - // Load Cross Language Panel $(".cl-line-no").on("click", function (e: JQuery.ClickEvent) { e.preventDefault(); diff --git a/src/dotnet/APIView/APIViewWeb/Helpers/HelperModelBinders.cs b/src/dotnet/APIView/APIViewWeb/Helpers/HelperModelBinders.cs deleted file mode 100644 index 1a1be285cd1..00000000000 --- a/src/dotnet/APIView/APIViewWeb/Helpers/HelperModelBinders.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc.ModelBinding; - -namespace APIViewWeb.Helpers -{ - public class DecodeModelBinder : IModelBinder - { - public Task BindModelAsync(ModelBindingContext bindingContext) - { - var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); - var decodedValues = new List(); - - foreach (var item in valueProviderResult.Values) - { - decodedValues.Add(Uri.UnescapeDataString(item)); - } - - bindingContext.Result = ModelBindingResult.Success(decodedValues); - return Task.CompletedTask; - } - } -} diff --git a/src/dotnet/APIView/APIViewWeb/Helpers/LanguageServiceHelpers.cs b/src/dotnet/APIView/APIViewWeb/Helpers/LanguageServiceHelpers.cs index a8949545316..4c13820b2ad 100644 --- a/src/dotnet/APIView/APIViewWeb/Helpers/LanguageServiceHelpers.cs +++ b/src/dotnet/APIView/APIViewWeb/Helpers/LanguageServiceHelpers.cs @@ -12,52 +12,6 @@ public class LanguageServiceHelpers { public static string[] SupportedLanguages = new string[] { "C", "C#", "C++", "Go", "Java", "JavaScript", "Json", "Kotlin", "Python", "Swagger", "Swift", "TypeSpec", "Xml" }; - public static string GetCorrespondingPackageName(string sourceLanguage, string targetlanguage, string packageName) - { - if (packageName.Equals("widgetmanagerclient") || packageName.Equals("Contoso.WidgetManager") || packageName.Equals("com.azure:contoso-widgetmanager")) - { - var result = string.Empty; - switch (targetlanguage) - { - case "TypeSpec": - result = "Contoso.WidgetManager"; - break; - case "Java": - result = "com.azure:contoso-widgetmanager"; - break; - case "Python": - result = "widgetmanagerclient"; - break; - } - return result; - } - else { - var result = string.Empty; - switch (targetlanguage) - { - case "C#": - result = "Azure.Identity"; - break; - case "C++": - result = "azure-identity-cpp"; - break; - case "Go": - result = "azidentity"; - break; - case "Java": - result = "com.azure:azure-identity"; - break; - case "JavaScript": - result = "@azure/identity"; - break; - case "Python": - result = "azure-identity"; - break; - } - return result; - } - } - public static IEnumerable MapLanguageAliases(IEnumerable languages) { HashSet result = new HashSet(); diff --git a/src/dotnet/APIView/APIViewWeb/Managers/APIRevisionsManager.cs b/src/dotnet/APIView/APIViewWeb/Managers/APIRevisionsManager.cs index c74de9b4f09..48861188413 100644 --- a/src/dotnet/APIView/APIViewWeb/Managers/APIRevisionsManager.cs +++ b/src/dotnet/APIView/APIViewWeb/Managers/APIRevisionsManager.cs @@ -793,6 +793,38 @@ public async Task> GetAPIRevisionsAssigned return await _apiRevisionsRepository.GetAPIRevisionsAssignedToUser(userName); } + public async Task UpdateRevisionMetadataAsync(APIRevisionListItemModel revision, string packageVersion, string label, bool setReleaseTag = false) + { + // Do not update package version metadata once a revision is marked as released + // This is to avoid updating metadata when a request is processed with a new version (auto incremented version change) right after a version is released + // without any API changes. + if (revision.IsReleased) + return revision; + + if (packageVersion != null && !packageVersion.Equals(revision.Files[0].PackageVersion)) + { + revision.Files[0].PackageVersion = packageVersion; + revision.Label = label; + } + + if (setReleaseTag) + { + revision.IsReleased = true; + revision.ReleasedOn = DateTime.UtcNow; + } + await _apiRevisionsRepository.UpsertAPIRevisionAsync(revision); + return revision; + } + + /// + /// Get ReviewIds of Language corresponding Review linked by CrossLanguagePackageId + /// + /// + /// + public async Task> GetReviewIdsOfLanguageCorrespondingReviewAsync(string crossLanguagePackageId) { + return await _apiRevisionsRepository.GetReviewIdsOfLanguageCorrespondingReviewAsync(crossLanguagePackageId); + } + /// /// Generate the Revision on a DevOps Pipeline /// @@ -855,28 +887,5 @@ private async Task GenerateAPIRevisionInExternalResource(ReviewListItemModel rev } return result; } - - public async Task UpdateRevisionMetadataAsync(APIRevisionListItemModel revision, string packageVersion, string label, bool setReleaseTag = false) - { - // Do not update package version metadata once a revision is marked as released - // This is to avoid updating metadata when a request is processed with a new version (auto incremented version change) right after a version is released - // without any API changes. - if (revision.IsReleased) - return revision; - - if (packageVersion != null && !packageVersion.Equals(revision.Files[0].PackageVersion)) - { - revision.Files[0].PackageVersion = packageVersion; - revision.Label = label; - } - - if (setReleaseTag) - { - revision.IsReleased = true; - revision.ReleasedOn = DateTime.UtcNow; - } - await _apiRevisionsRepository.UpsertAPIRevisionAsync(revision); - return revision; - } } } diff --git a/src/dotnet/APIView/APIViewWeb/Managers/Interfaces/IAPIRevisionsManager.cs b/src/dotnet/APIView/APIViewWeb/Managers/Interfaces/IAPIRevisionsManager.cs index f62706c0660..368c97a075f 100644 --- a/src/dotnet/APIView/APIViewWeb/Managers/Interfaces/IAPIRevisionsManager.cs +++ b/src/dotnet/APIView/APIViewWeb/Managers/Interfaces/IAPIRevisionsManager.cs @@ -41,5 +41,6 @@ public Task CreateAPIRevisionAsync(string userName, st public Task AssignReviewersToAPIRevisionAsync(ClaimsPrincipal User, string apiRevisionId, HashSet reviewers); public Task> GetAPIRevisionsAssignedToUser(string userName); public Task UpdateRevisionMetadataAsync(APIRevisionListItemModel revision, string packageVersion, string label, bool setReleaseTag = false); + public Task> GetReviewIdsOfLanguageCorrespondingReviewAsync(string crossLanguagePackageId); } } diff --git a/src/dotnet/APIView/APIViewWeb/Managers/Interfaces/IReviewManager.cs b/src/dotnet/APIView/APIViewWeb/Managers/Interfaces/IReviewManager.cs index 1101b1cd24e..47855c3d8b8 100644 --- a/src/dotnet/APIView/APIViewWeb/Managers/Interfaces/IReviewManager.cs +++ b/src/dotnet/APIView/APIViewWeb/Managers/Interfaces/IReviewManager.cs @@ -12,6 +12,7 @@ public interface IReviewManager public Task<(IEnumerable Reviews, int TotalCount, int TotalPages, int CurrentPage, int? PreviousPage, int? NextPage)> GetPagedReviewListAsync( IEnumerable search, IEnumerable languages, bool? isClosed, bool? isApproved, int offset, int limit, string orderBy); public Task GetReviewAsync(ClaimsPrincipal user, string id); + public Task> GetReviewsAsync(IEnumerable reviewIds, bool? isClosed = null); public Task GetLegacyReviewAsync(ClaimsPrincipal user, string id); public Task CreateReviewAsync(string packageName, string language, bool isClosed = true); public Task SoftDeleteReviewAsync(ClaimsPrincipal user, string id); diff --git a/src/dotnet/APIView/APIViewWeb/Managers/ReviewManager.cs b/src/dotnet/APIView/APIViewWeb/Managers/ReviewManager.cs index f076e089979..3ee528afc9c 100644 --- a/src/dotnet/APIView/APIViewWeb/Managers/ReviewManager.cs +++ b/src/dotnet/APIView/APIViewWeb/Managers/ReviewManager.cs @@ -126,6 +126,17 @@ public async Task GetReviewAsync(ClaimsPrincipal user, stri return review; } + /// + /// GEt Reviews using List of ReviewIds + /// + /// + /// + /// + public async Task> GetReviewsAsync(IEnumerable reviewIds, bool? isClosed = null) + { + return await _reviewsRepository.GetReviewsAsync(reviewIds, isClosed); + } + /// /// Get Legacy Reviews from old database /// diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml index 550b7256f0d..32d16a1d56b 100644 --- a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml +++ b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml @@ -527,13 +527,13 @@ }
- + - @if (Model.CrossLanguage.Any()) + @if (Model.ReviewContent.CrossLanguageViewContent.Any()) {
- @foreach(var language in Model.CrossLanguage) + @foreach (var language in Model.ReviewContent.CrossLanguageViewContent.Keys) { var reviewcontent = Model.ReviewContent.CrossLanguageViewContent[language]; var langId = PageModelHelpers.GetLanguageCssSafeName(language); diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml.cs b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml.cs index 03f5dcad430..beb42141e44 100644 --- a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml.cs +++ b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml.cs @@ -70,10 +70,6 @@ public ReviewPageModel( public bool ShowDiffOnly { get; set; } [BindProperty(Name = "notificationMessage", SupportsGet = true)] public string NotificationMessage { get; set; } - [BindProperty(Name = "crossLanguage", SupportsGet = true)] - [ModelBinder(BinderType = typeof(DecodeModelBinder))] - public IEnumerableCrossLanguage { get; set; } - /// /// Handler for loading page @@ -94,12 +90,11 @@ public async Task OnGetAsync(string id, string revisionId = null) showDocumentation: ShowDocumentation, showDiffOnly: ShowDiffOnly, diffContextSize: REVIEW_DIFF_CONTEXT_SIZE, diffContextSeperator: DIFF_CONTEXT_SEPERATOR); - // Get Cross Language View Details - foreach (var language in CrossLanguage) + if (!String.IsNullOrEmpty(ReviewContent.ActiveAPIRevision.Files.First().CrossLanguagePackageId)) { - var packageName = LanguageServiceHelpers.GetCorrespondingPackageName(ReviewContent.Review.Language, language, ReviewContent.Review.PackageName); - var review = await _reviewManager.GetReviewAsync(language, packageName); - if (review != null) + var correspondingReviewId = await _apiRevisionsManager.GetReviewIdsOfLanguageCorrespondingReviewAsync(ReviewContent.ActiveAPIRevision.Files.First().CrossLanguagePackageId); + var correspondingReviews = await _reviewManager.GetReviewsAsync(reviewIds: correspondingReviewId, isClosed: false); + foreach (var review in correspondingReviews) { var reviewContent = await PageModelHelpers.GetReviewContentAsync(configuration: _configuration, reviewManager: _reviewManager, preferenceCache: _preferenceCache, userProfileRepository: _userProfileRepository, @@ -108,7 +103,7 @@ public async Task OnGetAsync(string id, string revisionId = null) showDocumentation: ShowDocumentation, showDiffOnly: ShowDiffOnly, diffContextSize: REVIEW_DIFF_CONTEXT_SIZE, diffContextSeperator: DIFF_CONTEXT_SEPERATOR); - ReviewContent.CrossLanguageViewContent.Add(review.Language, reviewContent); + ReviewContent.CrossLanguageViewContent.Add(review.Language, reviewContent); } } diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/_CodeLine.cshtml b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/_CodeLine.cshtml index c11ab291241..2ffe64b8072 100644 --- a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/_CodeLine.cshtml +++ b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/_CodeLine.cshtml @@ -62,7 +62,6 @@ } var userPreference = TempData["UserPreference"] as UserPreferenceModel ?? new UserPreferenceModel(); - var crossLanguageView = TempData["CrossLanguageEntries"] as IEnumerable; // Always show hidden APIs if we are in Diff mode and there are changes. if (Model.CodeLine.IsHiddenApi && Model.Kind == DiffLineKind.Unchanged) @@ -114,7 +113,7 @@ else { var lineNumberClass = $"line-number"; - @if (crossLanguageView.Any() && !String.IsNullOrEmpty(Model.CodeLine.CrossLanguageDefinitionId) && PageModelHelpers.IsAPIStubHeader(Model.CodeLine.DisplayString)) + @if (!String.IsNullOrEmpty(Model.CodeLine.CrossLanguageDefinitionId) && PageModelHelpers.IsAPIStubHeader(Model.CodeLine.DisplayString)) { lineNumberClass = $"{lineNumberClass} cl-line-no"; } diff --git a/src/dotnet/APIView/APIViewWeb/Repositories/CosmosAPIRevisionsRepository.cs b/src/dotnet/APIView/APIViewWeb/Repositories/CosmosAPIRevisionsRepository.cs index a28054d09a5..63079a5adbf 100644 --- a/src/dotnet/APIView/APIViewWeb/Repositories/CosmosAPIRevisionsRepository.cs +++ b/src/dotnet/APIView/APIViewWeb/Repositories/CosmosAPIRevisionsRepository.cs @@ -232,6 +232,11 @@ public async Task> GetAPIRevisionsAsync(Da return revisions; } + /// + /// Get APIRevisions assigned to a user for review + /// + /// + /// public async Task> GetAPIRevisionsAssignedToUser(string userName) { var query = "SELECT * FROM Revisions r WHERE ARRAY_CONTAINS(r.AssignedReviewers, { 'AssingedTo': '" + userName + "' }, true)"; @@ -247,5 +252,25 @@ public async Task> GetAPIRevisionsAssigned return apiRevisions.OrderByDescending(r => r.LastUpdatedOn); } + + /// + /// Get ReviewIds for review that are linked by crossLanguagePackageId + /// + /// + /// + public async Task> GetReviewIdsOfLanguageCorrespondingReviewAsync(string crossLanguagePackageId) + { + var query = $"SELECT DISTINCT VALUE c.ReviewId FROM c WHERE ARRAY_LENGTH(c.Files) > 0 AND c.Files[0].CrossLanguagePackageId = '{crossLanguagePackageId}'"; + + var reviewIds = new List(); + var queryDefinition = new QueryDefinition(query); + var itemQueryIterator = _apiRevisionContainer.GetItemQueryIterator(queryDefinition); + while (itemQueryIterator.HasMoreResults) + { + var result = await itemQueryIterator.ReadNextAsync(); + reviewIds.AddRange(result.Resource); + } + return reviewIds; + } } } diff --git a/src/dotnet/APIView/APIViewWeb/Repositories/CosmosReviewRepository.cs b/src/dotnet/APIView/APIViewWeb/Repositories/CosmosReviewRepository.cs index d7b6a0077a1..7a75ad2641c 100644 --- a/src/dotnet/APIView/APIViewWeb/Repositories/CosmosReviewRepository.cs +++ b/src/dotnet/APIView/APIViewWeb/Repositories/CosmosReviewRepository.cs @@ -68,7 +68,7 @@ public async Task> GetReviewsAsync(string langu return reviews; } - public async Task> GetReviewsAsync(List reviewIds, bool? isClosed = null) + public async Task> GetReviewsAsync(IEnumerable reviewIds, bool? isClosed = null) { var reviewIdsAsQueryStr = CosmosQueryHelpers.ArrayToQueryString(reviewIds); var queryStringBuilder = new StringBuilder($"SELECT * FROM Reviews r WHERE r.id IN {reviewIdsAsQueryStr}"); diff --git a/src/dotnet/APIView/APIViewWeb/Repositories/Interfaces/ICosmosAPIRevisionsRepository.cs b/src/dotnet/APIView/APIViewWeb/Repositories/Interfaces/ICosmosAPIRevisionsRepository.cs index 6838cbfd114..72a9c249e9a 100644 --- a/src/dotnet/APIView/APIViewWeb/Repositories/Interfaces/ICosmosAPIRevisionsRepository.cs +++ b/src/dotnet/APIView/APIViewWeb/Repositories/Interfaces/ICosmosAPIRevisionsRepository.cs @@ -44,7 +44,18 @@ public interface ICosmosAPIRevisionsRepository /// /// public Task> GetAPIRevisionsAsync(DateTime lastUpdatedOn, APIRevisionType apiRevisionType = APIRevisionType.All); + /// + /// Get APIRevisions assigned to a user for review + /// + /// + /// public Task> GetAPIRevisionsAssignedToUser(string userName); + /// + /// Get ReviewIds for review that are linked by crossLanguagePackageId + /// + /// + /// + public Task> GetReviewIdsOfLanguageCorrespondingReviewAsync(string crossLanguagePackageId); } } diff --git a/src/dotnet/APIView/APIViewWeb/Repositories/Interfaces/ICosmosReviewRepository.cs b/src/dotnet/APIView/APIViewWeb/Repositories/Interfaces/ICosmosReviewRepository.cs index de37580a296..5b2bf227ce8 100644 --- a/src/dotnet/APIView/APIViewWeb/Repositories/Interfaces/ICosmosReviewRepository.cs +++ b/src/dotnet/APIView/APIViewWeb/Repositories/Interfaces/ICosmosReviewRepository.cs @@ -8,7 +8,7 @@ public interface ICosmosReviewRepository { public Task UpsertReviewAsync(ReviewListItemModel reviewModel); public Task GetReviewAsync(string reviewId); - public Task> GetReviewsAsync(List reviewIds, bool? isClosed = null); + public Task> GetReviewsAsync(IEnumerable reviewIds, bool? isClosed = null); public Task GetLegacyReviewAsync(string reviewId); public Task GetReviewAsync(string language, string packageName, bool? isClosed = false); public Task> GetReviewsAsync(string language, bool? isClosed = false); From ffb347f7b8461fc599b3f37c973bcbf68f7361d6 Mon Sep 17 00:00:00 2001 From: Chidozie Ononiwu Date: Fri, 8 Mar 2024 21:12:57 -0800 Subject: [PATCH 3/5] Update Cross Language CLient Code --- .../css/shared/bootstraps-overrides.scss | 4 - .../Client/src/pages/review.module.ts | 290 ++-- .../APIViewWeb/Client/src/pages/review.ts | 54 +- .../Helpers/LanguageServiceHelpers.cs | 5 - .../APIViewWeb/Helpers/PageModelHelpers.cs | 7 +- .../APIViewWeb/Pages/Assemblies/Review.cshtml | 1176 ++++++++--------- .../Pages/Assemblies/Review.cshtml.cs | 2 +- .../Pages/Assemblies/_CodeLine.cshtml | 2 +- .../Shared/_CrossLanguageViewPartial.cshtml | 24 +- .../Pages/Shared/_ReviewNavBar.cshtml | 37 - 10 files changed, 792 insertions(+), 809 deletions(-) delete mode 100644 src/dotnet/APIView/APIViewWeb/Pages/Shared/_ReviewNavBar.cshtml diff --git a/src/dotnet/APIView/APIViewWeb/Client/css/shared/bootstraps-overrides.scss b/src/dotnet/APIView/APIViewWeb/Client/css/shared/bootstraps-overrides.scss index 299be8a4037..eb4607eb5f4 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/css/shared/bootstraps-overrides.scss +++ b/src/dotnet/APIView/APIViewWeb/Client/css/shared/bootstraps-overrides.scss @@ -67,10 +67,6 @@ box-shadow: var(--box-shadow-link); } -.breadcrumb-item + .breadcrumb-item::before { - margin-top: 0.25rem; -} - .page-link { background-color: var(--base-fg-color); border: 1px solid var(--border-color); diff --git a/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.module.ts b/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.module.ts index aaf2f472e69..2d48bd8b664 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.module.ts +++ b/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.module.ts @@ -16,22 +16,22 @@ export function splitReviewPageContent() { const rl = $('#review-left'); const rr = $('#review-right'); - if (rl.length && rr.length) { - Split(['#review-left', '#review-right'], { - direction: 'horizontal', - sizes: [17, 83], - elementStyle: (dimension, size, gutterSize) => { - return { - 'flex-basis': `calc(${size}% - ${gutterSize}px` - } - }, - gutterStyle: (dimension, gutterSize) => { - return { - 'flex-basis': `${gutterSize}px` + if (rl.length && rr.length) { + Split(['#review-left', '#review-right'], { + direction: 'horizontal', + sizes: [17, 83], + elementStyle: (dimension, size, gutterSize) => { + return { + 'flex-basis': `calc(${size}% - ${gutterSize}px` + } + }, + gutterStyle: (dimension, gutterSize) => { + return { + 'flex-basis': `${gutterSize}px` + } } - } - }); - } + }); + } } //------------------------------------------------------------------------------------------------- @@ -587,160 +587,160 @@ export function addApprover(lowerTextSpan: HTMLElement, approvedByText: string, addApprovedBorder(); } addApproverHrefToApprovers(lowerTextSpan, approverHref, approver); -} + } -/** - * Removes the @approver from @lowerTextSpan of review page - * @param lowerTextSpan HTMLElement of the span that contains who approved the review or pending approval - * @param approver GitHub username of the review approver - * @param approvalPendingText string of approval pending text to use when removing the last approver - */ -export function removeApprover(lowerTextSpan: HTMLElement, approver: string, approvalPendingText: string) { - let children = lowerTextSpan.children; - let numApprovers = children.length; + /** + * Removes the @approver from @lowerTextSpan of review page + * @param lowerTextSpan HTMLElement of the span that contains who approved the review or pending approval + * @param approver GitHub username of the review approver + * @param approvalPendingText string of approval pending text to use when removing the last approver + */ + export function removeApprover(lowerTextSpan: HTMLElement, approver: string, approvalPendingText: string) { + let children = lowerTextSpan.children; + let numApprovers = children.length; - if (numApprovers > 1) { - removeApproverFromApproversList(children, approver); - } else { - lowerTextSpan.textContent = approvalPendingText; - removeApprovalBorder(); + if (numApprovers > 1) { + removeApproverFromApproversList(children, approver); + } else { + lowerTextSpan.textContent = approvalPendingText; + removeApprovalBorder(); + } } -} -/** - * adds the @approver with a hyperlink to their apiview profile to @lowerTextSpan - */ -export function addApproverHrefToApprovers(lowerTextSpan: HTMLElement, approverHref: string, approver: any) { - $(lowerTextSpan).append('' + approver + ''); -} + /** + * adds the @approver with a hyperlink to their apiview profile to @lowerTextSpan + */ + export function addApproverHrefToApprovers(lowerTextSpan: HTMLElement, approverHref: string, approver: any) { + $(lowerTextSpan).append('' + approver + ''); + } -/** - * adds the text above the approve button to indicate whether the current user approved the review - */ -export function addUpperTextSpan(approvesCurrentRevisionText: string) { - let $upperTextSpan = $("").text(approvesCurrentRevisionText).addClass("small text-muted"); - let $upperTextForm = $("ul#approveCollapse form.form-inline"); - $upperTextForm.prepend($upperTextSpan); -} + /** + * adds the text above the approve button to indicate whether the current user approved the review + */ + export function addUpperTextSpan(approvesCurrentRevisionText: string) { + let $upperTextSpan = $("").text(approvesCurrentRevisionText).addClass("small text-muted"); + let $upperTextForm = $("ul#approveCollapse form.form-inline"); + $upperTextForm.prepend($upperTextSpan); + } -/** - * change the button state from a green "not approved" to grey "approved" - */ -export function addButtonApproval() { - let $approveBtn = $("form.form-inline button.btn.btn-success"); - $approveBtn.removeClass("btn-success"); - $approveBtn.addClass("btn-outline-secondary"); - $approveBtn.text("Revert API Approval"); -} + /** + * change the button state from a green "not approved" to grey "approved" + */ + export function addButtonApproval() { + let $approveBtn = $("form.form-inline button.btn.btn-success"); + $approveBtn.removeClass("btn-success"); + $approveBtn.addClass("btn-outline-secondary"); + $approveBtn.text("Revert API Approval"); + } -/** - * change the button state from a grey "approved" to green "not approved" - */ -export function removeButtonApproval() { - let $approveBtn = $("form.form-inline button.btn.btn-outline-secondary"); - $approveBtn.removeClass("btn-outline-secondary"); - $approveBtn.addClass("btn-success"); - $approveBtn.text("Approve"); -} + /** + * change the button state from a grey "approved" to green "not approved" + */ + export function removeButtonApproval() { + let $approveBtn = $("form.form-inline button.btn.btn-outline-secondary"); + $approveBtn.removeClass("btn-outline-secondary"); + $approveBtn.addClass("btn-success"); + $approveBtn.text("Approve"); + } -/** - * change the review panel border state from grey "not approved" to green "approved" - */ -export function addApprovedBorder() { - let reviewLeft = $("#review-left"); - reviewLeft.addClass("review-approved"); - reviewLeft.removeClass("border"); - reviewLeft.removeClass("rounded-1"); + /** + * change the review panel border state from grey "not approved" to green "approved" + */ + export function addApprovedBorder() { + let reviewLeft = $("#review-left"); + reviewLeft.addClass("review-approved"); + reviewLeft.removeClass("border"); + reviewLeft.removeClass("rounded-1"); - let reviewRight = $("#review-right"); - reviewRight.addClass("review-approved"); - reviewRight.removeClass("border"); - reviewRight.removeClass("rounded-1"); -} + let reviewRight = $("#review-right"); + reviewRight.addClass("review-approved"); + reviewRight.removeClass("border"); + reviewRight.removeClass("rounded-1"); + } -/** - * change the review panel border state from green "approved" to grey "not approved" - */ -export function removeApprovalBorder() { - let $reviewLeft = $("#review-left"); - $reviewLeft.removeClass("review-approved"); - $reviewLeft.addClass("border"); - $reviewLeft.addClass("rounded-1"); + /** + * change the review panel border state from green "approved" to grey "not approved" + */ + export function removeApprovalBorder() { + let $reviewLeft = $("#review-left"); + $reviewLeft.removeClass("review-approved"); + $reviewLeft.addClass("border"); + $reviewLeft.addClass("rounded-1"); - let $reviewRight = $("#review-right"); - $reviewRight.removeClass("review-approved"); - $reviewRight.addClass("border"); - $reviewRight.addClass("rounded-1"); -} + let $reviewRight = $("#review-right"); + $reviewRight.removeClass("review-approved"); + $reviewRight.addClass("border"); + $reviewRight.addClass("rounded-1"); + } -/** - * parse the approval spans for its existence and order - * @param $approvalSpans may contain , , and/or - * @param approvedByText string for that indicates preexisting approvers - * @param approvalPendingText string for that indicates no current approvers - * @param approvesCurrentRevisionText string for that indicates the current user did not approve - * @returns a dictionary with the index of the upper and lower text elements. Value is -1 if an element does not exist. - */ -export function parseApprovalSpanIndex($approvalSpans: JQuery, approvedByText: string, approvalPendingText: string, approvesCurrentRevisionText: string) { - let indexResult = { - "approvers": -1, - "upperText": -1, - }; + /** + * parse the approval spans for its existence and order + * @param $approvalSpans may contain , , and/or + * @param approvedByText string for that indicates preexisting approvers + * @param approvalPendingText string for that indicates no current approvers + * @param approvesCurrentRevisionText string for that indicates the current user did not approve + * @returns a dictionary with the index of the upper and lower text elements. Value is -1 if an element does not exist. + */ + export function parseApprovalSpanIndex($approvalSpans: JQuery, approvedByText: string, approvalPendingText: string, approvesCurrentRevisionText: string) { + let indexResult = { + "approvers": -1, + "upperText": -1, + }; - for (var i = 0; i < $approvalSpans.length; i++) { - let content = $approvalSpans[i].textContent; + for (var i = 0; i < $approvalSpans.length; i++) { + let content = $approvalSpans[i].textContent; - if (!content) { - return indexResult; + if (!content) { + return indexResult; + } + + if (content.includes(approvedByText) || content.includes(approvalPendingText)) { + indexResult["approvers"] = i; + } + if (content.includes(approvesCurrentRevisionText)) { + indexResult["upperText"] = i; + } } - if (content.includes(approvedByText) || content.includes(approvalPendingText)) { - indexResult["approvers"] = i; - } - if (content.includes(approvesCurrentRevisionText)) { - indexResult["upperText"] = i; - } + return indexResult; } - return indexResult; -} - -/** - * call when the current user approves the current review. removes the upper text - * @param upperTextIndex index of the upper text in @$approvalSpans - * @param $approvalSpans span that includes revision approval block - */ -export function removeUpperTextSpan(upperTextIndex: number, $approvalSpans: JQuery) { - if (upperTextIndex !== -1) { - let upperTextSpan: HTMLElement = $approvalSpans[upperTextIndex]; - upperTextSpan.remove(); + /** + * call when the current user approves the current review. removes the upper text + * @param upperTextIndex index of the upper text in @$approvalSpans + * @param $approvalSpans span that includes revision approval block + */ + export function removeUpperTextSpan(upperTextIndex: number, $approvalSpans: JQuery) { + if (upperTextIndex !== -1) { + let upperTextSpan: HTMLElement = $approvalSpans[upperTextIndex]; + upperTextSpan.remove(); + } } -} -/** - * remove the @approver from list of @approvers - * @param approvers list of preexisting approvers - * @param approver GitHub username of user to remove from the list - */ -export function removeApproverFromApproversList(approvers, approver) { - for (var i = 0; i < approvers.length; i++) { - if (approvers[i].innerHTML === approver) { - if (i === 0) { - approvers[i].nextSibling?.remove(); - } else { - approvers[i].previousSibling?.remove(); + /** + * remove the @approver from list of @approvers + * @param approvers list of preexisting approvers + * @param approver GitHub username of user to remove from the list + */ + export function removeApproverFromApproversList(approvers, approver) { + for (var i = 0; i < approvers.length; i++) { + if (approvers[i].innerHTML === approver) { + if (i === 0) { + approvers[i].nextSibling?.remove(); + } else { + approvers[i].previousSibling?.remove(); + } + approvers[i].remove(); + break; } - approvers[i].remove(); - break; } } -} -/** + /** * Add event handler for cross language panel button */ export function addCrossLaguageCloseBtnHandler() { - $(".cross-language-panel .btn-close").on("click", function (e: JQuery.ClickEvent) { - $(this).closest(".cross-language-panel").addClass("d-none"); - }); -} + $(".cross-language-panel .btn-close").on("click", function (e: JQuery.ClickEvent) { + $(this).closest(".cross-language-panel").addClass("d-none"); + }); + } diff --git a/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.ts b/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.ts index b64572a3651..cbd29d3f335 100644 --- a/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.ts +++ b/src/dotnet/APIView/APIViewWeb/Client/src/pages/review.ts @@ -1,3 +1,4 @@ + import { rightOffCanvasNavToggle } from "../shared/off-canvas"; import * as rvM from "./review.module" @@ -162,6 +163,7 @@ $(() => { $(this).get(0).scrollIntoView({ block: "center"}); }); + /* BUTTON FOR REQUEST REVIEW (CHANGES BETWEEN REQUEST ALL AND REQUEST SELECTED IN THE REQUEST APPROVAL SECTION) --------------------------------------------------------------------------------------------------------------------------------------------------------*/ $('.selectReviewerForRequest').on("click", function () { @@ -220,7 +222,7 @@ $(() => { // Manage Expand / Collapse State of options [$("#approveCollapse"), $("#requestReviewersCollapse"), $("#reviewOptionsCollapse"), $("#pageSettingsCollapse"), - $("#associatedPRCollapse"), $("#associatedReviewsCollapse"), $("#generateAIReviewCollapse"), $("#crossLangReviewCollapse")].forEach(function (value, index) { + $("#associatedPRCollapse"), $("#associatedReviewsCollapse"), $("#generateAIReviewCollapse")].forEach(function (value, index) { const id = value.attr("id"); value.on('hidden.bs.collapse', function () { document.cookie = `${id}=hidden; max-age=${7 * 24 * 60 * 60}`; @@ -282,30 +284,56 @@ $(() => { const clTabs = crossLangPanel.find('[id^="cross-lang-pills-tab"]'); const clPills = crossLangPanel.find('[id^="cross-lang-pills-content-"]'); const randomizer = Date.now().toString(36); + const activeLanguage = sessionStorage.getItem("activeCrossLanguageTab") ?? ""; + + console.log("activeLanguage o%", activeLanguage); clTabs.each(function (index, value) { - const tbId = $(value).attr("id") + randomizer; - const tbTarget = $(value).attr("data-bs-target") + randomizer; - const tbAria = $(value).attr("aria-controls") + randomizer; - $(value).attr("id", tbId); - $(value).attr("data-bs-target", tbTarget); - $(value).attr("aria-controls", tbAria); + let tbId = $(value).attr("id")!; + const tbTarget = $(value).attr("data-bs-target")!; + const tbAria = $(value).attr("aria-controls")!; + + if (activeLanguage){ + if (tbId.includes(activeLanguage)){ + $(value).addClass("active"); + } + } + else if (index == 0) { + $(value).addClass("active"); + } + $(value).attr("id", `${tbId}-${randomizer}`); + $(value).attr("data-bs-target", `${tbTarget}-${randomizer}`); + $(value).attr("aria-controls", `${tbAria}-${randomizer}`); + $(value).on('shown.bs.tab', event => { + let activeLanguage = $(this).attr("id")!.split('-').at(-2)!; + sessionStorage.setItem("activeCrossLanguageTab", activeLanguage); + }) }); clPills.each(function (index, value) { - const pillId = $(value).attr("id"); + const pillId = $(value).attr("id")!; const pillIdParts = pillId?.split('-'); const pillLang = pillIdParts![pillIdParts!.length - 1]; - const pillLabel = $(value).attr("aria-labelledby") + randomizer; + const pillLabel = $(value).attr("aria-labelledby"); const crossLangContent = crossLangCodeLines.get(pillLang); - $(value).attr("id", (pillId + randomizer)); - $(value).attr("aria-labelledby", pillLabel); + + if (activeLanguage){ + if (pillId.includes(activeLanguage)){ + $(value).addClass("active"); + } + } + else if (index == 0) { + $(value).addClass("active"); + } + + $(value).attr("id", `${pillId}-${randomizer}`); + $(value).attr("aria-labelledby", `${pillLabel}-${randomizer}`); if (crossLangContent && crossLangContent.length > 0) { showPanel = true; - $(value).html(crossLangContent); + $(value).find("div").html(crossLangContent); const comments = crossLangContent.find(".review-comment"); if (comments.length > 0) { - crossLangPanel.find(`#cross-lang-pills-tab-${pillLang}${randomizer}`)[0].innerHTML += `${comments.length}`; + crossLangPanel.find(`#cross-lang-pills-tab-${pillLang}-${randomizer}`)[0].innerHTML += `${comments.length}`; } } }); diff --git a/src/dotnet/APIView/APIViewWeb/Helpers/LanguageServiceHelpers.cs b/src/dotnet/APIView/APIViewWeb/Helpers/LanguageServiceHelpers.cs index 4c13820b2ad..74f22021d46 100644 --- a/src/dotnet/APIView/APIViewWeb/Helpers/LanguageServiceHelpers.cs +++ b/src/dotnet/APIView/APIViewWeb/Helpers/LanguageServiceHelpers.cs @@ -1,10 +1,5 @@ using System.Collections.Generic; using System.Linq; -using APIViewWeb.LeanModels; -using Microsoft.AspNetCore.Http; -using Microsoft.Azure.Cosmos.Serialization.HybridRow; -using Microsoft.Identity.Client; -using Microsoft.VisualStudio.Services.Common; namespace APIViewWeb.Helpers { diff --git a/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs b/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs index cafc6c5d2a6..0cd4f134e82 100644 --- a/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs +++ b/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs @@ -541,11 +541,8 @@ public static async Task UploadAPIRevisionAsync(IAPIRe /// public static bool IsAPIStubHeader(string content) { - if (content.Contains(">model<") || content.Contains(">enum<") || content.Contains(">alias<")) - { - return true; - } - return false; + List apiStubHEaders = new List { ">model<", ">enum<", ">alias<", ">module<", ">package<", ">class<", ">interface<", ">def<" }; + return apiStubHEaders.Any(content.Contains); } /// /// Create DiffOnly Lines diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml index 32d16a1d56b..e7360d7804b 100644 --- a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml +++ b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml @@ -1,588 +1,588 @@ -@page "{id}/{revisionId?}" -@model APIViewWeb.Pages.Assemblies.ReviewPageModel -@using APIViewWeb.Helpers -@using APIViewWeb.LeanModels; -@using APIViewWeb.Models -@{ - Layout = "Shared/_Layout"; - ViewData["Title"] = Model.ReviewContent.Review.PackageName; - var userPreference = PageModelHelpers.GetUserPreference(Model._preferenceCache, User); - TempData["UserPreference"] = userPreference; - TempData["LanguageCssSafeName"] = PageModelHelpers.GetLanguageCssSafeName(Model.ReviewContent.Review.Language); - TempData["Comments"] = Model.Comments; - ViewBag.HasSections = Model.ReviewContent.PageHasLoadableSections; -} -@{ - var rightOffCanvasClass = " show-right-offcanvas"; - var leftOffCanvasClass = " show-left-offcanvas"; - var mainContainerLeftClass = " move-main-content-container-left"; - var mainContainerRightClass = " move-main-content-container-right"; - if (userPreference.HideReviewPageOptions.HasValue && userPreference.HideReviewPageOptions == true) - { - rightOffCanvasClass = String.Empty; - mainContainerRightClass = String.Empty; - } - var mainContainerClass = mainContainerLeftClass + mainContainerRightClass; -} - - -
-
-

- Approval   -

- @{ - var approvalCollapseState = " show"; - if (Request.Cookies.ContainsKey("approveCollapse")) - { - if (!Request.Cookies["approveCollapse"].Equals("shown")) - approvalCollapseState = String.Empty; - } - } -
    -
  • -
    - - @if (Model.ReviewContent.DiffAPIRevision == null || Model.ReviewContent.DiffAPIRevision.Approvers.Any()) - { - @if (Model.ReviewContent.ActiveAPIRevision.Approvers.Contains(User.GetGitHubLogin())) - { -
    - -
    - } - else - { - var isActiveRevisionAhead = (Model.ReviewContent.DiffAPIRevision == null)? true: Model.ReviewContent.ActiveAPIRevision.CreatedOn > Model.ReviewContent.DiffAPIRevision.CreatedOn; - @if ((Model.ReviewContent.ActiveConversationsInActiveAPIRevision > 0 - || Model.ReviewContent.ActiveConversationsInSampleRevisions > 0) - && Model.ReviewContent.PreferredApprovers.Contains(User.GetGitHubLogin()) - && isActiveRevisionAhead) - { - Approves the current revision of the API -
    - -
    - } - else - { - @if (Model.ReviewContent.PreferredApprovers.Contains(User.GetGitHubLogin()) - && isActiveRevisionAhead) - { - Approves the current revision of the API -
    - -
    - } - else - { -
    - -
    - } - } - } - } - else - { - @if (Model.ReviewContent.ActiveAPIRevision.Approvers.Contains(User.GetGitHubLogin())) - { -
    - -
    - } - else - { -
    - -
    - } - } -
    - @{ - var approvers = Model.ReviewContent.ActiveAPIRevision.Approvers; - @if (approvers.Count() > 0) - { - - Approved by: - @{ - int i = 0; - } - @foreach (var approver in approvers) - { - @approver - @if (i < (approvers.Count() - 1)) - { - @Html.Raw(", ") - ; - } - i++; - } - - } - else - { - Current Revision Approval Pending - } - } -
  • - @if (Model.ReviewContent.ActiveAPIRevision.PackageName != null && - !(LanguageServiceHelpers.MapLanguageAliases(new List { "Swagger", "TypeSpec" })).Contains(Model.ReviewContent.Review.Language)) - { - var reviewIsApproved = Model.ReviewContent.Review.IsApproved; - string approver = null; - if (reviewIsApproved) - { - var changeAction = Model.ReviewContent.Review.ChangeHistory.First(_ => _.ChangeAction == ReviewChangeAction.Approved); - if (changeAction != null) - { - approver = changeAction.ChangedBy; - } - else - { - approver = "azure-sdk"; - } - } - - @if (!reviewIsApproved) - { -
  • -
    - - Approves First Release of the package -
    - -
    -
    - First Revision Approval Pending -
  • - } - else - { -
  • - @if (approver != null) - { - Package has been approved for first release by @approver - } - else - { - Package has been approved for first release - } -
  • - } - } -
- @* Enables Button for generating AI Review - -

- Generate AI Review   -

- var generateAIReviewCollapseState = String.Empty; - if (Request.Cookies.ContainsKey("generateAIReviewCollapse")) - { - if (Request.Cookies["generateAIReviewCollapse"].Equals("shown")) - generateAIReviewCollapseState = " show"; - } -
    -
    - -
    -
- *@ -

- Request Reviewers   -

- @{ - var requestReviewersCollapseState = String.Empty; - if (Request.Cookies.ContainsKey("requestReviewersCollapse")) - { - if (Request.Cookies["requestReviewersCollapse"].Equals("shown")) - requestReviewersCollapseState = " show"; - } - } -
    - @{ - var anyChecked = false; - } -
    - -
  • -
      - @foreach (var approver in Model.ReviewContent.PreferredApprovers) - { -
    • -
      - @if (Model.ReviewContent.ActiveAPIRevision.AssignedReviewers != null && Model.ReviewContent.ActiveAPIRevision.AssignedReviewers.Where(a => a.AssingedTo == approver).Any()) - { - - - anyChecked = true; - } - else - { - - - } -
      -
    • - } -
    -
  • - - @if (anyChecked) - { - - } - else - { - - } - - -
  • -
    -
- @if (Model.ReviewContent.ActiveAPIRevision.APIRevisionType == APIRevisionType.PullRequest) - { - var associatedPRs = await Model.GetAssociatedPullRequest(); - @if (associatedPRs != null && associatedPRs.Count() > 0) - { - var associatedPRState = String.Empty; - if (Request.Cookies.ContainsKey("associatedPRCollapse")) - { - if (Request.Cookies["associatedPRCollapse"].Equals("shown")) - associatedPRState = " show"; - } -

- Associated Pull Requests   -

-
    - @foreach (var prModel in associatedPRs) - { - var url = $"https://github.com/{prModel.RepoName}/pull/{prModel.PullRequestNumber}"; - var txt = $"{prModel.RepoName}/{prModel.PullRequestNumber}"; -
  • - @txt -
  • - } -
- } - } - @if (Model.ReviewContent.ActiveAPIRevision.APIRevisionType == APIRevisionType.PullRequest) - { - var prsOfAssociatedAPIRevisions = await Model.GetPRsOfAssoicatedReviews(); - @if (prsOfAssociatedAPIRevisions != null && prsOfAssociatedAPIRevisions.Count() > 1) - { - var associatedReviewsState = String.Empty; - if (Request.Cookies.ContainsKey("associatedReviewsCollapse")) - { - if (Request.Cookies["associatedReviewsCollapse"].Equals("shown")) - associatedReviewsState = " show"; - } -

- Associated APIRevisions   -

-
    - @foreach (var pr in prsOfAssociatedAPIRevisions) - { - if (pr.ReviewId != Model.ReviewContent.Review.Id) - { - var url = @Url.ActionLink("Review", "Assemblies", new - { - id = pr.ReviewId, - revisionId = pr.APIRevisionId - }); -
  • - @pr.Language/@pr.PackageName -
  • - } - } -
- } - } -

- Review Options   -

- @{ - var reviewOptionsCollapseState = " show"; - if (Request.Cookies.ContainsKey("reviewOptionsCollapse")) - { - if (!Request.Cookies["reviewOptionsCollapse"].Equals("shown")) - reviewOptionsCollapseState = String.Empty; - } - } -
    -
  • -
    -
    - @if (PageModelHelpers.GetUserEmail(User) != null) - { - if (PageModelHelpers.IsUserSubscribed(User, Model.ReviewContent.Review.Subscribers)) - { - - } - else - { - - } - } - else - { - - } - -
    -
    -
  • -
-

- Page Settings   -

- @{ - var pageSettingsCollapseState = String.Empty; - if (Request.Cookies.ContainsKey("pageSettingsCollapse")) - { - if (Request.Cookies["pageSettingsCollapse"].Equals("shown")) - pageSettingsCollapseState = " show"; - } - } -
    -
  • -
    - @if (userPreference.ShowComments == true) - { - - } - else - { - - } - -
    -
  • -
  • -
    - @if (userPreference.ShowSystemComments == true) - { - - } - else - { - - } - -
    -
  • -
  • -
    - @if (Model.ShowDocumentation) - { - - } - else - { - - } - - - -
    -
  • -
  • -
    - @if (userPreference.ShowHiddenApis == true) - { - - } - else - { - - } - -
    -
  • -
  • -
    - @if (userPreference.HideLineNumbers == true) - { - - } - else - { - - } - -
    -
  • -
  • -
    - @if (userPreference.HideLeftNavigation == true) - { - - } - else - { - - } - -
    -
  • - @if (!String.IsNullOrEmpty(Model.DiffRevisionId) && Model.ReviewContent.Review.Language != "Swagger") - { -
  • -
    - @if (Model.ShowDiffOnly) - { - - } - else - { - - } - - - -
    -
  • - } -
-
-
- -
-
- -
-
- -
-
- @{ - var reviewLeftDisplay = String.Empty; - var reviewRightSize = "10"; - if (userPreference.HideLeftNavigation == true) - { - reviewLeftDisplay = "d-none"; - reviewRightSize = "12"; - } - - var reviewApprovedClass = (Model.ReviewContent.ActiveAPIRevision.Approvers.Count() > 0) ? "review-approved" : "border rounded-1"; - } -
-
-
- @if (Model.ReviewContent.Navigation != null) - { - - } -
-
-
- -
- @if (!string.IsNullOrEmpty(Model.NotificationMessage)) - { - - } - - - @foreach (var line in Model.ReviewContent.codeLines) - { - - } - -
- -
-
- @if (Model.ReviewContent.CrossLanguageViewContent.Any()) - { -
- @foreach (var language in Model.ReviewContent.CrossLanguageViewContent.Keys) - { - var reviewcontent = Model.ReviewContent.CrossLanguageViewContent[language]; - var langId = PageModelHelpers.GetLanguageCssSafeName(language); - - - @foreach (var line in reviewcontent.codeLines) - { - - } - -
- } -
- } -
- - -
- -
- - - -
-
-
Revisions
- -
-
- -
-
+@page "{id}/{revisionId?}" +@model APIViewWeb.Pages.Assemblies.ReviewPageModel +@using APIViewWeb.Helpers +@using APIViewWeb.LeanModels; +@using APIViewWeb.Models +@{ + Layout = "Shared/_Layout"; + ViewData["Title"] = Model.ReviewContent.Review.PackageName; + var userPreference = PageModelHelpers.GetUserPreference(Model._preferenceCache, User); + TempData["UserPreference"] = userPreference; + TempData["LanguageCssSafeName"] = PageModelHelpers.GetLanguageCssSafeName(Model.ReviewContent.Review.Language); + TempData["Comments"] = Model.Comments; + ViewBag.HasSections = Model.ReviewContent.PageHasLoadableSections; +} +@{ + var rightOffCanvasClass = " show-right-offcanvas"; + var leftOffCanvasClass = " show-left-offcanvas"; + var mainContainerLeftClass = " move-main-content-container-left"; + var mainContainerRightClass = " move-main-content-container-right"; + if (userPreference.HideReviewPageOptions.HasValue && userPreference.HideReviewPageOptions == true) + { + rightOffCanvasClass = String.Empty; + mainContainerRightClass = String.Empty; + } + var mainContainerClass = mainContainerLeftClass + mainContainerRightClass; +} + + +
+
+

+ Approval   +

+ @{ + var approvalCollapseState = " show"; + if (Request.Cookies.ContainsKey("approveCollapse")) + { + if (!Request.Cookies["approveCollapse"].Equals("shown")) + approvalCollapseState = String.Empty; + } + } +
    +
  • +
    + + @if (Model.ReviewContent.DiffAPIRevision == null || Model.ReviewContent.DiffAPIRevision.Approvers.Any()) + { + @if (Model.ReviewContent.ActiveAPIRevision.Approvers.Contains(User.GetGitHubLogin())) + { +
    + +
    + } + else + { + var isActiveRevisionAhead = (Model.ReviewContent.DiffAPIRevision == null)? true: Model.ReviewContent.ActiveAPIRevision.CreatedOn > Model.ReviewContent.DiffAPIRevision.CreatedOn; + @if ((Model.ReviewContent.ActiveConversationsInActiveAPIRevision > 0 + || Model.ReviewContent.ActiveConversationsInSampleRevisions > 0) + && Model.ReviewContent.PreferredApprovers.Contains(User.GetGitHubLogin()) + && isActiveRevisionAhead) + { + Approves the current revision of the API +
    + +
    + } + else + { + @if (Model.ReviewContent.PreferredApprovers.Contains(User.GetGitHubLogin()) + && isActiveRevisionAhead) + { + Approves the current revision of the API +
    + +
    + } + else + { +
    + +
    + } + } + } + } + else + { + @if (Model.ReviewContent.ActiveAPIRevision.Approvers.Contains(User.GetGitHubLogin())) + { +
    + +
    + } + else + { +
    + +
    + } + } +
    + @{ + var approvers = Model.ReviewContent.ActiveAPIRevision.Approvers; + @if (approvers.Count() > 0) + { + + Approved by: + @{ + int i = 0; + } + @foreach (var approver in approvers) + { + @approver + @if (i < (approvers.Count() - 1)) + { + @Html.Raw(", ") + ; + } + i++; + } + + } + else + { + Current Revision Approval Pending + } + } +
  • + @if (Model.ReviewContent.ActiveAPIRevision.PackageName != null && + !(LanguageServiceHelpers.MapLanguageAliases(new List { "Swagger", "TypeSpec" })).Contains(Model.ReviewContent.Review.Language)) + { + var reviewIsApproved = Model.ReviewContent.Review.IsApproved; + string approver = null; + if (reviewIsApproved) + { + var changeAction = Model.ReviewContent.Review.ChangeHistory.First(_ => _.ChangeAction == ReviewChangeAction.Approved); + if (changeAction != null) + { + approver = changeAction.ChangedBy; + } + else + { + approver = "azure-sdk"; + } + } + + @if (!reviewIsApproved) + { +
  • +
    + + Approves First Release of the package +
    + +
    +
    + First Revision Approval Pending +
  • + } + else + { +
  • + @if (approver != null) + { + Package has been approved for first release by @approver + } + else + { + Package has been approved for first release + } +
  • + } + } +
+ @* Enables Button for generating AI Review + +

+ Generate AI Review   +

+ var generateAIReviewCollapseState = String.Empty; + if (Request.Cookies.ContainsKey("generateAIReviewCollapse")) + { + if (Request.Cookies["generateAIReviewCollapse"].Equals("shown")) + generateAIReviewCollapseState = " show"; + } +
    +
    + +
    +
+ *@ +

+ Request Reviewers   +

+ @{ + var requestReviewersCollapseState = String.Empty; + if (Request.Cookies.ContainsKey("requestReviewersCollapse")) + { + if (Request.Cookies["requestReviewersCollapse"].Equals("shown")) + requestReviewersCollapseState = " show"; + } + } +
    + @{ + var anyChecked = false; + } +
    + +
  • +
      + @foreach (var approver in Model.ReviewContent.PreferredApprovers) + { +
    • +
      + @if (Model.ReviewContent.ActiveAPIRevision.AssignedReviewers != null && Model.ReviewContent.ActiveAPIRevision.AssignedReviewers.Where(a => a.AssingedTo == approver).Any()) + { + + + anyChecked = true; + } + else + { + + + } +
      +
    • + } +
    +
  • + + @if (anyChecked) + { + + } + else + { + + } + + +
  • +
    +
+ @if (Model.ReviewContent.ActiveAPIRevision.APIRevisionType == APIRevisionType.PullRequest) + { + var associatedPRs = await Model.GetAssociatedPullRequest(); + @if (associatedPRs != null && associatedPRs.Count() > 0) + { + var associatedPRState = String.Empty; + if (Request.Cookies.ContainsKey("associatedPRCollapse")) + { + if (Request.Cookies["associatedPRCollapse"].Equals("shown")) + associatedPRState = " show"; + } +

+ Associated Pull Requests   +

+
    + @foreach (var prModel in associatedPRs) + { + var url = $"https://github.com/{prModel.RepoName}/pull/{prModel.PullRequestNumber}"; + var txt = $"{prModel.RepoName}/{prModel.PullRequestNumber}"; +
  • + @txt +
  • + } +
+ } + } + @if (Model.ReviewContent.ActiveAPIRevision.APIRevisionType == APIRevisionType.PullRequest) + { + var prsOfAssociatedAPIRevisions = await Model.GetPRsOfAssoicatedReviews(); + @if (prsOfAssociatedAPIRevisions != null && prsOfAssociatedAPIRevisions.Count() > 1) + { + var associatedReviewsState = String.Empty; + if (Request.Cookies.ContainsKey("associatedReviewsCollapse")) + { + if (Request.Cookies["associatedReviewsCollapse"].Equals("shown")) + associatedReviewsState = " show"; + } +

+ Associated APIRevisions   +

+
    + @foreach (var pr in prsOfAssociatedAPIRevisions) + { + if (pr.ReviewId != Model.ReviewContent.Review.Id) + { + var url = @Url.ActionLink("Review", "Assemblies", new + { + id = pr.ReviewId, + revisionId = pr.APIRevisionId + }); +
  • + @pr.Language/@pr.PackageName +
  • + } + } +
+ } + } +

+ Review Options   +

+ @{ + var reviewOptionsCollapseState = " show"; + if (Request.Cookies.ContainsKey("reviewOptionsCollapse")) + { + if (!Request.Cookies["reviewOptionsCollapse"].Equals("shown")) + reviewOptionsCollapseState = String.Empty; + } + } +
    +
  • +
    +
    + @if (PageModelHelpers.GetUserEmail(User) != null) + { + if (PageModelHelpers.IsUserSubscribed(User, Model.ReviewContent.Review.Subscribers)) + { + + } + else + { + + } + } + else + { + + } + +
    +
    +
  • +
+

+ Page Settings   +

+ @{ + var pageSettingsCollapseState = String.Empty; + if (Request.Cookies.ContainsKey("pageSettingsCollapse")) + { + if (Request.Cookies["pageSettingsCollapse"].Equals("shown")) + pageSettingsCollapseState = " show"; + } + } +
    +
  • +
    + @if (userPreference.ShowComments == true) + { + + } + else + { + + } + +
    +
  • +
  • +
    + @if (userPreference.ShowSystemComments == true) + { + + } + else + { + + } + +
    +
  • +
  • +
    + @if (Model.ShowDocumentation) + { + + } + else + { + + } + + + +
    +
  • +
  • +
    + @if (userPreference.ShowHiddenApis == true) + { + + } + else + { + + } + +
    +
  • +
  • +
    + @if (userPreference.HideLineNumbers == true) + { + + } + else + { + + } + +
    +
  • +
  • +
    + @if (userPreference.HideLeftNavigation == true) + { + + } + else + { + + } + +
    +
  • + @if (!String.IsNullOrEmpty(Model.DiffRevisionId) && Model.ReviewContent.Review.Language != "Swagger") + { +
  • +
    + @if (Model.ShowDiffOnly) + { + + } + else + { + + } + + + +
    +
  • + } +
+
+
+ +
+
+ +
+
+ +
+
+ @{ + var reviewLeftDisplay = String.Empty; + var reviewRightSize = "10"; + if (userPreference.HideLeftNavigation == true) + { + reviewLeftDisplay = "d-none"; + reviewRightSize = "12"; + } + + var reviewApprovedClass = (Model.ReviewContent.ActiveAPIRevision.Approvers.Count() > 0) ? "review-approved" : "border rounded-1"; + } +
+
+
+ @if (Model.ReviewContent.Navigation != null) + { + + } +
+
+
+ +
+ @if (!string.IsNullOrEmpty(Model.NotificationMessage)) + { + + } + + + @foreach (var line in Model.ReviewContent.codeLines) + { + + } + +
+ +
+
+ @if (Model.ReviewContent.CrossLanguageViewContent.Any()) + { +
+ @foreach (var language in Model.ReviewContent.CrossLanguageViewContent.Keys) + { + var reviewcontent = Model.ReviewContent.CrossLanguageViewContent[language]; + var langId = PageModelHelpers.GetLanguageCssSafeName(language); + + + @foreach (var line in reviewcontent.codeLines) + { + + } + +
+ } +
+ } + +
+ + +
+ +
+ + + +
+
+
Revisions
+ +
+
+ +
+
\ No newline at end of file diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml.cs b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml.cs index beb42141e44..7eebe36841f 100644 --- a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml.cs +++ b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/Review.cshtml.cs @@ -93,7 +93,7 @@ public async Task OnGetAsync(string id, string revisionId = null) if (!String.IsNullOrEmpty(ReviewContent.ActiveAPIRevision.Files.First().CrossLanguagePackageId)) { var correspondingReviewId = await _apiRevisionsManager.GetReviewIdsOfLanguageCorrespondingReviewAsync(ReviewContent.ActiveAPIRevision.Files.First().CrossLanguagePackageId); - var correspondingReviews = await _reviewManager.GetReviewsAsync(reviewIds: correspondingReviewId, isClosed: false); + var correspondingReviews = await _reviewManager.GetReviewsAsync(reviewIds: correspondingReviewId.Where(_ => _ != id).ToList(), isClosed: false); foreach (var review in correspondingReviews) { var reviewContent = await PageModelHelpers.GetReviewContentAsync(configuration: _configuration, diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/_CodeLine.cshtml b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/_CodeLine.cshtml index 2ffe64b8072..e6398b27755 100644 --- a/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/_CodeLine.cshtml +++ b/src/dotnet/APIView/APIViewWeb/Pages/Assemblies/_CodeLine.cshtml @@ -98,7 +98,7 @@ "; } } - cellContent += Model.CodeLine.DisplayString; + cellContent += Model.CodeLine.DisplayString.Replace(' ', '\u00A0'); } diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Shared/_CrossLanguageViewPartial.cshtml b/src/dotnet/APIView/APIViewWeb/Pages/Shared/_CrossLanguageViewPartial.cshtml index e7733f3436d..ed54cb55c47 100644 --- a/src/dotnet/APIView/APIViewWeb/Pages/Shared/_CrossLanguageViewPartial.cshtml +++ b/src/dotnet/APIView/APIViewWeb/Pages/Shared/_CrossLanguageViewPartial.cshtml @@ -1,28 +1,32 @@ @using APIViewWeb.Helpers -@model IEnumerable +@using APIViewWeb.LeanModels +@model Dictionary
- @foreach (var language in Model) + @foreach (var item in Model) { - var activeClass = (Model.ElementAt(0) == language) ? "active" : ""; - var lang = PageModelHelpers.GetLanguageCssSafeName(language); -
- @language Content + var lang = PageModelHelpers.GetLanguageCssSafeName(item.Key); +
+
+   No @item.Key Cross Language Content +
+ + @item.Value.ActiveAPIRevision.Language/@item.Value.ActiveAPIRevision.PackageName +
}
diff --git a/src/dotnet/APIView/APIViewWeb/Pages/Shared/_ReviewNavBar.cshtml b/src/dotnet/APIView/APIViewWeb/Pages/Shared/_ReviewNavBar.cshtml deleted file mode 100644 index e28b5ed2648..00000000000 --- a/src/dotnet/APIView/APIViewWeb/Pages/Shared/_ReviewNavBar.cshtml +++ /dev/null @@ -1,37 +0,0 @@ -@using APIViewWeb.Helpers -@using APIViewWeb.Models -@{ - var id = ViewContext.RouteData.Values["id"]; - var userPreference = TempData["UserPreference"] as UserPreferenceModel; -} - -
- -
\ No newline at end of file From fbb0531aee4199d9ddf002aadaecad53e1c33c5e Mon Sep 17 00:00:00 2001 From: Praven Kuttappan <55455725+praveenkuttappan@users.noreply.github.com> Date: Mon, 11 Mar 2024 13:34:12 -0400 Subject: [PATCH 4/5] Update src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs --- src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs b/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs index 0cd4f134e82..60eb6e940b8 100644 --- a/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs +++ b/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs @@ -535,7 +535,7 @@ public static async Task UploadAPIRevisionAsync(IAPIRe } } - /// Deside if the content of the API is the header or content + /// Decide if the content of the API is the header or content /// /// /// From ae0706ab23c51ae5d146258053f81012374c224c Mon Sep 17 00:00:00 2001 From: Praven Kuttappan <55455725+praveenkuttappan@users.noreply.github.com> Date: Mon, 11 Mar 2024 14:17:47 -0400 Subject: [PATCH 5/5] Update src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs --- src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs b/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs index 60eb6e940b8..5d241c498f7 100644 --- a/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs +++ b/src/dotnet/APIView/APIViewWeb/Helpers/PageModelHelpers.cs @@ -535,6 +535,7 @@ public static async Task UploadAPIRevisionAsync(IAPIRe } } + /// /// Decide if the content of the API is the header or content /// ///